blob: 76ab61d5b688f39986dae72f7bc832fd88c91008 [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 tarreau598da412005-12-18 01:07:29 +010084#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010085
willy tarreau065f1c02006-01-29 22:10:07 +010086#define HAPROXY_VERSION "1.2.8"
87#define HAPROXY_DATE "2006/01/29"
willy tarreau0f7af912005-12-17 12:21:26 +010088
89/* this is for libc5 for example */
90#ifndef TCP_NODELAY
91#define TCP_NODELAY 1
92#endif
93
94#ifndef SHUT_RD
95#define SHUT_RD 0
96#endif
97
98#ifndef SHUT_WR
99#define SHUT_WR 1
100#endif
101
willy tarreau0174f312005-12-18 01:02:42 +0100102/*
103 * BUFSIZE defines the size of a read and write buffer. It is the maximum
104 * amount of bytes which can be stored by the proxy for each session. However,
105 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
106 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
107 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
108 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
109 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
110 */
111#ifndef BUFSIZE
112#define BUFSIZE 16384
113#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100114
115// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100116#ifndef MAXREWRITE
117#define MAXREWRITE (BUFSIZE / 2)
118#endif
119
willy tarreau9fe663a2005-12-17 13:02:59 +0100120#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100121#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100122
willy tarreau5cbea6f2005-12-17 12:48:26 +0100123// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100124#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100125
willy tarreaue39cd132005-12-17 13:00:18 +0100126// max # of added headers per request
127#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100128
129// max # of matches per regexp
130#define MAX_MATCH 10
131
willy tarreau0174f312005-12-18 01:02:42 +0100132// cookie delimitor in "prefix" mode. This character is inserted between the
133// persistence cookie and the original value. The '~' is allowed by RFC2965,
134// and should not be too common in server names.
135#ifndef COOKIE_DELIM
136#define COOKIE_DELIM '~'
137#endif
138
willy tarreau0f7af912005-12-17 12:21:26 +0100139#define CONN_RETRIES 3
140
willy tarreau5cbea6f2005-12-17 12:48:26 +0100141#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100142#define DEF_CHKINTR 2000
143#define DEF_FALLTIME 3
144#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100145#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100146
Willy TARREAU13032e72006-03-12 17:31:45 +0100147/* Default connections limit.
148 *
149 * A system limit can be enforced at build time in order to avoid using haproxy
150 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
151 * absolute limit accepted by the system. If the configuration specifies a
152 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
153 * emitted. The only way to override this limit will be to set it via the
154 * command-line '-n' argument.
155 */
156#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100157#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100158#else
159#define DEFAULT_MAXCONN SYSTEM_MAXCONN
160#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100161
willy tarreau0f7af912005-12-17 12:21:26 +0100162/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
163#define INTBITS 5
164
165/* show stats this every millisecond, 0 to disable */
166#ifndef STATTIME
167#define STATTIME 2000
168#endif
169
willy tarreau5cbea6f2005-12-17 12:48:26 +0100170/* this reduces the number of calls to select() by choosing appropriate
171 * sheduler precision in milliseconds. It should be near the minimum
172 * time that is needed by select() to collect all events. All timeouts
173 * are rounded up by adding this value prior to pass it to select().
174 */
175#define SCHEDULER_RESOLUTION 9
176
willy tarreaub952e1d2005-12-18 01:31:20 +0100177#define TIME_ETERNITY -1
178/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100179#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
180#define SETNOW(a) (*a=now)
181
willy tarreau9da061b2005-12-17 12:29:56 +0100182/****** string-specific macros and functions ******/
183/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
184#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
185
186/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
187#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
188
willy tarreau0174f312005-12-18 01:02:42 +0100189/* returns 1 only if only zero or one bit is set in X, which means that X is a
190 * power of 2, and 0 otherwise */
191#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100192/*
193 * copies at most <size-1> chars from <src> to <dst>. Last char is always
194 * set to 0, unless <size> is 0. The number of chars copied is returned
195 * (excluding the terminating zero).
196 * This code has been optimized for size and speed : on x86, it's 45 bytes
197 * long, uses only registers, and consumes only 4 cycles per char.
198 */
willy tarreau750a4722005-12-17 13:21:24 +0100199int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100200 char *orig = dst;
201 if (size) {
202 while (--size && (*dst = *src)) {
203 src++; dst++;
204 }
205 *dst = 0;
206 }
207 return dst - orig;
208}
willy tarreau9da061b2005-12-17 12:29:56 +0100209
willy tarreau4302f492005-12-18 01:00:37 +0100210/*
211 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
212 * dynamically allocated. In the first case, <__pool> is updated to point to
213 * the next element in the list.
214 */
215#define pool_alloc_from(__pool, __len) ({ \
216 void *__p; \
217 if ((__p = (__pool)) == NULL) \
218 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
219 else { \
220 __pool = *(void **)(__pool); \
221 } \
222 __p; \
223})
224
225/*
226 * Puts a memory area back to the corresponding pool.
227 * Items are chained directly through a pointer that
228 * is written in the beginning of the memory area, so
229 * there's no need for any carrier cell. This implies
230 * that each memory area is at least as big as one
231 * pointer.
232 */
233#define pool_free_to(__pool, __ptr) ({ \
234 *(void **)(__ptr) = (void *)(__pool); \
235 __pool = (void *)(__ptr); \
236})
237
238
willy tarreau0f7af912005-12-17 12:21:26 +0100239#define MEM_OPTIM
240#ifdef MEM_OPTIM
241/*
242 * Returns a pointer to type <type> taken from the
243 * pool <pool_type> or dynamically allocated. In the
244 * first case, <pool_type> is updated to point to the
245 * next element in the list.
246 */
247#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100248 void *__p; \
249 if ((__p = pool_##type) == NULL) \
250 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100251 else { \
252 pool_##type = *(void **)pool_##type; \
253 } \
willy tarreau4302f492005-12-18 01:00:37 +0100254 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100255})
256
257/*
258 * Puts a memory area back to the corresponding pool.
259 * Items are chained directly through a pointer that
260 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100261 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100262 * that each memory area is at least as big as one
263 * pointer.
264 */
265#define pool_free(type, ptr) ({ \
266 *(void **)ptr = (void *)pool_##type; \
267 pool_##type = (void *)ptr; \
268})
269
270#else
271#define pool_alloc(type) (calloc(1,sizeof_##type));
272#define pool_free(type, ptr) (free(ptr));
273#endif /* MEM_OPTIM */
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275#define sizeof_task sizeof(struct task)
276#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100277#define sizeof_buffer sizeof(struct buffer)
278#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100279#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100280#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100281#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100282#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100283
willy tarreau5cbea6f2005-12-17 12:48:26 +0100284/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100285#define FD_STCLOSE 0
286#define FD_STLISTEN 1
287#define FD_STCONN 2
288#define FD_STREADY 3
289#define FD_STERROR 4
290
willy tarreau5cbea6f2005-12-17 12:48:26 +0100291/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100292#define TASK_IDLE 0
293#define TASK_RUNNING 1
294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define PR_STNEW 0
297#define PR_STIDLE 1
298#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100299#define PR_STSTOPPED 3
300#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define PR_MODE_TCP 0
304#define PR_MODE_HTTP 1
305#define PR_MODE_HEALTH 2
306
willy tarreau1c2ad212005-12-18 01:11:29 +0100307/* possible actions for the *poll() loops */
308#define POLL_LOOP_ACTION_INIT 0
309#define POLL_LOOP_ACTION_RUN 1
310#define POLL_LOOP_ACTION_CLEAN 2
311
willy tarreau64a3cc32005-12-18 01:13:11 +0100312/* poll mechanisms available */
313#define POLL_USE_SELECT (1<<0)
314#define POLL_USE_POLL (1<<1)
315#define POLL_USE_EPOLL (1<<2)
316
willy tarreau5cbea6f2005-12-17 12:48:26 +0100317/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100318#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
319#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
320#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
321#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
322#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
323#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
324#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
325#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100327#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
328#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
329#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
330#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
331#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
332#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
333#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
334#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
335#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
336#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
337#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100338#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
339#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100340#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100341#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100342
willy tarreaue39cd132005-12-17 13:00:18 +0100343/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100344#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
345#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
346#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
347#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
348#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
349#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100350#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100351
352#define SN_CK_NONE 0x00000000 /* this session had no cookie */
353#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
354#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
355#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
356#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
357#define SN_CK_SHIFT 6 /* bit shift */
358
willy tarreaub1285d52005-12-18 01:20:14 +0100359#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100360#define SN_ERR_CLITO 0x00000100 /* client time-out */
361#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
362#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
363#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
364#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100365#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
366#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100367#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
368#define SN_ERR_SHIFT 8 /* bit shift */
369
370#define SN_FINST_R 0x00001000 /* session ended during client request */
371#define SN_FINST_C 0x00002000 /* session ended during server connect */
372#define SN_FINST_H 0x00003000 /* session ended during server headers */
373#define SN_FINST_D 0x00004000 /* session ended during data phase */
374#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
375#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
376#define SN_FINST_SHIFT 12 /* bit shift */
377
378#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
379#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
380#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
381#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
382#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100383#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_SCK_SHIFT 16 /* bit shift */
385
willy tarreau97f58572005-12-18 00:53:44 +0100386#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
387#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
388#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100389
390/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100391#define CL_STHEADERS 0
392#define CL_STDATA 1
393#define CL_STSHUTR 2
394#define CL_STSHUTW 3
395#define CL_STCLOSE 4
396
willy tarreau5cbea6f2005-12-17 12:48:26 +0100397/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100398#define SV_STIDLE 0
399#define SV_STCONN 1
400#define SV_STHEADERS 2
401#define SV_STDATA 3
402#define SV_STSHUTR 4
403#define SV_STSHUTW 5
404#define SV_STCLOSE 6
405
406/* result of an I/O event */
407#define RES_SILENT 0 /* didn't happen */
408#define RES_DATA 1 /* data were sent or received */
409#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
410#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
411
willy tarreau9fe663a2005-12-17 13:02:59 +0100412/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100413#define MODE_DEBUG 1
414#define MODE_STATS 2
415#define MODE_LOG 4
416#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100417#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100418#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100419#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100420#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100421
422/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100423#define SRV_RUNNING 1 /* the server is UP */
424#define SRV_BACKUP 2 /* this server is a backup server */
425#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100426#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100427#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100428
willy tarreaue39cd132005-12-17 13:00:18 +0100429/* what to do when a header matches a regex */
430#define ACT_ALLOW 0 /* allow the request */
431#define ACT_REPLACE 1 /* replace the matching header */
432#define ACT_REMOVE 2 /* remove the matching header */
433#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100434#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100435
willy tarreau9fe663a2005-12-17 13:02:59 +0100436/* configuration sections */
437#define CFG_NONE 0
438#define CFG_GLOBAL 1
439#define CFG_LISTEN 2
440
willy tarreaua1598082005-12-17 13:08:06 +0100441/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100442#define LW_DATE 1 /* date */
443#define LW_CLIP 2 /* CLient IP */
444#define LW_SVIP 4 /* SerVer IP */
445#define LW_SVID 8 /* server ID */
446#define LW_REQ 16 /* http REQuest */
447#define LW_RESP 32 /* http RESPonse */
448#define LW_PXIP 64 /* proxy IP */
449#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100450#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100451#define LW_COOKIE 512 /* captured cookie */
452#define LW_REQHDR 1024 /* request header(s) */
453#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100454
willy tarreau0f7af912005-12-17 12:21:26 +0100455/*********************************************************************/
456
457#define LIST_HEAD(a) ((void *)(&(a)))
458
459/*********************************************************************/
460
willy tarreau4302f492005-12-18 01:00:37 +0100461struct cap_hdr {
462 struct cap_hdr *next;
463 char *name; /* header name, case insensitive */
464 int namelen; /* length of the header name, to speed-up lookups */
465 int len; /* capture length, not including terminal zero */
466 int index; /* index in the output array */
467 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
468};
469
willy tarreau0f7af912005-12-17 12:21:26 +0100470struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100471 struct hdr_exp *next;
472 regex_t *preg; /* expression to look for */
473 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
474 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100475};
476
477struct buffer {
478 unsigned int l; /* data length */
479 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100480 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100481 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100482 char data[BUFSIZE];
483};
484
485struct server {
486 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100487 int state; /* server state (SRV_*) */
488 int cklen; /* the len of the cookie, to speed up checks */
489 char *cookie; /* the id set in the cookie */
490 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100491 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100492 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100493 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100494 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100495 int rise, fall; /* time in iterations */
496 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 int result; /* 0 = connect OK, -1 = connect KO */
498 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100499 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100500};
501
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100503struct task {
504 struct task *next, *prev; /* chaining ... */
505 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100506 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100507 int state; /* task state : IDLE or RUNNING */
508 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100509 int (*process)(struct task *t); /* the function which processes the task */
510 void *context; /* the task's context */
511};
512
513/* WARNING: if new fields are added, they must be initialized in event_accept() */
514struct session {
515 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100516 /* application specific below */
517 struct timeval crexpire; /* expiration date for a client read */
518 struct timeval cwexpire; /* expiration date for a client write */
519 struct timeval srexpire; /* expiration date for a server read */
520 struct timeval swexpire; /* expiration date for a server write */
521 struct timeval cnexpire; /* expiration date for a connect */
522 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
523 struct proxy *proxy; /* the proxy this socket belongs to */
524 int cli_fd; /* the client side fd */
525 int srv_fd; /* the server side fd */
526 int cli_state; /* state of the client side */
527 int srv_state; /* state of the server side */
528 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100529 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100530 struct buffer *req; /* request buffer */
531 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100532 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100533 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100534 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100535 char **req_cap; /* array of captured request headers (may be NULL) */
536 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100537 struct {
538 int logwait; /* log fields waiting to be collected : LW_* */
539 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
540 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
541 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
542 long t_data; /* delay before the first data byte from the server ... */
543 unsigned long t_close; /* total session duration */
544 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100545 char *cli_cookie; /* cookie presented by the client, in capture mode */
546 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100547 int status; /* HTTP status from the server, negative if from proxy */
548 long long bytes; /* number of bytes transferred from the server */
549 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100550 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100551};
552
willy tarreaua41a8b42005-12-17 14:02:24 +0100553struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100554 int fd; /* the listen socket */
555 struct sockaddr_storage addr; /* the address we listen to */
556 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100557};
558
559
willy tarreau0f7af912005-12-17 12:21:26 +0100560struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100561 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100562 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 +0100563 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100565 struct server *srv, *cursrv; /* known servers, current server */
566 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100567 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100568 int cookie_len; /* strlen(cookie_name), computed only once */
569 char *appsession_name; /* name of the cookie to look for */
570 int appsession_name_len; /* strlen(appsession_name), computed only once */
571 int appsession_len; /* length of the appsession cookie value to be used */
572 int appsession_timeout;
573 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100574 char *capture_name; /* beginning of the name of the cookie to capture */
575 int capture_namelen; /* length of the cookie name to match */
576 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100577 int clitimeout; /* client I/O timeout (in milliseconds) */
578 int srvtimeout; /* server I/O timeout (in milliseconds) */
579 int contimeout; /* connect timeout (in milliseconds) */
580 char *id; /* proxy id */
581 int nbconn; /* # of active sessions */
582 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100583 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100584 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100585 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100586 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100587 struct proxy *next;
588 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100589 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100590 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100591 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100592 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100593 int nb_reqadd, nb_rspadd;
594 struct hdr_exp *req_exp; /* regular expressions for request headers */
595 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100596 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
597 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
598 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
599 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100600 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100601 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100602 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
603 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100604 struct {
605 char *msg400; /* message for error 400 */
606 int len400; /* message length for error 400 */
607 char *msg403; /* message for error 403 */
608 int len403; /* message length for error 403 */
609 char *msg408; /* message for error 408 */
610 int len408; /* message length for error 408 */
611 char *msg500; /* message for error 500 */
612 int len500; /* message length for error 500 */
613 char *msg502; /* message for error 502 */
614 int len502; /* message length for error 502 */
615 char *msg503; /* message for error 503 */
616 int len503; /* message length for error 503 */
617 char *msg504; /* message for error 504 */
618 int len504; /* message length for error 504 */
619 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100620};
621
622/* info about one given fd */
623struct fdtab {
624 int (*read)(int fd); /* read function */
625 int (*write)(int fd); /* write function */
626 struct task *owner; /* the session (or proxy) associated with this fd */
627 int state; /* the state of this fd */
628};
629
630/*********************************************************************/
631
willy tarreaub952e1d2005-12-18 01:31:20 +0100632int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100633int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100634char *cfg_cfgfile = NULL; /* configuration file */
635char *progname = NULL; /* program name */
636int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100637
638/* global options */
639static struct {
640 int uid;
641 int gid;
642 int nbproc;
643 int maxconn;
644 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100645 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100646 int mode;
647 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100648 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100649 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100650 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100651 struct sockaddr_in logsrv1, logsrv2;
652} global = {
653 logfac1 : -1,
654 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100655 loglev1 : 7, /* max syslog level : debug */
656 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100657 /* others NULL OK */
658};
659
willy tarreau0f7af912005-12-17 12:21:26 +0100660/*********************************************************************/
661
willy tarreau1c2ad212005-12-18 01:11:29 +0100662fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100663 *StaticWriteEvent;
664
willy tarreau64a3cc32005-12-18 01:13:11 +0100665int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100666
willy tarreau0f7af912005-12-17 12:21:26 +0100667void **pool_session = NULL,
668 **pool_buffer = NULL,
669 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100670 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100671 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100672 **pool_capture = NULL,
673 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100674
675struct proxy *proxy = NULL; /* list of all existing proxies */
676struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100677struct task *rq = NULL; /* global run queue */
678struct task wait_queue = { /* global wait queue */
679 prev:LIST_HEAD(wait_queue),
680 next:LIST_HEAD(wait_queue)
681};
willy tarreau0f7af912005-12-17 12:21:26 +0100682
willy tarreau0f7af912005-12-17 12:21:26 +0100683static int totalconn = 0; /* total # of terminated sessions */
684static int actconn = 0; /* # of active sessions */
685static int maxfd = 0; /* # of the highest fd + 1 */
686static int listeners = 0; /* # of listeners */
687static int stopping = 0; /* non zero means stopping in progress */
688static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100689static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100690
willy tarreau08dedbe2005-12-18 01:13:48 +0100691#if defined(ENABLE_EPOLL)
692/* FIXME: this is dirty, but at the moment, there's no other solution to remove
693 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
694 * structure with pointers to functions such as init_fd() and close_fd(), plus
695 * a private structure with several pointers to places such as below.
696 */
697
698static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
699#endif
700
willy tarreau0f7af912005-12-17 12:21:26 +0100701static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100702/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100703static char trash[BUFSIZE];
704
willy tarreaudd07e972005-12-18 00:48:48 +0100705const int zero = 0;
706const int one = 1;
707
willy tarreau0f7af912005-12-17 12:21:26 +0100708/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100709 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100710 */
711
712#define MAX_SYSLOG_LEN 1024
713#define NB_LOG_FACILITIES 24
714const char *log_facilities[NB_LOG_FACILITIES] = {
715 "kern", "user", "mail", "daemon",
716 "auth", "syslog", "lpr", "news",
717 "uucp", "cron", "auth2", "ftp",
718 "ntp", "audit", "alert", "cron2",
719 "local0", "local1", "local2", "local3",
720 "local4", "local5", "local6", "local7"
721};
722
723
724#define NB_LOG_LEVELS 8
725const char *log_levels[NB_LOG_LEVELS] = {
726 "emerg", "alert", "crit", "err",
727 "warning", "notice", "info", "debug"
728};
729
730#define SYSLOG_PORT 514
731
732const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
733 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100734
willy tarreaub1285d52005-12-18 01:20:14 +0100735const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100736const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
737const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
738const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
739 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
740 unknown, Set-cookie Rewritten */
741
willy tarreau0f7af912005-12-17 12:21:26 +0100742#define MAX_HOSTNAME_LEN 32
743static char hostname[MAX_HOSTNAME_LEN] = "";
744
willy tarreau8337c6b2005-12-17 13:41:01 +0100745const char *HTTP_302 =
746 "HTTP/1.0 302 Found\r\n"
747 "Cache-Control: no-cache\r\n"
748 "Connection: close\r\n"
749 "Location: "; /* not terminated since it will be concatenated with the URL */
750
willy tarreauc1f47532005-12-18 01:08:26 +0100751/* same as 302 except that the browser MUST retry with the GET method */
752const char *HTTP_303 =
753 "HTTP/1.0 303 See Other\r\n"
754 "Cache-Control: no-cache\r\n"
755 "Connection: close\r\n"
756 "Location: "; /* not terminated since it will be concatenated with the URL */
757
willy tarreaua1598082005-12-17 13:08:06 +0100758const char *HTTP_400 =
759 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100760 "Cache-Control: no-cache\r\n"
761 "Connection: close\r\n"
762 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100763 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100764
willy tarreaua1598082005-12-17 13:08:06 +0100765const char *HTTP_403 =
766 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100767 "Cache-Control: no-cache\r\n"
768 "Connection: close\r\n"
769 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100770 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
771
willy tarreau8337c6b2005-12-17 13:41:01 +0100772const char *HTTP_408 =
773 "HTTP/1.0 408 Request Time-out\r\n"
774 "Cache-Control: no-cache\r\n"
775 "Connection: close\r\n"
776 "\r\n"
777 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
778
willy tarreau750a4722005-12-17 13:21:24 +0100779const char *HTTP_500 =
780 "HTTP/1.0 500 Server Error\r\n"
781 "Cache-Control: no-cache\r\n"
782 "Connection: close\r\n"
783 "\r\n"
784 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100785
786const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100787 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100788 "Cache-Control: no-cache\r\n"
789 "Connection: close\r\n"
790 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100791 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
792
793const char *HTTP_503 =
794 "HTTP/1.0 503 Service Unavailable\r\n"
795 "Cache-Control: no-cache\r\n"
796 "Connection: close\r\n"
797 "\r\n"
798 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
799
800const char *HTTP_504 =
801 "HTTP/1.0 504 Gateway Time-out\r\n"
802 "Cache-Control: no-cache\r\n"
803 "Connection: close\r\n"
804 "\r\n"
805 "<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 +0100806
willy tarreau0f7af912005-12-17 12:21:26 +0100807/*********************************************************************/
808/* statistics ******************************************************/
809/*********************************************************************/
810
willy tarreau750a4722005-12-17 13:21:24 +0100811#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100812static int stats_tsk_lsrch, stats_tsk_rsrch,
813 stats_tsk_good, stats_tsk_right, stats_tsk_left,
814 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100815#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100816
817
818/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100819/* debugging *******************************************************/
820/*********************************************************************/
821#ifdef DEBUG_FULL
822static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
823static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
824#endif
825
826/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100827/* function prototypes *********************************************/
828/*********************************************************************/
829
830int event_accept(int fd);
831int event_cli_read(int fd);
832int event_cli_write(int fd);
833int event_srv_read(int fd);
834int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100835int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100836
willy tarreau12350152005-12-18 01:03:27 +0100837static int appsession_task_init(void);
838static int appsession_init(void);
839static int appsession_refresh(struct task *t);
840
willy tarreau0f7af912005-12-17 12:21:26 +0100841/*********************************************************************/
842/* general purpose functions ***************************************/
843/*********************************************************************/
844
845void display_version() {
846 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100847 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100848}
849
850/*
851 * This function prints the command line usage and exits
852 */
853void usage(char *name) {
854 display_version();
855 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100856 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100857#if STATTIME > 0
858 "sl"
859#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100860 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100861 " -v displays version\n"
862 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100863 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100864#if STATTIME > 0
865 " -s enables statistics output\n"
866 " -l enables long statistics format\n"
867#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100868 " -D goes daemon ; implies -q\n"
869 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100870 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100871 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100872 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100873 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100874#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100875 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100876#endif
877#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100878 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100879#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100880 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100881 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100882 exit(1);
883}
884
885
886/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100887 * Displays the message on stderr with the date and pid. Overrides the quiet
888 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100889 */
890void Alert(char *fmt, ...) {
891 va_list argp;
892 struct timeval tv;
893 struct tm *tm;
894
willy tarreaud0fb4652005-12-18 01:32:04 +0100895 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100896 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100897
willy tarreau5cbea6f2005-12-17 12:48:26 +0100898 gettimeofday(&tv, NULL);
899 tm=localtime(&tv.tv_sec);
900 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100901 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100902 vfprintf(stderr, fmt, argp);
903 fflush(stderr);
904 va_end(argp);
905 }
willy tarreau0f7af912005-12-17 12:21:26 +0100906}
907
908
909/*
910 * Displays the message on stderr with the date and pid.
911 */
912void Warning(char *fmt, ...) {
913 va_list argp;
914 struct timeval tv;
915 struct tm *tm;
916
willy tarreau982249e2005-12-18 00:57:06 +0100917 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100918 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100919
willy tarreau5cbea6f2005-12-17 12:48:26 +0100920 gettimeofday(&tv, NULL);
921 tm=localtime(&tv.tv_sec);
922 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100923 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924 vfprintf(stderr, fmt, argp);
925 fflush(stderr);
926 va_end(argp);
927 }
928}
929
930/*
931 * Displays the message on <out> only if quiet mode is not set.
932 */
933void qfprintf(FILE *out, char *fmt, ...) {
934 va_list argp;
935
willy tarreau982249e2005-12-18 00:57:06 +0100936 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100937 va_start(argp, fmt);
938 vfprintf(out, fmt, argp);
939 fflush(out);
940 va_end(argp);
941 }
willy tarreau0f7af912005-12-17 12:21:26 +0100942}
943
944
945/*
946 * converts <str> to a struct sockaddr_in* which is locally allocated.
947 * The format is "addr:port", where "addr" can be empty or "*" to indicate
948 * INADDR_ANY.
949 */
950struct sockaddr_in *str2sa(char *str) {
951 static struct sockaddr_in sa;
952 char *c;
953 int port;
954
willy tarreaua1598082005-12-17 13:08:06 +0100955 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100956 str=strdup(str);
957
958 if ((c=strrchr(str,':')) != NULL) {
959 *c++=0;
960 port=atol(c);
961 }
962 else
963 port=0;
964
965 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
966 sa.sin_addr.s_addr = INADDR_ANY;
967 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100968 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100969 struct hostent *he;
970
971 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100972 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100973 }
974 else
975 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
976 }
977 sa.sin_port=htons(port);
978 sa.sin_family=AF_INET;
979
980 free(str);
981 return &sa;
982}
983
willy tarreaub1285d52005-12-18 01:20:14 +0100984/*
985 * converts <str> to a two struct in_addr* which are locally allocated.
986 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
987 * is optionnal and either in the dotted or CIDR notation.
988 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
989 */
990int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
991 char *c;
992 unsigned long len;
993
994 memset(mask, 0, sizeof(*mask));
995 memset(addr, 0, sizeof(*addr));
996 str=strdup(str);
997
998 if ((c = strrchr(str, '/')) != NULL) {
999 *c++ = 0;
1000 /* c points to the mask */
1001 if (strchr(c, '.') != NULL) { /* dotted notation */
1002 if (!inet_pton(AF_INET, c, mask))
1003 return 0;
1004 }
1005 else { /* mask length */
1006 char *err;
1007 len = strtol(c, &err, 10);
1008 if (!*c || (err && *err) || (unsigned)len > 32)
1009 return 0;
1010 if (len)
1011 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1012 else
1013 mask->s_addr = 0;
1014 }
1015 }
1016 else {
1017 mask->s_addr = 0xFFFFFFFF;
1018 }
1019 if (!inet_pton(AF_INET, str, addr)) {
1020 struct hostent *he;
1021
1022 if ((he = gethostbyname(str)) == NULL) {
1023 return 0;
1024 }
1025 else
1026 *addr = *(struct in_addr *) *(he->h_addr_list);
1027 }
1028 free(str);
1029 return 1;
1030}
1031
willy tarreau9fe663a2005-12-17 13:02:59 +01001032
1033/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001034 * converts <str> to a list of listeners which are dynamically allocated.
1035 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1036 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1037 * - <port> is a numerical port from 1 to 65535 ;
1038 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1039 * This can be repeated as many times as necessary, separated by a coma.
1040 * The <tail> argument is a pointer to a current list which should be appended
1041 * to the tail of the new list. The pointer to the new list is returned.
1042 */
1043struct listener *str2listener(char *str, struct listener *tail) {
1044 struct listener *l;
1045 char *c, *next, *range, *dupstr;
1046 int port, end;
1047
1048 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001049
willy tarreaua41a8b42005-12-17 14:02:24 +01001050 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001051 struct sockaddr_storage ss;
1052
willy tarreaua41a8b42005-12-17 14:02:24 +01001053 str = next;
1054 /* 1) look for the end of the first address */
1055 if ((next = strrchr(str, ',')) != NULL) {
1056 *next++ = 0;
1057 }
1058
willy tarreau8a86dbf2005-12-18 00:45:59 +01001059 /* 2) look for the addr/port delimiter, it's the last colon. */
1060 if ((range = strrchr(str, ':')) == NULL) {
1061 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001062 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001063 }
1064
1065 *range++ = 0;
1066
1067 if (strrchr(str, ':') != NULL) {
1068 /* IPv6 address contains ':' */
1069 memset(&ss, 0, sizeof(ss));
1070 ss.ss_family = AF_INET6;
1071
1072 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1073 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001074 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001075 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001076 }
1077 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001078 memset(&ss, 0, sizeof(ss));
1079 ss.ss_family = AF_INET;
1080
1081 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1082 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1083 }
1084 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1085 struct hostent *he;
1086
1087 if ((he = gethostbyname(str)) == NULL) {
1088 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001089 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001090 }
1091 else
1092 ((struct sockaddr_in *)&ss)->sin_addr =
1093 *(struct in_addr *) *(he->h_addr_list);
1094 }
1095 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001096
1097 /* 3) look for the port-end delimiter */
1098 if ((c = strchr(range, '-')) != NULL) {
1099 *c++ = 0;
1100 end = atol(c);
1101 }
1102 else {
1103 end = atol(range);
1104 }
1105
willy tarreaud0fb4652005-12-18 01:32:04 +01001106 port = atol(range);
1107
1108 if (port < 1 || port > 65535) {
1109 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1110 goto fail;
1111 }
1112
1113 if (end < 1 || end > 65535) {
1114 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1115 goto fail;
1116 }
1117
1118 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001119 l = (struct listener *)calloc(1, sizeof(struct listener));
1120 l->next = tail;
1121 tail = l;
1122
willy tarreau8a86dbf2005-12-18 00:45:59 +01001123 l->addr = ss;
1124 if (ss.ss_family == AF_INET6)
1125 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1126 else
1127 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1128
willy tarreaua41a8b42005-12-17 14:02:24 +01001129 } /* end for(port) */
1130 } /* end while(next) */
1131 free(dupstr);
1132 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001133 fail:
1134 free(dupstr);
1135 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001136}
1137
willy tarreau4302f492005-12-18 01:00:37 +01001138
1139#define FD_SETS_ARE_BITFIELDS
1140#ifdef FD_SETS_ARE_BITFIELDS
1141/*
1142 * This map is used with all the FD_* macros to check whether a particular bit
1143 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1144 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1145 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1146 * exclusively to the macros.
1147 */
1148fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1149fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1150
1151#else
1152#error "Check if your OS uses bitfields for fd_sets"
1153#endif
1154
1155/* will try to encode the string <string> replacing all characters tagged in
1156 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1157 * prefixed by <escape>, and will store the result between <start> (included
1158 *) and <stop> (excluded), and will always terminate the string with a '\0'
1159 * before <stop>. The position of the '\0' is returned if the conversion
1160 * completes. If bytes are missing between <start> and <stop>, then the
1161 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1162 * cannot even be stored so we return <start> without writing the 0.
1163 * The input string must also be zero-terminated.
1164 */
1165char hextab[16] = "0123456789ABCDEF";
1166char *encode_string(char *start, char *stop,
1167 const char escape, const fd_set *map,
1168 const char *string)
1169{
1170 if (start < stop) {
1171 stop--; /* reserve one byte for the final '\0' */
1172 while (start < stop && *string != 0) {
1173 if (!FD_ISSET((unsigned char)(*string), map))
1174 *start++ = *string;
1175 else {
1176 if (start + 3 >= stop)
1177 break;
1178 *start++ = escape;
1179 *start++ = hextab[(*string >> 4) & 15];
1180 *start++ = hextab[*string & 15];
1181 }
1182 string++;
1183 }
1184 *start = '\0';
1185 }
1186 return start;
1187}
willy tarreaua41a8b42005-12-17 14:02:24 +01001188
1189/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001190 * This function sends a syslog message to both log servers of a proxy,
1191 * or to global log servers if the proxy is NULL.
1192 * It also tries not to waste too much time computing the message header.
1193 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001194 */
1195void send_log(struct proxy *p, int level, char *message, ...) {
1196 static int logfd = -1; /* syslog UDP socket */
1197 static long tvsec = -1; /* to force the string to be initialized */
1198 struct timeval tv;
1199 va_list argp;
1200 static char logmsg[MAX_SYSLOG_LEN];
1201 static char *dataptr = NULL;
1202 int fac_level;
1203 int hdr_len, data_len;
1204 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001205 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001206 int nbloggers = 0;
1207 char *log_ptr;
1208
1209 if (logfd < 0) {
1210 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1211 return;
1212 }
1213
1214 if (level < 0 || progname == NULL || message == NULL)
1215 return;
1216
1217 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001218 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001219 /* this string is rebuild only once a second */
1220 struct tm *tm = localtime(&tv.tv_sec);
1221 tvsec = tv.tv_sec;
1222
willy tarreauc29948c2005-12-17 13:10:27 +01001223 hdr_len = snprintf(logmsg, sizeof(logmsg),
1224 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1225 monthname[tm->tm_mon],
1226 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1227 progname, pid);
1228 /* WARNING: depending upon implementations, snprintf may return
1229 * either -1 or the number of bytes that would be needed to store
1230 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001231 */
willy tarreauc29948c2005-12-17 13:10:27 +01001232 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1233 hdr_len = sizeof(logmsg);
1234
1235 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001236 }
1237
1238 va_start(argp, message);
1239 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001240 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1241 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001242 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001243 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001244
1245 if (p == NULL) {
1246 if (global.logfac1 >= 0) {
1247 sa[nbloggers] = &global.logsrv1;
1248 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001249 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001250 nbloggers++;
1251 }
1252 if (global.logfac2 >= 0) {
1253 sa[nbloggers] = &global.logsrv2;
1254 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001255 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001256 nbloggers++;
1257 }
1258 } else {
1259 if (p->logfac1 >= 0) {
1260 sa[nbloggers] = &p->logsrv1;
1261 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001262 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001263 nbloggers++;
1264 }
1265 if (p->logfac2 >= 0) {
1266 sa[nbloggers] = &p->logsrv2;
1267 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001268 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001269 nbloggers++;
1270 }
1271 }
1272
1273 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001274 /* we can filter the level of the messages that are sent to each logger */
1275 if (level > loglevel[nbloggers])
1276 continue;
1277
willy tarreauc29948c2005-12-17 13:10:27 +01001278 /* For each target, we may have a different facility.
1279 * We can also have a different log level for each message.
1280 * This induces variations in the message header length.
1281 * Since we don't want to recompute it each time, nor copy it every
1282 * time, we only change the facility in the pre-computed header,
1283 * and we change the pointer to the header accordingly.
1284 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 fac_level = (facilities[nbloggers] << 3) + level;
1286 log_ptr = logmsg + 3; /* last digit of the log level */
1287 do {
1288 *log_ptr = '0' + fac_level % 10;
1289 fac_level /= 10;
1290 log_ptr--;
1291 } while (fac_level && log_ptr > logmsg);
1292 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001293
willy tarreauc29948c2005-12-17 13:10:27 +01001294 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001295
1296#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001297 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001298 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1299#else
willy tarreauc29948c2005-12-17 13:10:27 +01001300 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001301 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1302#endif
1303 }
willy tarreau0f7af912005-12-17 12:21:26 +01001304}
1305
1306
1307/* sets <tv> to the current time */
1308static inline struct timeval *tv_now(struct timeval *tv) {
1309 if (tv)
1310 gettimeofday(tv, NULL);
1311 return tv;
1312}
1313
1314/*
1315 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1316 */
1317static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1318 if (!tv || !from)
1319 return NULL;
1320 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1321 tv->tv_sec = from->tv_sec + (ms/1000);
1322 while (tv->tv_usec >= 1000000) {
1323 tv->tv_usec -= 1000000;
1324 tv->tv_sec++;
1325 }
1326 return tv;
1327}
1328
1329/*
1330 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001331 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001332 */
1333static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001334 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001335 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001336 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001337 return 1;
1338 else if (tv1->tv_usec < tv2->tv_usec)
1339 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001340 else if (tv1->tv_usec > tv2->tv_usec)
1341 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001342 else
1343 return 0;
1344}
1345
1346/*
1347 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001348 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001349 */
1350unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1351 int cmp;
1352 unsigned long ret;
1353
1354
willy tarreauef900ab2005-12-17 12:52:52 +01001355 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001356 if (!cmp)
1357 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001358 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001359 struct timeval *tmp = tv1;
1360 tv1 = tv2;
1361 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001362 }
willy tarreauef900ab2005-12-17 12:52:52 +01001363 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001364 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001365 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001366 else
willy tarreauef900ab2005-12-17 12:52:52 +01001367 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 return (unsigned long) ret;
1369}
1370
1371/*
willy tarreau750a4722005-12-17 13:21:24 +01001372 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001373 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001374 */
1375static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1376 unsigned long ret;
1377
willy tarreau6e682ce2005-12-17 13:26:49 +01001378 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1379 if (tv2->tv_usec > tv1->tv_usec)
1380 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001381 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001382 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001383 return (unsigned long) ret;
1384}
1385
1386/*
willy tarreau0f7af912005-12-17 12:21:26 +01001387 * 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 +01001388 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001389 */
1390static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001391 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001392 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001393 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001394 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001395 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001396 else
1397 return 0;
1398 }
willy tarreau0f7af912005-12-17 12:21:26 +01001399 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001400 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001401 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001402 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001403 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001404 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001405 else
1406 return 0;
1407}
1408
1409/*
1410 * returns the remaining time between tv1=now and event=tv2
1411 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001412 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001413 */
1414static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1415 unsigned long ret;
1416
willy tarreau0f7af912005-12-17 12:21:26 +01001417 if (tv_cmp_ms(tv1, tv2) >= 0)
1418 return 0; /* event elapsed */
1419
willy tarreauef900ab2005-12-17 12:52:52 +01001420 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001421 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001422 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001423 else
willy tarreauef900ab2005-12-17 12:52:52 +01001424 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001425 return (unsigned long) ret;
1426}
1427
1428
1429/*
1430 * zeroes a struct timeval
1431 */
1432
1433static inline struct timeval *tv_eternity(struct timeval *tv) {
1434 tv->tv_sec = tv->tv_usec = 0;
1435 return tv;
1436}
1437
1438/*
1439 * returns 1 if tv is null, else 0
1440 */
1441static inline int tv_iseternity(struct timeval *tv) {
1442 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1443 return 1;
1444 else
1445 return 0;
1446}
1447
1448/*
1449 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1450 * considering that 0 is the eternity.
1451 */
1452static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1453 if (tv_iseternity(tv1))
1454 if (tv_iseternity(tv2))
1455 return 0; /* same */
1456 else
1457 return 1; /* tv1 later than tv2 */
1458 else if (tv_iseternity(tv2))
1459 return -1; /* tv2 later than tv1 */
1460
1461 if (tv1->tv_sec > tv2->tv_sec)
1462 return 1;
1463 else if (tv1->tv_sec < tv2->tv_sec)
1464 return -1;
1465 else if (tv1->tv_usec > tv2->tv_usec)
1466 return 1;
1467 else if (tv1->tv_usec < tv2->tv_usec)
1468 return -1;
1469 else
1470 return 0;
1471}
1472
1473/*
1474 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1475 * considering that 0 is the eternity.
1476 */
1477static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1478 if (tv_iseternity(tv1))
1479 if (tv_iseternity(tv2))
1480 return 0; /* same */
1481 else
1482 return 1; /* tv1 later than tv2 */
1483 else if (tv_iseternity(tv2))
1484 return -1; /* tv2 later than tv1 */
1485
willy tarreauefae1842005-12-17 12:51:03 +01001486 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001487 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001488 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001489 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001490 return -1;
1491 else
1492 return 0;
1493 }
1494 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001495 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001496 return 1;
1497 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001498 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001499 return -1;
1500 else
1501 return 0;
1502}
1503
1504/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001505 * returns the remaining time between tv1=now and event=tv2
1506 * if tv2 is passed, 0 is returned.
1507 * Returns TIME_ETERNITY if tv2 is eternity.
1508 */
1509static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1510 unsigned long ret;
1511
1512 if (tv_iseternity(tv2))
1513 return TIME_ETERNITY;
1514
1515 if (tv_cmp_ms(tv1, tv2) >= 0)
1516 return 0; /* event elapsed */
1517
1518 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1519 if (tv2->tv_usec > tv1->tv_usec)
1520 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1521 else
1522 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1523 return (unsigned long) ret;
1524}
1525
1526/*
willy tarreau0f7af912005-12-17 12:21:26 +01001527 * returns the first event between tv1 and tv2 into tvmin.
1528 * a zero tv is ignored. tvmin is returned.
1529 */
1530static inline struct timeval *tv_min(struct timeval *tvmin,
1531 struct timeval *tv1, struct timeval *tv2) {
1532
1533 if (tv_cmp2(tv1, tv2) <= 0)
1534 *tvmin = *tv1;
1535 else
1536 *tvmin = *tv2;
1537
1538 return tvmin;
1539}
1540
1541
1542
1543/***********************************************************/
1544/* fd management ***************************************/
1545/***********************************************************/
1546
1547
1548
willy tarreau5cbea6f2005-12-17 12:48:26 +01001549/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1550 * The file descriptor is also closed.
1551 */
willy tarreau0f7af912005-12-17 12:21:26 +01001552static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001553 FD_CLR(fd, StaticReadEvent);
1554 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001555#if defined(ENABLE_EPOLL)
1556 if (PrevReadEvent) {
1557 FD_CLR(fd, PrevReadEvent);
1558 FD_CLR(fd, PrevWriteEvent);
1559 }
1560#endif
1561
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 close(fd);
1563 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001564
1565 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1566 maxfd--;
1567}
1568
1569/* recomputes the maxfd limit from the fd */
1570static inline void fd_insert(int fd) {
1571 if (fd+1 > maxfd)
1572 maxfd = fd+1;
1573}
1574
1575/*************************************************************/
1576/* task management ***************************************/
1577/*************************************************************/
1578
willy tarreau5cbea6f2005-12-17 12:48:26 +01001579/* puts the task <t> in run queue <q>, and returns <t> */
1580static inline struct task *task_wakeup(struct task **q, struct task *t) {
1581 if (t->state == TASK_RUNNING)
1582 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001583 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001584 t->rqnext = *q;
1585 t->state = TASK_RUNNING;
1586 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001587 }
1588}
1589
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590/* removes the task <t> from the queue <q>
1591 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001592 * set the run queue to point to the next one, and return it
1593 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594static inline struct task *task_sleep(struct task **q, struct task *t) {
1595 if (t->state == TASK_RUNNING) {
1596 *q = t->rqnext;
1597 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001599 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001600}
1601
1602/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001604 * from the run queue. A pointer to the task itself is returned.
1605 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606static inline struct task *task_delete(struct task *t) {
1607 t->prev->next = t->next;
1608 t->next->prev = t->prev;
1609 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001610}
1611
1612/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001613 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001614 */
1615static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001616 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001617}
1618
willy tarreau5cbea6f2005-12-17 12:48:26 +01001619/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001620 * may be only moved or left where it was, depending on its timing requirements.
1621 * <task> is returned.
1622 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623struct task *task_queue(struct task *task) {
1624 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001625 struct task *start_from;
1626
1627 /* first, test if the task was already in a list */
1628 if (task->prev == NULL) {
1629 // start_from = list;
1630 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001631#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001632 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001633#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001634 /* insert the unlinked <task> into the list, searching back from the last entry */
1635 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1636 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001637#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001638 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001639#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001640 }
1641
1642 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1643 // start_from = start_from->next;
1644 // stats_tsk_nsrch++;
1645 // }
1646 }
1647 else if (task->prev == list ||
1648 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1649 start_from = task->next;
1650 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001651#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001652 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001653#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001654 return task; /* it's already in the right place */
1655 }
1656
willy tarreau750a4722005-12-17 13:21:24 +01001657#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001658 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001659#endif
1660
1661 /* if the task is not at the right place, there's little chance that
1662 * it has only shifted a bit, and it will nearly always be queued
1663 * at the end of the list because of constant timeouts
1664 * (observed in real case).
1665 */
1666#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1667 start_from = list->prev; /* assume we'll queue to the end of the list */
1668 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1669 start_from = start_from->prev;
1670#if STATTIME > 0
1671 stats_tsk_lsrch++;
1672#endif
1673 }
1674#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001675 /* insert the unlinked <task> into the list, searching after position <start_from> */
1676 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1677 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001678#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001679 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001680#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001681 }
willy tarreau750a4722005-12-17 13:21:24 +01001682#endif /* WE_REALLY_... */
1683
willy tarreau0f7af912005-12-17 12:21:26 +01001684 /* we need to unlink it now */
1685 task_delete(task);
1686 }
1687 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001688#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001689 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001690#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001691#ifdef LEFT_TO_TOP /* not very good */
1692 start_from = list;
1693 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1694 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001695#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001696 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001697#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001698 }
1699#else
1700 start_from = task->prev->prev; /* valid because of the previous test above */
1701 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1702 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001703#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001704 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001705#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001706 }
1707#endif
1708 /* we need to unlink it now */
1709 task_delete(task);
1710 }
1711 task->prev = start_from;
1712 task->next = start_from->next;
1713 task->next->prev = task;
1714 start_from->next = task;
1715 return task;
1716}
1717
1718
1719/*********************************************************************/
1720/* more specific functions ***************************************/
1721/*********************************************************************/
1722
1723/* some prototypes */
1724static int maintain_proxies(void);
1725
willy tarreaub952e1d2005-12-18 01:31:20 +01001726/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001727 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1728 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001729static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001730#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001731 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1732#else
willy tarreaua1598082005-12-17 13:08:06 +01001733#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001734 return getsockname(fd, (struct sockaddr *)sa, salen);
1735#else
1736 return -1;
1737#endif
1738#endif
1739}
1740
1741/*
1742 * frees the context associated to a session. It must have been removed first.
1743 */
1744static inline void session_free(struct session *s) {
1745 if (s->req)
1746 pool_free(buffer, s->req);
1747 if (s->rep)
1748 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001749
1750 if (s->rsp_cap != NULL) {
1751 struct cap_hdr *h;
1752 for (h = s->proxy->rsp_cap; h; h = h->next) {
1753 if (s->rsp_cap[h->index] != NULL)
1754 pool_free_to(h->pool, s->rsp_cap[h->index]);
1755 }
1756 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1757 }
1758 if (s->req_cap != NULL) {
1759 struct cap_hdr *h;
1760 for (h = s->proxy->req_cap; h; h = h->next) {
1761 if (s->req_cap[h->index] != NULL)
1762 pool_free_to(h->pool, s->req_cap[h->index]);
1763 }
1764 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1765 }
1766
willy tarreaua1598082005-12-17 13:08:06 +01001767 if (s->logs.uri)
1768 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001769 if (s->logs.cli_cookie)
1770 pool_free(capture, s->logs.cli_cookie);
1771 if (s->logs.srv_cookie)
1772 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001773
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774 pool_free(session, s);
1775}
1776
willy tarreau0f7af912005-12-17 12:21:26 +01001777
1778/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001779 * This function tries to find a running server for the proxy <px>. A first
1780 * pass looks for active servers, and if none is found, a second pass also
1781 * looks for backup servers.
1782 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1783 */
1784static inline struct server *find_server(struct proxy *px) {
1785 struct server *srv = px->cursrv;
1786 int ignore_backup = 1;
1787
1788 do {
1789 do {
1790 if (srv == NULL)
1791 srv = px->srv;
1792 if (srv->state & SRV_RUNNING
1793 && !((srv->state & SRV_BACKUP) && ignore_backup))
1794 return srv;
1795 srv = srv->next;
1796 } while (srv != px->cursrv);
Willy TARREAU3481c462006-03-01 22:37:57 +01001797
1798 /* By default, we look for the first backup server if all others are
1799 * DOWN. But in some cases, it may be desirable to load-balance across
1800 * all backup servers.
1801 */
1802 if (!(px->options & PR_O_USE_ALL_BK))
1803 srv = px->srv;
1804
willy tarreau8337c6b2005-12-17 13:41:01 +01001805 } while (ignore_backup--);
1806 return NULL;
1807}
1808
1809/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001810 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001811 * is set, or to the dispatch server if (s->direct) is 0.
1812 * It can return one of :
1813 * - SN_ERR_NONE if everything's OK
1814 * - SN_ERR_SRVTO if there are no more servers
1815 * - SN_ERR_SRVCL if the connection was refused by the server
1816 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1817 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1818 * - SN_ERR_INTERNAL for any other purely internal errors
1819 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001820 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001821int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001822 int fd;
1823
willy tarreau12350152005-12-18 01:03:27 +01001824#ifdef DEBUG_FULL
1825 fprintf(stderr,"connect_server : s=%p\n",s);
1826#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001827
willy tarreaue39cd132005-12-17 13:00:18 +01001828 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001829 s->srv_addr = s->srv->addr;
1830 }
1831 else if (s->proxy->options & PR_O_BALANCE) {
1832 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001833 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834
willy tarreau8337c6b2005-12-17 13:41:01 +01001835 srv = find_server(s->proxy);
1836
1837 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001838 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001839
willy tarreau8337c6b2005-12-17 13:41:01 +01001840 s->srv_addr = srv->addr;
1841 s->srv = srv;
1842 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001843 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001845 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001846 }
willy tarreaua1598082005-12-17 13:08:06 +01001847 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001848 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001849 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001850 }
1851 else if (s->proxy->options & PR_O_TRANSP) {
1852 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001853 socklen_t salen = sizeof(s->srv_addr);
1854
willy tarreau5cbea6f2005-12-17 12:48:26 +01001855 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1856 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001857 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 }
1859 }
willy tarreau0f7af912005-12-17 12:21:26 +01001860
willy tarreaua41a8b42005-12-17 14:02:24 +01001861 /* if this server remaps proxied ports, we'll use
1862 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001863 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001864 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001865 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001866
willy tarreaub952e1d2005-12-18 01:31:20 +01001867 if (!(s->proxy->options & PR_O_TRANSP) ||
1868 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001869 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1870 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1871 }
1872
willy tarreau0f7af912005-12-17 12:21:26 +01001873 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001874 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001875
1876 if (errno == ENFILE)
1877 send_log(s->proxy, LOG_EMERG,
1878 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1879 s->proxy->id, maxfd);
1880 else if (errno == EMFILE)
1881 send_log(s->proxy, LOG_EMERG,
1882 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1883 s->proxy->id, maxfd);
1884 else if (errno == ENOBUFS || errno == ENOMEM)
1885 send_log(s->proxy, LOG_EMERG,
1886 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1887 s->proxy->id, maxfd);
1888 /* this is a resource error */
1889 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001890 }
1891
willy tarreau9fe663a2005-12-17 13:02:59 +01001892 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001893 /* do not log anything there, it's a normal condition when this option
1894 * is used to serialize connections to a server !
1895 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001896 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1897 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001898 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 }
1900
willy tarreau0f7af912005-12-17 12:21:26 +01001901 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1902 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001903 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001904 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001905 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001906 }
1907
willy tarreaub952e1d2005-12-18 01:31:20 +01001908 if (s->proxy->options & PR_O_TCP_SRV_KA)
1909 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1910
willy tarreau0174f312005-12-18 01:02:42 +01001911 /* allow specific binding :
1912 * - server-specific at first
1913 * - proxy-specific next
1914 */
1915 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1916 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1917 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1918 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1919 s->proxy->id, s->srv->id);
1920 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001921 send_log(s->proxy, LOG_EMERG,
1922 "Cannot bind to source address before connect() for server %s/%s.\n",
1923 s->proxy->id, s->srv->id);
1924 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001925 }
1926 }
1927 else if (s->proxy->options & PR_O_BIND_SRC) {
1928 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1929 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1930 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1931 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001932 send_log(s->proxy, LOG_EMERG,
1933 "Cannot bind to source address before connect() for server %s/%s.\n",
1934 s->proxy->id, s->srv->id);
1935 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001936 }
willy tarreaua1598082005-12-17 13:08:06 +01001937 }
1938
willy tarreaub1285d52005-12-18 01:20:14 +01001939 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1940 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1941
1942 if (errno == EAGAIN || errno == EADDRINUSE) {
1943 char *msg;
1944 if (errno == EAGAIN) /* no free ports left, try again later */
1945 msg = "no free ports";
1946 else
1947 msg = "local address already in use";
1948
1949 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001950 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001951 send_log(s->proxy, LOG_EMERG,
1952 "Connect() failed for server %s/%s: %s.\n",
1953 s->proxy->id, s->srv->id, msg);
1954 return SN_ERR_RESOURCE;
1955 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001956 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001957 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001958 return SN_ERR_SRVTO;
1959 } else {
1960 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001961 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001962 close(fd);
1963 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001964 }
1965 }
1966
willy tarreau5cbea6f2005-12-17 12:48:26 +01001967 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001968 fdtab[fd].read = &event_srv_read;
1969 fdtab[fd].write = &event_srv_write;
1970 fdtab[fd].state = FD_STCONN; /* connection in progress */
1971
1972 FD_SET(fd, StaticWriteEvent); /* for connect status */
1973
1974 fd_insert(fd);
1975
1976 if (s->proxy->contimeout)
1977 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1978 else
1979 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001980 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001981}
1982
1983/*
1984 * this function is called on a read event from a client socket.
1985 * It returns 0.
1986 */
1987int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001988 struct task *t = fdtab[fd].owner;
1989 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001990 struct buffer *b = s->req;
1991 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001992
willy tarreau12350152005-12-18 01:03:27 +01001993#ifdef DEBUG_FULL
1994 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1995#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001996
willy tarreau0f7af912005-12-17 12:21:26 +01001997 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001998#ifdef FILL_BUFFERS
1999 while (1)
2000#else
2001 do
2002#endif
2003 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2005 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002006 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 }
2008 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002009 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002010 }
2011 else {
2012 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002013 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2014 * since it means that the rewrite protection has been removed. This
2015 * implies that the if statement can be removed.
2016 */
2017 if (max > b->rlim - b->data)
2018 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002019 }
2020
2021 if (max == 0) { /* not anymore room to store data */
2022 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002023 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002024 }
2025
willy tarreau3242e862005-12-17 12:27:53 +01002026#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002027 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002028 int skerr;
2029 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002030
willy tarreau5cbea6f2005-12-17 12:48:26 +01002031 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2032 if (skerr)
2033 ret = -1;
2034 else
2035 ret = recv(fd, b->r, max, 0);
2036 }
willy tarreau3242e862005-12-17 12:27:53 +01002037#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002038 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002039#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002040 if (ret > 0) {
2041 b->r += ret;
2042 b->l += ret;
2043 s->res_cr = RES_DATA;
2044
2045 if (b->r == b->data + BUFSIZE) {
2046 b->r = b->data; /* wrap around the buffer */
2047 }
willy tarreaua1598082005-12-17 13:08:06 +01002048
2049 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 /* we hope to read more data or to get a close on next round */
2051 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002052 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 else if (ret == 0) {
2054 s->res_cr = RES_NULL;
2055 break;
2056 }
2057 else if (errno == EAGAIN) {/* ignore EAGAIN */
2058 break;
2059 }
2060 else {
2061 s->res_cr = RES_ERROR;
2062 fdtab[fd].state = FD_STERROR;
2063 break;
2064 }
2065 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002066#ifndef FILL_BUFFERS
2067 while (0);
2068#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002069 }
2070 else {
2071 s->res_cr = RES_ERROR;
2072 fdtab[fd].state = FD_STERROR;
2073 }
2074
willy tarreau5cbea6f2005-12-17 12:48:26 +01002075 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002076 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002077 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2078 else
2079 tv_eternity(&s->crexpire);
2080
2081 task_wakeup(&rq, t);
2082 }
willy tarreau0f7af912005-12-17 12:21:26 +01002083
willy tarreau0f7af912005-12-17 12:21:26 +01002084 return 0;
2085}
2086
2087
2088/*
2089 * this function is called on a read event from a server socket.
2090 * It returns 0.
2091 */
2092int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002093 struct task *t = fdtab[fd].owner;
2094 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002095 struct buffer *b = s->rep;
2096 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002097
willy tarreau12350152005-12-18 01:03:27 +01002098#ifdef DEBUG_FULL
2099 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2100#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002101
willy tarreau0f7af912005-12-17 12:21:26 +01002102 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002103#ifdef FILL_BUFFERS
2104 while (1)
2105#else
2106 do
2107#endif
2108 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002109 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2110 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002111 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002112 }
2113 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002114 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002115 }
2116 else {
2117 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002118 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2119 * since it means that the rewrite protection has been removed. This
2120 * implies that the if statement can be removed.
2121 */
2122 if (max > b->rlim - b->data)
2123 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002124 }
2125
2126 if (max == 0) { /* not anymore room to store data */
2127 FD_CLR(fd, StaticReadEvent);
2128 break;
2129 }
2130
willy tarreau3242e862005-12-17 12:27:53 +01002131#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002132 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002133 int skerr;
2134 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002135
willy tarreau5cbea6f2005-12-17 12:48:26 +01002136 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2137 if (skerr)
2138 ret = -1;
2139 else
2140 ret = recv(fd, b->r, max, 0);
2141 }
willy tarreau3242e862005-12-17 12:27:53 +01002142#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002144#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 if (ret > 0) {
2146 b->r += ret;
2147 b->l += ret;
2148 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002149
willy tarreau5cbea6f2005-12-17 12:48:26 +01002150 if (b->r == b->data + BUFSIZE) {
2151 b->r = b->data; /* wrap around the buffer */
2152 }
willy tarreaua1598082005-12-17 13:08:06 +01002153
2154 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 /* we hope to read more data or to get a close on next round */
2156 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002157 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002158 else if (ret == 0) {
2159 s->res_sr = RES_NULL;
2160 break;
2161 }
2162 else if (errno == EAGAIN) {/* ignore EAGAIN */
2163 break;
2164 }
2165 else {
2166 s->res_sr = RES_ERROR;
2167 fdtab[fd].state = FD_STERROR;
2168 break;
2169 }
2170 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002171#ifndef FILL_BUFFERS
2172 while (0);
2173#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002174 }
2175 else {
2176 s->res_sr = RES_ERROR;
2177 fdtab[fd].state = FD_STERROR;
2178 }
2179
willy tarreau5cbea6f2005-12-17 12:48:26 +01002180 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002181 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002182 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2183 else
2184 tv_eternity(&s->srexpire);
2185
2186 task_wakeup(&rq, t);
2187 }
willy tarreau0f7af912005-12-17 12:21:26 +01002188
willy tarreau0f7af912005-12-17 12:21:26 +01002189 return 0;
2190}
2191
2192/*
2193 * this function is called on a write event from a client socket.
2194 * It returns 0.
2195 */
2196int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197 struct task *t = fdtab[fd].owner;
2198 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002199 struct buffer *b = s->rep;
2200 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002201
willy tarreau12350152005-12-18 01:03:27 +01002202#ifdef DEBUG_FULL
2203 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2204#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002205
2206 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002207 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002208 // max = BUFSIZE; BUG !!!!
2209 max = 0;
2210 }
2211 else if (b->r > b->w) {
2212 max = b->r - b->w;
2213 }
2214 else
2215 max = b->data + BUFSIZE - b->w;
2216
willy tarreau0f7af912005-12-17 12:21:26 +01002217 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002218 if (max == 0) {
2219 s->res_cw = RES_NULL;
2220 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002221 tv_eternity(&s->cwexpire);
2222 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002223 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002224 }
2225
willy tarreau3242e862005-12-17 12:27:53 +01002226#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002227 {
2228 int skerr;
2229 socklen_t lskerr = sizeof(skerr);
2230
2231 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2232 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002233 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002234 else
willy tarreau3242e862005-12-17 12:27:53 +01002235 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002236 }
willy tarreau3242e862005-12-17 12:27:53 +01002237#else
willy tarreau0f7af912005-12-17 12:21:26 +01002238 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002239#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002240
2241 if (ret > 0) {
2242 b->l -= ret;
2243 b->w += ret;
2244
2245 s->res_cw = RES_DATA;
2246
2247 if (b->w == b->data + BUFSIZE) {
2248 b->w = b->data; /* wrap around the buffer */
2249 }
2250 }
2251 else if (ret == 0) {
2252 /* nothing written, just make as if we were never called */
2253// s->res_cw = RES_NULL;
2254 return 0;
2255 }
2256 else if (errno == EAGAIN) /* ignore EAGAIN */
2257 return 0;
2258 else {
2259 s->res_cw = RES_ERROR;
2260 fdtab[fd].state = FD_STERROR;
2261 }
2262 }
2263 else {
2264 s->res_cw = RES_ERROR;
2265 fdtab[fd].state = FD_STERROR;
2266 }
2267
willy tarreaub1ff9db2005-12-17 13:51:03 +01002268 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002269 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002270 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2271 s->crexpire = s->cwexpire;
2272 }
willy tarreau0f7af912005-12-17 12:21:26 +01002273 else
2274 tv_eternity(&s->cwexpire);
2275
willy tarreau5cbea6f2005-12-17 12:48:26 +01002276 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002277 return 0;
2278}
2279
2280
2281/*
2282 * this function is called on a write event from a server socket.
2283 * It returns 0.
2284 */
2285int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002286 struct task *t = fdtab[fd].owner;
2287 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002288 struct buffer *b = s->req;
2289 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002290
willy tarreau12350152005-12-18 01:03:27 +01002291#ifdef DEBUG_FULL
2292 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2293#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002294
2295 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002296 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002297 // max = BUFSIZE; BUG !!!!
2298 max = 0;
2299 }
2300 else if (b->r > b->w) {
2301 max = b->r - b->w;
2302 }
2303 else
2304 max = b->data + BUFSIZE - b->w;
2305
willy tarreau0f7af912005-12-17 12:21:26 +01002306 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002307 if (max == 0) {
2308 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002309 if (s->srv_state == SV_STCONN) {
2310 int skerr;
2311 socklen_t lskerr = sizeof(skerr);
2312 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2313 if (skerr) {
2314 s->res_sw = RES_ERROR;
2315 fdtab[fd].state = FD_STERROR;
2316 task_wakeup(&rq, t);
2317 tv_eternity(&s->swexpire);
2318 FD_CLR(fd, StaticWriteEvent);
2319 return 0;
2320 }
2321 }
2322
willy tarreau0f7af912005-12-17 12:21:26 +01002323 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002324 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002325 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002326 tv_eternity(&s->swexpire);
2327 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002328 return 0;
2329 }
2330
willy tarreau3242e862005-12-17 12:27:53 +01002331#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002332 {
2333 int skerr;
2334 socklen_t lskerr = sizeof(skerr);
2335 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2336 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002337 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002338 else
willy tarreau3242e862005-12-17 12:27:53 +01002339 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002340 }
willy tarreau3242e862005-12-17 12:27:53 +01002341#else
willy tarreau0f7af912005-12-17 12:21:26 +01002342 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002343#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002344 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002345 if (ret > 0) {
2346 b->l -= ret;
2347 b->w += ret;
2348
2349 s->res_sw = RES_DATA;
2350
2351 if (b->w == b->data + BUFSIZE) {
2352 b->w = b->data; /* wrap around the buffer */
2353 }
2354 }
2355 else if (ret == 0) {
2356 /* nothing written, just make as if we were never called */
2357 // s->res_sw = RES_NULL;
2358 return 0;
2359 }
2360 else if (errno == EAGAIN) /* ignore EAGAIN */
2361 return 0;
2362 else {
2363 s->res_sw = RES_ERROR;
2364 fdtab[fd].state = FD_STERROR;
2365 }
2366 }
2367 else {
2368 s->res_sw = RES_ERROR;
2369 fdtab[fd].state = FD_STERROR;
2370 }
2371
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002372 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2373 * otherwise it could loop indefinitely !
2374 */
2375 if (s->srv_state != SV_STCONN) {
2376 if (s->proxy->srvtimeout) {
2377 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2378 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2379 s->srexpire = s->swexpire;
2380 }
2381 else
2382 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002383 }
willy tarreau0f7af912005-12-17 12:21:26 +01002384
willy tarreau5cbea6f2005-12-17 12:48:26 +01002385 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002386 return 0;
2387}
2388
2389
2390/*
willy tarreaue39cd132005-12-17 13:00:18 +01002391 * returns a message to the client ; the connection is shut down for read,
2392 * and the request is cleared so that no server connection can be initiated.
2393 * The client must be in a valid state for this (HEADER, DATA ...).
2394 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002395 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002396 */
2397void client_retnclose(struct session *s, int len, const char *msg) {
2398 FD_CLR(s->cli_fd, StaticReadEvent);
2399 FD_SET(s->cli_fd, StaticWriteEvent);
2400 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002401 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002402 shutdown(s->cli_fd, SHUT_RD);
2403 s->cli_state = CL_STSHUTR;
2404 strcpy(s->rep->data, msg);
2405 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002406 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002407 s->rep->r += len;
2408 s->req->l = 0;
2409}
2410
2411
2412/*
2413 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002414 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002415 */
2416void client_return(struct session *s, int len, const char *msg) {
2417 strcpy(s->rep->data, msg);
2418 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002419 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002420 s->rep->r += len;
2421 s->req->l = 0;
2422}
2423
willy tarreau9fe663a2005-12-17 13:02:59 +01002424/*
2425 * send a log for the session when we have enough info about it
2426 */
2427void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002428 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002429 struct proxy *p = s->proxy;
2430 int log;
2431 char *uri;
2432 char *pxid;
2433 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002434 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002435
2436 /* This is a first attempt at a better logging system.
2437 * For now, we rely on send_log() to provide the date, although it obviously
2438 * is the date of the log and not of the request, and most fields are not
2439 * computed.
2440 */
2441
willy tarreaua1598082005-12-17 13:08:06 +01002442 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002443
willy tarreau8a86dbf2005-12-18 00:45:59 +01002444 if (s->cli_addr.ss_family == AF_INET)
2445 inet_ntop(AF_INET,
2446 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2447 pn, sizeof(pn));
2448 else
2449 inet_ntop(AF_INET6,
2450 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2451 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002452
willy tarreauc1cae632005-12-17 14:12:23 +01002453 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002454 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002455 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002456
willy tarreauc1cae632005-12-17 14:12:23 +01002457 tm = localtime(&s->logs.tv_accept.tv_sec);
2458 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002459 char tmpline[MAX_SYSLOG_LEN], *h;
2460 int hdr;
2461
2462 h = tmpline;
2463 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2464 *(h++) = ' ';
2465 *(h++) = '{';
2466 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2467 if (hdr)
2468 *(h++) = '|';
2469 if (s->req_cap[hdr] != NULL)
2470 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2471 }
2472 *(h++) = '}';
2473 }
2474
2475 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2476 *(h++) = ' ';
2477 *(h++) = '{';
2478 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2479 if (hdr)
2480 *(h++) = '|';
2481 if (s->rsp_cap[hdr] != NULL)
2482 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2483 }
2484 *(h++) = '}';
2485 }
2486
2487 if (h < tmpline + sizeof(tmpline) - 4) {
2488 *(h++) = ' ';
2489 *(h++) = '"';
2490 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2491 *(h++) = '"';
2492 }
2493 *h = '\0';
2494
willy tarreau0fe39652005-12-18 01:25:24 +01002495 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 +01002496 pn,
2497 (s->cli_addr.ss_family == AF_INET) ?
2498 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2499 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002500 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2501 tm->tm_hour, tm->tm_min, tm->tm_sec,
2502 pxid, srv,
2503 s->logs.t_request,
2504 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2505 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002506 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2507 s->logs.status,
2508 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002509 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2510 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002511 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2512 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2513 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2514 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002515 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002516 }
2517 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002518 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 +01002519 pn,
2520 (s->cli_addr.ss_family == AF_INET) ?
2521 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2522 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002523 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2524 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002525 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002526 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002527 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2528 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002529 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002530 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2531 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002532 }
2533
2534 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002535}
2536
willy tarreaue39cd132005-12-17 13:00:18 +01002537
2538/*
willy tarreau0f7af912005-12-17 12:21:26 +01002539 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002540 * to an accept. It tries to accept as many connections as possible.
2541 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002542 */
2543int event_accept(int fd) {
2544 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 struct session *s;
2546 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002547 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002548
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002550 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002551 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002552
willy tarreaub1285d52005-12-18 01:20:14 +01002553 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2554 switch (errno) {
2555 case EAGAIN:
2556 case EINTR:
2557 case ECONNABORTED:
2558 return 0; /* nothing more to accept */
2559 case ENFILE:
2560 send_log(p, LOG_EMERG,
2561 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2562 p->id, maxfd);
2563 return 0;
2564 case EMFILE:
2565 send_log(p, LOG_EMERG,
2566 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2567 p->id, maxfd);
2568 return 0;
2569 case ENOBUFS:
2570 case ENOMEM:
2571 send_log(p, LOG_EMERG,
2572 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2573 p->id, maxfd);
2574 return 0;
2575 default:
2576 return 0;
2577 }
2578 }
willy tarreau0f7af912005-12-17 12:21:26 +01002579
willy tarreau5cbea6f2005-12-17 12:48:26 +01002580 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2581 Alert("out of memory in event_accept().\n");
2582 FD_CLR(fd, StaticReadEvent);
2583 p->state = PR_STIDLE;
2584 close(cfd);
2585 return 0;
2586 }
willy tarreau0f7af912005-12-17 12:21:26 +01002587
willy tarreaub1285d52005-12-18 01:20:14 +01002588 /* if this session comes from a known monitoring system, we want to ignore
2589 * it as soon as possible, which means closing it immediately for TCP.
2590 */
2591 s->flags = 0;
2592 if (addr.ss_family == AF_INET &&
2593 p->mon_mask.s_addr &&
2594 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2595 if (p->mode == PR_MODE_TCP) {
2596 close(cfd);
2597 pool_free(session, s);
2598 continue;
2599 }
2600 s->flags |= SN_MONITOR;
2601 }
2602
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2604 Alert("out of memory in event_accept().\n");
2605 FD_CLR(fd, StaticReadEvent);
2606 p->state = PR_STIDLE;
2607 close(cfd);
2608 pool_free(session, s);
2609 return 0;
2610 }
willy tarreau0f7af912005-12-17 12:21:26 +01002611
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002613 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002614 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2615 close(cfd);
2616 pool_free(task, t);
2617 pool_free(session, s);
2618 return 0;
2619 }
willy tarreau0f7af912005-12-17 12:21:26 +01002620
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2622 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2623 (char *) &one, sizeof(one)) == -1)) {
2624 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2625 close(cfd);
2626 pool_free(task, t);
2627 pool_free(session, s);
2628 return 0;
2629 }
willy tarreau0f7af912005-12-17 12:21:26 +01002630
willy tarreaub952e1d2005-12-18 01:31:20 +01002631 if (p->options & PR_O_TCP_CLI_KA)
2632 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2633
willy tarreau9fe663a2005-12-17 13:02:59 +01002634 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2635 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2636 t->state = TASK_IDLE;
2637 t->process = process_session;
2638 t->context = s;
2639
2640 s->task = t;
2641 s->proxy = p;
2642 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2643 s->srv_state = SV_STIDLE;
2644 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002645
willy tarreau9fe663a2005-12-17 13:02:59 +01002646 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2647 s->cli_fd = cfd;
2648 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002649 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002650 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002651
willy tarreaub1285d52005-12-18 01:20:14 +01002652 if (s->flags & SN_MONITOR)
2653 s->logs.logwait = 0;
2654 else
2655 s->logs.logwait = p->to_log;
2656
willy tarreaua1598082005-12-17 13:08:06 +01002657 s->logs.tv_accept = now;
2658 s->logs.t_request = -1;
2659 s->logs.t_connect = -1;
2660 s->logs.t_data = -1;
2661 s->logs.t_close = 0;
2662 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002663 s->logs.cli_cookie = NULL;
2664 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002665 s->logs.status = -1;
2666 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002667
willy tarreau2f6ba652005-12-17 13:57:42 +01002668 s->uniq_id = totalconn;
2669
willy tarreau4302f492005-12-18 01:00:37 +01002670 if (p->nb_req_cap > 0) {
2671 if ((s->req_cap =
2672 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2673 == NULL) { /* no memory */
2674 close(cfd); /* nothing can be done for this fd without memory */
2675 pool_free(task, t);
2676 pool_free(session, s);
2677 return 0;
2678 }
2679 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2680 }
2681 else
2682 s->req_cap = NULL;
2683
2684 if (p->nb_rsp_cap > 0) {
2685 if ((s->rsp_cap =
2686 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2687 == NULL) { /* no memory */
2688 if (s->req_cap != NULL)
2689 pool_free_to(p->req_cap_pool, s->req_cap);
2690 close(cfd); /* nothing can be done for this fd without memory */
2691 pool_free(task, t);
2692 pool_free(session, s);
2693 return 0;
2694 }
2695 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2696 }
2697 else
2698 s->rsp_cap = NULL;
2699
willy tarreau5cbea6f2005-12-17 12:48:26 +01002700 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2701 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002702 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002703 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002704
willy tarreau8a86dbf2005-12-18 00:45:59 +01002705 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002706 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002707 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002708 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002709
willy tarreau9fe663a2005-12-17 13:02:59 +01002710 if (p->to_log) {
2711 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002712 if (s->logs.logwait & LW_CLIP)
2713 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002714 sess_log(s);
2715 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002716 else if (s->cli_addr.ss_family == AF_INET) {
2717 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2718 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2719 sn, sizeof(sn)) &&
2720 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2721 pn, sizeof(pn))) {
2722 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2723 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2724 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2725 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2726 }
2727 }
2728 else {
2729 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2730 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2731 sn, sizeof(sn)) &&
2732 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2733 pn, sizeof(pn))) {
2734 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2735 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2736 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2737 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2738 }
2739 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002740 }
willy tarreau0f7af912005-12-17 12:21:26 +01002741
willy tarreau982249e2005-12-18 00:57:06 +01002742 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002743 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002744 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002745 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002746 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002747 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002748 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002749 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002750
willy tarreau8a86dbf2005-12-18 00:45:59 +01002751 if (s->cli_addr.ss_family == AF_INET) {
2752 char pn[INET_ADDRSTRLEN];
2753 inet_ntop(AF_INET,
2754 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2755 pn, sizeof(pn));
2756
2757 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2758 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2759 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2760 }
2761 else {
2762 char pn[INET6_ADDRSTRLEN];
2763 inet_ntop(AF_INET6,
2764 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2765 pn, sizeof(pn));
2766
2767 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2768 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2769 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2770 }
2771
willy tarreauef900ab2005-12-17 12:52:52 +01002772 write(1, trash, len);
2773 }
willy tarreau0f7af912005-12-17 12:21:26 +01002774
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002776 if (s->rsp_cap != NULL)
2777 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2778 if (s->req_cap != NULL)
2779 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002780 close(cfd); /* nothing can be done for this fd without memory */
2781 pool_free(task, t);
2782 pool_free(session, s);
2783 return 0;
2784 }
willy tarreau4302f492005-12-18 01:00:37 +01002785
willy tarreau5cbea6f2005-12-17 12:48:26 +01002786 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002787 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002788 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2789 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002790 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002791 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002792
willy tarreau5cbea6f2005-12-17 12:48:26 +01002793 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2794 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002795 if (s->rsp_cap != NULL)
2796 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2797 if (s->req_cap != NULL)
2798 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002799 close(cfd); /* nothing can be done for this fd without memory */
2800 pool_free(task, t);
2801 pool_free(session, s);
2802 return 0;
2803 }
2804 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002805 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002806 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 +01002807
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 fdtab[cfd].read = &event_cli_read;
2809 fdtab[cfd].write = &event_cli_write;
2810 fdtab[cfd].owner = t;
2811 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002812
willy tarreaub1285d52005-12-18 01:20:14 +01002813 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2814 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2815 /* Either we got a request from a monitoring system on an HTTP instance,
2816 * or we're in health check mode with the 'httpchk' option enabled. In
2817 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2818 */
2819 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2820 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2821 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002822 }
2823 else {
2824 FD_SET(cfd, StaticReadEvent);
2825 }
2826
willy tarreaub952e1d2005-12-18 01:31:20 +01002827#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2828 if (PrevReadEvent) {
2829 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2830 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2831 }
2832#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002833 fd_insert(cfd);
2834
2835 tv_eternity(&s->cnexpire);
2836 tv_eternity(&s->srexpire);
2837 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002838 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002839 tv_eternity(&s->cwexpire);
2840
willy tarreaub1285d52005-12-18 01:20:14 +01002841 if (s->proxy->clitimeout) {
2842 if (FD_ISSET(cfd, StaticReadEvent))
2843 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2844 if (FD_ISSET(cfd, StaticWriteEvent))
2845 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2846 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002847
willy tarreaub1285d52005-12-18 01:20:14 +01002848 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849
2850 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002851
2852 if (p->mode != PR_MODE_HEALTH)
2853 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002854
2855 p->nbconn++;
2856 actconn++;
2857 totalconn++;
2858
willy tarreaub952e1d2005-12-18 01:31:20 +01002859 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002860 } /* end of while (p->nbconn < p->maxconn) */
2861 return 0;
2862}
willy tarreau0f7af912005-12-17 12:21:26 +01002863
willy tarreau0f7af912005-12-17 12:21:26 +01002864
willy tarreau5cbea6f2005-12-17 12:48:26 +01002865/*
2866 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002867 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2868 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002869 * or -1 if an error occured.
2870 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002871int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 struct task *t = fdtab[fd].owner;
2873 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002874
willy tarreauc5f73ed2005-12-18 01:26:38 +01002875 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002876 socklen_t lskerr = sizeof(skerr);
2877
willy tarreau5cbea6f2005-12-17 12:48:26 +01002878 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002879 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002880 if (skerr)
2881 s->result = -1;
willy tarreaua4a583a2005-12-18 01:39:19 +01002882 else if (s->result != -1) {
2883 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002884 if (s->proxy->options & PR_O_HTTP_CHK) {
2885 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002886 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002887 * so we'll send the request, and won't wake the checker up now.
2888 */
2889#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002890 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002891#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002892 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002893#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002894 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002895 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2896 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2897 return 0;
2898 }
2899 else
2900 s->result = -1;
2901 }
2902 else {
2903 /* good TCP connection is enough */
2904 s->result = 1;
2905 }
2906 }
2907
2908 task_wakeup(&rq, t);
2909 return 0;
2910}
2911
willy tarreau0f7af912005-12-17 12:21:26 +01002912
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002913/*
2914 * This function is used only for server health-checks. It handles
2915 * the server's reply to an HTTP request. It returns 1 if the server replies
2916 * 2xx or 3xx (valid responses), or -1 in other cases.
2917 */
2918int event_srv_chk_r(int fd) {
2919 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002920 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002921 struct task *t = fdtab[fd].owner;
2922 struct server *s = t->context;
2923
willy tarreaua4a583a2005-12-18 01:39:19 +01002924 result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002925#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002926 {
2927 int skerr;
2928 socklen_t lskerr = sizeof(skerr);
2929
2930 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2931 if (!skerr)
2932 len = recv(fd, reply, sizeof(reply), 0);
2933 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002934#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002935 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2936 * but the connection was closed on the remote end. Fortunately, recv still
2937 * works correctly and we don't need to do the getsockopt() on linux.
2938 */
2939 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002940#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002941 if ((len >= sizeof("HTTP/1.0 000")) &&
2942 !memcmp(reply, "HTTP/1.", 7) &&
2943 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
willy tarreaua4a583a2005-12-18 01:39:19 +01002944 result = 1;
2945
2946 if (s->result != -1)
2947 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002948
2949 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002950 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002951 return 0;
2952}
2953
2954
2955/*
2956 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2957 * and moves <end> just after the end of <str>.
2958 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2959 * the shift value (positive or negative) is returned.
2960 * If there's no space left, the move is not done.
2961 *
2962 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002963int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002964 int delta;
2965 int len;
2966
2967 len = strlen(str);
2968 delta = len - (end - pos);
2969
2970 if (delta + b->r >= b->data + BUFSIZE)
2971 return 0; /* no space left */
2972
2973 /* first, protect the end of the buffer */
2974 memmove(end + delta, end, b->data + b->l - end);
2975
2976 /* now, copy str over pos */
2977 memcpy(pos, str,len);
2978
willy tarreau5cbea6f2005-12-17 12:48:26 +01002979 /* we only move data after the displaced zone */
2980 if (b->r > pos) b->r += delta;
2981 if (b->w > pos) b->w += delta;
2982 if (b->h > pos) b->h += delta;
2983 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002984 b->l += delta;
2985
2986 return delta;
2987}
2988
willy tarreau8337c6b2005-12-17 13:41:01 +01002989/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002990 * len is 0.
2991 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002992int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002993 int delta;
2994
2995 delta = len - (end - pos);
2996
2997 if (delta + b->r >= b->data + BUFSIZE)
2998 return 0; /* no space left */
2999
Willy TARREAUe78ae262006-01-08 01:24:12 +01003000 if (b->data + b->l < end)
3001 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3002 return 0;
3003
willy tarreau0f7af912005-12-17 12:21:26 +01003004 /* first, protect the end of the buffer */
3005 memmove(end + delta, end, b->data + b->l - end);
3006
3007 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003008 if (len)
3009 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003010
willy tarreau5cbea6f2005-12-17 12:48:26 +01003011 /* we only move data after the displaced zone */
3012 if (b->r > pos) b->r += delta;
3013 if (b->w > pos) b->w += delta;
3014 if (b->h > pos) b->h += delta;
3015 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003016 b->l += delta;
3017
3018 return delta;
3019}
3020
3021
3022int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3023 char *old_dst = dst;
3024
3025 while (*str) {
3026 if (*str == '\\') {
3027 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003028 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003029 int len, num;
3030
3031 num = *str - '0';
3032 str++;
3033
willy tarreau8a86dbf2005-12-18 00:45:59 +01003034 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003035 len = matches[num].rm_eo - matches[num].rm_so;
3036 memcpy(dst, src + matches[num].rm_so, len);
3037 dst += len;
3038 }
3039
3040 }
3041 else if (*str == 'x') {
3042 unsigned char hex1, hex2;
3043 str++;
3044
willy tarreauc1f47532005-12-18 01:08:26 +01003045 hex1 = toupper(*str++) - '0';
3046 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003047
3048 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3049 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3050 *dst++ = (hex1<<4) + hex2;
3051 }
3052 else
3053 *dst++ = *str++;
3054 }
3055 else
3056 *dst++ = *str++;
3057 }
3058 *dst = 0;
3059 return dst - old_dst;
3060}
3061
willy tarreauc1f47532005-12-18 01:08:26 +01003062static int ishex(char s)
3063{
3064 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3065}
3066
3067/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3068char *check_replace_string(char *str)
3069{
3070 char *err = NULL;
3071 while (*str) {
3072 if (*str == '\\') {
3073 err = str; /* in case of a backslash, we return the pointer to it */
3074 str++;
3075 if (!*str)
3076 return err;
3077 else if (isdigit((int)*str))
3078 err = NULL;
3079 else if (*str == 'x') {
3080 str++;
3081 if (!ishex(*str))
3082 return err;
3083 str++;
3084 if (!ishex(*str))
3085 return err;
3086 err = NULL;
3087 }
3088 else {
3089 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3090 err = NULL;
3091 }
3092 }
3093 str++;
3094 }
3095 return err;
3096}
3097
3098
willy tarreau9fe663a2005-12-17 13:02:59 +01003099
willy tarreau0f7af912005-12-17 12:21:26 +01003100/*
3101 * manages the client FSM and its socket. BTW, it also tries to handle the
3102 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3103 * 0 else.
3104 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003106 int s = t->srv_state;
3107 int c = t->cli_state;
3108 struct buffer *req = t->req;
3109 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003110 int method_checked = 0;
3111 appsess *asession_temp = NULL;
3112 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreau750a4722005-12-17 13:21:24 +01003114#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003115 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3116 cli_stnames[c], srv_stnames[s],
3117 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3118 t->crexpire.tv_sec, t->crexpire.tv_usec,
3119 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003120#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003121 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3122 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3123 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3124 //);
3125 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003126 /* now parse the partial (or complete) headers */
3127 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3128 char *ptr;
3129 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003130 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003131
willy tarreau5cbea6f2005-12-17 12:48:26 +01003132 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003133
willy tarreau0f7af912005-12-17 12:21:26 +01003134 /* look for the end of the current header */
3135 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3136 ptr++;
3137
willy tarreau5cbea6f2005-12-17 12:48:26 +01003138 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003139 int line, len;
3140 /* we can only get here after an end of headers */
3141 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003142
willy tarreaue39cd132005-12-17 13:00:18 +01003143 if (t->flags & SN_CLDENY) {
3144 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003145 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003146 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003147 if (!(t->flags & SN_ERR_MASK))
3148 t->flags |= SN_ERR_PRXCOND;
3149 if (!(t->flags & SN_FINST_MASK))
3150 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003151 return 1;
3152 }
3153
willy tarreau5cbea6f2005-12-17 12:48:26 +01003154 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003155 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3156 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003157 }
willy tarreau0f7af912005-12-17 12:21:26 +01003158
willy tarreau9fe663a2005-12-17 13:02:59 +01003159 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003160 if (t->cli_addr.ss_family == AF_INET) {
3161 unsigned char *pn;
3162 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3163 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3164 pn[0], pn[1], pn[2], pn[3]);
3165 buffer_replace2(req, req->h, req->h, trash, len);
3166 }
3167 else if (t->cli_addr.ss_family == AF_INET6) {
3168 char pn[INET6_ADDRSTRLEN];
3169 inet_ntop(AF_INET6,
3170 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3171 pn, sizeof(pn));
3172 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3173 buffer_replace2(req, req->h, req->h, trash, len);
3174 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003175 }
3176
willy tarreau25c4ea52005-12-18 00:49:49 +01003177 /* add a "connection: close" line if needed */
3178 if (t->proxy->options & PR_O_HTTP_CLOSE)
3179 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3180
willy tarreau982249e2005-12-18 00:57:06 +01003181 if (!memcmp(req->data, "POST ", 5)) {
3182 /* this is a POST request, which is not cacheable by default */
3183 t->flags |= SN_POST;
3184 }
willy tarreaucd878942005-12-17 13:27:43 +01003185
willy tarreau5cbea6f2005-12-17 12:48:26 +01003186 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003187 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003188
willy tarreau750a4722005-12-17 13:21:24 +01003189 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003190 /* FIXME: we'll set the client in a wait state while we try to
3191 * connect to the server. Is this really needed ? wouldn't it be
3192 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003193 //FD_CLR(t->cli_fd, StaticReadEvent);
3194 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003195
3196 /* FIXME: if we break here (as up to 1.1.23), having the client
3197 * shutdown its connection can lead to an abort further.
3198 * it's better to either return 1 or even jump directly to the
3199 * data state which will save one schedule.
3200 */
3201 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003202
3203 if (!t->proxy->clitimeout ||
3204 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3205 /* If the client has no timeout, or if the server is not ready yet,
3206 * and we know for sure that it can expire, then it's cleaner to
3207 * disable the timeout on the client side so that too low values
3208 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003209 *
3210 * FIXME-20050705: the server needs a way to re-enable this time-out
3211 * when it switches its state, otherwise a client can stay connected
3212 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003213 */
3214 tv_eternity(&t->crexpire);
3215
willy tarreau197e8ec2005-12-17 14:10:59 +01003216 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003217 }
willy tarreau0f7af912005-12-17 12:21:26 +01003218
Willy TARREAU13032e72006-03-12 17:31:45 +01003219 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3220 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003221 /* this is a partial header, let's wait for more to come */
3222 req->lr = ptr;
3223 break;
3224 }
willy tarreau0f7af912005-12-17 12:21:26 +01003225
willy tarreau5cbea6f2005-12-17 12:48:26 +01003226 /* now we know that *ptr is either \r or \n,
3227 * and that there are at least 1 char after it.
3228 */
3229 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3230 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3231 else
3232 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003233
willy tarreau5cbea6f2005-12-17 12:48:26 +01003234 /*
3235 * now we know that we have a full header ; we can do whatever
3236 * we want with these pointers :
3237 * req->h = beginning of header
3238 * ptr = end of header (first \r or \n)
3239 * req->lr = beginning of next line (next rep->h)
3240 * req->r = end of data (not used at this stage)
3241 */
willy tarreau0f7af912005-12-17 12:21:26 +01003242
willy tarreau12350152005-12-18 01:03:27 +01003243 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3244 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3245 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3246
3247 /* skip ; */
3248 request_line++;
3249
3250 /* look if we have a jsessionid */
3251
3252 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3253
3254 /* skip jsessionid= */
3255 request_line += t->proxy->appsession_name_len + 1;
3256
3257 /* First try if we allready have an appsession */
3258 asession_temp = &local_asession;
3259
3260 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3261 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3262 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3263 return 0;
3264 }
3265
3266 /* Copy the sessionid */
3267 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3268 asession_temp->sessid[t->proxy->appsession_len] = 0;
3269 asession_temp->serverid = NULL;
3270
3271 /* only do insert, if lookup fails */
3272 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3273 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3274 Alert("Not enough memory process_cli():asession:calloc().\n");
3275 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3276 return 0;
3277 }
3278 asession_temp->sessid = local_asession.sessid;
3279 asession_temp->serverid = local_asession.serverid;
3280 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003281 } /* end if (chtbl_lookup()) */
3282 else {
willy tarreau12350152005-12-18 01:03:27 +01003283 /*free wasted memory;*/
3284 pool_free_to(apools.sessid, local_asession.sessid);
3285 }
3286
3287 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3288 asession_temp->request_count++;
3289
3290#if defined(DEBUG_HASH)
3291 print_table(&(t->proxy->htbl_proxy));
3292#endif
3293
3294 if (asession_temp->serverid == NULL) {
3295 Alert("Found Application Session without matching server.\n");
3296 } else {
3297 struct server *srv = t->proxy->srv;
3298 while (srv) {
3299 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3300 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3301 /* we found the server and it's usable */
3302 t->flags &= ~SN_CK_MASK;
3303 t->flags |= SN_CK_VALID | SN_DIRECT;
3304 t->srv = srv;
3305 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003306 } else {
willy tarreau12350152005-12-18 01:03:27 +01003307 t->flags &= ~SN_CK_MASK;
3308 t->flags |= SN_CK_DOWN;
3309 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003310 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003311 srv = srv->next;
3312 }/* end while(srv) */
3313 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003314 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003315 else {
3316 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3317 }
willy tarreau598da412005-12-18 01:07:29 +01003318 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003319 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003320 else{
3321 //printf("No Methode-Header with Session-String\n");
3322 }
3323
willy tarreau8337c6b2005-12-17 13:41:01 +01003324 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003325 /* we have a complete HTTP request that we must log */
3326 int urilen;
3327
willy tarreaua1598082005-12-17 13:08:06 +01003328 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003329 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003330 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003331 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003332 if (!(t->flags & SN_ERR_MASK))
3333 t->flags |= SN_ERR_PRXCOND;
3334 if (!(t->flags & SN_FINST_MASK))
3335 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003336 return 1;
3337 }
3338
3339 urilen = ptr - req->h;
3340 if (urilen >= REQURI_LEN)
3341 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003342 memcpy(t->logs.uri, req->h, urilen);
3343 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003344
willy tarreaua1598082005-12-17 13:08:06 +01003345 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003346 sess_log(t);
3347 }
willy tarreau4302f492005-12-18 01:00:37 +01003348 else if (t->logs.logwait & LW_REQHDR) {
3349 struct cap_hdr *h;
3350 int len;
3351 for (h = t->proxy->req_cap; h; h = h->next) {
3352 if ((h->namelen + 2 <= ptr - req->h) &&
3353 (req->h[h->namelen] == ':') &&
3354 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3355
3356 if (t->req_cap[h->index] == NULL)
3357 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3358
3359 len = ptr - (req->h + h->namelen + 2);
3360 if (len > h->len)
3361 len = h->len;
3362
3363 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3364 t->req_cap[h->index][len]=0;
3365 }
3366 }
3367
3368 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003369
willy tarreau5cbea6f2005-12-17 12:48:26 +01003370 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003371
willy tarreau982249e2005-12-18 00:57:06 +01003372 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003373 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003374 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 +01003375 max = ptr - req->h;
3376 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003377 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 trash[len++] = '\n';
3379 write(1, trash, len);
3380 }
willy tarreau0f7af912005-12-17 12:21:26 +01003381
willy tarreau25c4ea52005-12-18 00:49:49 +01003382
3383 /* remove "connection: " if needed */
3384 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3385 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3386 delete_header = 1;
3387 }
3388
willy tarreau5cbea6f2005-12-17 12:48:26 +01003389 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003390 if (!delete_header && t->proxy->req_exp != NULL
3391 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003392 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003393 char term;
3394
3395 term = *ptr;
3396 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003397 exp = t->proxy->req_exp;
3398 do {
3399 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3400 switch (exp->action) {
3401 case ACT_ALLOW:
3402 if (!(t->flags & SN_CLDENY))
3403 t->flags |= SN_CLALLOW;
3404 break;
3405 case ACT_REPLACE:
3406 if (!(t->flags & SN_CLDENY)) {
3407 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3408 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3409 }
3410 break;
3411 case ACT_REMOVE:
3412 if (!(t->flags & SN_CLDENY))
3413 delete_header = 1;
3414 break;
3415 case ACT_DENY:
3416 if (!(t->flags & SN_CLALLOW))
3417 t->flags |= SN_CLDENY;
3418 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003419 case ACT_PASS: /* we simply don't deny this one */
3420 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003421 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003422 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003423 }
willy tarreaue39cd132005-12-17 13:00:18 +01003424 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003425 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003426 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003427
willy tarreau240afa62005-12-17 13:14:35 +01003428 /* Now look for cookies. Conforming to RFC2109, we have to support
3429 * attributes whose name begin with a '$', and associate them with
3430 * the right cookie, if we want to delete this cookie.
3431 * So there are 3 cases for each cookie read :
3432 * 1) it's a special attribute, beginning with a '$' : ignore it.
3433 * 2) it's a server id cookie that we *MAY* want to delete : save
3434 * some pointers on it (last semi-colon, beginning of cookie...)
3435 * 3) it's an application cookie : we *MAY* have to delete a previous
3436 * "special" cookie.
3437 * At the end of loop, if a "special" cookie remains, we may have to
3438 * remove it. If no application cookie persists in the header, we
3439 * *MUST* delete it
3440 */
willy tarreau12350152005-12-18 01:03:27 +01003441 if (!delete_header &&
3442 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003443 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003444 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003446 char *del_colon, *del_cookie, *colon;
3447 int app_cookies;
3448
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003450 colon = p1;
3451 /* del_cookie == NULL => nothing to be deleted */
3452 del_colon = del_cookie = NULL;
3453 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003454
3455 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003456 /* skip spaces and colons, but keep an eye on these ones */
3457 while (p1 < ptr) {
3458 if (*p1 == ';' || *p1 == ',')
3459 colon = p1;
3460 else if (!isspace((int)*p1))
3461 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003463 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003464
3465 if (p1 == ptr)
3466 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467
3468 /* p1 is at the beginning of the cookie name */
3469 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003470 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003471 p2++;
3472
3473 if (p2 == ptr)
3474 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003475
3476 p3 = p2 + 1; /* skips the '=' sign */
3477 if (p3 == ptr)
3478 break;
3479
willy tarreau240afa62005-12-17 13:14:35 +01003480 p4 = p3;
3481 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 p4++;
3483
3484 /* here, we have the cookie name between p1 and p2,
3485 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003486 * we can process it :
3487 *
3488 * Cookie: NAME=VALUE;
3489 * | || || |
3490 * | || || +--> p4
3491 * | || |+-------> p3
3492 * | || +--------> p2
3493 * | |+------------> p1
3494 * | +-------------> colon
3495 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003496 */
3497
willy tarreau240afa62005-12-17 13:14:35 +01003498 if (*p1 == '$') {
3499 /* skip this one */
3500 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003501 else {
3502 /* first, let's see if we want to capture it */
3503 if (t->proxy->capture_name != NULL &&
3504 t->logs.cli_cookie == NULL &&
3505 (p4 - p1 >= t->proxy->capture_namelen) &&
3506 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3507 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003508
willy tarreau8337c6b2005-12-17 13:41:01 +01003509 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3510 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003511 } else {
3512 if (log_len > t->proxy->capture_len)
3513 log_len = t->proxy->capture_len;
3514 memcpy(t->logs.cli_cookie, p1, log_len);
3515 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003516 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003517 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003518
3519 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3520 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3521 /* Cool... it's the right one */
3522 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003523 char *delim;
3524
3525 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3526 * have the server ID betweek p3 and delim, and the original cookie between
3527 * delim+1 and p4. Otherwise, delim==p4 :
3528 *
3529 * Cookie: NAME=SRV~VALUE;
3530 * | || || | |
3531 * | || || | +--> p4
3532 * | || || +--------> delim
3533 * | || |+-----------> p3
3534 * | || +------------> p2
3535 * | |+----------------> p1
3536 * | +-----------------> colon
3537 * +------------------------> req->h
3538 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003539
willy tarreau0174f312005-12-18 01:02:42 +01003540 if (t->proxy->options & PR_O_COOK_PFX) {
3541 for (delim = p3; delim < p4; delim++)
3542 if (*delim == COOKIE_DELIM)
3543 break;
3544 }
3545 else
3546 delim = p4;
3547
3548
3549 /* Here, we'll look for the first running server which supports the cookie.
3550 * This allows to share a same cookie between several servers, for example
3551 * to dedicate backup servers to specific servers only.
3552 */
3553 while (srv) {
3554 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3555 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3556 /* we found the server and it's usable */
3557 t->flags &= ~SN_CK_MASK;
3558 t->flags |= SN_CK_VALID | SN_DIRECT;
3559 t->srv = srv;
3560 break;
willy tarreau12350152005-12-18 01:03:27 +01003561 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003562 /* we found a server, but it's down */
3563 t->flags &= ~SN_CK_MASK;
3564 t->flags |= SN_CK_DOWN;
3565 }
3566 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003567 srv = srv->next;
3568 }
3569
willy tarreau0174f312005-12-18 01:02:42 +01003570 if (!srv && !(t->flags & SN_CK_DOWN)) {
3571 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003572 t->flags &= ~SN_CK_MASK;
3573 t->flags |= SN_CK_INVALID;
3574 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003575
willy tarreau0174f312005-12-18 01:02:42 +01003576 /* depending on the cookie mode, we may have to either :
3577 * - delete the complete cookie if we're in insert+indirect mode, so that
3578 * the server never sees it ;
3579 * - remove the server id from the cookie value, and tag the cookie as an
3580 * application cookie so that it does not get accidentely removed later,
3581 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003582 */
willy tarreau0174f312005-12-18 01:02:42 +01003583 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3584 buffer_replace2(req, p3, delim + 1, NULL, 0);
3585 p4 -= (delim + 1 - p3);
3586 ptr -= (delim + 1 - p3);
3587 del_cookie = del_colon = NULL;
3588 app_cookies++; /* protect the header from deletion */
3589 }
3590 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003591 (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 +01003592 del_cookie = p1;
3593 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003594 }
willy tarreau12350152005-12-18 01:03:27 +01003595 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003596 /* now we know that we must keep this cookie since it's
3597 * not ours. But if we wanted to delete our cookie
3598 * earlier, we cannot remove the complete header, but we
3599 * can remove the previous block itself.
3600 */
3601 app_cookies++;
3602
3603 if (del_cookie != NULL) {
3604 buffer_replace2(req, del_cookie, p1, NULL, 0);
3605 p4 -= (p1 - del_cookie);
3606 ptr -= (p1 - del_cookie);
3607 del_cookie = del_colon = NULL;
3608 }
willy tarreau240afa62005-12-17 13:14:35 +01003609 }
willy tarreau12350152005-12-18 01:03:27 +01003610
3611 if ((t->proxy->appsession_name != NULL) &&
3612 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3613 /* first, let's see if the cookie is our appcookie*/
3614
3615 /* Cool... it's the right one */
3616
3617 asession_temp = &local_asession;
3618
3619 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3620 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3621 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3622 return 0;
3623 }
3624
3625 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3626 asession_temp->sessid[t->proxy->appsession_len] = 0;
3627 asession_temp->serverid = NULL;
3628
3629 /* only do insert, if lookup fails */
3630 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3631 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3632 Alert("Not enough memory process_cli():asession:calloc().\n");
3633 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3634 return 0;
3635 }
3636
3637 asession_temp->sessid = local_asession.sessid;
3638 asession_temp->serverid = local_asession.serverid;
3639 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3640 }
3641 else{
3642 /* free wasted memory */
3643 pool_free_to(apools.sessid, local_asession.sessid);
3644 }
3645
3646 if (asession_temp->serverid == NULL) {
3647 Alert("Found Application Session without matching server.\n");
3648 } else {
3649 struct server *srv = t->proxy->srv;
3650 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003651 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003652 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3653 /* we found the server and it's usable */
3654 t->flags &= ~SN_CK_MASK;
3655 t->flags |= SN_CK_VALID | SN_DIRECT;
3656 t->srv = srv;
3657 break;
3658 } else {
3659 t->flags &= ~SN_CK_MASK;
3660 t->flags |= SN_CK_DOWN;
3661 }
3662 }
3663 srv = srv->next;
3664 }/* end while(srv) */
3665 }/* end else if server == NULL */
3666
3667 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003668 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 }
willy tarreau240afa62005-12-17 13:14:35 +01003670
willy tarreau5cbea6f2005-12-17 12:48:26 +01003671 /* we'll have to look for another cookie ... */
3672 p1 = p4;
3673 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003674
3675 /* There's no more cookie on this line.
3676 * We may have marked the last one(s) for deletion.
3677 * We must do this now in two ways :
3678 * - if there is no app cookie, we simply delete the header ;
3679 * - if there are app cookies, we must delete the end of the
3680 * string properly, including the colon/semi-colon before
3681 * the cookie name.
3682 */
3683 if (del_cookie != NULL) {
3684 if (app_cookies) {
3685 buffer_replace2(req, del_colon, ptr, NULL, 0);
3686 /* WARNING! <ptr> becomes invalid for now. If some code
3687 * below needs to rely on it before the end of the global
3688 * header loop, we need to correct it with this code :
3689 * ptr = del_colon;
3690 */
3691 }
3692 else
3693 delete_header = 1;
3694 }
3695 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003696
3697 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003698 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003699 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003700 }
willy tarreau240afa62005-12-17 13:14:35 +01003701 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3702
willy tarreau5cbea6f2005-12-17 12:48:26 +01003703 req->h = req->lr;
3704 } /* while (req->lr < req->r) */
3705
3706 /* end of header processing (even if incomplete) */
3707
willy tarreauef900ab2005-12-17 12:52:52 +01003708 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3709 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3710 * full. We cannot loop here since event_cli_read will disable it only if
3711 * req->l == rlim-data
3712 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003713 FD_SET(t->cli_fd, StaticReadEvent);
3714 if (t->proxy->clitimeout)
3715 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3716 else
3717 tv_eternity(&t->crexpire);
3718 }
3719
willy tarreaue39cd132005-12-17 13:00:18 +01003720 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003721 * won't be able to free more later, so the session will never terminate.
3722 */
willy tarreaue39cd132005-12-17 13:00:18 +01003723 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003724 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003725 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003726 if (!(t->flags & SN_ERR_MASK))
3727 t->flags |= SN_ERR_PRXCOND;
3728 if (!(t->flags & SN_FINST_MASK))
3729 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003730 return 1;
3731 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003732 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003733 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003734 tv_eternity(&t->crexpire);
3735 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003736 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003737 if (!(t->flags & SN_ERR_MASK))
3738 t->flags |= SN_ERR_CLICL;
3739 if (!(t->flags & SN_FINST_MASK))
3740 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003741 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003742 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003743 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3744
3745 /* read timeout : give up with an error message.
3746 */
3747 t->logs.status = 408;
3748 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003749 if (!(t->flags & SN_ERR_MASK))
3750 t->flags |= SN_ERR_CLITO;
3751 if (!(t->flags & SN_FINST_MASK))
3752 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003753 return 1;
3754 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755
3756 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003757 }
3758 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003759 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003760 /* FIXME: this error handling is partly buggy because we always report
3761 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3762 * or HEADER phase. BTW, it's not logical to expire the client while
3763 * we're waiting for the server to connect.
3764 */
willy tarreau0f7af912005-12-17 12:21:26 +01003765 /* read or write error */
3766 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003767 tv_eternity(&t->crexpire);
3768 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003769 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003770 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003771 if (!(t->flags & SN_ERR_MASK))
3772 t->flags |= SN_ERR_CLICL;
3773 if (!(t->flags & SN_FINST_MASK))
3774 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003775 return 1;
3776 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003777 /* last read, or end of server write */
3778 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003779 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003780 tv_eternity(&t->crexpire);
3781 shutdown(t->cli_fd, SHUT_RD);
3782 t->cli_state = CL_STSHUTR;
3783 return 1;
3784 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003785 /* last server read and buffer empty */
3786 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003787 FD_CLR(t->cli_fd, StaticWriteEvent);
3788 tv_eternity(&t->cwexpire);
3789 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003790 /* We must ensure that the read part is still alive when switching
3791 * to shutw */
3792 FD_SET(t->cli_fd, StaticReadEvent);
3793 if (t->proxy->clitimeout)
3794 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003795 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003796 //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 +01003797 return 1;
3798 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003799 /* read timeout */
3800 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3801 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003802 tv_eternity(&t->crexpire);
3803 shutdown(t->cli_fd, SHUT_RD);
3804 t->cli_state = CL_STSHUTR;
3805 if (!(t->flags & SN_ERR_MASK))
3806 t->flags |= SN_ERR_CLITO;
3807 if (!(t->flags & SN_FINST_MASK))
3808 t->flags |= SN_FINST_D;
3809 return 1;
3810 }
3811 /* write timeout */
3812 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3813 FD_CLR(t->cli_fd, StaticWriteEvent);
3814 tv_eternity(&t->cwexpire);
3815 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003816 /* We must ensure that the read part is still alive when switching
3817 * to shutw */
3818 FD_SET(t->cli_fd, StaticReadEvent);
3819 if (t->proxy->clitimeout)
3820 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3821
willy tarreau036e1ce2005-12-17 13:46:33 +01003822 t->cli_state = CL_STSHUTW;
3823 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003824 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003825 if (!(t->flags & SN_FINST_MASK))
3826 t->flags |= SN_FINST_D;
3827 return 1;
3828 }
willy tarreau0f7af912005-12-17 12:21:26 +01003829
willy tarreauc58fc692005-12-17 14:13:08 +01003830 if (req->l >= req->rlim - req->data) {
3831 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003832 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003833 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003834 FD_CLR(t->cli_fd, StaticReadEvent);
3835 tv_eternity(&t->crexpire);
3836 }
3837 }
3838 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003839 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003840 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3841 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003842 if (!t->proxy->clitimeout ||
3843 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3844 /* If the client has no timeout, or if the server not ready yet, and we
3845 * know for sure that it can expire, then it's cleaner to disable the
3846 * timeout on the client side so that too low values cannot make the
3847 * sessions abort too early.
3848 */
willy tarreau0f7af912005-12-17 12:21:26 +01003849 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003850 else
3851 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003852 }
3853 }
3854
3855 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003856 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003857 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3858 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3859 tv_eternity(&t->cwexpire);
3860 }
3861 }
3862 else { /* buffer not empty */
3863 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3864 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003865 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003866 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003867 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3868 t->crexpire = t->cwexpire;
3869 }
willy tarreau0f7af912005-12-17 12:21:26 +01003870 else
3871 tv_eternity(&t->cwexpire);
3872 }
3873 }
3874 return 0; /* other cases change nothing */
3875 }
3876 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003877 if (t->res_cw == RES_ERROR) {
3878 tv_eternity(&t->cwexpire);
3879 fd_delete(t->cli_fd);
3880 t->cli_state = CL_STCLOSE;
3881 if (!(t->flags & SN_ERR_MASK))
3882 t->flags |= SN_ERR_CLICL;
3883 if (!(t->flags & SN_FINST_MASK))
3884 t->flags |= SN_FINST_D;
3885 return 1;
3886 }
3887 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003888 tv_eternity(&t->cwexpire);
3889 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003890 t->cli_state = CL_STCLOSE;
3891 return 1;
3892 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003893 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3894 tv_eternity(&t->cwexpire);
3895 fd_delete(t->cli_fd);
3896 t->cli_state = CL_STCLOSE;
3897 if (!(t->flags & SN_ERR_MASK))
3898 t->flags |= SN_ERR_CLITO;
3899 if (!(t->flags & SN_FINST_MASK))
3900 t->flags |= SN_FINST_D;
3901 return 1;
3902 }
willy tarreau0f7af912005-12-17 12:21:26 +01003903 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003904 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003905 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3906 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3907 tv_eternity(&t->cwexpire);
3908 }
3909 }
3910 else { /* buffer not empty */
3911 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3912 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003913 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003914 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003915 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3916 t->crexpire = t->cwexpire;
3917 }
willy tarreau0f7af912005-12-17 12:21:26 +01003918 else
3919 tv_eternity(&t->cwexpire);
3920 }
3921 }
3922 return 0;
3923 }
3924 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003925 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003926 tv_eternity(&t->crexpire);
3927 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003928 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003929 if (!(t->flags & SN_ERR_MASK))
3930 t->flags |= SN_ERR_CLICL;
3931 if (!(t->flags & SN_FINST_MASK))
3932 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003933 return 1;
3934 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003935 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3936 tv_eternity(&t->crexpire);
3937 fd_delete(t->cli_fd);
3938 t->cli_state = CL_STCLOSE;
3939 return 1;
3940 }
3941 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3942 tv_eternity(&t->crexpire);
3943 fd_delete(t->cli_fd);
3944 t->cli_state = CL_STCLOSE;
3945 if (!(t->flags & SN_ERR_MASK))
3946 t->flags |= SN_ERR_CLITO;
3947 if (!(t->flags & SN_FINST_MASK))
3948 t->flags |= SN_FINST_D;
3949 return 1;
3950 }
willy tarreauef900ab2005-12-17 12:52:52 +01003951 else if (req->l >= req->rlim - req->data) {
3952 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003953
3954 /* FIXME-20050705: is it possible for a client to maintain a session
3955 * after the timeout by sending more data after it receives a close ?
3956 */
3957
willy tarreau0f7af912005-12-17 12:21:26 +01003958 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003959 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003960 FD_CLR(t->cli_fd, StaticReadEvent);
3961 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003962 //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 +01003963 }
3964 }
3965 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003966 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003967 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3968 FD_SET(t->cli_fd, StaticReadEvent);
3969 if (t->proxy->clitimeout)
3970 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3971 else
3972 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003973 //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 +01003974 }
3975 }
3976 return 0;
3977 }
3978 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003979 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003980 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003981 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 +01003982 write(1, trash, len);
3983 }
3984 return 0;
3985 }
3986 return 0;
3987}
3988
3989
3990/*
3991 * manages the server FSM and its socket. It returns 1 if a state has changed
3992 * (and a resync may be needed), 0 else.
3993 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003994int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003995 int s = t->srv_state;
3996 int c = t->cli_state;
3997 struct buffer *req = t->req;
3998 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003999 appsess *asession_temp = NULL;
4000 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004001 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004002
willy tarreau750a4722005-12-17 13:21:24 +01004003#ifdef DEBUG_FULL
4004 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4005#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4007 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4008 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4009 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004010 if (s == SV_STIDLE) {
4011 if (c == CL_STHEADERS)
4012 return 0; /* stay in idle, waiting for data to reach the client side */
4013 else if (c == CL_STCLOSE ||
4014 c == CL_STSHUTW ||
4015 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4016 tv_eternity(&t->cnexpire);
4017 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004018 if (!(t->flags & SN_ERR_MASK))
4019 t->flags |= SN_ERR_CLICL;
4020 if (!(t->flags & SN_FINST_MASK))
4021 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004022 return 1;
4023 }
4024 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004025 /* initiate a connection to the server */
4026 conn_err = connect_server(t);
4027 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004028 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4029 t->srv_state = SV_STCONN;
4030 }
4031 else { /* try again */
4032 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004033 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004034 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004035 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004036 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4037 t->flags &= ~SN_CK_MASK;
4038 t->flags |= SN_CK_DOWN;
4039 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 }
4041
willy tarreaub1285d52005-12-18 01:20:14 +01004042 conn_err = connect_server(t);
4043 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004044 t->srv_state = SV_STCONN;
4045 break;
4046 }
4047 }
4048 if (t->conn_retries < 0) {
4049 /* if conn_retries < 0 or other error, let's abort */
4050 tv_eternity(&t->cnexpire);
4051 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004052 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004053 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004054 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004055 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004056 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004057 if (!(t->flags & SN_FINST_MASK))
4058 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004059 }
4060 }
4061 return 1;
4062 }
4063 }
4064 else if (s == SV_STCONN) { /* connection in progress */
4065 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004066 //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 +01004067 return 0; /* nothing changed */
4068 }
4069 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4070 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4071 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004072 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004073 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004074 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004075 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004076 if (t->conn_retries >= 0) {
4077 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004078 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004079 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004080 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4081 t->flags &= ~SN_CK_MASK;
4082 t->flags |= SN_CK_DOWN;
4083 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004084 }
willy tarreaub1285d52005-12-18 01:20:14 +01004085 conn_err = connect_server(t);
4086 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004087 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004088 }
willy tarreaub1285d52005-12-18 01:20:14 +01004089 else if (t->res_sw == RES_SILENT)
4090 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4091 else
4092 conn_err = SN_ERR_SRVCL; // it was a connect error.
4093
willy tarreau0f7af912005-12-17 12:21:26 +01004094 /* if conn_retries < 0 or other error, let's abort */
4095 tv_eternity(&t->cnexpire);
4096 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004097 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004098 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004099 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004100 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004101 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004102 if (!(t->flags & SN_FINST_MASK))
4103 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004104 return 1;
4105 }
4106 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004107 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004108
willy tarreau0f7af912005-12-17 12:21:26 +01004109 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004110 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004111 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004112 tv_eternity(&t->swexpire);
4113 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004114 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004115 if (t->proxy->srvtimeout) {
4116 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4117 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4118 t->srexpire = t->swexpire;
4119 }
4120 else
4121 tv_eternity(&t->swexpire);
4122 }
willy tarreau0f7af912005-12-17 12:21:26 +01004123
4124 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4125 FD_SET(t->srv_fd, StaticReadEvent);
4126 if (t->proxy->srvtimeout)
4127 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4128 else
4129 tv_eternity(&t->srexpire);
4130
4131 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004132 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004133
4134 /* if the user wants to log as soon as possible, without counting
4135 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004136 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004137 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4138 sess_log(t);
4139 }
willy tarreau0f7af912005-12-17 12:21:26 +01004140 }
willy tarreauef900ab2005-12-17 12:52:52 +01004141 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004142 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004143 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4144 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004145 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004146 return 1;
4147 }
4148 }
4149 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004150 /* now parse the partial (or complete) headers */
4151 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4152 char *ptr;
4153 int delete_header;
4154
4155 ptr = rep->lr;
4156
4157 /* look for the end of the current header */
4158 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4159 ptr++;
4160
4161 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004162 int line, len;
4163
4164 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004165
4166 /* first, we'll block if security checks have caught nasty things */
4167 if (t->flags & SN_CACHEABLE) {
4168 if ((t->flags & SN_CACHE_COOK) &&
4169 (t->flags & SN_SCK_ANY) &&
4170 (t->proxy->options & PR_O_CHK_CACHE)) {
4171
4172 /* we're in presence of a cacheable response containing
4173 * a set-cookie header. We'll block it as requested by
4174 * the 'checkcache' option, and send an alert.
4175 */
4176 tv_eternity(&t->srexpire);
4177 tv_eternity(&t->swexpire);
4178 fd_delete(t->srv_fd);
4179 t->srv_state = SV_STCLOSE;
4180 t->logs.status = 502;
4181 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4182 if (!(t->flags & SN_ERR_MASK))
4183 t->flags |= SN_ERR_PRXCOND;
4184 if (!(t->flags & SN_FINST_MASK))
4185 t->flags |= SN_FINST_H;
4186
4187 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4188 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4189
4190 return 1;
4191 }
4192 }
4193
willy tarreau982249e2005-12-18 00:57:06 +01004194 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4195 if (t->flags & SN_SVDENY) {
4196 tv_eternity(&t->srexpire);
4197 tv_eternity(&t->swexpire);
4198 fd_delete(t->srv_fd);
4199 t->srv_state = SV_STCLOSE;
4200 t->logs.status = 502;
4201 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4202 if (!(t->flags & SN_ERR_MASK))
4203 t->flags |= SN_ERR_PRXCOND;
4204 if (!(t->flags & SN_FINST_MASK))
4205 t->flags |= SN_FINST_H;
4206 return 1;
4207 }
4208
willy tarreau5cbea6f2005-12-17 12:48:26 +01004209 /* we'll have something else to do here : add new headers ... */
4210
willy tarreaucd878942005-12-17 13:27:43 +01004211 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4212 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004214 * insert a set-cookie here, except if we want to insert only on POST
4215 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004216 */
willy tarreau750a4722005-12-17 13:21:24 +01004217 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004218 t->proxy->cookie_name,
4219 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004220
willy tarreau036e1ce2005-12-17 13:46:33 +01004221 t->flags |= SN_SCK_INSERTED;
4222
willy tarreau750a4722005-12-17 13:21:24 +01004223 /* Here, we will tell an eventual cache on the client side that we don't
4224 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4225 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4226 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4227 */
willy tarreau240afa62005-12-17 13:14:35 +01004228 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004229 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4230 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004231
4232 if (rep->data + rep->l < rep->h)
4233 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4234 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004235 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236 }
4237
4238 /* headers to be added */
4239 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004240 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4241 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004242 }
4243
willy tarreau25c4ea52005-12-18 00:49:49 +01004244 /* add a "connection: close" line if needed */
4245 if (t->proxy->options & PR_O_HTTP_CLOSE)
4246 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4247
willy tarreau5cbea6f2005-12-17 12:48:26 +01004248 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004249 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004250 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004251
Willy TARREAU767ba712006-03-01 22:40:50 +01004252 /* client connection already closed or option 'httpclose' required :
4253 * we close the server's outgoing connection right now.
4254 */
4255 if ((req->l == 0) &&
4256 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4257 FD_CLR(t->srv_fd, StaticWriteEvent);
4258 tv_eternity(&t->swexpire);
4259
4260 /* We must ensure that the read part is still alive when switching
4261 * to shutw */
4262 FD_SET(t->srv_fd, StaticReadEvent);
4263 if (t->proxy->srvtimeout)
4264 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4265
4266 shutdown(t->srv_fd, SHUT_WR);
4267 t->srv_state = SV_STSHUTW;
4268 }
4269
willy tarreau25c4ea52005-12-18 00:49:49 +01004270 /* if the user wants to log as soon as possible, without counting
4271 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004272 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004273 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4274 t->logs.bytes = rep->h - rep->data;
4275 sess_log(t);
4276 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004277 break;
4278 }
4279
4280 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4281 if (ptr > rep->r - 2) {
4282 /* this is a partial header, let's wait for more to come */
4283 rep->lr = ptr;
4284 break;
4285 }
4286
4287 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4288 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4289
4290 /* now we know that *ptr is either \r or \n,
4291 * and that there are at least 1 char after it.
4292 */
4293 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4294 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4295 else
4296 rep->lr = ptr + 2; /* \r\n or \n\r */
4297
4298 /*
4299 * now we know that we have a full header ; we can do whatever
4300 * we want with these pointers :
4301 * rep->h = beginning of header
4302 * ptr = end of header (first \r or \n)
4303 * rep->lr = beginning of next line (next rep->h)
4304 * rep->r = end of data (not used at this stage)
4305 */
4306
willy tarreaua1598082005-12-17 13:08:06 +01004307
willy tarreau982249e2005-12-18 00:57:06 +01004308 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004309 t->logs.logwait &= ~LW_RESP;
4310 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004311 switch (t->logs.status) {
4312 case 200:
4313 case 203:
4314 case 206:
4315 case 300:
4316 case 301:
4317 case 410:
4318 /* RFC2616 @13.4:
4319 * "A response received with a status code of
4320 * 200, 203, 206, 300, 301 or 410 MAY be stored
4321 * by a cache (...) unless a cache-control
4322 * directive prohibits caching."
4323 *
4324 * RFC2616 @9.5: POST method :
4325 * "Responses to this method are not cacheable,
4326 * unless the response includes appropriate
4327 * Cache-Control or Expires header fields."
4328 */
4329 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4330 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4331 break;
4332 default:
4333 break;
4334 }
willy tarreau4302f492005-12-18 01:00:37 +01004335 }
4336 else if (t->logs.logwait & LW_RSPHDR) {
4337 struct cap_hdr *h;
4338 int len;
4339 for (h = t->proxy->rsp_cap; h; h = h->next) {
4340 if ((h->namelen + 2 <= ptr - rep->h) &&
4341 (rep->h[h->namelen] == ':') &&
4342 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4343
4344 if (t->rsp_cap[h->index] == NULL)
4345 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4346
4347 len = ptr - (rep->h + h->namelen + 2);
4348 if (len > h->len)
4349 len = h->len;
4350
4351 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4352 t->rsp_cap[h->index][len]=0;
4353 }
4354 }
4355
willy tarreaua1598082005-12-17 13:08:06 +01004356 }
4357
willy tarreau5cbea6f2005-12-17 12:48:26 +01004358 delete_header = 0;
4359
willy tarreau982249e2005-12-18 00:57:06 +01004360 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004361 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004362 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 +01004363 max = ptr - rep->h;
4364 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004365 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004366 trash[len++] = '\n';
4367 write(1, trash, len);
4368 }
4369
willy tarreau25c4ea52005-12-18 00:49:49 +01004370 /* remove "connection: " if needed */
4371 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4372 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4373 delete_header = 1;
4374 }
4375
willy tarreau5cbea6f2005-12-17 12:48:26 +01004376 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004377 if (!delete_header && t->proxy->rsp_exp != NULL
4378 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004379 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004380 char term;
4381
4382 term = *ptr;
4383 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004384 exp = t->proxy->rsp_exp;
4385 do {
4386 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4387 switch (exp->action) {
4388 case ACT_ALLOW:
4389 if (!(t->flags & SN_SVDENY))
4390 t->flags |= SN_SVALLOW;
4391 break;
4392 case ACT_REPLACE:
4393 if (!(t->flags & SN_SVDENY)) {
4394 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4395 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4396 }
4397 break;
4398 case ACT_REMOVE:
4399 if (!(t->flags & SN_SVDENY))
4400 delete_header = 1;
4401 break;
4402 case ACT_DENY:
4403 if (!(t->flags & SN_SVALLOW))
4404 t->flags |= SN_SVDENY;
4405 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004406 case ACT_PASS: /* we simply don't deny this one */
4407 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004408 }
4409 break;
4410 }
willy tarreaue39cd132005-12-17 13:00:18 +01004411 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004412 *ptr = term; /* restore the string terminator */
4413 }
4414
willy tarreau97f58572005-12-18 00:53:44 +01004415 /* check for cache-control: or pragma: headers */
4416 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4417 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4418 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4419 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4420 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004421 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004422 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4423 else {
4424 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004425 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004426 t->flags &= ~SN_CACHE_COOK;
4427 }
4428 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004429 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004430 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004431 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004432 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4433 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004434 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004435 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004436 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4437 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4438 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4439 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4440 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4441 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004442 }
4443 }
4444 }
4445
willy tarreau5cbea6f2005-12-17 12:48:26 +01004446 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004447 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004448 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004449 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004450 char *p1, *p2, *p3, *p4;
4451
willy tarreau97f58572005-12-18 00:53:44 +01004452 t->flags |= SN_SCK_ANY;
4453
willy tarreau5cbea6f2005-12-17 12:48:26 +01004454 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4455
4456 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004457 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004458 p1++;
4459
4460 if (p1 == ptr || *p1 == ';') /* end of cookie */
4461 break;
4462
4463 /* p1 is at the beginning of the cookie name */
4464 p2 = p1;
4465
4466 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4467 p2++;
4468
4469 if (p2 == ptr || *p2 == ';') /* next cookie */
4470 break;
4471
4472 p3 = p2 + 1; /* skips the '=' sign */
4473 if (p3 == ptr)
4474 break;
4475
4476 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004477 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004478 p4++;
4479
4480 /* here, we have the cookie name between p1 and p2,
4481 * and its value between p3 and p4.
4482 * we can process it.
4483 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004484
4485 /* first, let's see if we want to capture it */
4486 if (t->proxy->capture_name != NULL &&
4487 t->logs.srv_cookie == NULL &&
4488 (p4 - p1 >= t->proxy->capture_namelen) &&
4489 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4490 int log_len = p4 - p1;
4491
4492 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4493 Alert("HTTP logging : out of memory.\n");
4494 }
4495
4496 if (log_len > t->proxy->capture_len)
4497 log_len = t->proxy->capture_len;
4498 memcpy(t->logs.srv_cookie, p1, log_len);
4499 t->logs.srv_cookie[log_len] = 0;
4500 }
4501
4502 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4503 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004504 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004505 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004506
4507 /* If the cookie is in insert mode on a known server, we'll delete
4508 * this occurrence because we'll insert another one later.
4509 * We'll delete it too if the "indirect" option is set and we're in
4510 * a direct access. */
4511 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004512 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004513 /* this header must be deleted */
4514 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004515 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004516 }
4517 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4518 /* replace bytes p3->p4 with the cookie name associated
4519 * with this server since we know it.
4520 */
4521 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004522 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004523 }
willy tarreau0174f312005-12-18 01:02:42 +01004524 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4525 /* insert the cookie name associated with this server
4526 * before existing cookie, and insert a delimitor between them..
4527 */
4528 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4529 p3[t->srv->cklen] = COOKIE_DELIM;
4530 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4531 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004532 break;
4533 }
willy tarreau12350152005-12-18 01:03:27 +01004534
4535 /* first, let's see if the cookie is our appcookie*/
4536 if ((t->proxy->appsession_name != NULL) &&
4537 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4538
4539 /* Cool... it's the right one */
4540
willy tarreaub952e1d2005-12-18 01:31:20 +01004541 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004542 asession_temp = &local_asession;
4543
willy tarreaub952e1d2005-12-18 01:31:20 +01004544 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004545 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4546 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4547 }
4548 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4549 asession_temp->sessid[t->proxy->appsession_len] = 0;
4550 asession_temp->serverid = NULL;
4551
4552 /* only do insert, if lookup fails */
4553 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4554 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4555 Alert("Not enought Memory process_srv():asession:calloc().\n");
4556 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4557 return 0;
4558 }
4559 asession_temp->sessid = local_asession.sessid;
4560 asession_temp->serverid = local_asession.serverid;
4561 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004562 }/* end if (chtbl_lookup()) */
4563 else {
willy tarreau12350152005-12-18 01:03:27 +01004564 /* free wasted memory */
4565 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004566 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004567
willy tarreaub952e1d2005-12-18 01:31:20 +01004568 if (asession_temp->serverid == NULL) {
4569 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004570 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4571 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4572 }
4573 asession_temp->serverid[0] = '\0';
4574 }
4575
willy tarreaub952e1d2005-12-18 01:31:20 +01004576 if (asession_temp->serverid[0] == '\0')
4577 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004578
4579 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4580
4581#if defined(DEBUG_HASH)
4582 print_table(&(t->proxy->htbl_proxy));
4583#endif
4584 break;
4585 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004586 else {
4587 // fprintf(stderr,"Ignoring unknown cookie : ");
4588 // write(2, p1, p2-p1);
4589 // fprintf(stderr," = ");
4590 // write(2, p3, p4-p3);
4591 // fprintf(stderr,"\n");
4592 }
4593 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4594 } /* we're now at the end of the cookie value */
4595 } /* end of cookie processing */
4596
willy tarreau97f58572005-12-18 00:53:44 +01004597 /* check for any set-cookie in case we check for cacheability */
4598 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4599 (t->proxy->options & PR_O_CHK_CACHE) &&
4600 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4601 t->flags |= SN_SCK_ANY;
4602 }
4603
willy tarreau5cbea6f2005-12-17 12:48:26 +01004604 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004605 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004606 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004607
willy tarreau5cbea6f2005-12-17 12:48:26 +01004608 rep->h = rep->lr;
4609 } /* while (rep->lr < rep->r) */
4610
4611 /* end of header processing (even if incomplete) */
4612
willy tarreauef900ab2005-12-17 12:52:52 +01004613 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4614 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4615 * full. We cannot loop here since event_srv_read will disable it only if
4616 * rep->l == rlim-data
4617 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004618 FD_SET(t->srv_fd, StaticReadEvent);
4619 if (t->proxy->srvtimeout)
4620 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4621 else
4622 tv_eternity(&t->srexpire);
4623 }
willy tarreau0f7af912005-12-17 12:21:26 +01004624
willy tarreau8337c6b2005-12-17 13:41:01 +01004625 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004626 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004627 tv_eternity(&t->srexpire);
4628 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004629 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004630 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004631 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004632 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004633 if (!(t->flags & SN_ERR_MASK))
4634 t->flags |= SN_ERR_SRVCL;
4635 if (!(t->flags & SN_FINST_MASK))
4636 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004637 return 1;
4638 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004639 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004640 * since we are in header mode, if there's no space left for headers, we
4641 * won't be able to free more later, so the session will never terminate.
4642 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004643 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 +01004644 FD_CLR(t->srv_fd, StaticReadEvent);
4645 tv_eternity(&t->srexpire);
4646 shutdown(t->srv_fd, SHUT_RD);
4647 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004648 //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 +01004649 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004650 }
4651 /* read timeout : return a 504 to the client.
4652 */
4653 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4654 tv_eternity(&t->srexpire);
4655 tv_eternity(&t->swexpire);
4656 fd_delete(t->srv_fd);
4657 t->srv_state = SV_STCLOSE;
4658 t->logs.status = 504;
4659 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004660 if (!(t->flags & SN_ERR_MASK))
4661 t->flags |= SN_ERR_SRVTO;
4662 if (!(t->flags & SN_FINST_MASK))
4663 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004664 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004665
4666 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004667 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004668 /* FIXME!!! here, we don't want to switch to SHUTW if the
4669 * client shuts read too early, because we may still have
4670 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004671 * The side-effect is that if the client completely closes its
4672 * connection during SV_STHEADER, the connection to the server
4673 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004674 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004675 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004676 FD_CLR(t->srv_fd, StaticWriteEvent);
4677 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004678
4679 /* We must ensure that the read part is still alive when switching
4680 * to shutw */
4681 FD_SET(t->srv_fd, StaticReadEvent);
4682 if (t->proxy->srvtimeout)
4683 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4684
willy tarreau0f7af912005-12-17 12:21:26 +01004685 shutdown(t->srv_fd, SHUT_WR);
4686 t->srv_state = SV_STSHUTW;
4687 return 1;
4688 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004689 /* write timeout */
4690 /* FIXME!!! here, we don't want to switch to SHUTW if the
4691 * client shuts read too early, because we may still have
4692 * some work to do on the headers.
4693 */
4694 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4695 FD_CLR(t->srv_fd, StaticWriteEvent);
4696 tv_eternity(&t->swexpire);
4697 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004698 /* We must ensure that the read part is still alive when switching
4699 * to shutw */
4700 FD_SET(t->srv_fd, StaticReadEvent);
4701 if (t->proxy->srvtimeout)
4702 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4703
4704 /* We must ensure that the read part is still alive when switching
4705 * to shutw */
4706 FD_SET(t->srv_fd, StaticReadEvent);
4707 if (t->proxy->srvtimeout)
4708 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4709
willy tarreau036e1ce2005-12-17 13:46:33 +01004710 t->srv_state = SV_STSHUTW;
4711 if (!(t->flags & SN_ERR_MASK))
4712 t->flags |= SN_ERR_SRVTO;
4713 if (!(t->flags & SN_FINST_MASK))
4714 t->flags |= SN_FINST_H;
4715 return 1;
4716 }
willy tarreau0f7af912005-12-17 12:21:26 +01004717
4718 if (req->l == 0) {
4719 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4720 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4721 tv_eternity(&t->swexpire);
4722 }
4723 }
4724 else { /* client buffer not empty */
4725 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4726 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004727 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004728 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004729 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4730 t->srexpire = t->swexpire;
4731 }
willy tarreau0f7af912005-12-17 12:21:26 +01004732 else
4733 tv_eternity(&t->swexpire);
4734 }
4735 }
4736
willy tarreau5cbea6f2005-12-17 12:48:26 +01004737 /* be nice with the client side which would like to send a complete header
4738 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4739 * would read all remaining data at once ! The client should not write past rep->lr
4740 * when the server is in header state.
4741 */
4742 //return header_processed;
4743 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004744 }
4745 else if (s == SV_STDATA) {
4746 /* read or write error */
4747 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004748 tv_eternity(&t->srexpire);
4749 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004750 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004751 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004752 if (!(t->flags & SN_ERR_MASK))
4753 t->flags |= SN_ERR_SRVCL;
4754 if (!(t->flags & SN_FINST_MASK))
4755 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004756 return 1;
4757 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004758 /* last read, or end of client write */
4759 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004760 FD_CLR(t->srv_fd, StaticReadEvent);
4761 tv_eternity(&t->srexpire);
4762 shutdown(t->srv_fd, SHUT_RD);
4763 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004764 //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 +01004765 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004766 }
4767 /* end of client read and no more data to send */
4768 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4769 FD_CLR(t->srv_fd, StaticWriteEvent);
4770 tv_eternity(&t->swexpire);
4771 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004772 /* We must ensure that the read part is still alive when switching
4773 * to shutw */
4774 FD_SET(t->srv_fd, StaticReadEvent);
4775 if (t->proxy->srvtimeout)
4776 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4777
willy tarreaua41a8b42005-12-17 14:02:24 +01004778 t->srv_state = SV_STSHUTW;
4779 return 1;
4780 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004781 /* read timeout */
4782 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4783 FD_CLR(t->srv_fd, StaticReadEvent);
4784 tv_eternity(&t->srexpire);
4785 shutdown(t->srv_fd, SHUT_RD);
4786 t->srv_state = SV_STSHUTR;
4787 if (!(t->flags & SN_ERR_MASK))
4788 t->flags |= SN_ERR_SRVTO;
4789 if (!(t->flags & SN_FINST_MASK))
4790 t->flags |= SN_FINST_D;
4791 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004792 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004793 /* write timeout */
4794 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004795 FD_CLR(t->srv_fd, StaticWriteEvent);
4796 tv_eternity(&t->swexpire);
4797 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004798 /* We must ensure that the read part is still alive when switching
4799 * to shutw */
4800 FD_SET(t->srv_fd, StaticReadEvent);
4801 if (t->proxy->srvtimeout)
4802 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004803 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004804 if (!(t->flags & SN_ERR_MASK))
4805 t->flags |= SN_ERR_SRVTO;
4806 if (!(t->flags & SN_FINST_MASK))
4807 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004808 return 1;
4809 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004810
4811 /* recompute request time-outs */
4812 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004813 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4814 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4815 tv_eternity(&t->swexpire);
4816 }
4817 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004818 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004819 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4820 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004821 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004822 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004823 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4824 t->srexpire = t->swexpire;
4825 }
willy tarreau0f7af912005-12-17 12:21:26 +01004826 else
4827 tv_eternity(&t->swexpire);
4828 }
4829 }
4830
willy tarreaub1ff9db2005-12-17 13:51:03 +01004831 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004832 if (rep->l == BUFSIZE) { /* no room to read more data */
4833 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4834 FD_CLR(t->srv_fd, StaticReadEvent);
4835 tv_eternity(&t->srexpire);
4836 }
4837 }
4838 else {
4839 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4840 FD_SET(t->srv_fd, StaticReadEvent);
4841 if (t->proxy->srvtimeout)
4842 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4843 else
4844 tv_eternity(&t->srexpire);
4845 }
4846 }
4847
4848 return 0; /* other cases change nothing */
4849 }
4850 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004851 if (t->res_sw == RES_ERROR) {
4852 //FD_CLR(t->srv_fd, StaticWriteEvent);
4853 tv_eternity(&t->swexpire);
4854 fd_delete(t->srv_fd);
4855 //close(t->srv_fd);
4856 t->srv_state = SV_STCLOSE;
4857 if (!(t->flags & SN_ERR_MASK))
4858 t->flags |= SN_ERR_SRVCL;
4859 if (!(t->flags & SN_FINST_MASK))
4860 t->flags |= SN_FINST_D;
4861 return 1;
4862 }
4863 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004864 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004865 tv_eternity(&t->swexpire);
4866 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004867 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004868 t->srv_state = SV_STCLOSE;
4869 return 1;
4870 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004871 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4872 //FD_CLR(t->srv_fd, StaticWriteEvent);
4873 tv_eternity(&t->swexpire);
4874 fd_delete(t->srv_fd);
4875 //close(t->srv_fd);
4876 t->srv_state = SV_STCLOSE;
4877 if (!(t->flags & SN_ERR_MASK))
4878 t->flags |= SN_ERR_SRVTO;
4879 if (!(t->flags & SN_FINST_MASK))
4880 t->flags |= SN_FINST_D;
4881 return 1;
4882 }
willy tarreau0f7af912005-12-17 12:21:26 +01004883 else if (req->l == 0) {
4884 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4885 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4886 tv_eternity(&t->swexpire);
4887 }
4888 }
4889 else { /* buffer not empty */
4890 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4891 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004892 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004893 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004894 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4895 t->srexpire = t->swexpire;
4896 }
willy tarreau0f7af912005-12-17 12:21:26 +01004897 else
4898 tv_eternity(&t->swexpire);
4899 }
4900 }
4901 return 0;
4902 }
4903 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004904 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004905 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004906 tv_eternity(&t->srexpire);
4907 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004908 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004909 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004910 if (!(t->flags & SN_ERR_MASK))
4911 t->flags |= SN_ERR_SRVCL;
4912 if (!(t->flags & SN_FINST_MASK))
4913 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004914 return 1;
4915 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004916 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4917 //FD_CLR(t->srv_fd, StaticReadEvent);
4918 tv_eternity(&t->srexpire);
4919 fd_delete(t->srv_fd);
4920 //close(t->srv_fd);
4921 t->srv_state = SV_STCLOSE;
4922 return 1;
4923 }
4924 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4925 //FD_CLR(t->srv_fd, StaticReadEvent);
4926 tv_eternity(&t->srexpire);
4927 fd_delete(t->srv_fd);
4928 //close(t->srv_fd);
4929 t->srv_state = SV_STCLOSE;
4930 if (!(t->flags & SN_ERR_MASK))
4931 t->flags |= SN_ERR_SRVTO;
4932 if (!(t->flags & SN_FINST_MASK))
4933 t->flags |= SN_FINST_D;
4934 return 1;
4935 }
willy tarreau0f7af912005-12-17 12:21:26 +01004936 else if (rep->l == BUFSIZE) { /* no room to read more data */
4937 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4938 FD_CLR(t->srv_fd, StaticReadEvent);
4939 tv_eternity(&t->srexpire);
4940 }
4941 }
4942 else {
4943 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4944 FD_SET(t->srv_fd, StaticReadEvent);
4945 if (t->proxy->srvtimeout)
4946 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4947 else
4948 tv_eternity(&t->srexpire);
4949 }
4950 }
4951 return 0;
4952 }
4953 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004954 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004955 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004956 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 +01004957 write(1, trash, len);
4958 }
4959 return 0;
4960 }
4961 return 0;
4962}
4963
4964
willy tarreau5cbea6f2005-12-17 12:48:26 +01004965/* Processes the client and server jobs of a session task, then
4966 * puts it back to the wait queue in a clean state, or
4967 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004968 * the time the task accepts to wait, or TIME_ETERNITY for
4969 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004970 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004971int process_session(struct task *t) {
4972 struct session *s = t->context;
4973 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004974
willy tarreau5cbea6f2005-12-17 12:48:26 +01004975 do {
4976 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01004977 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004978 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004979 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004980 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004981 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004982 } while (fsm_resync);
4983
4984 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004985 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004986 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004987
willy tarreau5cbea6f2005-12-17 12:48:26 +01004988 tv_min(&min1, &s->crexpire, &s->cwexpire);
4989 tv_min(&min2, &s->srexpire, &s->swexpire);
4990 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004991 tv_min(&t->expire, &min1, &min2);
4992
4993 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004994 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004995
Willy TARREAU1cec83c2006-03-01 22:33:49 +01004996#ifdef DEBUG_FULL
4997 /* DEBUG code : this should never ever happen, otherwise it indicates
4998 * that a task still has something to do and will provoke a quick loop.
4999 */
5000 if (tv_remain2(&now, &t->expire) <= 0)
5001 exit(100);
5002#endif
5003
willy tarreaub952e1d2005-12-18 01:31:20 +01005004 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005005 }
5006
willy tarreau5cbea6f2005-12-17 12:48:26 +01005007 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005008 actconn--;
5009
willy tarreau982249e2005-12-18 00:57:06 +01005010 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005011 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005012 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 +01005013 write(1, trash, len);
5014 }
5015
willy tarreau750a4722005-12-17 13:21:24 +01005016 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005017 if (s->rep != NULL)
5018 s->logs.bytes = s->rep->total;
5019
willy tarreau9fe663a2005-12-17 13:02:59 +01005020 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005021 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005022 sess_log(s);
5023
willy tarreau0f7af912005-12-17 12:21:26 +01005024 /* the task MUST not be in the run queue anymore */
5025 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005026 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005027 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005028 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005029}
5030
5031
5032
5033/*
5034 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005035 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005036 */
5037int process_chk(struct task *t) {
5038 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005039 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005040 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005041
willy tarreauef900ab2005-12-17 12:52:52 +01005042 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005043
5044 if (fd < 0) { /* no check currently running */
5045 //fprintf(stderr, "process_chk: 2\n");
5046 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5047 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005048 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005049 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005050
5051 /* we don't send any health-checks when the proxy is stopped or when
5052 * the server should not be checked.
5053 */
5054 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
5055 tv_delayfrom(&t->expire, &now, s->inter);
5056 task_queue(t); /* restore t to its place in the task list */
5057 return tv_remain2(&now, &t->expire);
5058 }
5059
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 /* we'll initiate a new check */
5061 s->result = 0; /* no result yet */
5062 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005063 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005064 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5065 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5066 //fprintf(stderr, "process_chk: 3\n");
5067
willy tarreaua41a8b42005-12-17 14:02:24 +01005068 /* we'll connect to the check port on the server */
5069 sa = s->addr;
5070 sa.sin_port = htons(s->check_port);
5071
willy tarreau0174f312005-12-18 01:02:42 +01005072 /* allow specific binding :
5073 * - server-specific at first
5074 * - proxy-specific next
5075 */
5076 if (s->state & SRV_BIND_SRC) {
5077 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5078 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5079 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5080 s->proxy->id, s->id);
5081 s->result = -1;
5082 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005083 }
willy tarreau0174f312005-12-18 01:02:42 +01005084 else if (s->proxy->options & PR_O_BIND_SRC) {
5085 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5086 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5087 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5088 s->proxy->id);
5089 s->result = -1;
5090 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091 }
willy tarreau0174f312005-12-18 01:02:42 +01005092
5093 if (!s->result) {
5094 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5095 /* OK, connection in progress or established */
5096
5097 //fprintf(stderr, "process_chk: 4\n");
5098
5099 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5100 fdtab[fd].owner = t;
5101 fdtab[fd].read = &event_srv_chk_r;
5102 fdtab[fd].write = &event_srv_chk_w;
5103 fdtab[fd].state = FD_STCONN; /* connection in progress */
5104 FD_SET(fd, StaticWriteEvent); /* for connect status */
5105 fd_insert(fd);
5106 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5107 tv_delayfrom(&t->expire, &now, s->inter);
5108 task_queue(t); /* restore t to its place in the task list */
5109 return tv_remain(&now, &t->expire);
5110 }
5111 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5112 s->result = -1; /* a real error */
5113 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005114 }
5115 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005116 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005117 }
5118
5119 if (!s->result) { /* nothing done */
5120 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005121 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005122 task_queue(t); /* restore t to its place in the task list */
5123 return tv_remain(&now, &t->expire);
5124 }
5125
5126 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005127 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005128 s->health--; /* still good */
5129 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005130 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005131 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005132 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005133 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005134
willy tarreaudd07e972005-12-18 00:48:48 +01005135 if (find_server(s->proxy) == NULL) {
5136 Alert("Proxy %s has no server available !\n", s->proxy->id);
5137 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5138 }
5139 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005140 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005141 }
5142
5143 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005144 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5145 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005146 }
5147 else {
5148 //fprintf(stderr, "process_chk: 8\n");
5149 /* there was a test running */
5150 if (s->result > 0) { /* good server detected */
5151 //fprintf(stderr, "process_chk: 9\n");
5152 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005153 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005154 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005155 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005156 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005157 }
willy tarreauef900ab2005-12-17 12:52:52 +01005158
willy tarreaue47c8d72005-12-17 12:55:52 +01005159 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005160 s->state |= SRV_RUNNING;
5161 }
willy tarreauef900ab2005-12-17 12:52:52 +01005162 s->curfd = -1; /* no check running anymore */
5163 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005164 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005165 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005166 }
5167 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5168 //fprintf(stderr, "process_chk: 10\n");
5169 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005170 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171 s->health--; /* still good */
5172 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005173 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005174
willy tarreaudd07e972005-12-18 00:48:48 +01005175 if (s->health == s->rise) {
5176 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005177 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005178
5179 if (find_server(s->proxy) == NULL) {
5180 Alert("Proxy %s has no server available !\n", s->proxy->id);
5181 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5182 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005183 }
willy tarreauef900ab2005-12-17 12:52:52 +01005184
willy tarreau5cbea6f2005-12-17 12:48:26 +01005185 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186 }
5187 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005188 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005189 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005190 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005191 }
5192 /* if result is 0 and there's no timeout, we have to wait again */
5193 }
5194 //fprintf(stderr, "process_chk: 11\n");
5195 s->result = 0;
5196 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005197 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005198}
5199
5200
willy tarreau5cbea6f2005-12-17 12:48:26 +01005201
willy tarreau0f7af912005-12-17 12:21:26 +01005202#if STATTIME > 0
5203int stats(void);
5204#endif
5205
5206/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005207 * This does 4 things :
5208 * - wake up all expired tasks
5209 * - call all runnable tasks
5210 * - call maintain_proxies() to enable/disable the listeners
5211 * - return the delay till next event in ms, -1 = wait indefinitely
5212 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5213 *
willy tarreau0f7af912005-12-17 12:21:26 +01005214 */
5215
willy tarreau1c2ad212005-12-18 01:11:29 +01005216int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005217 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005218 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005219 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005220
willy tarreaub952e1d2005-12-18 01:31:20 +01005221 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005222
willy tarreau1c2ad212005-12-18 01:11:29 +01005223 /* look for expired tasks and add them to the run queue.
5224 */
5225 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5226 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5227 tnext = t->next;
5228 if (t->state & TASK_RUNNING)
5229 continue;
5230
willy tarreaub952e1d2005-12-18 01:31:20 +01005231 if (tv_iseternity(&t->expire))
5232 continue;
5233
willy tarreau1c2ad212005-12-18 01:11:29 +01005234 /* wakeup expired entries. It doesn't matter if they are
5235 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005236 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005237 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005238 task_wakeup(&rq, t);
5239 }
5240 else {
5241 /* first non-runnable task. Use its expiration date as an upper bound */
5242 int temp_time = tv_remain(&now, &t->expire);
5243 if (temp_time)
5244 next_time = temp_time;
5245 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005246 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005247 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005248
willy tarreau1c2ad212005-12-18 01:11:29 +01005249 /* process each task in the run queue now. Each task may be deleted
5250 * since we only use tnext.
5251 */
5252 tnext = rq;
5253 while ((t = tnext) != NULL) {
5254 int temp_time;
5255
5256 tnext = t->rqnext;
5257 task_sleep(&rq, t);
5258 temp_time = t->process(t);
5259 next_time = MINTIME(temp_time, next_time);
5260 }
5261
5262 /* maintain all proxies in a consistent state. This should quickly become a task */
5263 time2 = maintain_proxies();
5264 return MINTIME(time2, next_time);
5265}
5266
5267
5268#if defined(ENABLE_EPOLL)
5269
5270/*
5271 * Main epoll() loop.
5272 */
5273
5274/* does 3 actions :
5275 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5276 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5277 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5278 *
5279 * returns 0 if initialization failed, !0 otherwise.
5280 */
5281
5282int epoll_loop(int action) {
5283 int next_time;
5284 int status;
5285 int fd;
5286
5287 int fds, count;
5288 int pr, pw, sr, sw;
5289 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5290 struct epoll_event ev;
5291
5292 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005293 static struct epoll_event *epoll_events = NULL;
5294 static int epoll_fd;
5295
5296 if (action == POLL_LOOP_ACTION_INIT) {
5297 epoll_fd = epoll_create(global.maxsock + 1);
5298 if (epoll_fd < 0)
5299 return 0;
5300 else {
5301 epoll_events = (struct epoll_event*)
5302 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5303 PrevReadEvent = (fd_set *)
5304 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5305 PrevWriteEvent = (fd_set *)
5306 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005307 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005308 return 1;
5309 }
5310 else if (action == POLL_LOOP_ACTION_CLEAN) {
5311 if (PrevWriteEvent) free(PrevWriteEvent);
5312 if (PrevReadEvent) free(PrevReadEvent);
5313 if (epoll_events) free(epoll_events);
5314 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005315 epoll_fd = 0;
5316 return 1;
5317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005318
willy tarreau1c2ad212005-12-18 01:11:29 +01005319 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005320
willy tarreau1c2ad212005-12-18 01:11:29 +01005321 tv_now(&now);
5322
5323 while (1) {
5324 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005325
5326 /* stop when there's no connection left and we don't allow them anymore */
5327 if (!actconn && listeners == 0)
5328 break;
5329
willy tarreau0f7af912005-12-17 12:21:26 +01005330#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005331 {
5332 int time2;
5333 time2 = stats();
5334 next_time = MINTIME(time2, next_time);
5335 }
willy tarreau0f7af912005-12-17 12:21:26 +01005336#endif
5337
willy tarreau1c2ad212005-12-18 01:11:29 +01005338 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5339
5340 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5341 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5342
5343 if ((ro^rn) | (wo^wn)) {
5344 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5345#define FDSETS_ARE_INT_ALIGNED
5346#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005347
willy tarreauad90a0c2005-12-18 01:09:15 +01005348#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5349#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005350 pr = (ro >> count) & 1;
5351 pw = (wo >> count) & 1;
5352 sr = (rn >> count) & 1;
5353 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005354#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005355 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5356 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5357 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5358 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005359#endif
5360#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005361 pr = FD_ISSET(fd, PrevReadEvent);
5362 pw = FD_ISSET(fd, PrevWriteEvent);
5363 sr = FD_ISSET(fd, StaticReadEvent);
5364 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005365#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005366 if (!((sr^pr) | (sw^pw)))
5367 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005368
willy tarreau1c2ad212005-12-18 01:11:29 +01005369 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5370 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005371
willy tarreaub952e1d2005-12-18 01:31:20 +01005372#ifdef EPOLL_CTL_MOD_WORKAROUND
5373 /* I encountered a rarely reproducible problem with
5374 * EPOLL_CTL_MOD where a modified FD (systematically
5375 * the one in epoll_events[0], fd#7) would sometimes
5376 * be set EPOLL_OUT while asked for a read ! This is
5377 * with the 2.4 epoll patch. The workaround is to
5378 * delete then recreate in case of modification.
5379 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5380 * nor RHEL kernels.
5381 */
5382
5383 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5384 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5385
5386 if ((sr | sw))
5387 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5388#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005389 if ((pr | pw)) {
5390 /* the file-descriptor already exists... */
5391 if ((sr | sw)) {
5392 /* ...and it will still exist */
5393 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5394 // perror("epoll_ctl(MOD)");
5395 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005396 }
5397 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005398 /* ...and it will be removed */
5399 if (fdtab[fd].state != FD_STCLOSE &&
5400 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5401 // perror("epoll_ctl(DEL)");
5402 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005403 }
5404 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005405 } else {
5406 /* the file-descriptor did not exist, let's add it */
5407 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5408 // perror("epoll_ctl(ADD)");
5409 // exit(1);
5410 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005411 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005412#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005413 }
5414 ((int*)PrevReadEvent)[fds] = rn;
5415 ((int*)PrevWriteEvent)[fds] = wn;
5416 }
5417 }
5418
5419 /* now let's wait for events */
5420 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5421 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005422
willy tarreau1c2ad212005-12-18 01:11:29 +01005423 for (count = 0; count < status; count++) {
5424 fd = epoll_events[count].data.fd;
5425
5426 if (fdtab[fd].state == FD_STCLOSE)
5427 continue;
5428
Willy TARREAUe78ae262006-01-08 01:24:12 +01005429 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) {
5430 if (FD_ISSET(fd, StaticReadEvent))
5431 fdtab[fd].read(fd);
5432 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005433
5434 if (fdtab[fd].state == FD_STCLOSE)
5435 continue;
5436
Willy TARREAUe78ae262006-01-08 01:24:12 +01005437 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) {
5438 if (FD_ISSET(fd, StaticWriteEvent))
5439 fdtab[fd].write(fd);
5440 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005441 }
5442 }
5443 return 1;
5444}
5445#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005446
willy tarreauad90a0c2005-12-18 01:09:15 +01005447
willy tarreau5cbea6f2005-12-17 12:48:26 +01005448
willy tarreau1c2ad212005-12-18 01:11:29 +01005449#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005450
willy tarreau1c2ad212005-12-18 01:11:29 +01005451/*
5452 * Main poll() loop.
5453 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005454
willy tarreau1c2ad212005-12-18 01:11:29 +01005455/* does 3 actions :
5456 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5457 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5458 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5459 *
5460 * returns 0 if initialization failed, !0 otherwise.
5461 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005462
willy tarreau1c2ad212005-12-18 01:11:29 +01005463int poll_loop(int action) {
5464 int next_time;
5465 int status;
5466 int fd, nbfd;
5467
5468 int fds, count;
5469 int sr, sw;
5470 unsigned rn, wn; /* read new, write new */
5471
5472 /* private data */
5473 static struct pollfd *poll_events = NULL;
5474
5475 if (action == POLL_LOOP_ACTION_INIT) {
5476 poll_events = (struct pollfd*)
5477 calloc(1, sizeof(struct pollfd) * global.maxsock);
5478 return 1;
5479 }
5480 else if (action == POLL_LOOP_ACTION_CLEAN) {
5481 if (poll_events)
5482 free(poll_events);
5483 return 1;
5484 }
5485
5486 /* OK, it's POLL_LOOP_ACTION_RUN */
5487
5488 tv_now(&now);
5489
5490 while (1) {
5491 next_time = process_runnable_tasks();
5492
5493 /* stop when there's no connection left and we don't allow them anymore */
5494 if (!actconn && listeners == 0)
5495 break;
5496
5497#if STATTIME > 0
5498 {
5499 int time2;
5500 time2 = stats();
5501 next_time = MINTIME(time2, next_time);
5502 }
5503#endif
5504
5505
5506 nbfd = 0;
5507 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5508
5509 rn = ((int*)StaticReadEvent)[fds];
5510 wn = ((int*)StaticWriteEvent)[fds];
5511
5512 if ((rn|wn)) {
5513 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5514#define FDSETS_ARE_INT_ALIGNED
5515#ifdef FDSETS_ARE_INT_ALIGNED
5516
5517#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5518#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5519 sr = (rn >> count) & 1;
5520 sw = (wn >> count) & 1;
5521#else
5522 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5523 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5524#endif
5525#else
5526 sr = FD_ISSET(fd, StaticReadEvent);
5527 sw = FD_ISSET(fd, StaticWriteEvent);
5528#endif
5529 if ((sr|sw)) {
5530 poll_events[nbfd].fd = fd;
5531 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5532 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005533 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005534 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005535 }
5536 }
5537
5538 /* now let's wait for events */
5539 status = poll(poll_events, nbfd, next_time);
5540 tv_now(&now);
5541
5542 for (count = 0; status > 0 && count < nbfd; count++) {
5543 fd = poll_events[count].fd;
5544
5545 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5546 continue;
5547
5548 /* ok, we found one active fd */
5549 status--;
5550
5551 if (fdtab[fd].state == FD_STCLOSE)
5552 continue;
5553
Willy TARREAUe78ae262006-01-08 01:24:12 +01005554 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) {
5555 if (FD_ISSET(fd, StaticReadEvent))
5556 fdtab[fd].read(fd);
5557 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005558
5559 if (fdtab[fd].state == FD_STCLOSE)
5560 continue;
5561
Willy TARREAUe78ae262006-01-08 01:24:12 +01005562 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) {
5563 if (FD_ISSET(fd, StaticWriteEvent))
5564 fdtab[fd].write(fd);
5565 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005566 }
5567 }
5568 return 1;
5569}
willy tarreauad90a0c2005-12-18 01:09:15 +01005570#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005571
willy tarreauad90a0c2005-12-18 01:09:15 +01005572
willy tarreauad90a0c2005-12-18 01:09:15 +01005573
willy tarreau1c2ad212005-12-18 01:11:29 +01005574/*
5575 * Main select() loop.
5576 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005577
willy tarreau1c2ad212005-12-18 01:11:29 +01005578/* does 3 actions :
5579 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5580 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5581 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5582 *
5583 * returns 0 if initialization failed, !0 otherwise.
5584 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005585
willy tarreauad90a0c2005-12-18 01:09:15 +01005586
willy tarreau1c2ad212005-12-18 01:11:29 +01005587int select_loop(int action) {
5588 int next_time;
5589 int status;
5590 int fd,i;
5591 struct timeval delta;
5592 int readnotnull, writenotnull;
5593 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005594
willy tarreau1c2ad212005-12-18 01:11:29 +01005595 if (action == POLL_LOOP_ACTION_INIT) {
5596 ReadEvent = (fd_set *)
5597 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5598 WriteEvent = (fd_set *)
5599 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5600 return 1;
5601 }
5602 else if (action == POLL_LOOP_ACTION_CLEAN) {
5603 if (WriteEvent) free(WriteEvent);
5604 if (ReadEvent) free(ReadEvent);
5605 return 1;
5606 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005607
willy tarreau1c2ad212005-12-18 01:11:29 +01005608 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005609
willy tarreau1c2ad212005-12-18 01:11:29 +01005610 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005611
willy tarreau1c2ad212005-12-18 01:11:29 +01005612 while (1) {
5613 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005614
willy tarreau1c2ad212005-12-18 01:11:29 +01005615 /* stop when there's no connection left and we don't allow them anymore */
5616 if (!actconn && listeners == 0)
5617 break;
5618
5619#if STATTIME > 0
5620 {
5621 int time2;
5622 time2 = stats();
5623 next_time = MINTIME(time2, next_time);
5624 }
5625#endif
5626
willy tarreau1c2ad212005-12-18 01:11:29 +01005627 if (next_time > 0) { /* FIXME */
5628 /* Convert to timeval */
5629 /* to avoid eventual select loops due to timer precision */
5630 next_time += SCHEDULER_RESOLUTION;
5631 delta.tv_sec = next_time / 1000;
5632 delta.tv_usec = (next_time % 1000) * 1000;
5633 }
5634 else if (next_time == 0) { /* allow select to return immediately when needed */
5635 delta.tv_sec = delta.tv_usec = 0;
5636 }
5637
5638
5639 /* let's restore fdset state */
5640
5641 readnotnull = 0; writenotnull = 0;
5642 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5643 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5644 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5645 }
5646
5647 // /* just a verification code, needs to be removed for performance */
5648 // for (i=0; i<maxfd; i++) {
5649 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5650 // abort();
5651 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5652 // abort();
5653 //
5654 // }
5655
5656 status = select(maxfd,
5657 readnotnull ? ReadEvent : NULL,
5658 writenotnull ? WriteEvent : NULL,
5659 NULL,
5660 (next_time >= 0) ? &delta : NULL);
5661
5662 /* this is an experiment on the separation of the select work */
5663 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5664 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5665
5666 tv_now(&now);
5667
5668 if (status > 0) { /* must proceed with events */
5669
5670 int fds;
5671 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005672
willy tarreau1c2ad212005-12-18 01:11:29 +01005673 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5674 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5675 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5676
5677 /* if we specify read first, the accepts and zero reads will be
5678 * seen first. Moreover, system buffers will be flushed faster.
5679 */
5680 if (fdtab[fd].state == FD_STCLOSE)
5681 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005682
willy tarreau1c2ad212005-12-18 01:11:29 +01005683 if (FD_ISSET(fd, ReadEvent))
5684 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005685
willy tarreau1c2ad212005-12-18 01:11:29 +01005686 if (FD_ISSET(fd, WriteEvent))
5687 fdtab[fd].write(fd);
5688 }
5689 }
5690 else {
5691 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005692 }
willy tarreau0f7af912005-12-17 12:21:26 +01005693 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005694 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005695}
5696
5697
5698#if STATTIME > 0
5699/*
5700 * Display proxy statistics regularly. It is designed to be called from the
5701 * select_loop().
5702 */
5703int stats(void) {
5704 static int lines;
5705 static struct timeval nextevt;
5706 static struct timeval lastevt;
5707 static struct timeval starttime = {0,0};
5708 unsigned long totaltime, deltatime;
5709 int ret;
5710
willy tarreau750a4722005-12-17 13:21:24 +01005711 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005712 deltatime = (tv_diff(&lastevt, &now)?:1);
5713 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005714
willy tarreau9fe663a2005-12-17 13:02:59 +01005715 if (global.mode & MODE_STATS) {
5716 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005717 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005718 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5719 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005720 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005721 actconn, totalconn,
5722 stats_tsk_new, stats_tsk_good,
5723 stats_tsk_left, stats_tsk_right,
5724 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5725 }
5726 }
5727
5728 tv_delayfrom(&nextevt, &now, STATTIME);
5729
5730 lastevt=now;
5731 }
5732 ret = tv_remain(&now, &nextevt);
5733 return ret;
5734}
5735#endif
5736
5737
5738/*
5739 * this function enables proxies when there are enough free sessions,
5740 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005741 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005742 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005743 */
5744static int maintain_proxies(void) {
5745 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005746 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005747 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005748
5749 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005750 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005751
5752 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005753 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005754 while (p) {
5755 if (p->nbconn < p->maxconn) {
5756 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005757 for (l = p->listen; l != NULL; l = l->next) {
5758 FD_SET(l->fd, StaticReadEvent);
5759 }
willy tarreau0f7af912005-12-17 12:21:26 +01005760 p->state = PR_STRUN;
5761 }
5762 }
5763 else {
5764 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005765 for (l = p->listen; l != NULL; l = l->next) {
5766 FD_CLR(l->fd, StaticReadEvent);
5767 }
willy tarreau0f7af912005-12-17 12:21:26 +01005768 p->state = PR_STIDLE;
5769 }
5770 }
5771 p = p->next;
5772 }
5773 }
5774 else { /* block all proxies */
5775 while (p) {
5776 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005777 for (l = p->listen; l != NULL; l = l->next) {
5778 FD_CLR(l->fd, StaticReadEvent);
5779 }
willy tarreau0f7af912005-12-17 12:21:26 +01005780 p->state = PR_STIDLE;
5781 }
5782 p = p->next;
5783 }
5784 }
5785
willy tarreau5cbea6f2005-12-17 12:48:26 +01005786 if (stopping) {
5787 p = proxy;
5788 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005789 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005790 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005791 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005792 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005793 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005794 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005795
willy tarreaua41a8b42005-12-17 14:02:24 +01005796 for (l = p->listen; l != NULL; l = l->next) {
5797 fd_delete(l->fd);
5798 listeners--;
5799 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005800 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005801 }
5802 else {
5803 tleft = MINTIME(t, tleft);
5804 }
5805 }
5806 p = p->next;
5807 }
5808 }
5809 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005810}
5811
5812/*
5813 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005814 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5815 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005816 */
5817static void soft_stop(void) {
5818 struct proxy *p;
5819
5820 stopping = 1;
5821 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005822 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005823 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01005824 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005825 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005826 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005827 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005828 }
willy tarreau0f7af912005-12-17 12:21:26 +01005829 p = p->next;
5830 }
5831}
5832
willy tarreaudbd3bef2006-01-20 19:35:18 +01005833static void pause_proxy(struct proxy *p) {
5834 struct listener *l;
5835 for (l = p->listen; l != NULL; l = l->next) {
5836 shutdown(l->fd, SHUT_RD);
5837 FD_CLR(l->fd, StaticReadEvent);
5838 p->state = PR_STPAUSED;
5839 }
5840}
5841
5842/*
5843 * This function temporarily disables listening so that another new instance
5844 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005845 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005846 * the proxy, or a SIGTTIN can be sent to listen again.
5847 */
5848static void pause_proxies(void) {
5849 struct proxy *p;
5850
5851 p = proxy;
5852 tv_now(&now); /* else, the old time before select will be used */
5853 while (p) {
5854 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5855 Warning("Pausing proxy %s.\n", p->id);
5856 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5857 pause_proxy(p);
5858 }
5859 p = p->next;
5860 }
5861}
5862
5863
5864/*
5865 * This function reactivates listening. This can be used after a call to
5866 * sig_pause(), for example when a new instance has failed starting up.
5867 * It is designed to be called upon reception of a SIGTTIN.
5868 */
5869static void listen_proxies(void) {
5870 struct proxy *p;
5871 struct listener *l;
5872
5873 p = proxy;
5874 tv_now(&now); /* else, the old time before select will be used */
5875 while (p) {
5876 if (p->state == PR_STPAUSED) {
5877 Warning("Enabling proxy %s.\n", p->id);
5878 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5879
5880 for (l = p->listen; l != NULL; l = l->next) {
5881 if (listen(l->fd, p->maxconn) == 0) {
5882 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5883 FD_SET(l->fd, StaticReadEvent);
5884 p->state = PR_STRUN;
5885 }
5886 else
5887 p->state = PR_STIDLE;
5888 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005889 int port;
5890
5891 if (l->addr.ss_family == AF_INET6)
5892 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5893 else
5894 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5895
willy tarreaudbd3bef2006-01-20 19:35:18 +01005896 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005897 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005898 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005899 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005900 /* Another port might have been enabled. Let's stop everything. */
5901 pause_proxy(p);
5902 break;
5903 }
5904 }
5905 }
5906 p = p->next;
5907 }
5908}
5909
5910
willy tarreau0f7af912005-12-17 12:21:26 +01005911/*
5912 * upon SIGUSR1, let's have a soft stop.
5913 */
5914void sig_soft_stop(int sig) {
5915 soft_stop();
5916 signal(sig, SIG_IGN);
5917}
5918
willy tarreaudbd3bef2006-01-20 19:35:18 +01005919/*
5920 * upon SIGTTOU, we pause everything
5921 */
5922void sig_pause(int sig) {
5923 pause_proxies();
5924 signal(sig, sig_pause);
5925}
willy tarreau0f7af912005-12-17 12:21:26 +01005926
willy tarreau8337c6b2005-12-17 13:41:01 +01005927/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005928 * upon SIGTTIN, let's have a soft stop.
5929 */
5930void sig_listen(int sig) {
5931 listen_proxies();
5932 signal(sig, sig_listen);
5933}
5934
5935/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005936 * this function dumps every server's state when the process receives SIGHUP.
5937 */
5938void sig_dump_state(int sig) {
5939 struct proxy *p = proxy;
5940
5941 Warning("SIGHUP received, dumping servers states.\n");
5942 while (p) {
5943 struct server *s = p->srv;
5944
5945 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5946 while (s) {
5947 if (s->state & SRV_RUNNING) {
5948 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5949 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5950 }
5951 else {
5952 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5953 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5954 }
5955 s = s->next;
5956 }
willy tarreaudd07e972005-12-18 00:48:48 +01005957
5958 if (find_server(p) == NULL) {
5959 Warning("SIGHUP: proxy %s has no server available !\n", p);
5960 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5961 }
5962
willy tarreau8337c6b2005-12-17 13:41:01 +01005963 p = p->next;
5964 }
5965 signal(sig, sig_dump_state);
5966}
5967
willy tarreau0f7af912005-12-17 12:21:26 +01005968void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005969 struct task *t, *tnext;
5970 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005971
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5973 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5974 tnext = t->next;
5975 s = t->context;
5976 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5977 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5978 "req=%d, rep=%d, clifd=%d\n",
5979 s, tv_remain(&now, &t->expire),
5980 s->cli_state,
5981 s->srv_state,
5982 FD_ISSET(s->cli_fd, StaticReadEvent),
5983 FD_ISSET(s->cli_fd, StaticWriteEvent),
5984 FD_ISSET(s->srv_fd, StaticReadEvent),
5985 FD_ISSET(s->srv_fd, StaticWriteEvent),
5986 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5987 );
willy tarreau0f7af912005-12-17 12:21:26 +01005988 }
willy tarreau12350152005-12-18 01:03:27 +01005989}
5990
willy tarreau64a3cc32005-12-18 01:13:11 +01005991#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005992static void fast_stop(void)
5993{
5994 struct proxy *p;
5995 p = proxy;
5996 while (p) {
5997 p->grace = 0;
5998 p = p->next;
5999 }
6000 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006001}
6002
willy tarreau12350152005-12-18 01:03:27 +01006003void sig_int(int sig) {
6004 /* This would normally be a hard stop,
6005 but we want to be sure about deallocation,
6006 and so on, so we do a soft stop with
6007 0 GRACE time
6008 */
6009 fast_stop();
6010 /* If we are killed twice, we decide to die*/
6011 signal(sig, SIG_DFL);
6012}
6013
6014void sig_term(int sig) {
6015 /* This would normally be a hard stop,
6016 but we want to be sure about deallocation,
6017 and so on, so we do a soft stop with
6018 0 GRACE time
6019 */
6020 fast_stop();
6021 /* If we are killed twice, we decide to die*/
6022 signal(sig, SIG_DFL);
6023}
willy tarreau64a3cc32005-12-18 01:13:11 +01006024#endif
willy tarreau12350152005-12-18 01:03:27 +01006025
willy tarreauc1f47532005-12-18 01:08:26 +01006026/* returns the pointer to an error in the replacement string, or NULL if OK */
6027char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006028 struct hdr_exp *exp;
6029
willy tarreauc1f47532005-12-18 01:08:26 +01006030 if (replace != NULL) {
6031 char *err;
6032 err = check_replace_string(replace);
6033 if (err)
6034 return err;
6035 }
6036
willy tarreaue39cd132005-12-17 13:00:18 +01006037 while (*head != NULL)
6038 head = &(*head)->next;
6039
6040 exp = calloc(1, sizeof(struct hdr_exp));
6041
6042 exp->preg = preg;
6043 exp->replace = replace;
6044 exp->action = action;
6045 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006046
6047 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006048}
6049
willy tarreau9fe663a2005-12-17 13:02:59 +01006050
willy tarreau0f7af912005-12-17 12:21:26 +01006051/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006052 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006053 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006054int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006055
willy tarreau9fe663a2005-12-17 13:02:59 +01006056 if (!strcmp(args[0], "global")) { /* new section */
6057 /* no option, nothing special to do */
6058 return 0;
6059 }
6060 else if (!strcmp(args[0], "daemon")) {
6061 global.mode |= MODE_DAEMON;
6062 }
6063 else if (!strcmp(args[0], "debug")) {
6064 global.mode |= MODE_DEBUG;
6065 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006066 else if (!strcmp(args[0], "noepoll")) {
6067 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6068 }
6069 else if (!strcmp(args[0], "nopoll")) {
6070 cfg_polling_mechanism &= ~POLL_USE_POLL;
6071 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006072 else if (!strcmp(args[0], "quiet")) {
6073 global.mode |= MODE_QUIET;
6074 }
6075 else if (!strcmp(args[0], "stats")) {
6076 global.mode |= MODE_STATS;
6077 }
6078 else if (!strcmp(args[0], "uid")) {
6079 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006080 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006081 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006082 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006083 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006084 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006085 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006086 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006087 global.uid = atol(args[1]);
6088 }
6089 else if (!strcmp(args[0], "gid")) {
6090 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006091 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006092 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006094 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006095 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006096 return -1;
6097 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006098 global.gid = atol(args[1]);
6099 }
6100 else if (!strcmp(args[0], "nbproc")) {
6101 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006102 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006103 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006104 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006105 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006106 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006107 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006108 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006109 global.nbproc = atol(args[1]);
6110 }
6111 else if (!strcmp(args[0], "maxconn")) {
6112 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006113 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006114 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006115 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006116 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006117 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006118 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006119 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006120 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006121#ifdef SYSTEM_MAXCONN
6122 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6123 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);
6124 global.maxconn = DEFAULT_MAXCONN;
6125 }
6126#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 }
willy tarreaub1285d52005-12-18 01:20:14 +01006128 else if (!strcmp(args[0], "ulimit-n")) {
6129 if (global.rlimit_nofile != 0) {
6130 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6131 return 0;
6132 }
6133 if (*(args[1]) == 0) {
6134 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6135 return -1;
6136 }
6137 global.rlimit_nofile = atol(args[1]);
6138 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006139 else if (!strcmp(args[0], "chroot")) {
6140 if (global.chroot != NULL) {
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;
6143 }
6144 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006145 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006146 return -1;
6147 }
6148 global.chroot = strdup(args[1]);
6149 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006150 else if (!strcmp(args[0], "pidfile")) {
6151 if (global.pidfile != NULL) {
6152 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6153 return 0;
6154 }
6155 if (*(args[1]) == 0) {
6156 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6157 return -1;
6158 }
6159 global.pidfile = strdup(args[1]);
6160 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006161 else if (!strcmp(args[0], "log")) { /* syslog server address */
6162 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006163 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006164
6165 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006166 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006167 return -1;
6168 }
6169
6170 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6171 if (!strcmp(log_facilities[facility], args[2]))
6172 break;
6173
6174 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006175 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006176 exit(1);
6177 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006178
6179 level = 7; /* max syslog level = debug */
6180 if (*(args[3])) {
6181 while (level >= 0 && strcmp(log_levels[level], args[3]))
6182 level--;
6183 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006184 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006185 exit(1);
6186 }
6187 }
6188
willy tarreau9fe663a2005-12-17 13:02:59 +01006189 sa = str2sa(args[1]);
6190 if (!sa->sin_port)
6191 sa->sin_port = htons(SYSLOG_PORT);
6192
6193 if (global.logfac1 == -1) {
6194 global.logsrv1 = *sa;
6195 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006196 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006197 }
6198 else if (global.logfac2 == -1) {
6199 global.logsrv2 = *sa;
6200 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006201 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006202 }
6203 else {
6204 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6205 return -1;
6206 }
6207
6208 }
6209 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006210 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006211 return -1;
6212 }
6213 return 0;
6214}
6215
6216
willy tarreaua41a8b42005-12-17 14:02:24 +01006217void init_default_instance() {
6218 memset(&defproxy, 0, sizeof(defproxy));
6219 defproxy.mode = PR_MODE_TCP;
6220 defproxy.state = PR_STNEW;
6221 defproxy.maxconn = cfg_maxpconn;
6222 defproxy.conn_retries = CONN_RETRIES;
6223 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6224}
6225
willy tarreau9fe663a2005-12-17 13:02:59 +01006226/*
6227 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6228 */
6229int cfg_parse_listen(char *file, int linenum, char **args) {
6230 static struct proxy *curproxy = NULL;
6231 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006232 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006233 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006234
6235 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006236 if (!*args[1]) {
6237 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6238 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006239 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006240 return -1;
6241 }
6242
6243 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006244 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006245 return -1;
6246 }
6247 curproxy->next = proxy;
6248 proxy = curproxy;
6249 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006250
6251 /* parse the listener address if any */
6252 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006253 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006254 if (!curproxy->listen)
6255 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006256 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006257 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006258
willy tarreau9fe663a2005-12-17 13:02:59 +01006259 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006260 curproxy->state = defproxy.state;
6261 curproxy->maxconn = defproxy.maxconn;
6262 curproxy->conn_retries = defproxy.conn_retries;
6263 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006264
6265 if (defproxy.check_req)
6266 curproxy->check_req = strdup(defproxy.check_req);
6267 curproxy->check_len = defproxy.check_len;
6268
6269 if (defproxy.cookie_name)
6270 curproxy->cookie_name = strdup(defproxy.cookie_name);
6271 curproxy->cookie_len = defproxy.cookie_len;
6272
6273 if (defproxy.capture_name)
6274 curproxy->capture_name = strdup(defproxy.capture_name);
6275 curproxy->capture_namelen = defproxy.capture_namelen;
6276 curproxy->capture_len = defproxy.capture_len;
6277
6278 if (defproxy.errmsg.msg400)
6279 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6280 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6281
6282 if (defproxy.errmsg.msg403)
6283 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6284 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6285
6286 if (defproxy.errmsg.msg408)
6287 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6288 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6289
6290 if (defproxy.errmsg.msg500)
6291 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6292 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6293
6294 if (defproxy.errmsg.msg502)
6295 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6296 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6297
6298 if (defproxy.errmsg.msg503)
6299 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6300 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6301
6302 if (defproxy.errmsg.msg504)
6303 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6304 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6305
willy tarreaua41a8b42005-12-17 14:02:24 +01006306 curproxy->clitimeout = defproxy.clitimeout;
6307 curproxy->contimeout = defproxy.contimeout;
6308 curproxy->srvtimeout = defproxy.srvtimeout;
6309 curproxy->mode = defproxy.mode;
6310 curproxy->logfac1 = defproxy.logfac1;
6311 curproxy->logsrv1 = defproxy.logsrv1;
6312 curproxy->loglev1 = defproxy.loglev1;
6313 curproxy->logfac2 = defproxy.logfac2;
6314 curproxy->logsrv2 = defproxy.logsrv2;
6315 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006316 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006317 curproxy->grace = defproxy.grace;
6318 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006319 curproxy->mon_net = defproxy.mon_net;
6320 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006321 return 0;
6322 }
6323 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006324 /* some variables may have already been initialized earlier */
6325 if (defproxy.check_req) free(defproxy.check_req);
6326 if (defproxy.cookie_name) free(defproxy.cookie_name);
6327 if (defproxy.capture_name) free(defproxy.capture_name);
6328 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6329 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6330 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6331 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6332 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6333 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6334 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6335
6336 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006337 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006338 return 0;
6339 }
6340 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006341 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006342 return -1;
6343 }
6344
willy tarreaua41a8b42005-12-17 14:02:24 +01006345 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6346 if (curproxy == &defproxy) {
6347 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6348 return -1;
6349 }
6350
6351 if (strchr(args[1], ':') == NULL) {
6352 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6353 file, linenum, args[0]);
6354 return -1;
6355 }
6356 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006357 if (!curproxy->listen)
6358 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006359 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006360 return 0;
6361 }
willy tarreaub1285d52005-12-18 01:20:14 +01006362 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6363 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6364 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6365 file, linenum, args[0]);
6366 return -1;
6367 }
6368 /* flush useless bits */
6369 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6370 return 0;
6371 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006372 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006373 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6374 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6375 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6376 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006377 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return -1;
6379 }
6380 }
6381 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006382 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006384 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6385 curproxy->state = PR_STNEW;
6386 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006387 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6388 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006389// if (curproxy == &defproxy) {
6390// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6391// return -1;
6392// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006393
willy tarreau9fe663a2005-12-17 13:02:59 +01006394 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006395// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6396// file, linenum);
6397// return 0;
6398 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006399 }
6400
6401 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006402 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6403 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 return -1;
6405 }
6406 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006407 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006408
6409 cur_arg = 2;
6410 while (*(args[cur_arg])) {
6411 if (!strcmp(args[cur_arg], "rewrite")) {
6412 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006413 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006414 else if (!strcmp(args[cur_arg], "indirect")) {
6415 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006416 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006417 else if (!strcmp(args[cur_arg], "insert")) {
6418 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006419 }
willy tarreau240afa62005-12-17 13:14:35 +01006420 else if (!strcmp(args[cur_arg], "nocache")) {
6421 curproxy->options |= PR_O_COOK_NOC;
6422 }
willy tarreaucd878942005-12-17 13:27:43 +01006423 else if (!strcmp(args[cur_arg], "postonly")) {
6424 curproxy->options |= PR_O_COOK_POST;
6425 }
willy tarreau0174f312005-12-18 01:02:42 +01006426 else if (!strcmp(args[cur_arg], "prefix")) {
6427 curproxy->options |= PR_O_COOK_PFX;
6428 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006429 else {
willy tarreau0174f312005-12-18 01:02:42 +01006430 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006431 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006432 return -1;
6433 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006434 cur_arg++;
6435 }
willy tarreau0174f312005-12-18 01:02:42 +01006436 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6437 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6438 file, linenum);
6439 return -1;
6440 }
6441
6442 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6443 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006444 file, linenum);
6445 return -1;
6446 }
willy tarreau12350152005-12-18 01:03:27 +01006447 }/* end else if (!strcmp(args[0], "cookie")) */
6448 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6449// if (curproxy == &defproxy) {
6450// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6451// return -1;
6452// }
6453
6454 if (curproxy->appsession_name != NULL) {
6455// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6456// file, linenum);
6457// return 0;
6458 free(curproxy->appsession_name);
6459 }
6460
6461 if (*(args[5]) == 0) {
6462 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6463 file, linenum, args[0]);
6464 return -1;
6465 }
6466 have_appsession = 1;
6467 curproxy->appsession_name = strdup(args[1]);
6468 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6469 curproxy->appsession_len = atoi(args[3]);
6470 curproxy->appsession_timeout = atoi(args[5]);
6471 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6472 if (rc) {
6473 Alert("Error Init Appsession Hashtable.\n");
6474 return -1;
6475 }
6476 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006477 else if (!strcmp(args[0], "capture")) {
6478 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6479 // if (curproxy == &defproxy) {
6480 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6481 // return -1;
6482 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006483
willy tarreau4302f492005-12-18 01:00:37 +01006484 if (curproxy->capture_name != NULL) {
6485 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6486 // file, linenum, args[0]);
6487 // return 0;
6488 free(curproxy->capture_name);
6489 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006490
willy tarreau4302f492005-12-18 01:00:37 +01006491 if (*(args[4]) == 0) {
6492 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6493 file, linenum, args[0]);
6494 return -1;
6495 }
6496 curproxy->capture_name = strdup(args[2]);
6497 curproxy->capture_namelen = strlen(curproxy->capture_name);
6498 curproxy->capture_len = atol(args[4]);
6499 if (curproxy->capture_len >= CAPTURE_LEN) {
6500 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6501 file, linenum, CAPTURE_LEN - 1);
6502 curproxy->capture_len = CAPTURE_LEN - 1;
6503 }
6504 curproxy->to_log |= LW_COOKIE;
6505 }
6506 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6507 struct cap_hdr *hdr;
6508
6509 if (curproxy == &defproxy) {
6510 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6511 return -1;
6512 }
6513
6514 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6515 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6516 file, linenum, args[0], args[1]);
6517 return -1;
6518 }
6519
6520 hdr = calloc(sizeof(struct cap_hdr), 1);
6521 hdr->next = curproxy->req_cap;
6522 hdr->name = strdup(args[3]);
6523 hdr->namelen = strlen(args[3]);
6524 hdr->len = atol(args[5]);
6525 hdr->index = curproxy->nb_req_cap++;
6526 curproxy->req_cap = hdr;
6527 curproxy->to_log |= LW_REQHDR;
6528 }
6529 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6530 struct cap_hdr *hdr;
6531
6532 if (curproxy == &defproxy) {
6533 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6534 return -1;
6535 }
6536
6537 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6538 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6539 file, linenum, args[0], args[1]);
6540 return -1;
6541 }
6542 hdr = calloc(sizeof(struct cap_hdr), 1);
6543 hdr->next = curproxy->rsp_cap;
6544 hdr->name = strdup(args[3]);
6545 hdr->namelen = strlen(args[3]);
6546 hdr->len = atol(args[5]);
6547 hdr->index = curproxy->nb_rsp_cap++;
6548 curproxy->rsp_cap = hdr;
6549 curproxy->to_log |= LW_RSPHDR;
6550 }
6551 else {
6552 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006553 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006554 return -1;
6555 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006556 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006557 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006558 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006559 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006560 return 0;
6561 }
6562 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006563 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6564 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006565 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006566 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006567 curproxy->contimeout = atol(args[1]);
6568 }
6569 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006570 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006571 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6572 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006573 return 0;
6574 }
6575 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006576 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6577 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006578 return -1;
6579 }
6580 curproxy->clitimeout = atol(args[1]);
6581 }
6582 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006583 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006584 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006585 return 0;
6586 }
6587 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006588 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6589 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006590 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006591 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006592 curproxy->srvtimeout = atol(args[1]);
6593 }
6594 else if (!strcmp(args[0], "retries")) { /* connection retries */
6595 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006596 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6597 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006598 return -1;
6599 }
6600 curproxy->conn_retries = atol(args[1]);
6601 }
6602 else if (!strcmp(args[0], "option")) {
6603 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006604 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006605 return -1;
6606 }
6607 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006608 /* enable reconnections to dispatch */
6609 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006610#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006611 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006612 /* enable transparent proxy connections */
6613 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006614#endif
6615 else if (!strcmp(args[1], "keepalive"))
6616 /* enable keep-alive */
6617 curproxy->options |= PR_O_KEEPALIVE;
6618 else if (!strcmp(args[1], "forwardfor"))
6619 /* insert x-forwarded-for field */
6620 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006621 else if (!strcmp(args[1], "logasap"))
6622 /* log as soon as possible, without waiting for the session to complete */
6623 curproxy->options |= PR_O_LOGASAP;
6624 else if (!strcmp(args[1], "httpclose"))
6625 /* force connection: close in both directions in HTTP mode */
6626 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006627 else if (!strcmp(args[1], "forceclose"))
6628 /* force connection: close in both directions in HTTP mode and enforce end of session */
6629 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006630 else if (!strcmp(args[1], "checkcache"))
6631 /* require examination of cacheability of the 'set-cookie' field */
6632 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006633 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006634 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006635 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006636 else if (!strcmp(args[1], "tcplog"))
6637 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006638 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006639 else if (!strcmp(args[1], "dontlognull")) {
6640 /* don't log empty requests */
6641 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006642 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006643 else if (!strcmp(args[1], "tcpka")) {
6644 /* enable TCP keep-alives on client and server sessions */
6645 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6646 }
6647 else if (!strcmp(args[1], "clitcpka")) {
6648 /* enable TCP keep-alives on client sessions */
6649 curproxy->options |= PR_O_TCP_CLI_KA;
6650 }
6651 else if (!strcmp(args[1], "srvtcpka")) {
6652 /* enable TCP keep-alives on server sessions */
6653 curproxy->options |= PR_O_TCP_SRV_KA;
6654 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006655 else if (!strcmp(args[1], "allbackups")) {
6656 /* Use all backup servers simultaneously */
6657 curproxy->options |= PR_O_USE_ALL_BK;
6658 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006659 else if (!strcmp(args[1], "httpchk")) {
6660 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006661 if (curproxy->check_req != NULL) {
6662 free(curproxy->check_req);
6663 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006664 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006665 if (!*args[2]) { /* no argument */
6666 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6667 curproxy->check_len = strlen(DEF_CHECK_REQ);
6668 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006669 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6670 curproxy->check_req = (char *)malloc(reqlen);
6671 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6672 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006673 } else { /* more arguments : METHOD URI [HTTP_VER] */
6674 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6675 if (*args[4])
6676 reqlen += strlen(args[4]);
6677 else
6678 reqlen += strlen("HTTP/1.0");
6679
6680 curproxy->check_req = (char *)malloc(reqlen);
6681 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6682 "%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 +01006683 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006684 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006685 else if (!strcmp(args[1], "persist")) {
6686 /* persist on using the server specified by the cookie, even when it's down */
6687 curproxy->options |= PR_O_PERSIST;
6688 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006689 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006690 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006691 return -1;
6692 }
6693 return 0;
6694 }
6695 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6696 /* enable reconnections to dispatch */
6697 curproxy->options |= PR_O_REDISP;
6698 }
willy tarreaua1598082005-12-17 13:08:06 +01006699#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006700 else if (!strcmp(args[0], "transparent")) {
6701 /* enable transparent proxy connections */
6702 curproxy->options |= PR_O_TRANSP;
6703 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006704#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006705 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6706 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006707 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006708 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006709 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006710 curproxy->maxconn = atol(args[1]);
6711 }
6712 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6713 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006714 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006715 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006716 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006717 curproxy->grace = atol(args[1]);
6718 }
6719 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006720 if (curproxy == &defproxy) {
6721 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6722 return -1;
6723 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006724 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006725 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006726 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006727 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006728 curproxy->dispatch_addr = *str2sa(args[1]);
6729 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006730 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006731 if (*(args[1])) {
6732 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006733 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006734 }
6735 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006736 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006737 return -1;
6738 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006739 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006740 else /* if no option is set, use round-robin by default */
6741 curproxy->options |= PR_O_BALANCE_RR;
6742 }
6743 else if (!strcmp(args[0], "server")) { /* server address */
6744 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006745 char *rport;
6746 char *raddr;
6747 short realport;
6748 int do_check;
6749
6750 if (curproxy == &defproxy) {
6751 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6752 return -1;
6753 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006754
willy tarreaua41a8b42005-12-17 14:02:24 +01006755 if (!*args[2]) {
6756 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006757 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006758 return -1;
6759 }
6760 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6761 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6762 return -1;
6763 }
willy tarreau0174f312005-12-18 01:02:42 +01006764
6765 if (curproxy->srv == NULL)
6766 curproxy->srv = newsrv;
6767 else
6768 curproxy->cursrv->next = newsrv;
6769 curproxy->cursrv = newsrv;
6770
6771 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006772 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006773
6774 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006775 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006776 newsrv->id = strdup(args[1]);
6777
6778 /* several ways to check the port component :
6779 * - IP => port=+0, relative
6780 * - IP: => port=+0, relative
6781 * - IP:N => port=N, absolute
6782 * - IP:+N => port=+N, relative
6783 * - IP:-N => port=-N, relative
6784 */
6785 raddr = strdup(args[2]);
6786 rport = strchr(raddr, ':');
6787 if (rport) {
6788 *rport++ = 0;
6789 realport = atol(rport);
6790 if (!isdigit((int)*rport))
6791 newsrv->state |= SRV_MAPPORTS;
6792 } else {
6793 realport = 0;
6794 newsrv->state |= SRV_MAPPORTS;
6795 }
6796
6797 newsrv->addr = *str2sa(raddr);
6798 newsrv->addr.sin_port = htons(realport);
6799 free(raddr);
6800
willy tarreau9fe663a2005-12-17 13:02:59 +01006801 newsrv->curfd = -1; /* no health-check in progress */
6802 newsrv->inter = DEF_CHKINTR;
6803 newsrv->rise = DEF_RISETIME;
6804 newsrv->fall = DEF_FALLTIME;
6805 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6806 cur_arg = 3;
6807 while (*args[cur_arg]) {
6808 if (!strcmp(args[cur_arg], "cookie")) {
6809 newsrv->cookie = strdup(args[cur_arg + 1]);
6810 newsrv->cklen = strlen(args[cur_arg + 1]);
6811 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813 else if (!strcmp(args[cur_arg], "rise")) {
6814 newsrv->rise = atol(args[cur_arg + 1]);
6815 newsrv->health = newsrv->rise;
6816 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006818 else if (!strcmp(args[cur_arg], "fall")) {
6819 newsrv->fall = atol(args[cur_arg + 1]);
6820 cur_arg += 2;
6821 }
6822 else if (!strcmp(args[cur_arg], "inter")) {
6823 newsrv->inter = atol(args[cur_arg + 1]);
6824 cur_arg += 2;
6825 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006826 else if (!strcmp(args[cur_arg], "port")) {
6827 newsrv->check_port = atol(args[cur_arg + 1]);
6828 cur_arg += 2;
6829 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006830 else if (!strcmp(args[cur_arg], "backup")) {
6831 newsrv->state |= SRV_BACKUP;
6832 cur_arg ++;
6833 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006834 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01006835 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006836 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006837 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006838 }
willy tarreau0174f312005-12-18 01:02:42 +01006839 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6840 if (!*args[cur_arg + 1]) {
6841 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6842 file, linenum, "source");
6843 return -1;
6844 }
6845 newsrv->state |= SRV_BIND_SRC;
6846 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6847 cur_arg += 2;
6848 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006849 else {
willy tarreau0174f312005-12-18 01:02:42 +01006850 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 +01006851 file, linenum, newsrv->id);
6852 return -1;
6853 }
6854 }
6855
6856 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006857 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6858 newsrv->check_port = realport; /* by default */
6859 if (!newsrv->check_port) {
6860 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 +01006861 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006862 return -1;
6863 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006864 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006865 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006866
willy tarreau9fe663a2005-12-17 13:02:59 +01006867 curproxy->nbservers++;
6868 }
6869 else if (!strcmp(args[0], "log")) { /* syslog server address */
6870 struct sockaddr_in *sa;
6871 int facility;
6872
6873 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6874 curproxy->logfac1 = global.logfac1;
6875 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006876 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006877 curproxy->logfac2 = global.logfac2;
6878 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006879 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006880 }
6881 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006882 int level;
6883
willy tarreau0f7af912005-12-17 12:21:26 +01006884 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6885 if (!strcmp(log_facilities[facility], args[2]))
6886 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006887
willy tarreau0f7af912005-12-17 12:21:26 +01006888 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006889 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006890 exit(1);
6891 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006892
willy tarreau8337c6b2005-12-17 13:41:01 +01006893 level = 7; /* max syslog level = debug */
6894 if (*(args[3])) {
6895 while (level >= 0 && strcmp(log_levels[level], args[3]))
6896 level--;
6897 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006898 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006899 exit(1);
6900 }
6901 }
6902
willy tarreau0f7af912005-12-17 12:21:26 +01006903 sa = str2sa(args[1]);
6904 if (!sa->sin_port)
6905 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006906
willy tarreau0f7af912005-12-17 12:21:26 +01006907 if (curproxy->logfac1 == -1) {
6908 curproxy->logsrv1 = *sa;
6909 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006910 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006911 }
6912 else if (curproxy->logfac2 == -1) {
6913 curproxy->logsrv2 = *sa;
6914 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006915 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006916 }
6917 else {
6918 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006920 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006921 }
6922 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006923 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006924 file, linenum);
6925 return -1;
6926 }
6927 }
willy tarreaua1598082005-12-17 13:08:06 +01006928 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006929 if (!*args[1]) {
6930 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006931 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006932 return -1;
6933 }
6934
6935 curproxy->source_addr = *str2sa(args[1]);
6936 curproxy->options |= PR_O_BIND_SRC;
6937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6939 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006940 if (curproxy == &defproxy) {
6941 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6942 return -1;
6943 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006944
6945 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006946 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6947 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006948 return -1;
6949 }
6950
6951 preg = calloc(1, sizeof(regex_t));
6952 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006953 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 return -1;
6955 }
6956
willy tarreauc1f47532005-12-18 01:08:26 +01006957 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6958 if (err) {
6959 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6960 file, linenum, *err);
6961 return -1;
6962 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 }
6964 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6965 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006966 if (curproxy == &defproxy) {
6967 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6968 return -1;
6969 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006970
6971 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006972 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 return -1;
6974 }
6975
6976 preg = calloc(1, sizeof(regex_t));
6977 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006978 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 return -1;
6980 }
6981
6982 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6983 }
6984 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6985 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006986 if (curproxy == &defproxy) {
6987 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6988 return -1;
6989 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006990
6991 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006992 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 return -1;
6994 }
6995
6996 preg = calloc(1, sizeof(regex_t));
6997 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006998 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 return -1;
7000 }
7001
7002 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7003 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007004 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7005 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007006 if (curproxy == &defproxy) {
7007 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7008 return -1;
7009 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007010
7011 if (*(args[1]) == 0) {
7012 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7013 return -1;
7014 }
7015
7016 preg = calloc(1, sizeof(regex_t));
7017 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7018 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7019 return -1;
7020 }
7021
7022 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7023 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7025 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007026 if (curproxy == &defproxy) {
7027 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7028 return -1;
7029 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007030
7031 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007032 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007033 return -1;
7034 }
7035
7036 preg = calloc(1, sizeof(regex_t));
7037 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007038 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007039 return -1;
7040 }
7041
7042 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7043 }
7044 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7045 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007046 if (curproxy == &defproxy) {
7047 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7048 return -1;
7049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007050
7051 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007052 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7053 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007054 return -1;
7055 }
7056
7057 preg = calloc(1, sizeof(regex_t));
7058 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007059 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007060 return -1;
7061 }
7062
willy tarreauc1f47532005-12-18 01:08:26 +01007063 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7064 if (err) {
7065 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7066 file, linenum, *err);
7067 return -1;
7068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007069 }
7070 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7071 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007072 if (curproxy == &defproxy) {
7073 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7074 return -1;
7075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007076
7077 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007078 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007079 return -1;
7080 }
7081
7082 preg = calloc(1, sizeof(regex_t));
7083 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007084 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007085 return -1;
7086 }
7087
7088 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7089 }
7090 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7091 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007092 if (curproxy == &defproxy) {
7093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7094 return -1;
7095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007096
7097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007098 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 return -1;
7100 }
7101
7102 preg = calloc(1, sizeof(regex_t));
7103 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007105 return -1;
7106 }
7107
7108 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007110 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7111 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007112 if (curproxy == &defproxy) {
7113 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7114 return -1;
7115 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007116
7117 if (*(args[1]) == 0) {
7118 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7119 return -1;
7120 }
7121
7122 preg = calloc(1, sizeof(regex_t));
7123 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7124 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7125 return -1;
7126 }
7127
7128 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007130 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7131 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007132 if (curproxy == &defproxy) {
7133 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7134 return -1;
7135 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007136
7137 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007138 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 return -1;
7140 }
7141
7142 preg = calloc(1, sizeof(regex_t));
7143 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007144 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007145 return -1;
7146 }
7147
7148 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7149 }
7150 else if (!strcmp(args[0], "reqadd")) { /* add request header */
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 }
7155
willy tarreau9fe663a2005-12-17 13:02:59 +01007156 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007157 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007158 return 0;
7159 }
7160
7161 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007162 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007163 return -1;
7164 }
7165
willy tarreau4302f492005-12-18 01:00:37 +01007166 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7167 }
7168 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7169 regex_t *preg;
7170
7171 if (*(args[1]) == 0 || *(args[2]) == 0) {
7172 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7173 file, linenum, args[0]);
7174 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007175 }
willy tarreau4302f492005-12-18 01:00:37 +01007176
7177 preg = calloc(1, sizeof(regex_t));
7178 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7179 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7180 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007181 }
willy tarreau4302f492005-12-18 01:00:37 +01007182
willy tarreauc1f47532005-12-18 01:08:26 +01007183 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7184 if (err) {
7185 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7186 file, linenum, *err);
7187 return -1;
7188 }
willy tarreau4302f492005-12-18 01:00:37 +01007189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007190 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7191 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007192 if (curproxy == &defproxy) {
7193 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7194 return -1;
7195 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007196
7197 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007198 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 return -1;
7200 }
willy tarreaue39cd132005-12-17 13:00:18 +01007201
willy tarreau9fe663a2005-12-17 13:02:59 +01007202 preg = calloc(1, sizeof(regex_t));
7203 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007204 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007205 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007206 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007207
willy tarreauc1f47532005-12-18 01:08:26 +01007208 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7209 if (err) {
7210 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7211 file, linenum, *err);
7212 return -1;
7213 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007214 }
willy tarreau982249e2005-12-18 00:57:06 +01007215 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7216 regex_t *preg;
7217 if (curproxy == &defproxy) {
7218 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7219 return -1;
7220 }
7221
7222 if (*(args[1]) == 0) {
7223 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7224 return -1;
7225 }
7226
7227 preg = calloc(1, sizeof(regex_t));
7228 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7229 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7230 return -1;
7231 }
7232
willy tarreauc1f47532005-12-18 01:08:26 +01007233 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7234 if (err) {
7235 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7236 file, linenum, *err);
7237 return -1;
7238 }
willy tarreau982249e2005-12-18 00:57:06 +01007239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007241 regex_t *preg;
7242 if (curproxy == &defproxy) {
7243 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7244 return -1;
7245 }
willy tarreaue39cd132005-12-17 13:00:18 +01007246
willy tarreaua41a8b42005-12-17 14:02:24 +01007247 if (*(args[1]) == 0 || *(args[2]) == 0) {
7248 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7249 file, linenum, args[0]);
7250 return -1;
7251 }
willy tarreaue39cd132005-12-17 13:00:18 +01007252
willy tarreaua41a8b42005-12-17 14:02:24 +01007253 preg = calloc(1, sizeof(regex_t));
7254 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7255 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7256 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007257 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007258
willy tarreauc1f47532005-12-18 01:08:26 +01007259 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7260 if (err) {
7261 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7262 file, linenum, *err);
7263 return -1;
7264 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007265 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007266 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7267 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007268 if (curproxy == &defproxy) {
7269 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7270 return -1;
7271 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007272
7273 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007274 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 return -1;
7276 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007277
willy tarreau9fe663a2005-12-17 13:02:59 +01007278 preg = calloc(1, sizeof(regex_t));
7279 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007280 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007281 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007282 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007283
willy tarreauc1f47532005-12-18 01:08:26 +01007284 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7285 if (err) {
7286 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7287 file, linenum, *err);
7288 return -1;
7289 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007290 }
willy tarreau982249e2005-12-18 00:57:06 +01007291 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7292 regex_t *preg;
7293 if (curproxy == &defproxy) {
7294 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7295 return -1;
7296 }
7297
7298 if (*(args[1]) == 0) {
7299 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7300 return -1;
7301 }
7302
7303 preg = calloc(1, sizeof(regex_t));
7304 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7305 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7306 return -1;
7307 }
7308
willy tarreauc1f47532005-12-18 01:08:26 +01007309 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7310 if (err) {
7311 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7312 file, linenum, *err);
7313 return -1;
7314 }
willy tarreau982249e2005-12-18 00:57:06 +01007315 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007317 if (curproxy == &defproxy) {
7318 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7319 return -1;
7320 }
7321
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007323 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007324 return 0;
7325 }
7326
7327 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007328 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 return -1;
7330 }
7331
7332 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7333 }
willy tarreauc1f47532005-12-18 01:08:26 +01007334 else if (!strcmp(args[0], "errorloc") ||
7335 !strcmp(args[0], "errorloc302") ||
7336 !strcmp(args[0], "errorloc303")) { /* error location */
7337 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007338 char *err;
7339
willy tarreaueedaa9f2005-12-17 14:08:03 +01007340 // if (curproxy == &defproxy) {
7341 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7342 // return -1;
7343 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007344
willy tarreau8337c6b2005-12-17 13:41:01 +01007345 if (*(args[2]) == 0) {
7346 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7347 return -1;
7348 }
7349
7350 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007351 if (!strcmp(args[0], "errorloc303")) {
7352 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7353 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7354 } else {
7355 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7356 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7357 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007358
7359 if (errnum == 400) {
7360 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007361 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007362 free(curproxy->errmsg.msg400);
7363 }
7364 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007365 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007366 }
7367 else if (errnum == 403) {
7368 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007369 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007370 free(curproxy->errmsg.msg403);
7371 }
7372 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007373 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007374 }
7375 else if (errnum == 408) {
7376 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007377 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007378 free(curproxy->errmsg.msg408);
7379 }
7380 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007381 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007382 }
7383 else if (errnum == 500) {
7384 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007385 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007386 free(curproxy->errmsg.msg500);
7387 }
7388 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007389 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007390 }
7391 else if (errnum == 502) {
7392 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007393 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007394 free(curproxy->errmsg.msg502);
7395 }
7396 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007397 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007398 }
7399 else if (errnum == 503) {
7400 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007401 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007402 free(curproxy->errmsg.msg503);
7403 }
7404 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007405 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007406 }
7407 else if (errnum == 504) {
7408 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007409 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007410 free(curproxy->errmsg.msg504);
7411 }
7412 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007413 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007414 }
7415 else {
7416 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7417 free(err);
7418 }
7419 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007421 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007422 return -1;
7423 }
7424 return 0;
7425}
willy tarreaue39cd132005-12-17 13:00:18 +01007426
willy tarreau5cbea6f2005-12-17 12:48:26 +01007427
willy tarreau9fe663a2005-12-17 13:02:59 +01007428/*
7429 * This function reads and parses the configuration file given in the argument.
7430 * returns 0 if OK, -1 if error.
7431 */
7432int readcfgfile(char *file) {
7433 char thisline[256];
7434 char *line;
7435 FILE *f;
7436 int linenum = 0;
7437 char *end;
7438 char *args[MAX_LINE_ARGS];
7439 int arg;
7440 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007441 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007442 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007443
willy tarreau9fe663a2005-12-17 13:02:59 +01007444 struct proxy *curproxy = NULL;
7445 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007446
willy tarreau9fe663a2005-12-17 13:02:59 +01007447 if ((f=fopen(file,"r")) == NULL)
7448 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007449
willy tarreaueedaa9f2005-12-17 14:08:03 +01007450 init_default_instance();
7451
willy tarreau9fe663a2005-12-17 13:02:59 +01007452 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7453 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007454
willy tarreau9fe663a2005-12-17 13:02:59 +01007455 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007456
willy tarreau9fe663a2005-12-17 13:02:59 +01007457 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007458 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007459 line++;
7460
7461 arg = 0;
7462 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007463
willy tarreau9fe663a2005-12-17 13:02:59 +01007464 while (*line && arg < MAX_LINE_ARGS) {
7465 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7466 * C equivalent value. Other combinations left unchanged (eg: \1).
7467 */
7468 if (*line == '\\') {
7469 int skip = 0;
7470 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7471 *line = line[1];
7472 skip = 1;
7473 }
7474 else if (line[1] == 'r') {
7475 *line = '\r';
7476 skip = 1;
7477 }
7478 else if (line[1] == 'n') {
7479 *line = '\n';
7480 skip = 1;
7481 }
7482 else if (line[1] == 't') {
7483 *line = '\t';
7484 skip = 1;
7485 }
willy tarreauc1f47532005-12-18 01:08:26 +01007486 else if (line[1] == 'x') {
7487 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7488 unsigned char hex1, hex2;
7489 hex1 = toupper(line[2]) - '0';
7490 hex2 = toupper(line[3]) - '0';
7491 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7492 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7493 *line = (hex1<<4) + hex2;
7494 skip = 3;
7495 }
7496 else {
7497 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7498 return -1;
7499 }
7500 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007501 if (skip) {
7502 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7503 end -= skip;
7504 }
7505 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007506 }
willy tarreaua1598082005-12-17 13:08:06 +01007507 else if (*line == '#' || *line == '\n' || *line == '\r') {
7508 /* end of string, end of loop */
7509 *line = 0;
7510 break;
7511 }
willy tarreauc29948c2005-12-17 13:10:27 +01007512 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007513 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007514 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007515 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007516 line++;
7517 args[++arg] = line;
7518 }
7519 else {
7520 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007521 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007522 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007523
willy tarreau9fe663a2005-12-17 13:02:59 +01007524 /* empty line */
7525 if (!**args)
7526 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007527
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 /* zero out remaining args */
7529 while (++arg < MAX_LINE_ARGS) {
7530 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007531 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007532
willy tarreaua41a8b42005-12-17 14:02:24 +01007533 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007534 confsect = CFG_LISTEN;
7535 else if (!strcmp(args[0], "global")) /* global config */
7536 confsect = CFG_GLOBAL;
7537 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007538
willy tarreau9fe663a2005-12-17 13:02:59 +01007539 switch (confsect) {
7540 case CFG_LISTEN:
7541 if (cfg_parse_listen(file, linenum, args) < 0)
7542 return -1;
7543 break;
7544 case CFG_GLOBAL:
7545 if (cfg_parse_global(file, linenum, args) < 0)
7546 return -1;
7547 break;
7548 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007549 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007550 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007551 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007552
7553
willy tarreau0f7af912005-12-17 12:21:26 +01007554 }
7555 fclose(f);
7556
7557 /*
7558 * Now, check for the integrity of all that we have collected.
7559 */
7560
Willy TARREAU3759f982006-03-01 22:44:17 +01007561 /* will be needed further to delay some tasks */
7562 tv_now(&now);
7563
willy tarreau0f7af912005-12-17 12:21:26 +01007564 if ((curproxy = proxy) == NULL) {
7565 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7566 file);
7567 return -1;
7568 }
7569
7570 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007571 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007572 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007573 curproxy = curproxy->next;
7574 continue;
7575 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007576
7577 if (curproxy->listen == NULL) {
7578 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);
7579 cfgerr++;
7580 }
7581 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007582 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007583 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007584 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7585 file, curproxy->id);
7586 cfgerr++;
7587 }
7588 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7589 if (curproxy->options & PR_O_TRANSP) {
7590 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7591 file, curproxy->id);
7592 cfgerr++;
7593 }
7594 else if (curproxy->srv == NULL) {
7595 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7596 file, curproxy->id);
7597 cfgerr++;
7598 }
willy tarreaua1598082005-12-17 13:08:06 +01007599 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007600 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7601 file, curproxy->id);
7602 }
7603 }
7604 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007605 if (curproxy->cookie_name != NULL) {
7606 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7607 file, curproxy->id);
7608 }
7609 if ((newsrv = curproxy->srv) != NULL) {
7610 Warning("parsing %s : servers will be ignored for listener %s.\n",
7611 file, curproxy->id);
7612 }
willy tarreaue39cd132005-12-17 13:00:18 +01007613 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007614 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7615 file, curproxy->id);
7616 }
willy tarreaue39cd132005-12-17 13:00:18 +01007617 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007618 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7619 file, curproxy->id);
7620 }
7621 }
7622 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7623 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7624 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7625 file, curproxy->id);
7626 cfgerr++;
7627 }
7628 else {
7629 while (newsrv != NULL) {
7630 /* nothing to check for now */
7631 newsrv = newsrv->next;
7632 }
7633 }
7634 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007635
7636 if (curproxy->options & PR_O_LOGASAP)
7637 curproxy->to_log &= ~LW_BYTES;
7638
willy tarreau8337c6b2005-12-17 13:41:01 +01007639 if (curproxy->errmsg.msg400 == NULL) {
7640 curproxy->errmsg.msg400 = (char *)HTTP_400;
7641 curproxy->errmsg.len400 = strlen(HTTP_400);
7642 }
7643 if (curproxy->errmsg.msg403 == NULL) {
7644 curproxy->errmsg.msg403 = (char *)HTTP_403;
7645 curproxy->errmsg.len403 = strlen(HTTP_403);
7646 }
7647 if (curproxy->errmsg.msg408 == NULL) {
7648 curproxy->errmsg.msg408 = (char *)HTTP_408;
7649 curproxy->errmsg.len408 = strlen(HTTP_408);
7650 }
7651 if (curproxy->errmsg.msg500 == NULL) {
7652 curproxy->errmsg.msg500 = (char *)HTTP_500;
7653 curproxy->errmsg.len500 = strlen(HTTP_500);
7654 }
7655 if (curproxy->errmsg.msg502 == NULL) {
7656 curproxy->errmsg.msg502 = (char *)HTTP_502;
7657 curproxy->errmsg.len502 = strlen(HTTP_502);
7658 }
7659 if (curproxy->errmsg.msg503 == NULL) {
7660 curproxy->errmsg.msg503 = (char *)HTTP_503;
7661 curproxy->errmsg.len503 = strlen(HTTP_503);
7662 }
7663 if (curproxy->errmsg.msg504 == NULL) {
7664 curproxy->errmsg.msg504 = (char *)HTTP_504;
7665 curproxy->errmsg.len504 = strlen(HTTP_504);
7666 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007667
7668 /* now we'll start this proxy's health checks if any */
7669 /* 1- count the checkers to run simultaneously */
7670 nbchk = 0;
7671 mininter = 0;
7672 newsrv = curproxy->srv;
7673 while (newsrv != NULL) {
7674 if (newsrv->state & SRV_CHECKED) {
7675 if (!mininter || mininter > newsrv->inter)
7676 mininter = newsrv->inter;
7677 nbchk++;
7678 }
7679 newsrv = newsrv->next;
7680 }
7681
7682 /* 2- start them as far as possible from each others while respecting
7683 * their own intervals. For this, we will start them after their own
7684 * interval added to the min interval divided by the number of servers,
7685 * weighted by the server's position in the list.
7686 */
7687 if (nbchk > 0) {
7688 struct task *t;
7689 int srvpos;
7690
7691 newsrv = curproxy->srv;
7692 srvpos = 0;
7693 while (newsrv != NULL) {
7694 /* should this server be checked ? */
7695 if (newsrv->state & SRV_CHECKED) {
7696 if ((t = pool_alloc(task)) == NULL) {
7697 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7698 return -1;
7699 }
7700
7701 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7702 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7703 t->state = TASK_IDLE;
7704 t->process = process_chk;
7705 t->context = newsrv;
7706
7707 /* check this every ms */
7708 tv_delayfrom(&t->expire, &now,
7709 newsrv->inter + mininter * srvpos / nbchk);
7710 task_queue(t);
7711 //task_wakeup(&rq, t);
7712 srvpos++;
7713 }
7714 newsrv = newsrv->next;
7715 }
7716 }
7717
willy tarreau0f7af912005-12-17 12:21:26 +01007718 curproxy = curproxy->next;
7719 }
7720 if (cfgerr > 0) {
7721 Alert("Errors found in configuration file, aborting.\n");
7722 return -1;
7723 }
7724 else
7725 return 0;
7726}
7727
7728
7729/*
7730 * This function initializes all the necessary variables. It only returns
7731 * if everything is OK. If something fails, it exits.
7732 */
7733void init(int argc, char **argv) {
7734 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007735 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007736 char *old_argv = *argv;
7737 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007738 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007739
7740 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007741 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007742 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007743 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007744 exit(1);
7745 }
7746
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007747 /* initialize the libc's localtime structures once for all so that we
7748 * won't be missing memory if we want to send alerts under OOM conditions.
7749 */
7750 tv_now(&now);
7751 localtime(&now.tv_sec);
7752
willy tarreau4302f492005-12-18 01:00:37 +01007753 /* initialize the log header encoding map : '{|}"#' should be encoded with
7754 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7755 * URL encoding only requires '"', '#' to be encoded as well as non-
7756 * printable characters above.
7757 */
7758 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7759 memset(url_encode_map, 0, sizeof(url_encode_map));
7760 for (i = 0; i < 32; i++) {
7761 FD_SET(i, hdr_encode_map);
7762 FD_SET(i, url_encode_map);
7763 }
7764 for (i = 127; i < 256; i++) {
7765 FD_SET(i, hdr_encode_map);
7766 FD_SET(i, url_encode_map);
7767 }
7768
7769 tmp = "\"#{|}";
7770 while (*tmp) {
7771 FD_SET(*tmp, hdr_encode_map);
7772 tmp++;
7773 }
7774
7775 tmp = "\"#";
7776 while (*tmp) {
7777 FD_SET(*tmp, url_encode_map);
7778 tmp++;
7779 }
7780
willy tarreau64a3cc32005-12-18 01:13:11 +01007781 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7782#if defined(ENABLE_POLL)
7783 cfg_polling_mechanism |= POLL_USE_POLL;
7784#endif
7785#if defined(ENABLE_EPOLL)
7786 cfg_polling_mechanism |= POLL_USE_EPOLL;
7787#endif
7788
willy tarreau0f7af912005-12-17 12:21:26 +01007789 pid = getpid();
7790 progname = *argv;
7791 while ((tmp = strchr(progname, '/')) != NULL)
7792 progname = tmp + 1;
7793
7794 argc--; argv++;
7795 while (argc > 0) {
7796 char *flag;
7797
7798 if (**argv == '-') {
7799 flag = *argv+1;
7800
7801 /* 1 arg */
7802 if (*flag == 'v') {
7803 display_version();
7804 exit(0);
7805 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007806#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007807 else if (*flag == 'd' && flag[1] == 'e')
7808 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007809#endif
7810#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007811 else if (*flag == 'd' && flag[1] == 'p')
7812 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007813#endif
willy tarreau982249e2005-12-18 00:57:06 +01007814 else if (*flag == 'V')
7815 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007816 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007817 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007818 else if (*flag == 'c')
7819 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007820 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007821 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007822 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007823 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007824#if STATTIME > 0
7825 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007826 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007827 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007828 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007829#endif
7830 else { /* >=2 args */
7831 argv++; argc--;
7832 if (argc == 0)
7833 usage(old_argv);
7834
7835 switch (*flag) {
7836 case 'n' : cfg_maxconn = atol(*argv); break;
7837 case 'N' : cfg_maxpconn = atol(*argv); break;
7838 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007839 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007840 default: usage(old_argv);
7841 }
7842 }
7843 }
7844 else
7845 usage(old_argv);
7846 argv++; argc--;
7847 }
7848
willy tarreaud0fb4652005-12-18 01:32:04 +01007849 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7850 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007851
willy tarreau0f7af912005-12-17 12:21:26 +01007852 if (!cfg_cfgfile)
7853 usage(old_argv);
7854
7855 gethostname(hostname, MAX_HOSTNAME_LEN);
7856
willy tarreau12350152005-12-18 01:03:27 +01007857 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007858 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01007859 if (readcfgfile(cfg_cfgfile) < 0) {
7860 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7861 exit(1);
7862 }
willy tarreau12350152005-12-18 01:03:27 +01007863 if (have_appsession)
7864 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007865
willy tarreau982249e2005-12-18 00:57:06 +01007866 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007867 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7868 exit(0);
7869 }
7870
willy tarreau9fe663a2005-12-17 13:02:59 +01007871 if (cfg_maxconn > 0)
7872 global.maxconn = cfg_maxconn;
7873
willy tarreaufe2c5c12005-12-17 14:14:34 +01007874 if (cfg_pidfile) {
7875 if (global.pidfile)
7876 free(global.pidfile);
7877 global.pidfile = strdup(cfg_pidfile);
7878 }
7879
willy tarreau9fe663a2005-12-17 13:02:59 +01007880 if (global.maxconn == 0)
7881 global.maxconn = DEFAULT_MAXCONN;
7882
Willy TARREAU203b0b62006-03-12 18:00:28 +01007883 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01007884
7885 if (arg_mode & MODE_DEBUG) {
7886 /* command line debug mode inhibits configuration mode */
7887 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7888 }
willy tarreau982249e2005-12-18 00:57:06 +01007889 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7890 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007891
7892 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7893 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7894 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7895 }
7896
7897 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7898 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7899 global.nbproc = 1;
7900 }
7901
7902 if (global.nbproc < 1)
7903 global.nbproc = 1;
7904
willy tarreau0f7af912005-12-17 12:21:26 +01007905 StaticReadEvent = (fd_set *)calloc(1,
7906 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007907 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007908 StaticWriteEvent = (fd_set *)calloc(1,
7909 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007910 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007911
7912 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007913 sizeof(struct fdtab) * (global.maxsock));
7914 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007915 fdtab[i].state = FD_STCLOSE;
7916 }
7917}
7918
7919/*
7920 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7921 */
7922int start_proxies() {
7923 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007924 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007925 int fd;
7926
7927 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007928 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007929 continue;
7930
willy tarreaua41a8b42005-12-17 14:02:24 +01007931 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7932 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007933 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007934 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7935 curproxy->id);
7936 return -1;
7937 }
willy tarreau0f7af912005-12-17 12:21:26 +01007938
willy tarreaua41a8b42005-12-17 14:02:24 +01007939 if (fd >= global.maxsock) {
7940 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7941 curproxy->id);
7942 close(fd);
7943 return -1;
7944 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007945
willy tarreaua41a8b42005-12-17 14:02:24 +01007946 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7947 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7948 (char *) &one, sizeof(one)) == -1)) {
7949 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7950 curproxy->id);
7951 close(fd);
7952 return -1;
7953 }
willy tarreau0f7af912005-12-17 12:21:26 +01007954
willy tarreaua41a8b42005-12-17 14:02:24 +01007955 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7956 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7957 curproxy->id);
7958 }
willy tarreau0f7af912005-12-17 12:21:26 +01007959
willy tarreaua41a8b42005-12-17 14:02:24 +01007960 if (bind(fd,
7961 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007962 listener->addr.ss_family == AF_INET6 ?
7963 sizeof(struct sockaddr_in6) :
7964 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007965 Alert("cannot bind socket for proxy %s. Aborting.\n",
7966 curproxy->id);
7967 close(fd);
7968 return -1;
7969 }
willy tarreau0f7af912005-12-17 12:21:26 +01007970
willy tarreaua41a8b42005-12-17 14:02:24 +01007971 if (listen(fd, curproxy->maxconn) == -1) {
7972 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7973 curproxy->id);
7974 close(fd);
7975 return -1;
7976 }
willy tarreau0f7af912005-12-17 12:21:26 +01007977
willy tarreaua41a8b42005-12-17 14:02:24 +01007978 /* the function for the accept() event */
7979 fdtab[fd].read = &event_accept;
7980 fdtab[fd].write = NULL; /* never called */
7981 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7982 curproxy->state = PR_STRUN;
7983 fdtab[fd].state = FD_STLISTEN;
7984 FD_SET(fd, StaticReadEvent);
7985 fd_insert(fd);
7986 listeners++;
7987 }
willy tarreaua1598082005-12-17 13:08:06 +01007988 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007989 }
7990 return 0;
7991}
7992
willy tarreaub952e1d2005-12-18 01:31:20 +01007993int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007994
7995 appsess *temp1,*temp2;
7996 temp1 = (appsess *)key1;
7997 temp2 = (appsess *)key2;
7998
7999 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8000 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8001
8002 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8003}/* end match_str */
8004
willy tarreaub952e1d2005-12-18 01:31:20 +01008005void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008006 appsess *temp1;
8007
8008 //printf("destroy called\n");
8009 temp1 = (appsess *)data;
8010
8011 if (temp1->sessid)
8012 pool_free_to(apools.sessid, temp1->sessid);
8013
8014 if (temp1->serverid)
8015 pool_free_to(apools.serverid, temp1->serverid);
8016
8017 pool_free(appsess, temp1);
8018} /* end destroy */
8019
8020void appsession_cleanup( void )
8021{
8022 struct proxy *p = proxy;
8023
8024 while(p) {
8025 chtbl_destroy(&(p->htbl_proxy));
8026 p = p->next;
8027 }
8028}/* end appsession_cleanup() */
8029
8030void pool_destroy(void **pool)
8031{
8032 void *temp, *next;
8033 next = pool;
8034 while (next) {
8035 temp = next;
8036 next = *(void **)temp;
8037 free(temp);
8038 }
8039}/* end pool_destroy() */
8040
willy tarreaub952e1d2005-12-18 01:31:20 +01008041void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008042 struct proxy *p = proxy;
8043 struct cap_hdr *h,*h_next;
8044 struct server *s,*s_next;
8045 struct listener *l,*l_next;
8046
8047 while (p) {
8048 if (p->id)
8049 free(p->id);
8050
8051 if (p->check_req)
8052 free(p->check_req);
8053
8054 if (p->cookie_name)
8055 free(p->cookie_name);
8056
8057 if (p->capture_name)
8058 free(p->capture_name);
8059
8060 /* only strup if the user have set in config.
8061 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008062 if (p->errmsg.msg400) free(p->errmsg.msg400);
8063 if (p->errmsg.msg403) free(p->errmsg.msg403);
8064 if (p->errmsg.msg408) free(p->errmsg.msg408);
8065 if (p->errmsg.msg500) free(p->errmsg.msg500);
8066 if (p->errmsg.msg502) free(p->errmsg.msg502);
8067 if (p->errmsg.msg503) free(p->errmsg.msg503);
8068 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008069 */
8070 if (p->appsession_name)
8071 free(p->appsession_name);
8072
8073 h = p->req_cap;
8074 while (h) {
8075 h_next = h->next;
8076 if (h->name)
8077 free(h->name);
8078 pool_destroy(h->pool);
8079 free(h);
8080 h = h_next;
8081 }/* end while(h) */
8082
8083 h = p->rsp_cap;
8084 while (h) {
8085 h_next = h->next;
8086 if (h->name)
8087 free(h->name);
8088
8089 pool_destroy(h->pool);
8090 free(h);
8091 h = h_next;
8092 }/* end while(h) */
8093
8094 s = p->srv;
8095 while (s) {
8096 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008097 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008098 free(s->id);
8099
willy tarreaub952e1d2005-12-18 01:31:20 +01008100 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008101 free(s->cookie);
8102
8103 free(s);
8104 s = s_next;
8105 }/* end while(s) */
8106
8107 l = p->listen;
8108 while (l) {
8109 l_next = l->next;
8110 free(l);
8111 l = l_next;
8112 }/* end while(l) */
8113
8114 pool_destroy((void **) p->req_cap_pool);
8115 pool_destroy((void **) p->rsp_cap_pool);
8116 p = p->next;
8117 }/* end while(p) */
8118
8119 if (global.chroot) free(global.chroot);
8120 if (global.pidfile) free(global.pidfile);
8121
willy tarreau12350152005-12-18 01:03:27 +01008122 if (StaticReadEvent) free(StaticReadEvent);
8123 if (StaticWriteEvent) free(StaticWriteEvent);
8124 if (fdtab) free(fdtab);
8125
8126 pool_destroy(pool_session);
8127 pool_destroy(pool_buffer);
8128 pool_destroy(pool_fdtab);
8129 pool_destroy(pool_requri);
8130 pool_destroy(pool_task);
8131 pool_destroy(pool_capture);
8132 pool_destroy(pool_appsess);
8133
8134 if (have_appsession) {
8135 pool_destroy(apools.serverid);
8136 pool_destroy(apools.sessid);
8137 }
8138} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008139
8140int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008141 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008142 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008143 init(argc, argv);
8144
willy tarreau0f7af912005-12-17 12:21:26 +01008145 signal(SIGQUIT, dump);
8146 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008147 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008148#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008149 signal(SIGINT, sig_int);
8150 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008151#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008152
8153 /* on very high loads, a sigpipe sometimes happen just between the
8154 * getsockopt() which tells "it's OK to write", and the following write :-(
8155 */
willy tarreau3242e862005-12-17 12:27:53 +01008156#ifndef MSG_NOSIGNAL
8157 signal(SIGPIPE, SIG_IGN);
8158#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008159
willy tarreaud0fb4652005-12-18 01:32:04 +01008160 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008161 if (start_proxies() < 0)
8162 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008163
8164 if (listeners == 0) {
8165 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8166 exit(1);
8167 }
8168
willy tarreaudbd3bef2006-01-20 19:35:18 +01008169 /* prepare pause/play signals */
8170 signal(SIGTTOU, sig_pause);
8171 signal(SIGTTIN, sig_listen);
8172
Willy TARREAUe3283d12006-03-01 22:15:29 +01008173 if (global.mode & MODE_DAEMON) {
8174 global.mode &= ~MODE_VERBOSE;
8175 global.mode |= MODE_QUIET;
8176 }
8177
willy tarreaud0fb4652005-12-18 01:32:04 +01008178 /* MODE_QUIET can inhibit alerts and warnings below this line */
8179
8180 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008181 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008182 /* detach from the tty */
8183 fclose(stdin); fclose(stdout); fclose(stderr);
8184 close(0); close(1); close(2);
8185 }
willy tarreau0f7af912005-12-17 12:21:26 +01008186
willy tarreaufe2c5c12005-12-17 14:14:34 +01008187 /* open log & pid files before the chroot */
8188 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8189 int pidfd;
8190 unlink(global.pidfile);
8191 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8192 if (pidfd < 0) {
8193 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8194 exit(1);
8195 }
8196 pidfile = fdopen(pidfd, "w");
8197 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008198
8199 /* chroot if needed */
8200 if (global.chroot != NULL) {
8201 if (chroot(global.chroot) == -1) {
8202 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8203 exit(1);
8204 }
8205 chdir("/");
8206 }
8207
willy tarreaub1285d52005-12-18 01:20:14 +01008208 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008209 if (!global.rlimit_nofile)
8210 global.rlimit_nofile = global.maxsock;
8211
willy tarreaub1285d52005-12-18 01:20:14 +01008212 if (global.rlimit_nofile) {
8213 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8214 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8215 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8216 }
8217 }
8218
willy tarreau9fe663a2005-12-17 13:02:59 +01008219 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008220 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008221 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8222 exit(1);
8223 }
8224
willy tarreau036e1ce2005-12-17 13:46:33 +01008225 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008226 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8227 exit(1);
8228 }
8229
willy tarreaub1285d52005-12-18 01:20:14 +01008230 /* check ulimits */
8231 limit.rlim_cur = limit.rlim_max = 0;
8232 getrlimit(RLIMIT_NOFILE, &limit);
8233 if (limit.rlim_cur < global.maxsock) {
8234 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",
8235 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8236 }
8237
willy tarreau9fe663a2005-12-17 13:02:59 +01008238 if (global.mode & MODE_DAEMON) {
8239 int ret = 0;
8240 int proc;
8241
8242 /* the father launches the required number of processes */
8243 for (proc = 0; proc < global.nbproc; proc++) {
8244 ret = fork();
8245 if (ret < 0) {
8246 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8247 exit(1); /* there has been an error */
8248 }
8249 else if (ret == 0) /* child breaks here */
8250 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008251 if (pidfile != NULL) {
8252 fprintf(pidfile, "%d\n", ret);
8253 fflush(pidfile);
8254 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008255 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008256 /* close the pidfile both in children and father */
8257 if (pidfile != NULL)
8258 fclose(pidfile);
8259 free(global.pidfile);
8260
willy tarreau9fe663a2005-12-17 13:02:59 +01008261 if (proc == global.nbproc)
8262 exit(0); /* parent must leave */
8263
willy tarreau750a4722005-12-17 13:21:24 +01008264 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8265 * that we can detach from the TTY. We MUST NOT do it in other cases since
8266 * it would have already be done, and 0-2 would have been affected to listening
8267 * sockets
8268 */
8269 if (!(global.mode & MODE_QUIET)) {
8270 /* detach from the tty */
8271 fclose(stdin); fclose(stdout); fclose(stderr);
8272 close(0); close(1); close(2); /* close all fd's */
8273 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8274 }
willy tarreaua1598082005-12-17 13:08:06 +01008275 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008276 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008277 }
8278
willy tarreau1c2ad212005-12-18 01:11:29 +01008279#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008280 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008281 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8282 epoll_loop(POLL_LOOP_ACTION_RUN);
8283 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008284 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008285 }
8286 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008287 Warning("epoll() is not available. Using poll()/select() instead.\n");
8288 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008289 }
8290 }
8291#endif
8292
8293#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008294 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008295 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8296 poll_loop(POLL_LOOP_ACTION_RUN);
8297 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008298 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008299 }
8300 else {
8301 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008302 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008303 }
8304 }
8305#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008306 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008307 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8308 select_loop(POLL_LOOP_ACTION_RUN);
8309 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008310 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008311 }
8312 }
8313
willy tarreau0f7af912005-12-17 12:21:26 +01008314
willy tarreau12350152005-12-18 01:03:27 +01008315 /* Free all Hash Keys and all Hash elements */
8316 appsession_cleanup();
8317 /* Do some cleanup */
8318 deinit();
8319
willy tarreau0f7af912005-12-17 12:21:26 +01008320 exit(0);
8321}
willy tarreau12350152005-12-18 01:03:27 +01008322
8323#if defined(DEBUG_HASH)
8324static void print_table(const CHTbl *htbl) {
8325
8326 ListElmt *element;
8327 int i;
8328 appsess *asession;
8329
8330 /*****************************************************************************
8331 * *
8332 * Display the chained hash table. *
8333 * *
8334 *****************************************************************************/
8335
8336 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8337
8338 for (i = 0; i < TBLSIZ; i++) {
8339 fprintf(stdout, "Bucket[%03d]\n", i);
8340
8341 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8342 //fprintf(stdout, "%c", *(char *)list_data(element));
8343 asession = (appsess *)list_data(element);
8344 fprintf(stdout, "ELEM :%s:", asession->sessid);
8345 fprintf(stdout, " Server :%s: \n", asession->serverid);
8346 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8347 }
8348
8349 fprintf(stdout, "\n");
8350 }
8351 return;
8352} /* end print_table */
8353#endif
8354
8355static int appsession_init(void)
8356{
8357 static int initialized = 0;
8358 int idlen;
8359 struct server *s;
8360 struct proxy *p = proxy;
8361
8362 if (!initialized) {
8363 if (!appsession_task_init()) {
8364 apools.sessid = NULL;
8365 apools.serverid = NULL;
8366 apools.ser_waste = 0;
8367 apools.ser_use = 0;
8368 apools.ser_msize = sizeof(void *);
8369 apools.ses_waste = 0;
8370 apools.ses_use = 0;
8371 apools.ses_msize = sizeof(void *);
8372 while (p) {
8373 s = p->srv;
8374 if (apools.ses_msize < p->appsession_len)
8375 apools.ses_msize = p->appsession_len;
8376 while (s) {
8377 idlen = strlen(s->id);
8378 if (apools.ser_msize < idlen)
8379 apools.ser_msize = idlen;
8380 s = s->next;
8381 }
8382 p = p->next;
8383 }
8384 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8385 apools.ses_msize ++;
8386 }
8387 else {
8388 fprintf(stderr, "appsession_task_init failed\n");
8389 return -1;
8390 }
8391 initialized ++;
8392 }
8393 return 0;
8394}
8395
8396static int appsession_task_init(void)
8397{
8398 static int initialized = 0;
8399 struct task *t;
8400 if (!initialized) {
8401 if ((t = pool_alloc(task)) == NULL)
8402 return -1;
8403 t->next = t->prev = t->rqnext = NULL;
8404 t->wq = LIST_HEAD(wait_queue);
8405 t->state = TASK_IDLE;
8406 t->context = NULL;
8407 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8408 task_queue(t);
8409 t->process = appsession_refresh;
8410 initialized ++;
8411 }
8412 return 0;
8413}
8414
8415static int appsession_refresh(struct task *t) {
8416 struct proxy *p = proxy;
8417 CHTbl *htbl;
8418 ListElmt *element, *last;
8419 int i;
8420 appsess *asession;
8421 void *data;
8422
8423 while (p) {
8424 if (p->appsession_name != NULL) {
8425 htbl = &p->htbl_proxy;
8426 /* if we ever give up the use of TBLSIZ, we need to change this */
8427 for (i = 0; i < TBLSIZ; i++) {
8428 last = NULL;
8429 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8430 asession = (appsess *)list_data(element);
8431 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8432 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8433 int len;
8434 /*
8435 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8436 */
8437 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8438 asession->sessid, asession->serverid?asession->serverid:"(null)");
8439 write(1, trash, len);
8440 }
8441 /* delete the expired element from within the hash table */
8442 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8443 && (htbl->table[i].destroy != NULL)) {
8444 htbl->table[i].destroy(data);
8445 }
8446 if (last == NULL) {/* patient lost his head, get a new one */
8447 element = list_head(&htbl->table[i]);
8448 if (element == NULL) break; /* no heads left, go to next patient */
8449 }
8450 else
8451 element = last;
8452 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8453 else
8454 last = element;
8455 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8456 }
8457 }
8458 p = p->next;
8459 }
8460 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8461 return TBLCHKINT;
8462} /* end appsession_refresh */
8463