blob: d74ce72eb7522f72bd07e6b4c110829277816082 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau18a957c2006-04-12 19:26:23 +020089#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010090
willy tarreaubfad5742006-03-23 14:19:11 +010091#ifndef HAPROXY_VERSION
willy tarreauc0d4bbd2006-04-15 21:47:50 +020092#define HAPROXY_VERSION "1.2.12"
willy tarreaubfad5742006-03-23 14:19:11 +010093#endif
94
95#ifndef HAPROXY_DATE
willy tarreauc0d4bbd2006-04-15 21:47:50 +020096#define HAPROXY_DATE "2006/04/15"
willy tarreaubfad5742006-03-23 14:19:11 +010097#endif
willy tarreau0f7af912005-12-17 12:21:26 +010098
99/* this is for libc5 for example */
100#ifndef TCP_NODELAY
101#define TCP_NODELAY 1
102#endif
103
104#ifndef SHUT_RD
105#define SHUT_RD 0
106#endif
107
108#ifndef SHUT_WR
109#define SHUT_WR 1
110#endif
111
willy tarreau0174f312005-12-18 01:02:42 +0100112/*
113 * BUFSIZE defines the size of a read and write buffer. It is the maximum
114 * amount of bytes which can be stored by the proxy for each session. However,
115 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
116 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
117 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
118 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
119 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
120 */
121#ifndef BUFSIZE
122#define BUFSIZE 16384
123#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100124
125// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100126#ifndef MAXREWRITE
127#define MAXREWRITE (BUFSIZE / 2)
128#endif
129
willy tarreau9fe663a2005-12-17 13:02:59 +0100130#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100131#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100132
willy tarreau5cbea6f2005-12-17 12:48:26 +0100133// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100134#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135
willy tarreaue39cd132005-12-17 13:00:18 +0100136// max # of added headers per request
137#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100138
139// max # of matches per regexp
140#define MAX_MATCH 10
141
willy tarreau0174f312005-12-18 01:02:42 +0100142// cookie delimitor in "prefix" mode. This character is inserted between the
143// persistence cookie and the original value. The '~' is allowed by RFC2965,
144// and should not be too common in server names.
145#ifndef COOKIE_DELIM
146#define COOKIE_DELIM '~'
147#endif
148
willy tarreau0f7af912005-12-17 12:21:26 +0100149#define CONN_RETRIES 3
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100152#define DEF_CHKINTR 2000
153#define DEF_FALLTIME 3
154#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100155#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100156
Willy TARREAU13032e72006-03-12 17:31:45 +0100157/* Default connections limit.
158 *
159 * A system limit can be enforced at build time in order to avoid using haproxy
160 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
161 * absolute limit accepted by the system. If the configuration specifies a
162 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
163 * emitted. The only way to override this limit will be to set it via the
164 * command-line '-n' argument.
165 */
166#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100167#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100168#else
169#define DEFAULT_MAXCONN SYSTEM_MAXCONN
170#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100171
willy tarreau0f7af912005-12-17 12:21:26 +0100172/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
173#define INTBITS 5
174
175/* show stats this every millisecond, 0 to disable */
176#ifndef STATTIME
177#define STATTIME 2000
178#endif
179
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180/* this reduces the number of calls to select() by choosing appropriate
181 * sheduler precision in milliseconds. It should be near the minimum
182 * time that is needed by select() to collect all events. All timeouts
183 * are rounded up by adding this value prior to pass it to select().
184 */
185#define SCHEDULER_RESOLUTION 9
186
willy tarreaub952e1d2005-12-18 01:31:20 +0100187#define TIME_ETERNITY -1
188/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
190#define SETNOW(a) (*a=now)
191
willy tarreau9da061b2005-12-17 12:29:56 +0100192/****** string-specific macros and functions ******/
193/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
194#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
195
196/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
197#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
198
willy tarreau0174f312005-12-18 01:02:42 +0100199/* returns 1 only if only zero or one bit is set in X, which means that X is a
200 * power of 2, and 0 otherwise */
201#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100202/*
203 * copies at most <size-1> chars from <src> to <dst>. Last char is always
204 * set to 0, unless <size> is 0. The number of chars copied is returned
205 * (excluding the terminating zero).
206 * This code has been optimized for size and speed : on x86, it's 45 bytes
207 * long, uses only registers, and consumes only 4 cycles per char.
208 */
willy tarreau750a4722005-12-17 13:21:24 +0100209int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100210 char *orig = dst;
211 if (size) {
212 while (--size && (*dst = *src)) {
213 src++; dst++;
214 }
215 *dst = 0;
216 }
217 return dst - orig;
218}
willy tarreau9da061b2005-12-17 12:29:56 +0100219
willy tarreau4302f492005-12-18 01:00:37 +0100220/*
221 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
222 * dynamically allocated. In the first case, <__pool> is updated to point to
223 * the next element in the list.
224 */
225#define pool_alloc_from(__pool, __len) ({ \
226 void *__p; \
227 if ((__p = (__pool)) == NULL) \
228 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
229 else { \
230 __pool = *(void **)(__pool); \
231 } \
232 __p; \
233})
234
235/*
236 * Puts a memory area back to the corresponding pool.
237 * Items are chained directly through a pointer that
238 * is written in the beginning of the memory area, so
239 * there's no need for any carrier cell. This implies
240 * that each memory area is at least as big as one
241 * pointer.
242 */
243#define pool_free_to(__pool, __ptr) ({ \
244 *(void **)(__ptr) = (void *)(__pool); \
245 __pool = (void *)(__ptr); \
246})
247
248
willy tarreau0f7af912005-12-17 12:21:26 +0100249#define MEM_OPTIM
250#ifdef MEM_OPTIM
251/*
252 * Returns a pointer to type <type> taken from the
253 * pool <pool_type> or dynamically allocated. In the
254 * first case, <pool_type> is updated to point to the
255 * next element in the list.
256 */
257#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100258 void *__p; \
259 if ((__p = pool_##type) == NULL) \
260 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100261 else { \
262 pool_##type = *(void **)pool_##type; \
263 } \
willy tarreau4302f492005-12-18 01:00:37 +0100264 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100265})
266
267/*
268 * Puts a memory area back to the corresponding pool.
269 * Items are chained directly through a pointer that
270 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100271 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100272 * that each memory area is at least as big as one
273 * pointer.
274 */
275#define pool_free(type, ptr) ({ \
276 *(void **)ptr = (void *)pool_##type; \
277 pool_##type = (void *)ptr; \
278})
279
280#else
281#define pool_alloc(type) (calloc(1,sizeof_##type));
282#define pool_free(type, ptr) (free(ptr));
283#endif /* MEM_OPTIM */
284
willy tarreau5cbea6f2005-12-17 12:48:26 +0100285#define sizeof_task sizeof(struct task)
286#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200287#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100288#define sizeof_buffer sizeof(struct buffer)
289#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100290#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100291#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100292#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100293#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define FD_STCLOSE 0
297#define FD_STLISTEN 1
298#define FD_STCONN 2
299#define FD_STREADY 3
300#define FD_STERROR 4
301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define TASK_IDLE 0
304#define TASK_RUNNING 1
305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_STNEW 0
308#define PR_STIDLE 1
309#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100310#define PR_STSTOPPED 3
311#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100314#define PR_MODE_TCP 0
315#define PR_MODE_HTTP 1
316#define PR_MODE_HEALTH 2
317
willy tarreau1c2ad212005-12-18 01:11:29 +0100318/* possible actions for the *poll() loops */
319#define POLL_LOOP_ACTION_INIT 0
320#define POLL_LOOP_ACTION_RUN 1
321#define POLL_LOOP_ACTION_CLEAN 2
322
willy tarreau64a3cc32005-12-18 01:13:11 +0100323/* poll mechanisms available */
324#define POLL_USE_SELECT (1<<0)
325#define POLL_USE_POLL (1<<1)
326#define POLL_USE_EPOLL (1<<2)
327
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100329#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
330#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
331#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
332#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
333#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
334#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
335#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
336#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100337#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
338#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
339#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
340#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
341#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
342#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
343#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
344#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
345#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
346#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
347#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100348#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
349#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100350#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100351#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100352#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
353#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
willy tarreaua5e8c662006-04-29 10:43:46 +0200355/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100356#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
357#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
358#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
359#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
360#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
361#define SN_POST 0x00000020 /* the request was an HTTP POST */
362
willy tarreaua5e8c662006-04-29 10:43:46 +0200363/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_CK_NONE 0x00000000 /* this session had no cookie */
365#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
366#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
367#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
368#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
369#define SN_CK_SHIFT 6 /* bit shift */
370
willy tarreaua5e8c662006-04-29 10:43:46 +0200371/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100372#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100373#define SN_ERR_CLITO 0x00000100 /* client time-out */
374#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
375#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
376#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
377#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100378#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
379#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100380#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
381#define SN_ERR_SHIFT 8 /* bit shift */
382
willy tarreaua5e8c662006-04-29 10:43:46 +0200383/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_FINST_R 0x00001000 /* session ended during client request */
385#define SN_FINST_C 0x00002000 /* session ended during server connect */
386#define SN_FINST_H 0x00003000 /* session ended during server headers */
387#define SN_FINST_D 0x00004000 /* session ended during data phase */
388#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
389#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
390#define SN_FINST_SHIFT 12 /* bit shift */
391
willy tarreaua5e8c662006-04-29 10:43:46 +0200392/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
394#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
395#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
396#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
397#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100398#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100399#define SN_SCK_SHIFT 16 /* bit shift */
400
willy tarreaua5e8c662006-04-29 10:43:46 +0200401/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100402#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
403#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
404#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100405
willy tarreaua5e8c662006-04-29 10:43:46 +0200406/* various other session flags, bits values 0x400000 and above */
407#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200408#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
409#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaua5e8c662006-04-29 10:43:46 +0200410
411
willy tarreau5cbea6f2005-12-17 12:48:26 +0100412/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100413#define CL_STHEADERS 0
414#define CL_STDATA 1
415#define CL_STSHUTR 2
416#define CL_STSHUTW 3
417#define CL_STCLOSE 4
418
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100420#define SV_STIDLE 0
willy tarreau18a957c2006-04-12 19:26:23 +0200421#define SV_STCPEND 1
422#define SV_STCONN 2
423#define SV_STHEADERS 3
424#define SV_STDATA 4
425#define SV_STSHUTR 5
426#define SV_STSHUTW 6
427#define SV_STCLOSE 7
willy tarreau0f7af912005-12-17 12:21:26 +0100428
429/* result of an I/O event */
430#define RES_SILENT 0 /* didn't happen */
431#define RES_DATA 1 /* data were sent or received */
432#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
433#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
434
willy tarreau9fe663a2005-12-17 13:02:59 +0100435/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100436#define MODE_DEBUG 1
437#define MODE_STATS 2
438#define MODE_LOG 4
439#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100440#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100441#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100442#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100443#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100444#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100445
446/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100447#define SRV_RUNNING 1 /* the server is UP */
448#define SRV_BACKUP 2 /* this server is a backup server */
449#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100450#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100451#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100452
willy tarreaudfece232006-05-02 00:19:57 +0200453/* function which act on servers need to return various errors */
454#define SRV_STATUS_OK 0 /* everything is OK. */
455#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
456#define SRV_STATUS_NOSRV 2 /* no server is available */
457#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
458#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
459
willy tarreaue39cd132005-12-17 13:00:18 +0100460/* what to do when a header matches a regex */
461#define ACT_ALLOW 0 /* allow the request */
462#define ACT_REPLACE 1 /* replace the matching header */
463#define ACT_REMOVE 2 /* remove the matching header */
464#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100465#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100466
willy tarreau9fe663a2005-12-17 13:02:59 +0100467/* configuration sections */
468#define CFG_NONE 0
469#define CFG_GLOBAL 1
470#define CFG_LISTEN 2
471
willy tarreaua1598082005-12-17 13:08:06 +0100472/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100473#define LW_DATE 1 /* date */
474#define LW_CLIP 2 /* CLient IP */
475#define LW_SVIP 4 /* SerVer IP */
476#define LW_SVID 8 /* server ID */
477#define LW_REQ 16 /* http REQuest */
478#define LW_RESP 32 /* http RESPonse */
479#define LW_PXIP 64 /* proxy IP */
480#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100481#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100482#define LW_COOKIE 512 /* captured cookie */
483#define LW_REQHDR 1024 /* request header(s) */
484#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100485
willy tarreau41310e72006-03-25 18:17:56 +0100486#define ERR_NONE 0 /* no error */
487#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
488#define ERR_FATAL 2 /* fatal error, may be cumulated */
489
willy tarreau0f7af912005-12-17 12:21:26 +0100490/*********************************************************************/
491
492#define LIST_HEAD(a) ((void *)(&(a)))
493
494/*********************************************************************/
495
willy tarreau4302f492005-12-18 01:00:37 +0100496struct cap_hdr {
497 struct cap_hdr *next;
498 char *name; /* header name, case insensitive */
499 int namelen; /* length of the header name, to speed-up lookups */
500 int len; /* capture length, not including terminal zero */
501 int index; /* index in the output array */
502 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100506 struct hdr_exp *next;
507 regex_t *preg; /* expression to look for */
508 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
509 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100510};
511
512struct buffer {
513 unsigned int l; /* data length */
514 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100515 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100516 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 char data[BUFSIZE];
518};
519
willy tarreau18a957c2006-04-12 19:26:23 +0200520struct pendconn {
521 struct list list; /* chaining ... */
522 struct session *sess; /* the session waiting for a connection */
523 struct server *srv; /* the server we are waiting for */
524};
525
willy tarreau0f7af912005-12-17 12:21:26 +0100526struct server {
527 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int state; /* server state (SRV_*) */
529 int cklen; /* the len of the cookie, to speed up checks */
530 char *cookie; /* the id set in the cookie */
531 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200532 struct list pendconns; /* pending connections */
533 int nbpend; /* number of pending connections */
willy tarreau0f7af912005-12-17 12:21:26 +0100534 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100535 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100536 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100537 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100538 int rise, fall; /* time in iterations */
539 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100540 int result; /* 0 = connect OK, -1 = connect KO */
541 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200542 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200543 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200544 int cur_sess; /* number of currently active sessions (including syn_sent) */
545 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200546 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100547 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100548};
549
willy tarreau5cbea6f2005-12-17 12:48:26 +0100550/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100551struct task {
552 struct task *next, *prev; /* chaining ... */
553 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100554 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100555 int state; /* task state : IDLE or RUNNING */
556 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100557 int (*process)(struct task *t); /* the function which processes the task */
558 void *context; /* the task's context */
559};
560
561/* WARNING: if new fields are added, they must be initialized in event_accept() */
562struct session {
563 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 /* application specific below */
565 struct timeval crexpire; /* expiration date for a client read */
566 struct timeval cwexpire; /* expiration date for a client write */
567 struct timeval srexpire; /* expiration date for a server read */
568 struct timeval swexpire; /* expiration date for a server write */
569 struct timeval cnexpire; /* expiration date for a connect */
570 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
571 struct proxy *proxy; /* the proxy this socket belongs to */
572 int cli_fd; /* the client side fd */
573 int srv_fd; /* the server side fd */
574 int cli_state; /* state of the client side */
575 int srv_state; /* state of the server side */
576 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100577 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 struct buffer *req; /* request buffer */
579 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100580 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100582 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200583 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100584 char **req_cap; /* array of captured request headers (may be NULL) */
585 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100586 struct {
587 int logwait; /* log fields waiting to be collected : LW_* */
588 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
589 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
willy tarreauf32f5242006-05-02 22:54:52 +0200590 long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
willy tarreaua1598082005-12-17 13:08:06 +0100591 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
592 long t_data; /* delay before the first data byte from the server ... */
593 unsigned long t_close; /* total session duration */
willy tarreauf32f5242006-05-02 22:54:52 +0200594 unsigned long queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100595 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100596 char *cli_cookie; /* cookie presented by the client, in capture mode */
597 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100598 int status; /* HTTP status from the server, negative if from proxy */
599 long long bytes; /* number of bytes transferred from the server */
600 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100601 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100602};
603
willy tarreaua41a8b42005-12-17 14:02:24 +0100604struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100605 int fd; /* the listen socket */
606 struct sockaddr_storage addr; /* the address we listen to */
607 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100608};
willy tarreauf32f5242006-05-02 22:54:52 +0200609
willy tarreau0f7af912005-12-17 12:21:26 +0100610struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100611 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100612 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 +0100613 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100614 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200615 struct server *srv; /* known servers */
616 int srv_act, srv_bck; /* # of running servers */
617 int tot_wact, tot_wbck; /* total weights of active and backup servers */
618 struct server **srv_map; /* the server map used to apply weights */
619 int srv_map_sz; /* the size of the effective server map */
620 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100621 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100622 int cookie_len; /* strlen(cookie_name), computed only once */
623 char *appsession_name; /* name of the cookie to look for */
624 int appsession_name_len; /* strlen(appsession_name), computed only once */
625 int appsession_len; /* length of the appsession cookie value to be used */
626 int appsession_timeout;
627 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100628 char *capture_name; /* beginning of the name of the cookie to capture */
629 int capture_namelen; /* length of the cookie name to match */
630 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100631 int clitimeout; /* client I/O timeout (in milliseconds) */
632 int srvtimeout; /* server I/O timeout (in milliseconds) */
633 int contimeout; /* connect timeout (in milliseconds) */
634 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200635 struct list pendconns; /* pending connections with no server assigned yet */
636 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200637 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100638 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200639 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100640 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100641 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100642 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100643 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100644 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100645 struct proxy *next;
646 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100647 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100648 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100649 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100650 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100651 int nb_reqadd, nb_rspadd;
652 struct hdr_exp *req_exp; /* regular expressions for request headers */
653 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100654 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
655 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
656 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
657 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100658 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100659 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100660 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
661 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100662 struct {
663 char *msg400; /* message for error 400 */
664 int len400; /* message length for error 400 */
665 char *msg403; /* message for error 403 */
666 int len403; /* message length for error 403 */
667 char *msg408; /* message for error 408 */
668 int len408; /* message length for error 408 */
669 char *msg500; /* message for error 500 */
670 int len500; /* message length for error 500 */
671 char *msg502; /* message for error 502 */
672 int len502; /* message length for error 502 */
673 char *msg503; /* message for error 503 */
674 int len503; /* message length for error 503 */
675 char *msg504; /* message for error 504 */
676 int len504; /* message length for error 504 */
677 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100678};
679
680/* info about one given fd */
681struct fdtab {
682 int (*read)(int fd); /* read function */
683 int (*write)(int fd); /* write function */
684 struct task *owner; /* the session (or proxy) associated with this fd */
685 int state; /* the state of this fd */
686};
687
688/*********************************************************************/
689
willy tarreaub952e1d2005-12-18 01:31:20 +0100690int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100691int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100692char *cfg_cfgfile = NULL; /* configuration file */
693char *progname = NULL; /* program name */
694int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100695
696/* global options */
697static struct {
698 int uid;
699 int gid;
700 int nbproc;
701 int maxconn;
702 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100703 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100704 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100705 int mode;
706 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100707 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100708 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100709 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100710 struct sockaddr_in logsrv1, logsrv2;
711} global = {
712 logfac1 : -1,
713 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100714 loglev1 : 7, /* max syslog level : debug */
715 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100716 /* others NULL OK */
717};
718
willy tarreau0f7af912005-12-17 12:21:26 +0100719/*********************************************************************/
720
willy tarreau1c2ad212005-12-18 01:11:29 +0100721fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100722 *StaticWriteEvent;
723
willy tarreau64a3cc32005-12-18 01:13:11 +0100724int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100725
willy tarreau0f7af912005-12-17 12:21:26 +0100726void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200727 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100728 **pool_buffer = NULL,
729 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100730 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100731 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100732 **pool_capture = NULL,
733 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100734
735struct proxy *proxy = NULL; /* list of all existing proxies */
736struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100737struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200738struct task wait_queue[2] = { /* global wait queue */
739 {
740 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
741 next:LIST_HEAD(wait_queue[0]),
742 },
743 {
744 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
745 next:LIST_HEAD(wait_queue[1]),
746 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100747};
willy tarreau0f7af912005-12-17 12:21:26 +0100748
willy tarreau0f7af912005-12-17 12:21:26 +0100749static int totalconn = 0; /* total # of terminated sessions */
750static int actconn = 0; /* # of active sessions */
751static int maxfd = 0; /* # of the highest fd + 1 */
752static int listeners = 0; /* # of listeners */
753static int stopping = 0; /* non zero means stopping in progress */
754static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100755static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100756
willy tarreau53e99702006-03-25 18:53:50 +0100757/* Here we store informations about the pids of the processes we may pause
758 * or kill. We will send them a signal every 10 ms until we can bind to all
759 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100760 */
willy tarreau53e99702006-03-25 18:53:50 +0100761#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100762static int nb_oldpids = 0;
763static int *oldpids = NULL;
764static int oldpids_sig; /* use USR1 or TERM */
765
willy tarreau08dedbe2005-12-18 01:13:48 +0100766#if defined(ENABLE_EPOLL)
767/* FIXME: this is dirty, but at the moment, there's no other solution to remove
768 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
769 * structure with pointers to functions such as init_fd() and close_fd(), plus
770 * a private structure with several pointers to places such as below.
771 */
772
773static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
774#endif
775
willy tarreau0f7af912005-12-17 12:21:26 +0100776static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100777/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100778static char trash[BUFSIZE];
779
willy tarreaudd07e972005-12-18 00:48:48 +0100780const int zero = 0;
781const int one = 1;
782
willy tarreau0f7af912005-12-17 12:21:26 +0100783/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100784 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100785 */
786
787#define MAX_SYSLOG_LEN 1024
788#define NB_LOG_FACILITIES 24
789const char *log_facilities[NB_LOG_FACILITIES] = {
790 "kern", "user", "mail", "daemon",
791 "auth", "syslog", "lpr", "news",
792 "uucp", "cron", "auth2", "ftp",
793 "ntp", "audit", "alert", "cron2",
794 "local0", "local1", "local2", "local3",
795 "local4", "local5", "local6", "local7"
796};
797
798
799#define NB_LOG_LEVELS 8
800const char *log_levels[NB_LOG_LEVELS] = {
801 "emerg", "alert", "crit", "err",
802 "warning", "notice", "info", "debug"
803};
804
805#define SYSLOG_PORT 514
806
807const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
808 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100809
willy tarreaub1285d52005-12-18 01:20:14 +0100810const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100811const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
812const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
813const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
814 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
815 unknown, Set-cookie Rewritten */
816
willy tarreau0f7af912005-12-17 12:21:26 +0100817#define MAX_HOSTNAME_LEN 32
818static char hostname[MAX_HOSTNAME_LEN] = "";
819
willy tarreau8337c6b2005-12-17 13:41:01 +0100820const char *HTTP_302 =
821 "HTTP/1.0 302 Found\r\n"
822 "Cache-Control: no-cache\r\n"
823 "Connection: close\r\n"
824 "Location: "; /* not terminated since it will be concatenated with the URL */
825
willy tarreauc1f47532005-12-18 01:08:26 +0100826/* same as 302 except that the browser MUST retry with the GET method */
827const char *HTTP_303 =
828 "HTTP/1.0 303 See Other\r\n"
829 "Cache-Control: no-cache\r\n"
830 "Connection: close\r\n"
831 "Location: "; /* not terminated since it will be concatenated with the URL */
832
willy tarreaua1598082005-12-17 13:08:06 +0100833const char *HTTP_400 =
834 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100835 "Cache-Control: no-cache\r\n"
836 "Connection: close\r\n"
837 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100838 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100839
willy tarreaua1598082005-12-17 13:08:06 +0100840const char *HTTP_403 =
841 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100842 "Cache-Control: no-cache\r\n"
843 "Connection: close\r\n"
844 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100845 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
846
willy tarreau8337c6b2005-12-17 13:41:01 +0100847const char *HTTP_408 =
848 "HTTP/1.0 408 Request Time-out\r\n"
849 "Cache-Control: no-cache\r\n"
850 "Connection: close\r\n"
851 "\r\n"
852 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
853
willy tarreau750a4722005-12-17 13:21:24 +0100854const char *HTTP_500 =
855 "HTTP/1.0 500 Server Error\r\n"
856 "Cache-Control: no-cache\r\n"
857 "Connection: close\r\n"
858 "\r\n"
859 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100860
861const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100862 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100863 "Cache-Control: no-cache\r\n"
864 "Connection: close\r\n"
865 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100866 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
867
868const char *HTTP_503 =
869 "HTTP/1.0 503 Service Unavailable\r\n"
870 "Cache-Control: no-cache\r\n"
871 "Connection: close\r\n"
872 "\r\n"
873 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
874
875const char *HTTP_504 =
876 "HTTP/1.0 504 Gateway Time-out\r\n"
877 "Cache-Control: no-cache\r\n"
878 "Connection: close\r\n"
879 "\r\n"
880 "<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 +0100881
willy tarreau0f7af912005-12-17 12:21:26 +0100882/*********************************************************************/
883/* statistics ******************************************************/
884/*********************************************************************/
885
willy tarreau750a4722005-12-17 13:21:24 +0100886#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100887static int stats_tsk_lsrch, stats_tsk_rsrch,
888 stats_tsk_good, stats_tsk_right, stats_tsk_left,
889 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100890#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100891
892
893/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100894/* debugging *******************************************************/
895/*********************************************************************/
896#ifdef DEBUG_FULL
897static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200898static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100899#endif
900
901/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100902/* function prototypes *********************************************/
903/*********************************************************************/
904
905int event_accept(int fd);
906int event_cli_read(int fd);
907int event_cli_write(int fd);
908int event_srv_read(int fd);
909int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100910int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100911
willy tarreau12350152005-12-18 01:03:27 +0100912static int appsession_task_init(void);
913static int appsession_init(void);
914static int appsession_refresh(struct task *t);
915
willy tarreau0f7af912005-12-17 12:21:26 +0100916/*********************************************************************/
917/* general purpose functions ***************************************/
918/*********************************************************************/
919
920void display_version() {
921 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100922 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100923}
924
925/*
926 * This function prints the command line usage and exits
927 */
928void usage(char *name) {
929 display_version();
930 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100931 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100932#if STATTIME > 0
933 "sl"
934#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100935 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
936 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100937 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100938 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100939 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100940#if STATTIME > 0
941 " -s enables statistics output\n"
942 " -l enables long statistics format\n"
943#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100944 " -D goes daemon ; implies -q\n"
945 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100946 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100947 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100948 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100949 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100950 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100951#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100952 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100953#endif
954#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100955 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100956#endif
willy tarreau53e99702006-03-25 18:53:50 +0100957 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100958 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100959 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100960 exit(1);
961}
962
963
964/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100965 * Displays the message on stderr with the date and pid. Overrides the quiet
966 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100967 */
968void Alert(char *fmt, ...) {
969 va_list argp;
970 struct timeval tv;
971 struct tm *tm;
972
willy tarreaud0fb4652005-12-18 01:32:04 +0100973 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100974 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100975
willy tarreau5cbea6f2005-12-17 12:48:26 +0100976 gettimeofday(&tv, NULL);
977 tm=localtime(&tv.tv_sec);
978 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100979 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100980 vfprintf(stderr, fmt, argp);
981 fflush(stderr);
982 va_end(argp);
983 }
willy tarreau0f7af912005-12-17 12:21:26 +0100984}
985
986
987/*
988 * Displays the message on stderr with the date and pid.
989 */
990void Warning(char *fmt, ...) {
991 va_list argp;
992 struct timeval tv;
993 struct tm *tm;
994
willy tarreau982249e2005-12-18 00:57:06 +0100995 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100996 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100997
willy tarreau5cbea6f2005-12-17 12:48:26 +0100998 gettimeofday(&tv, NULL);
999 tm=localtime(&tv.tv_sec);
1000 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001001 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001002 vfprintf(stderr, fmt, argp);
1003 fflush(stderr);
1004 va_end(argp);
1005 }
1006}
1007
1008/*
1009 * Displays the message on <out> only if quiet mode is not set.
1010 */
1011void qfprintf(FILE *out, char *fmt, ...) {
1012 va_list argp;
1013
willy tarreau982249e2005-12-18 00:57:06 +01001014 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001015 va_start(argp, fmt);
1016 vfprintf(out, fmt, argp);
1017 fflush(out);
1018 va_end(argp);
1019 }
willy tarreau0f7af912005-12-17 12:21:26 +01001020}
1021
1022
1023/*
1024 * converts <str> to a struct sockaddr_in* which is locally allocated.
1025 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1026 * INADDR_ANY.
1027 */
1028struct sockaddr_in *str2sa(char *str) {
1029 static struct sockaddr_in sa;
1030 char *c;
1031 int port;
1032
willy tarreaua1598082005-12-17 13:08:06 +01001033 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001034 str=strdup(str);
1035
1036 if ((c=strrchr(str,':')) != NULL) {
1037 *c++=0;
1038 port=atol(c);
1039 }
1040 else
1041 port=0;
1042
1043 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1044 sa.sin_addr.s_addr = INADDR_ANY;
1045 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001046 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001047 struct hostent *he;
1048
1049 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001050 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001051 }
1052 else
1053 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1054 }
1055 sa.sin_port=htons(port);
1056 sa.sin_family=AF_INET;
1057
1058 free(str);
1059 return &sa;
1060}
1061
willy tarreaub1285d52005-12-18 01:20:14 +01001062/*
1063 * converts <str> to a two struct in_addr* which are locally allocated.
1064 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1065 * is optionnal and either in the dotted or CIDR notation.
1066 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1067 */
1068int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1069 char *c;
1070 unsigned long len;
1071
1072 memset(mask, 0, sizeof(*mask));
1073 memset(addr, 0, sizeof(*addr));
1074 str=strdup(str);
1075
1076 if ((c = strrchr(str, '/')) != NULL) {
1077 *c++ = 0;
1078 /* c points to the mask */
1079 if (strchr(c, '.') != NULL) { /* dotted notation */
1080 if (!inet_pton(AF_INET, c, mask))
1081 return 0;
1082 }
1083 else { /* mask length */
1084 char *err;
1085 len = strtol(c, &err, 10);
1086 if (!*c || (err && *err) || (unsigned)len > 32)
1087 return 0;
1088 if (len)
1089 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1090 else
1091 mask->s_addr = 0;
1092 }
1093 }
1094 else {
1095 mask->s_addr = 0xFFFFFFFF;
1096 }
1097 if (!inet_pton(AF_INET, str, addr)) {
1098 struct hostent *he;
1099
1100 if ((he = gethostbyname(str)) == NULL) {
1101 return 0;
1102 }
1103 else
1104 *addr = *(struct in_addr *) *(he->h_addr_list);
1105 }
1106 free(str);
1107 return 1;
1108}
1109
willy tarreau9fe663a2005-12-17 13:02:59 +01001110
1111/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001112 * converts <str> to a list of listeners which are dynamically allocated.
1113 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1114 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1115 * - <port> is a numerical port from 1 to 65535 ;
1116 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1117 * This can be repeated as many times as necessary, separated by a coma.
1118 * The <tail> argument is a pointer to a current list which should be appended
1119 * to the tail of the new list. The pointer to the new list is returned.
1120 */
1121struct listener *str2listener(char *str, struct listener *tail) {
1122 struct listener *l;
1123 char *c, *next, *range, *dupstr;
1124 int port, end;
1125
1126 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001127
willy tarreaua41a8b42005-12-17 14:02:24 +01001128 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001129 struct sockaddr_storage ss;
1130
willy tarreaua41a8b42005-12-17 14:02:24 +01001131 str = next;
1132 /* 1) look for the end of the first address */
1133 if ((next = strrchr(str, ',')) != NULL) {
1134 *next++ = 0;
1135 }
1136
willy tarreau8a86dbf2005-12-18 00:45:59 +01001137 /* 2) look for the addr/port delimiter, it's the last colon. */
1138 if ((range = strrchr(str, ':')) == NULL) {
1139 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001140 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001141 }
1142
1143 *range++ = 0;
1144
1145 if (strrchr(str, ':') != NULL) {
1146 /* IPv6 address contains ':' */
1147 memset(&ss, 0, sizeof(ss));
1148 ss.ss_family = AF_INET6;
1149
1150 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1151 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001152 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001153 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001154 }
1155 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001156 memset(&ss, 0, sizeof(ss));
1157 ss.ss_family = AF_INET;
1158
1159 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1160 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1161 }
1162 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1163 struct hostent *he;
1164
1165 if ((he = gethostbyname(str)) == NULL) {
1166 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001167 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001168 }
1169 else
1170 ((struct sockaddr_in *)&ss)->sin_addr =
1171 *(struct in_addr *) *(he->h_addr_list);
1172 }
1173 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001174
1175 /* 3) look for the port-end delimiter */
1176 if ((c = strchr(range, '-')) != NULL) {
1177 *c++ = 0;
1178 end = atol(c);
1179 }
1180 else {
1181 end = atol(range);
1182 }
1183
willy tarreaud0fb4652005-12-18 01:32:04 +01001184 port = atol(range);
1185
1186 if (port < 1 || port > 65535) {
1187 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1188 goto fail;
1189 }
1190
1191 if (end < 1 || end > 65535) {
1192 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1193 goto fail;
1194 }
1195
1196 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001197 l = (struct listener *)calloc(1, sizeof(struct listener));
1198 l->next = tail;
1199 tail = l;
1200
willy tarreau41310e72006-03-25 18:17:56 +01001201 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001202 l->addr = ss;
1203 if (ss.ss_family == AF_INET6)
1204 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1205 else
1206 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1207
willy tarreaua41a8b42005-12-17 14:02:24 +01001208 } /* end for(port) */
1209 } /* end while(next) */
1210 free(dupstr);
1211 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 fail:
1213 free(dupstr);
1214 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001215}
1216
willy tarreau4302f492005-12-18 01:00:37 +01001217
1218#define FD_SETS_ARE_BITFIELDS
1219#ifdef FD_SETS_ARE_BITFIELDS
1220/*
1221 * This map is used with all the FD_* macros to check whether a particular bit
1222 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1223 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1224 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1225 * exclusively to the macros.
1226 */
1227fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1228fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1229
1230#else
1231#error "Check if your OS uses bitfields for fd_sets"
1232#endif
1233
1234/* will try to encode the string <string> replacing all characters tagged in
1235 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1236 * prefixed by <escape>, and will store the result between <start> (included
1237 *) and <stop> (excluded), and will always terminate the string with a '\0'
1238 * before <stop>. The position of the '\0' is returned if the conversion
1239 * completes. If bytes are missing between <start> and <stop>, then the
1240 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1241 * cannot even be stored so we return <start> without writing the 0.
1242 * The input string must also be zero-terminated.
1243 */
1244char hextab[16] = "0123456789ABCDEF";
1245char *encode_string(char *start, char *stop,
1246 const char escape, const fd_set *map,
1247 const char *string)
1248{
1249 if (start < stop) {
1250 stop--; /* reserve one byte for the final '\0' */
1251 while (start < stop && *string != 0) {
1252 if (!FD_ISSET((unsigned char)(*string), map))
1253 *start++ = *string;
1254 else {
1255 if (start + 3 >= stop)
1256 break;
1257 *start++ = escape;
1258 *start++ = hextab[(*string >> 4) & 15];
1259 *start++ = hextab[*string & 15];
1260 }
1261 string++;
1262 }
1263 *start = '\0';
1264 }
1265 return start;
1266}
willy tarreaua41a8b42005-12-17 14:02:24 +01001267
1268/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001269 * This function sends a syslog message to both log servers of a proxy,
1270 * or to global log servers if the proxy is NULL.
1271 * It also tries not to waste too much time computing the message header.
1272 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 */
1274void send_log(struct proxy *p, int level, char *message, ...) {
1275 static int logfd = -1; /* syslog UDP socket */
1276 static long tvsec = -1; /* to force the string to be initialized */
1277 struct timeval tv;
1278 va_list argp;
1279 static char logmsg[MAX_SYSLOG_LEN];
1280 static char *dataptr = NULL;
1281 int fac_level;
1282 int hdr_len, data_len;
1283 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001284 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 int nbloggers = 0;
1286 char *log_ptr;
1287
1288 if (logfd < 0) {
1289 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1290 return;
1291 }
1292
1293 if (level < 0 || progname == NULL || message == NULL)
1294 return;
1295
1296 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001297 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001298 /* this string is rebuild only once a second */
1299 struct tm *tm = localtime(&tv.tv_sec);
1300 tvsec = tv.tv_sec;
1301
willy tarreauc29948c2005-12-17 13:10:27 +01001302 hdr_len = snprintf(logmsg, sizeof(logmsg),
1303 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1304 monthname[tm->tm_mon],
1305 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1306 progname, pid);
1307 /* WARNING: depending upon implementations, snprintf may return
1308 * either -1 or the number of bytes that would be needed to store
1309 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001310 */
willy tarreauc29948c2005-12-17 13:10:27 +01001311 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1312 hdr_len = sizeof(logmsg);
1313
1314 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001315 }
1316
1317 va_start(argp, message);
1318 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001319 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1320 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001321 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001322 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001323
1324 if (p == NULL) {
1325 if (global.logfac1 >= 0) {
1326 sa[nbloggers] = &global.logsrv1;
1327 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001328 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001329 nbloggers++;
1330 }
1331 if (global.logfac2 >= 0) {
1332 sa[nbloggers] = &global.logsrv2;
1333 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001334 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001335 nbloggers++;
1336 }
1337 } else {
1338 if (p->logfac1 >= 0) {
1339 sa[nbloggers] = &p->logsrv1;
1340 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001341 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001342 nbloggers++;
1343 }
1344 if (p->logfac2 >= 0) {
1345 sa[nbloggers] = &p->logsrv2;
1346 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001347 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001348 nbloggers++;
1349 }
1350 }
1351
1352 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001353 /* we can filter the level of the messages that are sent to each logger */
1354 if (level > loglevel[nbloggers])
1355 continue;
1356
willy tarreauc29948c2005-12-17 13:10:27 +01001357 /* For each target, we may have a different facility.
1358 * We can also have a different log level for each message.
1359 * This induces variations in the message header length.
1360 * Since we don't want to recompute it each time, nor copy it every
1361 * time, we only change the facility in the pre-computed header,
1362 * and we change the pointer to the header accordingly.
1363 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001364 fac_level = (facilities[nbloggers] << 3) + level;
1365 log_ptr = logmsg + 3; /* last digit of the log level */
1366 do {
1367 *log_ptr = '0' + fac_level % 10;
1368 fac_level /= 10;
1369 log_ptr--;
1370 } while (fac_level && log_ptr > logmsg);
1371 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001372
willy tarreauc29948c2005-12-17 13:10:27 +01001373 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001374
1375#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001376 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001377 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1378#else
willy tarreauc29948c2005-12-17 13:10:27 +01001379 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001380 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1381#endif
1382 }
willy tarreau0f7af912005-12-17 12:21:26 +01001383}
1384
1385
1386/* sets <tv> to the current time */
1387static inline struct timeval *tv_now(struct timeval *tv) {
1388 if (tv)
1389 gettimeofday(tv, NULL);
1390 return tv;
1391}
1392
1393/*
1394 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1395 */
1396static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1397 if (!tv || !from)
1398 return NULL;
1399 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1400 tv->tv_sec = from->tv_sec + (ms/1000);
1401 while (tv->tv_usec >= 1000000) {
1402 tv->tv_usec -= 1000000;
1403 tv->tv_sec++;
1404 }
1405 return tv;
1406}
1407
1408/*
1409 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001410 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001411 */
1412static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001413 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001414 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001415 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001416 return 1;
1417 else if (tv1->tv_usec < tv2->tv_usec)
1418 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001419 else if (tv1->tv_usec > tv2->tv_usec)
1420 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001421 else
1422 return 0;
1423}
1424
1425/*
1426 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001427 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001428 */
1429unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1430 int cmp;
1431 unsigned long ret;
1432
1433
willy tarreauef900ab2005-12-17 12:52:52 +01001434 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001435 if (!cmp)
1436 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001437 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001438 struct timeval *tmp = tv1;
1439 tv1 = tv2;
1440 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001441 }
willy tarreauef900ab2005-12-17 12:52:52 +01001442 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001444 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 else
willy tarreauef900ab2005-12-17 12:52:52 +01001446 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001447 return (unsigned long) ret;
1448}
1449
1450/*
willy tarreau750a4722005-12-17 13:21:24 +01001451 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001452 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001453 */
1454static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1455 unsigned long ret;
1456
willy tarreau6e682ce2005-12-17 13:26:49 +01001457 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1458 if (tv2->tv_usec > tv1->tv_usec)
1459 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001460 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001461 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001462 return (unsigned long) ret;
1463}
1464
1465/*
willy tarreau0f7af912005-12-17 12:21:26 +01001466 * 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 +01001467 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001468 */
1469static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001470 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001471 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001472 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001473 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001474 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001475 else
1476 return 0;
1477 }
willy tarreau0f7af912005-12-17 12:21:26 +01001478 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001479 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001480 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001481 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001482 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001483 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001484 else
1485 return 0;
1486}
1487
1488/*
1489 * returns the remaining time between tv1=now and event=tv2
1490 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001491 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001492 */
1493static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1494 unsigned long ret;
1495
willy tarreau0f7af912005-12-17 12:21:26 +01001496 if (tv_cmp_ms(tv1, tv2) >= 0)
1497 return 0; /* event elapsed */
1498
willy tarreauef900ab2005-12-17 12:52:52 +01001499 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001500 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001501 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 else
willy tarreauef900ab2005-12-17 12:52:52 +01001503 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001504 return (unsigned long) ret;
1505}
1506
1507
1508/*
1509 * zeroes a struct timeval
1510 */
1511
1512static inline struct timeval *tv_eternity(struct timeval *tv) {
1513 tv->tv_sec = tv->tv_usec = 0;
1514 return tv;
1515}
1516
1517/*
1518 * returns 1 if tv is null, else 0
1519 */
1520static inline int tv_iseternity(struct timeval *tv) {
1521 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1522 return 1;
1523 else
1524 return 0;
1525}
1526
1527/*
1528 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1529 * considering that 0 is the eternity.
1530 */
1531static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1532 if (tv_iseternity(tv1))
1533 if (tv_iseternity(tv2))
1534 return 0; /* same */
1535 else
1536 return 1; /* tv1 later than tv2 */
1537 else if (tv_iseternity(tv2))
1538 return -1; /* tv2 later than tv1 */
1539
1540 if (tv1->tv_sec > tv2->tv_sec)
1541 return 1;
1542 else if (tv1->tv_sec < tv2->tv_sec)
1543 return -1;
1544 else if (tv1->tv_usec > tv2->tv_usec)
1545 return 1;
1546 else if (tv1->tv_usec < tv2->tv_usec)
1547 return -1;
1548 else
1549 return 0;
1550}
1551
1552/*
1553 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1554 * considering that 0 is the eternity.
1555 */
1556static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1557 if (tv_iseternity(tv1))
1558 if (tv_iseternity(tv2))
1559 return 0; /* same */
1560 else
1561 return 1; /* tv1 later than tv2 */
1562 else if (tv_iseternity(tv2))
1563 return -1; /* tv2 later than tv1 */
1564
willy tarreauefae1842005-12-17 12:51:03 +01001565 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001566 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001567 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001568 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001569 return -1;
1570 else
1571 return 0;
1572 }
1573 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001574 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001575 return 1;
1576 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001577 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001578 return -1;
1579 else
1580 return 0;
1581}
1582
1583/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001584 * returns the remaining time between tv1=now and event=tv2
1585 * if tv2 is passed, 0 is returned.
1586 * Returns TIME_ETERNITY if tv2 is eternity.
1587 */
1588static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1589 unsigned long ret;
1590
1591 if (tv_iseternity(tv2))
1592 return TIME_ETERNITY;
1593
1594 if (tv_cmp_ms(tv1, tv2) >= 0)
1595 return 0; /* event elapsed */
1596
1597 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1598 if (tv2->tv_usec > tv1->tv_usec)
1599 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1600 else
1601 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1602 return (unsigned long) ret;
1603}
1604
1605/*
willy tarreau0f7af912005-12-17 12:21:26 +01001606 * returns the first event between tv1 and tv2 into tvmin.
1607 * a zero tv is ignored. tvmin is returned.
1608 */
1609static inline struct timeval *tv_min(struct timeval *tvmin,
1610 struct timeval *tv1, struct timeval *tv2) {
1611
1612 if (tv_cmp2(tv1, tv2) <= 0)
1613 *tvmin = *tv1;
1614 else
1615 *tvmin = *tv2;
1616
1617 return tvmin;
1618}
1619
1620
1621
1622/***********************************************************/
1623/* fd management ***************************************/
1624/***********************************************************/
1625
1626
1627
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1629 * The file descriptor is also closed.
1630 */
willy tarreau0f7af912005-12-17 12:21:26 +01001631static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001632 FD_CLR(fd, StaticReadEvent);
1633 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001634#if defined(ENABLE_EPOLL)
1635 if (PrevReadEvent) {
1636 FD_CLR(fd, PrevReadEvent);
1637 FD_CLR(fd, PrevWriteEvent);
1638 }
1639#endif
1640
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641 close(fd);
1642 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001643
1644 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1645 maxfd--;
1646}
1647
1648/* recomputes the maxfd limit from the fd */
1649static inline void fd_insert(int fd) {
1650 if (fd+1 > maxfd)
1651 maxfd = fd+1;
1652}
1653
1654/*************************************************************/
1655/* task management ***************************************/
1656/*************************************************************/
1657
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658/* puts the task <t> in run queue <q>, and returns <t> */
1659static inline struct task *task_wakeup(struct task **q, struct task *t) {
1660 if (t->state == TASK_RUNNING)
1661 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001662 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001663 t->rqnext = *q;
1664 t->state = TASK_RUNNING;
1665 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001666 }
1667}
1668
willy tarreau5cbea6f2005-12-17 12:48:26 +01001669/* removes the task <t> from the queue <q>
1670 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001671 * set the run queue to point to the next one, and return it
1672 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001673static inline struct task *task_sleep(struct task **q, struct task *t) {
1674 if (t->state == TASK_RUNNING) {
1675 *q = t->rqnext;
1676 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001677 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001678 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001679}
1680
1681/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001682 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001683 * from the run queue. A pointer to the task itself is returned.
1684 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685static inline struct task *task_delete(struct task *t) {
1686 t->prev->next = t->next;
1687 t->next->prev = t->prev;
1688 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001689}
1690
1691/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001692 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001693 */
1694static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001696}
1697
willy tarreau5cbea6f2005-12-17 12:48:26 +01001698/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001699 * may be only moved or left where it was, depending on its timing requirements.
1700 * <task> is returned.
1701 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001702struct task *task_queue(struct task *task) {
1703 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001704 struct task *start_from;
1705
willy tarreau5e698ef2006-05-02 14:51:00 +02001706 /* This is a very dirty hack to queue non-expirable tasks in another queue
1707 * in order to avoid pulluting the tail of the standard queue. This will go
1708 * away with the new O(log(n)) scheduler anyway.
1709 */
1710 if (tv_iseternity(&task->expire)) {
1711 /* if the task was queued in the standard wait queue, we must dequeue it */
1712 if (task->prev) {
1713 if (task->wq == LIST_HEAD(wait_queue[1]))
1714 return task;
1715 else {
1716 task_delete(task);
1717 task->prev = NULL;
1718 }
1719 }
1720 list = task->wq = LIST_HEAD(wait_queue[1]);
1721 } else {
1722 /* if the task was queued in the eternity queue, we must dequeue it */
1723 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1724 task_delete(task);
1725 task->prev = NULL;
1726 list = task->wq = LIST_HEAD(wait_queue[0]);
1727 }
1728 }
1729
1730 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001731 if (task->prev == NULL) {
1732 // start_from = list;
1733 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001734#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001735 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001737 /* insert the unlinked <task> into the list, searching back from the last entry */
1738 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1739 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001740#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001741 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001742#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001743 }
1744
1745 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1746 // start_from = start_from->next;
1747 // stats_tsk_nsrch++;
1748 // }
1749 }
1750 else if (task->prev == list ||
1751 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1752 start_from = task->next;
1753 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001754#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001755 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001756#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001757 return task; /* it's already in the right place */
1758 }
1759
willy tarreau750a4722005-12-17 13:21:24 +01001760#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001761 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001762#endif
1763
1764 /* if the task is not at the right place, there's little chance that
1765 * it has only shifted a bit, and it will nearly always be queued
1766 * at the end of the list because of constant timeouts
1767 * (observed in real case).
1768 */
1769#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1770 start_from = list->prev; /* assume we'll queue to the end of the list */
1771 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1772 start_from = start_from->prev;
1773#if STATTIME > 0
1774 stats_tsk_lsrch++;
1775#endif
1776 }
1777#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001778 /* insert the unlinked <task> into the list, searching after position <start_from> */
1779 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1780 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001781#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001782 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001783#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001784 }
willy tarreau750a4722005-12-17 13:21:24 +01001785#endif /* WE_REALLY_... */
1786
willy tarreau0f7af912005-12-17 12:21:26 +01001787 /* we need to unlink it now */
1788 task_delete(task);
1789 }
1790 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001791#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001792 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001793#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001794#ifdef LEFT_TO_TOP /* not very good */
1795 start_from = list;
1796 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1797 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001798#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001799 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001800#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001801 }
1802#else
1803 start_from = task->prev->prev; /* valid because of the previous test above */
1804 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1805 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001806#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001807 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001808#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001809 }
1810#endif
1811 /* we need to unlink it now */
1812 task_delete(task);
1813 }
1814 task->prev = start_from;
1815 task->next = start_from->next;
1816 task->next->prev = task;
1817 start_from->next = task;
1818 return task;
1819}
1820
1821
1822/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001823/* pending connections queues **************************************/
1824/*********************************************************************/
1825
1826/*
willy tarreaudfece232006-05-02 00:19:57 +02001827 * Detaches pending connection <p>, decreases the pending count, and frees
1828 * the pending connection. The connection might have been queued to a specific
1829 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001830 */
willy tarreaudfece232006-05-02 00:19:57 +02001831static void pendconn_free(struct pendconn *p) {
1832 LIST_DEL(&p->list);
1833 p->sess->pend_pos = NULL;
1834 if (p->srv)
1835 p->srv->nbpend--;
1836 else
1837 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001838 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001839 pool_free(pendconn, p);
1840}
1841
1842/* Returns the first pending connection for server <s>, which may be NULL if
1843 * nothing is pending.
1844 */
1845static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001846 if (!s->nbpend)
1847 return NULL;
1848
1849 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1850}
1851
willy tarreaudfece232006-05-02 00:19:57 +02001852/* Returns the first pending connection for proxy <px>, which may be NULL if
1853 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001854 */
willy tarreaudfece232006-05-02 00:19:57 +02001855static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1856 if (!px->nbpend)
1857 return NULL;
1858
1859 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001860}
1861
willy tarreaubc2eda62006-05-04 15:16:23 +02001862/* Detaches the next pending connection from either a server or a proxy, and
1863 * returns its associated session. If no pending connection is found, NULL is
1864 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001865 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001866static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001867 struct pendconn *p;
1868 struct session *sess;
1869
willy tarreaubc2eda62006-05-04 15:16:23 +02001870 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001871 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001872 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001873 if (!p)
1874 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001875 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001876 }
willy tarreau18a957c2006-04-12 19:26:23 +02001877 sess = p->sess;
1878 pendconn_free(p);
1879 return sess;
1880}
1881
willy tarreaubc2eda62006-05-04 15:16:23 +02001882/* Checks if other sessions are waiting for a known server, and wakes the
1883 * first one up. Note that neither <srv> nor <px> can be NULL. Returns 1
1884 * if a session has been assigned, 0 if nothing has been done.
willy tarreaudfece232006-05-02 00:19:57 +02001885 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001886static int offer_connection_slot(struct server *srv, struct proxy *px) {
willy tarreaudfece232006-05-02 00:19:57 +02001887 struct session *sess;
1888
willy tarreaubc2eda62006-05-04 15:16:23 +02001889 sess = pendconn_get_next_sess(srv, px);
willy tarreaudfece232006-05-02 00:19:57 +02001890 if (sess == NULL)
willy tarreaubc2eda62006-05-04 15:16:23 +02001891 return 0;
willy tarreaudfece232006-05-02 00:19:57 +02001892 task_wakeup(&rq, sess->task);
willy tarreaubc2eda62006-05-04 15:16:23 +02001893 return 1;
willy tarreaudfece232006-05-02 00:19:57 +02001894}
1895
1896/* Adds the session <sess> to the pending connection list of server <sess>->srv
1897 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1898 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1899 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001900 */
willy tarreaudfece232006-05-02 00:19:57 +02001901static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001902 struct pendconn *p;
1903
1904 p = pool_alloc(pendconn);
1905 if (!p)
1906 return NULL;
1907
willy tarreau18a957c2006-04-12 19:26:23 +02001908 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001909 p->sess = sess;
1910 p->srv = sess->srv;
1911 if (sess->srv) {
1912 LIST_ADDQ(&sess->srv->pendconns, &p->list);
1913 sess->srv->nbpend++;
1914 } else {
1915 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
1916 sess->proxy->nbpend++;
1917 }
willy tarreauf32f5242006-05-02 22:54:52 +02001918 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001919 return p;
1920}
1921
1922/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001923/* more specific functions ***************************************/
1924/*********************************************************************/
1925
1926/* some prototypes */
1927static int maintain_proxies(void);
1928
willy tarreaub952e1d2005-12-18 01:31:20 +01001929/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1931 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001932static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001933#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1935#else
willy tarreaua1598082005-12-17 13:08:06 +01001936#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001937 return getsockname(fd, (struct sockaddr *)sa, salen);
1938#else
1939 return -1;
1940#endif
1941#endif
1942}
1943
1944/*
1945 * frees the context associated to a session. It must have been removed first.
1946 */
willy tarreaudfece232006-05-02 00:19:57 +02001947static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001948 if (s->pend_pos)
1949 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001950 if (s->req)
1951 pool_free(buffer, s->req);
1952 if (s->rep)
1953 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001954
1955 if (s->rsp_cap != NULL) {
1956 struct cap_hdr *h;
1957 for (h = s->proxy->rsp_cap; h; h = h->next) {
1958 if (s->rsp_cap[h->index] != NULL)
1959 pool_free_to(h->pool, s->rsp_cap[h->index]);
1960 }
1961 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1962 }
1963 if (s->req_cap != NULL) {
1964 struct cap_hdr *h;
1965 for (h = s->proxy->req_cap; h; h = h->next) {
1966 if (s->req_cap[h->index] != NULL)
1967 pool_free_to(h->pool, s->req_cap[h->index]);
1968 }
1969 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1970 }
1971
willy tarreaua1598082005-12-17 13:08:06 +01001972 if (s->logs.uri)
1973 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001974 if (s->logs.cli_cookie)
1975 pool_free(capture, s->logs.cli_cookie);
1976 if (s->logs.srv_cookie)
1977 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001978
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 pool_free(session, s);
1980}
1981
willy tarreau0f7af912005-12-17 12:21:26 +01001982
1983/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001984 * This function recounts the number of usable active and backup servers for
1985 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001986 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001987 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001988static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001989 struct server *srv;
1990
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001991 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001992 for (srv = px->srv; srv != NULL; srv = srv->next) {
1993 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001994 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001995 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001996 px->tot_wbck += srv->eweight + 1;
1997 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001998 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001999 px->tot_wact += srv->eweight + 1;
2000 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002001 }
2002 }
2003}
2004
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002005/* This function recomputes the server map for proxy px. It
2006 * relies on px->tot_wact and px->tot_wbck, so it must be
2007 * called after recount_servers(). It also expects px->srv_map
2008 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002009 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002010static void recalc_server_map(struct proxy *px) {
2011 int o, tot, flag;
2012 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002013
willy tarreau4c8c2b52006-03-24 19:36:41 +01002014 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002015 flag = SRV_RUNNING;
2016 tot = px->tot_wact;
2017 } else if (px->srv_bck) {
2018 flag = SRV_RUNNING | SRV_BACKUP;
2019 if (px->options & PR_O_USE_ALL_BK)
2020 tot = px->tot_wbck;
2021 else
2022 tot = 1; /* the first server is enough */
2023 } else {
2024 px->srv_map_sz = 0;
2025 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002026 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002027
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002028 /* this algorithm gives priority to the first server, which means that
2029 * it will respect the declaration order for equivalent weights, and
2030 * that whatever the weights, the first server called will always be
2031 * the first declard. This is an important asumption for the backup
2032 * case, where we want the first server only.
2033 */
2034 for (cur = px->srv; cur; cur = cur->next)
2035 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002036
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002037 for (o = 0; o < tot; o++) {
2038 int max = 0;
2039 best = NULL;
2040 for (cur = px->srv; cur; cur = cur->next) {
2041 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2042 int v;
2043
2044 /* If we are forced to return only one server, we don't want to
2045 * go further, because we would return the wrong one due to
2046 * divide overflow.
2047 */
2048 if (tot == 1) {
2049 best = cur;
2050 break;
2051 }
2052
2053 cur->wscore += cur->eweight + 1;
2054 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2055 if (best == NULL || v > max) {
2056 max = v;
2057 best = cur;
2058 }
2059 }
2060 }
2061 px->srv_map[o] = best;
2062 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002063 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002064 px->srv_map_sz = tot;
2065}
Willy TARREAU3481c462006-03-01 22:37:57 +01002066
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002067/*
willy tarreau898db9d2006-04-12 20:29:08 +02002068 * This function tries to find a running server with free connection slots for
2069 * the proxy <px> following the round-robin method.
2070 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2071 * to point to the next server. If no valid server is found, NULL is returned.
2072 */
2073static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2074 int newidx;
2075 struct server *srv;
2076
2077 if (px->srv_map_sz == 0)
2078 return NULL;
2079
2080 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2081 px->srv_rr_idx = 0;
2082 newidx = px->srv_rr_idx;
2083
2084 do {
2085 srv = px->srv_map[newidx++];
2086 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2087 px->srv_rr_idx = newidx;
2088 return srv;
2089 }
2090 if (newidx == px->srv_map_sz)
2091 newidx = 0;
2092 } while (newidx != px->srv_rr_idx);
2093
2094 return NULL;
2095}
2096
2097
2098/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002100 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002101 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2102 * to point to the next server. If no valid server is found, NULL is returned.
2103 */
2104static inline struct server *get_server_rr(struct proxy *px) {
2105 if (px->srv_map_sz == 0)
2106 return NULL;
2107
2108 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2109 px->srv_rr_idx = 0;
2110 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002111}
2112
willy tarreau62084d42006-03-24 18:57:41 +01002113
2114/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002115 * This function tries to find a running server for the proxy <px> following
2116 * the source hash method. Depending on the number of active/backup servers,
2117 * it will either look for active servers, or for backup servers.
2118 * If any server is found, it will be returned. If no valid server is found,
2119 * NULL is returned.
2120 */
2121static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002122 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002123
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002124 if (px->srv_map_sz == 0)
2125 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002126
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002127 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002128 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129 while ((l + sizeof (int)) <= len) {
2130 h ^= ntohl(*(unsigned int *)(&addr[l]));
2131 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002132 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002133 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002134 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002135 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002136}
2137
2138
2139/*
willy tarreaudfece232006-05-02 00:19:57 +02002140 * This function marks the session as 'assigned' in direct or dispatch modes,
2141 * or tries to assign one in balance mode, according to the algorithm. It does
2142 * nothing if the session had already been assigned a server.
2143 *
2144 * It may return :
2145 * SRV_STATUS_OK if everything is OK.
2146 * SRV_STATUS_NOSRV if no server is available
2147 * SRV_STATUS_FULL if all servers are saturated
2148 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2149 *
2150 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2151 * not need to be called anymore. This usually means that s->srv can be trusted
2152 * in balance and direct modes. This flag is not cleared, so it's to the caller
2153 * to clear it if required (eg: redispatch).
2154 *
willy tarreau0f7af912005-12-17 12:21:26 +01002155 */
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreaudfece232006-05-02 00:19:57 +02002157int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002158#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002159 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002160#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002161
willy tarreaudfece232006-05-02 00:19:57 +02002162 if (s->pend_pos)
2163 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002164
willy tarreaudfece232006-05-02 00:19:57 +02002165 if (!(s->flags & SN_ASSIGNED)) {
2166 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2167 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2168 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169
willy tarreaudfece232006-05-02 00:19:57 +02002170 if (s->proxy->options & PR_O_BALANCE_RR) {
2171 s->srv = get_server_rr_with_conns(s->proxy);
2172 if (!s->srv)
2173 return SRV_STATUS_FULL;
2174 }
2175 else if (s->proxy->options & PR_O_BALANCE_SH) {
2176 int len;
2177
2178 if (s->cli_addr.ss_family == AF_INET)
2179 len = 4;
2180 else if (s->cli_addr.ss_family == AF_INET6)
2181 len = 16;
2182 else /* unknown IP family */
2183 return SRV_STATUS_INTERNAL;
2184
2185 s->srv = get_server_sh(s->proxy,
2186 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2187 len);
2188 }
2189 else /* unknown balancing algorithm */
2190 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002191 }
willy tarreaudfece232006-05-02 00:19:57 +02002192 s->flags |= SN_ASSIGNED;
2193 }
2194 return SRV_STATUS_OK;
2195}
willy tarreau1a3442d2006-03-24 21:03:20 +01002196
willy tarreaudfece232006-05-02 00:19:57 +02002197/*
2198 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2199 * The address is taken from the currently assigned server, or from the
2200 * dispatch or transparent address.
2201 *
2202 * It may return :
2203 * SRV_STATUS_OK if everything is OK.
2204 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2205 *
2206 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2207 * not cleared, so it's to the caller to clear it if required.
2208 *
2209 */
2210int assign_server_address(struct session *s) {
2211#ifdef DEBUG_FULL
2212 fprintf(stderr,"assign_server_address : s=%p\n",s);
2213#endif
2214
2215 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2216 /* A server is necessarily known for this session */
2217 if (!(s->flags & SN_ASSIGNED))
2218 return SRV_STATUS_INTERNAL;
2219
2220 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002221
willy tarreaudfece232006-05-02 00:19:57 +02002222 /* if this server remaps proxied ports, we'll use
2223 * the port the client connected to with an offset. */
2224 if (s->srv->state & SRV_MAPPORTS) {
2225 struct sockaddr_in sockname;
2226 socklen_t namelen = sizeof(sockname);
2227
2228 if (!(s->proxy->options & PR_O_TRANSP) ||
2229 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2230 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2231 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002232 }
willy tarreau0f7af912005-12-17 12:21:26 +01002233 }
willy tarreaua1598082005-12-17 13:08:06 +01002234 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002236 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002237 }
2238 else if (s->proxy->options & PR_O_TRANSP) {
2239 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002240 socklen_t salen = sizeof(s->srv_addr);
2241
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2243 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002244 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002245 }
2246 }
willy tarreau0f7af912005-12-17 12:21:26 +01002247
willy tarreaudfece232006-05-02 00:19:57 +02002248 s->flags |= SN_ADDR_SET;
2249 return SRV_STATUS_OK;
2250}
willy tarreaua41a8b42005-12-17 14:02:24 +01002251
willy tarreaudfece232006-05-02 00:19:57 +02002252/* This function assigns a server to session <s> if required, and can add the
2253 * connection to either the assigned server's queue or to the proxy's queue.
2254 *
2255 * Returns :
2256 *
2257 * SRV_STATUS_OK if everything is OK.
2258 * SRV_STATUS_NOSRV if no server is available
2259 * SRV_STATUS_QUEUED if the connection has been queued.
2260 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2261 * connection could not be queued.
2262 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2263 *
2264 */
2265int assign_server_and_queue(struct session *s) {
2266 struct pendconn *p;
2267 int err;
2268
2269 if (s->pend_pos)
2270 return SRV_STATUS_INTERNAL;
2271
2272 if (s->flags & SN_ASSIGNED) {
2273 /* a server does not need to be assigned, perhaps because we're in
2274 * direct mode, or in dispatch or transparent modes where the server
2275 * is not needed.
2276 */
2277 if (s->srv &&
2278 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2279 p = pendconn_add(s);
2280 if (p)
2281 return SRV_STATUS_QUEUED;
2282 else
2283 return SRV_STATUS_FULL;
2284 }
2285 return SRV_STATUS_OK;
2286 }
2287
2288 /* a server needs to be assigned */
2289 err = assign_server(s);
2290 switch (err) {
2291 case SRV_STATUS_OK:
2292 /* in balance mode, we might have servers with connection limits */
2293 if (s->srv != NULL &&
2294 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2295 p = pendconn_add(s);
2296 if (p)
2297 return SRV_STATUS_QUEUED;
2298 else
2299 return SRV_STATUS_FULL;
2300 }
2301 return SRV_STATUS_OK;
2302
2303 case SRV_STATUS_FULL:
2304 /* queue this session into the proxy's queue */
2305 p = pendconn_add(s);
2306 if (p)
2307 return SRV_STATUS_QUEUED;
2308 else
2309 return SRV_STATUS_FULL;
2310
2311 case SRV_STATUS_NOSRV:
2312 case SRV_STATUS_INTERNAL:
2313 return err;
2314 default:
2315 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002316 }
willy tarreaudfece232006-05-02 00:19:57 +02002317}
2318
2319
2320/*
2321 * This function initiates a connection to the server assigned to this session
2322 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2323 * It can return one of :
2324 * - SN_ERR_NONE if everything's OK
2325 * - SN_ERR_SRVTO if there are no more servers
2326 * - SN_ERR_SRVCL if the connection was refused by the server
2327 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2328 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2329 * - SN_ERR_INTERNAL for any other purely internal errors
2330 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2331 */
2332int connect_server(struct session *s) {
2333 int fd, err;
2334
2335 if (!(s->flags & SN_ADDR_SET)) {
2336 err = assign_server_address(s);
2337 if (err != SRV_STATUS_OK)
2338 return SN_ERR_INTERNAL;
2339 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002340
willy tarreau0f7af912005-12-17 12:21:26 +01002341 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002342 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002343
2344 if (errno == ENFILE)
2345 send_log(s->proxy, LOG_EMERG,
2346 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2347 s->proxy->id, maxfd);
2348 else if (errno == EMFILE)
2349 send_log(s->proxy, LOG_EMERG,
2350 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2351 s->proxy->id, maxfd);
2352 else if (errno == ENOBUFS || errno == ENOMEM)
2353 send_log(s->proxy, LOG_EMERG,
2354 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2355 s->proxy->id, maxfd);
2356 /* this is a resource error */
2357 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002358 }
2359
willy tarreau9fe663a2005-12-17 13:02:59 +01002360 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002361 /* do not log anything there, it's a normal condition when this option
2362 * is used to serialize connections to a server !
2363 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002364 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2365 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002366 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 }
2368
willy tarreau0f7af912005-12-17 12:21:26 +01002369 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2370 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002371 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002372 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002373 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002374 }
2375
willy tarreaub952e1d2005-12-18 01:31:20 +01002376 if (s->proxy->options & PR_O_TCP_SRV_KA)
2377 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2378
willy tarreau0174f312005-12-18 01:02:42 +01002379 /* allow specific binding :
2380 * - server-specific at first
2381 * - proxy-specific next
2382 */
2383 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2384 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2385 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2386 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2387 s->proxy->id, s->srv->id);
2388 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002389 send_log(s->proxy, LOG_EMERG,
2390 "Cannot bind to source address before connect() for server %s/%s.\n",
2391 s->proxy->id, s->srv->id);
2392 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002393 }
2394 }
2395 else if (s->proxy->options & PR_O_BIND_SRC) {
2396 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2397 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2398 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2399 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002400 send_log(s->proxy, LOG_EMERG,
2401 "Cannot bind to source address before connect() for server %s/%s.\n",
2402 s->proxy->id, s->srv->id);
2403 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002404 }
willy tarreaua1598082005-12-17 13:08:06 +01002405 }
2406
willy tarreaub1285d52005-12-18 01:20:14 +01002407 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2408 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2409
2410 if (errno == EAGAIN || errno == EADDRINUSE) {
2411 char *msg;
2412 if (errno == EAGAIN) /* no free ports left, try again later */
2413 msg = "no free ports";
2414 else
2415 msg = "local address already in use";
2416
2417 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002418 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002419 send_log(s->proxy, LOG_EMERG,
2420 "Connect() failed for server %s/%s: %s.\n",
2421 s->proxy->id, s->srv->id, msg);
2422 return SN_ERR_RESOURCE;
2423 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002424 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002425 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002426 return SN_ERR_SRVTO;
2427 } else {
2428 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002429 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002430 close(fd);
2431 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 }
2433 }
2434
willy tarreau5cbea6f2005-12-17 12:48:26 +01002435 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002436 fdtab[fd].read = &event_srv_read;
2437 fdtab[fd].write = &event_srv_write;
2438 fdtab[fd].state = FD_STCONN; /* connection in progress */
2439
2440 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002441#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2442 if (PrevReadEvent) {
2443 assert(!(FD_ISSET(fd, PrevReadEvent)));
2444 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2445 }
2446#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002447
2448 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002449 if (s->srv)
2450 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002451
2452 if (s->proxy->contimeout)
2453 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2454 else
2455 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002456 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002457}
2458
2459/*
2460 * this function is called on a read event from a client socket.
2461 * It returns 0.
2462 */
2463int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002464 struct task *t = fdtab[fd].owner;
2465 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002466 struct buffer *b = s->req;
2467 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002468
willy tarreau12350152005-12-18 01:03:27 +01002469#ifdef DEBUG_FULL
2470 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2471#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002472
willy tarreau0f7af912005-12-17 12:21:26 +01002473 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002474#ifdef FILL_BUFFERS
2475 while (1)
2476#else
2477 do
2478#endif
2479 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002480 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2481 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002482 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002483 }
2484 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002485 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 }
2487 else {
2488 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002489 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2490 * since it means that the rewrite protection has been removed. This
2491 * implies that the if statement can be removed.
2492 */
2493 if (max > b->rlim - b->data)
2494 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 }
2496
2497 if (max == 0) { /* not anymore room to store data */
2498 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002499 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500 }
2501
willy tarreau3242e862005-12-17 12:27:53 +01002502#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002504 int skerr;
2505 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2508 if (skerr)
2509 ret = -1;
2510 else
2511 ret = recv(fd, b->r, max, 0);
2512 }
willy tarreau3242e862005-12-17 12:27:53 +01002513#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002514 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002515#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 if (ret > 0) {
2517 b->r += ret;
2518 b->l += ret;
2519 s->res_cr = RES_DATA;
2520
2521 if (b->r == b->data + BUFSIZE) {
2522 b->r = b->data; /* wrap around the buffer */
2523 }
willy tarreaua1598082005-12-17 13:08:06 +01002524
2525 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002526 /* we hope to read more data or to get a close on next round */
2527 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002528 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002529 else if (ret == 0) {
2530 s->res_cr = RES_NULL;
2531 break;
2532 }
2533 else if (errno == EAGAIN) {/* ignore EAGAIN */
2534 break;
2535 }
2536 else {
2537 s->res_cr = RES_ERROR;
2538 fdtab[fd].state = FD_STERROR;
2539 break;
2540 }
2541 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002542#ifndef FILL_BUFFERS
2543 while (0);
2544#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002545 }
2546 else {
2547 s->res_cr = RES_ERROR;
2548 fdtab[fd].state = FD_STERROR;
2549 }
2550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002552 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002553 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2554 else
2555 tv_eternity(&s->crexpire);
2556
2557 task_wakeup(&rq, t);
2558 }
willy tarreau0f7af912005-12-17 12:21:26 +01002559
willy tarreau0f7af912005-12-17 12:21:26 +01002560 return 0;
2561}
2562
2563
2564/*
2565 * this function is called on a read event from a server socket.
2566 * It returns 0.
2567 */
2568int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 struct task *t = fdtab[fd].owner;
2570 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002571 struct buffer *b = s->rep;
2572 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002573
willy tarreau12350152005-12-18 01:03:27 +01002574#ifdef DEBUG_FULL
2575 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2576#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002577
willy tarreau0f7af912005-12-17 12:21:26 +01002578 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002579#ifdef FILL_BUFFERS
2580 while (1)
2581#else
2582 do
2583#endif
2584 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2586 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002587 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002588 }
2589 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002590 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 }
2592 else {
2593 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002594 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2595 * since it means that the rewrite protection has been removed. This
2596 * implies that the if statement can be removed.
2597 */
2598 if (max > b->rlim - b->data)
2599 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002600 }
2601
2602 if (max == 0) { /* not anymore room to store data */
2603 FD_CLR(fd, StaticReadEvent);
2604 break;
2605 }
2606
willy tarreau3242e862005-12-17 12:27:53 +01002607#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002609 int skerr;
2610 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611
willy tarreau5cbea6f2005-12-17 12:48:26 +01002612 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2613 if (skerr)
2614 ret = -1;
2615 else
2616 ret = recv(fd, b->r, max, 0);
2617 }
willy tarreau3242e862005-12-17 12:27:53 +01002618#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002620#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002621 if (ret > 0) {
2622 b->r += ret;
2623 b->l += ret;
2624 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002625
willy tarreau5cbea6f2005-12-17 12:48:26 +01002626 if (b->r == b->data + BUFSIZE) {
2627 b->r = b->data; /* wrap around the buffer */
2628 }
willy tarreaua1598082005-12-17 13:08:06 +01002629
2630 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 /* we hope to read more data or to get a close on next round */
2632 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002633 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002634 else if (ret == 0) {
2635 s->res_sr = RES_NULL;
2636 break;
2637 }
2638 else if (errno == EAGAIN) {/* ignore EAGAIN */
2639 break;
2640 }
2641 else {
2642 s->res_sr = RES_ERROR;
2643 fdtab[fd].state = FD_STERROR;
2644 break;
2645 }
2646 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002647#ifndef FILL_BUFFERS
2648 while (0);
2649#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002650 }
2651 else {
2652 s->res_sr = RES_ERROR;
2653 fdtab[fd].state = FD_STERROR;
2654 }
2655
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002657 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002658 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2659 else
2660 tv_eternity(&s->srexpire);
2661
2662 task_wakeup(&rq, t);
2663 }
willy tarreau0f7af912005-12-17 12:21:26 +01002664
willy tarreau0f7af912005-12-17 12:21:26 +01002665 return 0;
2666}
2667
2668/*
2669 * this function is called on a write event from a client socket.
2670 * It returns 0.
2671 */
2672int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 struct task *t = fdtab[fd].owner;
2674 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002675 struct buffer *b = s->rep;
2676 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002677
willy tarreau12350152005-12-18 01:03:27 +01002678#ifdef DEBUG_FULL
2679 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2680#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002681
2682 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002683 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002684 // max = BUFSIZE; BUG !!!!
2685 max = 0;
2686 }
2687 else if (b->r > b->w) {
2688 max = b->r - b->w;
2689 }
2690 else
2691 max = b->data + BUFSIZE - b->w;
2692
willy tarreau0f7af912005-12-17 12:21:26 +01002693 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002694 if (max == 0) {
2695 s->res_cw = RES_NULL;
2696 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002697 tv_eternity(&s->cwexpire);
2698 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002699 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002700 }
2701
willy tarreau3242e862005-12-17 12:27:53 +01002702#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002703 {
2704 int skerr;
2705 socklen_t lskerr = sizeof(skerr);
2706
2707 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2708 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002709 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002710 else
willy tarreau3242e862005-12-17 12:27:53 +01002711 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002712 }
willy tarreau3242e862005-12-17 12:27:53 +01002713#else
willy tarreau0f7af912005-12-17 12:21:26 +01002714 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002715#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002716
2717 if (ret > 0) {
2718 b->l -= ret;
2719 b->w += ret;
2720
2721 s->res_cw = RES_DATA;
2722
2723 if (b->w == b->data + BUFSIZE) {
2724 b->w = b->data; /* wrap around the buffer */
2725 }
2726 }
2727 else if (ret == 0) {
2728 /* nothing written, just make as if we were never called */
2729// s->res_cw = RES_NULL;
2730 return 0;
2731 }
2732 else if (errno == EAGAIN) /* ignore EAGAIN */
2733 return 0;
2734 else {
2735 s->res_cw = RES_ERROR;
2736 fdtab[fd].state = FD_STERROR;
2737 }
2738 }
2739 else {
2740 s->res_cw = RES_ERROR;
2741 fdtab[fd].state = FD_STERROR;
2742 }
2743
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002745 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002746 /* FIXME: to prevent the client from expiring read timeouts during writes,
2747 * we refresh it. A solution would be to merge read+write timeouts into a
2748 * unique one, although that needs some study particularly on full-duplex
2749 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002750 s->crexpire = s->cwexpire;
2751 }
willy tarreau0f7af912005-12-17 12:21:26 +01002752 else
2753 tv_eternity(&s->cwexpire);
2754
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002756 return 0;
2757}
2758
2759
2760/*
2761 * this function is called on a write event from a server socket.
2762 * It returns 0.
2763 */
2764int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002765 struct task *t = fdtab[fd].owner;
2766 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002767 struct buffer *b = s->req;
2768 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002769
willy tarreau12350152005-12-18 01:03:27 +01002770#ifdef DEBUG_FULL
2771 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2772#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002773
2774 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002775 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002776 // max = BUFSIZE; BUG !!!!
2777 max = 0;
2778 }
2779 else if (b->r > b->w) {
2780 max = b->r - b->w;
2781 }
2782 else
2783 max = b->data + BUFSIZE - b->w;
2784
willy tarreau0f7af912005-12-17 12:21:26 +01002785 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002786 if (max == 0) {
2787 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002788 if (s->srv_state == SV_STCONN) {
2789 int skerr;
2790 socklen_t lskerr = sizeof(skerr);
2791 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2792 if (skerr) {
2793 s->res_sw = RES_ERROR;
2794 fdtab[fd].state = FD_STERROR;
2795 task_wakeup(&rq, t);
2796 tv_eternity(&s->swexpire);
2797 FD_CLR(fd, StaticWriteEvent);
2798 return 0;
2799 }
2800 }
2801
willy tarreau0f7af912005-12-17 12:21:26 +01002802 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002804 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002805 tv_eternity(&s->swexpire);
2806 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002807 return 0;
2808 }
2809
willy tarreau3242e862005-12-17 12:27:53 +01002810#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002811 {
2812 int skerr;
2813 socklen_t lskerr = sizeof(skerr);
2814 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2815 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002816 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002817 else
willy tarreau3242e862005-12-17 12:27:53 +01002818 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002819 }
willy tarreau3242e862005-12-17 12:27:53 +01002820#else
willy tarreau0f7af912005-12-17 12:21:26 +01002821 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002822#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002823 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002824 if (ret > 0) {
2825 b->l -= ret;
2826 b->w += ret;
2827
2828 s->res_sw = RES_DATA;
2829
2830 if (b->w == b->data + BUFSIZE) {
2831 b->w = b->data; /* wrap around the buffer */
2832 }
2833 }
2834 else if (ret == 0) {
2835 /* nothing written, just make as if we were never called */
2836 // s->res_sw = RES_NULL;
2837 return 0;
2838 }
2839 else if (errno == EAGAIN) /* ignore EAGAIN */
2840 return 0;
2841 else {
2842 s->res_sw = RES_ERROR;
2843 fdtab[fd].state = FD_STERROR;
2844 }
2845 }
2846 else {
2847 s->res_sw = RES_ERROR;
2848 fdtab[fd].state = FD_STERROR;
2849 }
2850
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002851 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2852 * otherwise it could loop indefinitely !
2853 */
2854 if (s->srv_state != SV_STCONN) {
2855 if (s->proxy->srvtimeout) {
2856 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002857 /* FIXME: to prevent the server from expiring read timeouts during writes,
2858 * we refresh it. A solution would be to merge read+write+connect timeouts
2859 * into a unique one since we don't mind expiring on read or write, and none
2860 * of them is enabled while waiting for connect(), although that needs some
2861 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002862 s->srexpire = s->swexpire;
2863 }
2864 else
2865 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002866 }
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002869 return 0;
2870}
2871
2872
2873/*
willy tarreaue39cd132005-12-17 13:00:18 +01002874 * returns a message to the client ; the connection is shut down for read,
2875 * and the request is cleared so that no server connection can be initiated.
2876 * The client must be in a valid state for this (HEADER, DATA ...).
2877 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002878 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002879 */
2880void client_retnclose(struct session *s, int len, const char *msg) {
2881 FD_CLR(s->cli_fd, StaticReadEvent);
2882 FD_SET(s->cli_fd, StaticWriteEvent);
2883 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002884 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002885 shutdown(s->cli_fd, SHUT_RD);
2886 s->cli_state = CL_STSHUTR;
2887 strcpy(s->rep->data, msg);
2888 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002889 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002890 s->rep->r += len;
2891 s->req->l = 0;
2892}
2893
2894
2895/*
2896 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002897 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002898 */
2899void client_return(struct session *s, int len, const char *msg) {
2900 strcpy(s->rep->data, msg);
2901 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002902 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002903 s->rep->r += len;
2904 s->req->l = 0;
2905}
2906
willy tarreau9fe663a2005-12-17 13:02:59 +01002907/*
2908 * send a log for the session when we have enough info about it
2909 */
2910void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002911 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002912 struct proxy *p = s->proxy;
2913 int log;
2914 char *uri;
2915 char *pxid;
2916 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002917 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002918
2919 /* This is a first attempt at a better logging system.
2920 * For now, we rely on send_log() to provide the date, although it obviously
2921 * is the date of the log and not of the request, and most fields are not
2922 * computed.
2923 */
2924
willy tarreaua1598082005-12-17 13:08:06 +01002925 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002926
willy tarreau8a86dbf2005-12-18 00:45:59 +01002927 if (s->cli_addr.ss_family == AF_INET)
2928 inet_ntop(AF_INET,
2929 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2930 pn, sizeof(pn));
2931 else
2932 inet_ntop(AF_INET6,
2933 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2934 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002935
willy tarreauc1cae632005-12-17 14:12:23 +01002936 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002937 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002938 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002939
willy tarreauc1cae632005-12-17 14:12:23 +01002940 tm = localtime(&s->logs.tv_accept.tv_sec);
2941 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002942 char tmpline[MAX_SYSLOG_LEN], *h;
2943 int hdr;
2944
2945 h = tmpline;
2946 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2947 *(h++) = ' ';
2948 *(h++) = '{';
2949 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2950 if (hdr)
2951 *(h++) = '|';
2952 if (s->req_cap[hdr] != NULL)
2953 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2954 }
2955 *(h++) = '}';
2956 }
2957
2958 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2959 *(h++) = ' ';
2960 *(h++) = '{';
2961 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2962 if (hdr)
2963 *(h++) = '|';
2964 if (s->rsp_cap[hdr] != NULL)
2965 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2966 }
2967 *(h++) = '}';
2968 }
2969
2970 if (h < tmpline + sizeof(tmpline) - 4) {
2971 *(h++) = ' ';
2972 *(h++) = '"';
2973 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2974 *(h++) = '"';
2975 }
2976 *h = '\0';
2977
willy tarreauf32f5242006-05-02 22:54:52 +02002978 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002979 pn,
2980 (s->cli_addr.ss_family == AF_INET) ?
2981 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2982 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002983 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2984 tm->tm_hour, tm->tm_min, tm->tm_sec,
2985 pxid, srv,
2986 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002987 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2988 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002989 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002990 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2991 s->logs.status,
2992 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002993 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2994 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002995 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2996 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2997 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2998 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauf32f5242006-05-02 22:54:52 +02002999 s->srv ? s->srv->cur_sess : 0, s->logs.queue_size,
3000 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003001 }
3002 else {
willy tarreauf32f5242006-05-02 22:54:52 +02003003 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003004 pn,
3005 (s->cli_addr.ss_family == AF_INET) ?
3006 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3007 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003008 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3009 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003010 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003011 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003012 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3013 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003014 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003015 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauf32f5242006-05-02 22:54:52 +02003016 s->srv ? s->srv->cur_sess : 0, s->logs.queue_size,
3017 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01003018 }
3019
3020 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003021}
3022
willy tarreaue39cd132005-12-17 13:00:18 +01003023
3024/*
willy tarreau0f7af912005-12-17 12:21:26 +01003025 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 * to an accept. It tries to accept as many connections as possible.
3027 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003028 */
3029int event_accept(int fd) {
3030 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 struct session *s;
3032 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003033 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003034 int max_accept;
3035
3036 if (global.nbproc > 1)
3037 max_accept = 8; /* let other processes catch some connections too */
3038 else
3039 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003040
willy tarreauc2becdc2006-03-19 19:36:48 +01003041 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003042 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003043 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003044
willy tarreaub1285d52005-12-18 01:20:14 +01003045 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3046 switch (errno) {
3047 case EAGAIN:
3048 case EINTR:
3049 case ECONNABORTED:
3050 return 0; /* nothing more to accept */
3051 case ENFILE:
3052 send_log(p, LOG_EMERG,
3053 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3054 p->id, maxfd);
3055 return 0;
3056 case EMFILE:
3057 send_log(p, LOG_EMERG,
3058 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3059 p->id, maxfd);
3060 return 0;
3061 case ENOBUFS:
3062 case ENOMEM:
3063 send_log(p, LOG_EMERG,
3064 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3065 p->id, maxfd);
3066 return 0;
3067 default:
3068 return 0;
3069 }
3070 }
willy tarreau0f7af912005-12-17 12:21:26 +01003071
willy tarreau5cbea6f2005-12-17 12:48:26 +01003072 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3073 Alert("out of memory in event_accept().\n");
3074 FD_CLR(fd, StaticReadEvent);
3075 p->state = PR_STIDLE;
3076 close(cfd);
3077 return 0;
3078 }
willy tarreau0f7af912005-12-17 12:21:26 +01003079
willy tarreaub1285d52005-12-18 01:20:14 +01003080 /* if this session comes from a known monitoring system, we want to ignore
3081 * it as soon as possible, which means closing it immediately for TCP.
3082 */
3083 s->flags = 0;
3084 if (addr.ss_family == AF_INET &&
3085 p->mon_mask.s_addr &&
3086 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3087 if (p->mode == PR_MODE_TCP) {
3088 close(cfd);
3089 pool_free(session, s);
3090 continue;
3091 }
3092 s->flags |= SN_MONITOR;
3093 }
3094
willy tarreau5cbea6f2005-12-17 12:48:26 +01003095 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3096 Alert("out of memory in event_accept().\n");
3097 FD_CLR(fd, StaticReadEvent);
3098 p->state = PR_STIDLE;
3099 close(cfd);
3100 pool_free(session, s);
3101 return 0;
3102 }
willy tarreau0f7af912005-12-17 12:21:26 +01003103
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003105 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003106 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3107 close(cfd);
3108 pool_free(task, t);
3109 pool_free(session, s);
3110 return 0;
3111 }
willy tarreau0f7af912005-12-17 12:21:26 +01003112
willy tarreau5cbea6f2005-12-17 12:48:26 +01003113 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3114 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3115 (char *) &one, sizeof(one)) == -1)) {
3116 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3117 close(cfd);
3118 pool_free(task, t);
3119 pool_free(session, s);
3120 return 0;
3121 }
willy tarreau0f7af912005-12-17 12:21:26 +01003122
willy tarreaub952e1d2005-12-18 01:31:20 +01003123 if (p->options & PR_O_TCP_CLI_KA)
3124 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3125
willy tarreau9fe663a2005-12-17 13:02:59 +01003126 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003127 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003128 t->state = TASK_IDLE;
3129 t->process = process_session;
3130 t->context = s;
3131
3132 s->task = t;
3133 s->proxy = p;
3134 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3135 s->srv_state = SV_STIDLE;
3136 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003137
willy tarreau9fe663a2005-12-17 13:02:59 +01003138 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3139 s->cli_fd = cfd;
3140 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003141 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003142 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003143
willy tarreaub1285d52005-12-18 01:20:14 +01003144 if (s->flags & SN_MONITOR)
3145 s->logs.logwait = 0;
3146 else
3147 s->logs.logwait = p->to_log;
3148
willy tarreaua1598082005-12-17 13:08:06 +01003149 s->logs.tv_accept = now;
3150 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003151 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003152 s->logs.t_connect = -1;
3153 s->logs.t_data = -1;
3154 s->logs.t_close = 0;
3155 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003156 s->logs.cli_cookie = NULL;
3157 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003158 s->logs.status = -1;
3159 s->logs.bytes = 0;
willy tarreauf32f5242006-05-02 22:54:52 +02003160 s->logs.queue_size = p->totpend; /* we get the number of pending conns before us */
willy tarreau9fe663a2005-12-17 13:02:59 +01003161
willy tarreau2f6ba652005-12-17 13:57:42 +01003162 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003163 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003164
willy tarreau4302f492005-12-18 01:00:37 +01003165 if (p->nb_req_cap > 0) {
3166 if ((s->req_cap =
3167 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3168 == NULL) { /* no memory */
3169 close(cfd); /* nothing can be done for this fd without memory */
3170 pool_free(task, t);
3171 pool_free(session, s);
3172 return 0;
3173 }
3174 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3175 }
3176 else
3177 s->req_cap = NULL;
3178
3179 if (p->nb_rsp_cap > 0) {
3180 if ((s->rsp_cap =
3181 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3182 == NULL) { /* no memory */
3183 if (s->req_cap != NULL)
3184 pool_free_to(p->req_cap_pool, s->req_cap);
3185 close(cfd); /* nothing can be done for this fd without memory */
3186 pool_free(task, t);
3187 pool_free(session, s);
3188 return 0;
3189 }
3190 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3191 }
3192 else
3193 s->rsp_cap = NULL;
3194
willy tarreau5cbea6f2005-12-17 12:48:26 +01003195 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3196 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003197 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003198 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003199
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003201 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003202 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003203 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003204
willy tarreau9fe663a2005-12-17 13:02:59 +01003205 if (p->to_log) {
3206 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003207 if (s->logs.logwait & LW_CLIP)
3208 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003209 sess_log(s);
3210 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003211 else if (s->cli_addr.ss_family == AF_INET) {
3212 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3213 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3214 sn, sizeof(sn)) &&
3215 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3216 pn, sizeof(pn))) {
3217 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3218 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3219 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3220 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3221 }
3222 }
3223 else {
3224 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3225 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3226 sn, sizeof(sn)) &&
3227 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3228 pn, sizeof(pn))) {
3229 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3230 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3231 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3232 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3233 }
3234 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003235 }
willy tarreau0f7af912005-12-17 12:21:26 +01003236
willy tarreau982249e2005-12-18 00:57:06 +01003237 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003238 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003239 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003240 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003241 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003242 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003243 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003244 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003245
willy tarreau8a86dbf2005-12-18 00:45:59 +01003246 if (s->cli_addr.ss_family == AF_INET) {
3247 char pn[INET_ADDRSTRLEN];
3248 inet_ntop(AF_INET,
3249 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3250 pn, sizeof(pn));
3251
3252 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3253 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3254 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3255 }
3256 else {
3257 char pn[INET6_ADDRSTRLEN];
3258 inet_ntop(AF_INET6,
3259 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3260 pn, sizeof(pn));
3261
3262 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3263 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3264 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3265 }
3266
willy tarreauef900ab2005-12-17 12:52:52 +01003267 write(1, trash, len);
3268 }
willy tarreau0f7af912005-12-17 12:21:26 +01003269
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003271 if (s->rsp_cap != NULL)
3272 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3273 if (s->req_cap != NULL)
3274 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003275 close(cfd); /* nothing can be done for this fd without memory */
3276 pool_free(task, t);
3277 pool_free(session, s);
3278 return 0;
3279 }
willy tarreau4302f492005-12-18 01:00:37 +01003280
willy tarreau5cbea6f2005-12-17 12:48:26 +01003281 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003282 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003283 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3284 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003285 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003286 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003287
willy tarreau5cbea6f2005-12-17 12:48:26 +01003288 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3289 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003290 if (s->rsp_cap != NULL)
3291 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3292 if (s->req_cap != NULL)
3293 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003294 close(cfd); /* nothing can be done for this fd without memory */
3295 pool_free(task, t);
3296 pool_free(session, s);
3297 return 0;
3298 }
3299 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003300 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003301 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 +01003302
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303 fdtab[cfd].read = &event_cli_read;
3304 fdtab[cfd].write = &event_cli_write;
3305 fdtab[cfd].owner = t;
3306 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003307
willy tarreaub1285d52005-12-18 01:20:14 +01003308 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3309 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3310 /* Either we got a request from a monitoring system on an HTTP instance,
3311 * or we're in health check mode with the 'httpchk' option enabled. In
3312 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3313 */
3314 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3315 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3316 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 }
3318 else {
3319 FD_SET(cfd, StaticReadEvent);
3320 }
3321
willy tarreaub952e1d2005-12-18 01:31:20 +01003322#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3323 if (PrevReadEvent) {
3324 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3325 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3326 }
3327#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003328 fd_insert(cfd);
3329
3330 tv_eternity(&s->cnexpire);
3331 tv_eternity(&s->srexpire);
3332 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003333 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 tv_eternity(&s->cwexpire);
3335
willy tarreaub1285d52005-12-18 01:20:14 +01003336 if (s->proxy->clitimeout) {
3337 if (FD_ISSET(cfd, StaticReadEvent))
3338 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3339 if (FD_ISSET(cfd, StaticWriteEvent))
3340 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342
willy tarreaub1285d52005-12-18 01:20:14 +01003343 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344
3345 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003346
3347 if (p->mode != PR_MODE_HEALTH)
3348 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349
3350 p->nbconn++;
3351 actconn++;
3352 totalconn++;
3353
willy tarreaub952e1d2005-12-18 01:31:20 +01003354 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355 } /* end of while (p->nbconn < p->maxconn) */
3356 return 0;
3357}
willy tarreau0f7af912005-12-17 12:21:26 +01003358
willy tarreau0f7af912005-12-17 12:21:26 +01003359
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360/*
3361 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003362 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3363 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 * or -1 if an error occured.
3365 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003366int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 struct task *t = fdtab[fd].owner;
3368 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003369 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003370 socklen_t lskerr = sizeof(skerr);
3371
willy tarreau05be12b2006-03-19 19:35:00 +01003372 skerr = 1;
3373 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3374 || (skerr != 0)) {
3375 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003377 fdtab[fd].state = FD_STERROR;
3378 FD_CLR(fd, StaticWriteEvent);
3379 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003380 else if (s->result != -1) {
3381 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003382 if (s->proxy->options & PR_O_HTTP_CHK) {
3383 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003384 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003385 * so we'll send the request, and won't wake the checker up now.
3386 */
3387#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003388 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003389#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003390 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003391#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003392 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003393 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3394 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3395 return 0;
3396 }
willy tarreau05be12b2006-03-19 19:35:00 +01003397 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003398 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003399 FD_CLR(fd, StaticWriteEvent);
3400 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003401 }
3402 else {
3403 /* good TCP connection is enough */
3404 s->result = 1;
3405 }
3406 }
3407
3408 task_wakeup(&rq, t);
3409 return 0;
3410}
3411
willy tarreau0f7af912005-12-17 12:21:26 +01003412
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003413/*
3414 * This function is used only for server health-checks. It handles
3415 * the server's reply to an HTTP request. It returns 1 if the server replies
3416 * 2xx or 3xx (valid responses), or -1 in other cases.
3417 */
3418int event_srv_chk_r(int fd) {
3419 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003420 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003421 struct task *t = fdtab[fd].owner;
3422 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003423 int skerr;
3424 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003425
willy tarreaua4a583a2005-12-18 01:39:19 +01003426 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003427
willy tarreau05be12b2006-03-19 19:35:00 +01003428 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3429 if (!skerr) {
3430#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003431 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003432#else
willy tarreau05be12b2006-03-19 19:35:00 +01003433 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3434 * but the connection was closed on the remote end. Fortunately, recv still
3435 * works correctly and we don't need to do the getsockopt() on linux.
3436 */
3437 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003438#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003439
3440 if ((len >= sizeof("HTTP/1.0 000")) &&
3441 !memcmp(reply, "HTTP/1.", 7) &&
3442 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3443 result = 1;
3444 }
3445
3446 if (result == -1)
3447 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003448
3449 if (s->result != -1)
3450 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003451
3452 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003454 return 0;
3455}
3456
3457
3458/*
3459 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3460 * and moves <end> just after the end of <str>.
3461 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3462 * the shift value (positive or negative) is returned.
3463 * If there's no space left, the move is not done.
3464 *
3465 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003466int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003467 int delta;
3468 int len;
3469
3470 len = strlen(str);
3471 delta = len - (end - pos);
3472
3473 if (delta + b->r >= b->data + BUFSIZE)
3474 return 0; /* no space left */
3475
3476 /* first, protect the end of the buffer */
3477 memmove(end + delta, end, b->data + b->l - end);
3478
3479 /* now, copy str over pos */
3480 memcpy(pos, str,len);
3481
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 /* we only move data after the displaced zone */
3483 if (b->r > pos) b->r += delta;
3484 if (b->w > pos) b->w += delta;
3485 if (b->h > pos) b->h += delta;
3486 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003487 b->l += delta;
3488
3489 return delta;
3490}
3491
willy tarreau8337c6b2005-12-17 13:41:01 +01003492/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003493 * len is 0.
3494 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003496 int delta;
3497
3498 delta = len - (end - pos);
3499
3500 if (delta + b->r >= b->data + BUFSIZE)
3501 return 0; /* no space left */
3502
Willy TARREAUe78ae262006-01-08 01:24:12 +01003503 if (b->data + b->l < end)
3504 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3505 return 0;
3506
willy tarreau0f7af912005-12-17 12:21:26 +01003507 /* first, protect the end of the buffer */
3508 memmove(end + delta, end, b->data + b->l - end);
3509
3510 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003511 if (len)
3512 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003513
willy tarreau5cbea6f2005-12-17 12:48:26 +01003514 /* we only move data after the displaced zone */
3515 if (b->r > pos) b->r += delta;
3516 if (b->w > pos) b->w += delta;
3517 if (b->h > pos) b->h += delta;
3518 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003519 b->l += delta;
3520
3521 return delta;
3522}
3523
3524
3525int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3526 char *old_dst = dst;
3527
3528 while (*str) {
3529 if (*str == '\\') {
3530 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003531 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003532 int len, num;
3533
3534 num = *str - '0';
3535 str++;
3536
willy tarreau8a86dbf2005-12-18 00:45:59 +01003537 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003538 len = matches[num].rm_eo - matches[num].rm_so;
3539 memcpy(dst, src + matches[num].rm_so, len);
3540 dst += len;
3541 }
3542
3543 }
3544 else if (*str == 'x') {
3545 unsigned char hex1, hex2;
3546 str++;
3547
willy tarreauc1f47532005-12-18 01:08:26 +01003548 hex1 = toupper(*str++) - '0';
3549 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003550
3551 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3552 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3553 *dst++ = (hex1<<4) + hex2;
3554 }
3555 else
3556 *dst++ = *str++;
3557 }
3558 else
3559 *dst++ = *str++;
3560 }
3561 *dst = 0;
3562 return dst - old_dst;
3563}
3564
willy tarreauc1f47532005-12-18 01:08:26 +01003565static int ishex(char s)
3566{
3567 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3568}
3569
3570/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3571char *check_replace_string(char *str)
3572{
3573 char *err = NULL;
3574 while (*str) {
3575 if (*str == '\\') {
3576 err = str; /* in case of a backslash, we return the pointer to it */
3577 str++;
3578 if (!*str)
3579 return err;
3580 else if (isdigit((int)*str))
3581 err = NULL;
3582 else if (*str == 'x') {
3583 str++;
3584 if (!ishex(*str))
3585 return err;
3586 str++;
3587 if (!ishex(*str))
3588 return err;
3589 err = NULL;
3590 }
3591 else {
3592 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3593 err = NULL;
3594 }
3595 }
3596 str++;
3597 }
3598 return err;
3599}
3600
3601
willy tarreau9fe663a2005-12-17 13:02:59 +01003602
willy tarreau0f7af912005-12-17 12:21:26 +01003603/*
3604 * manages the client FSM and its socket. BTW, it also tries to handle the
3605 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3606 * 0 else.
3607 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003609 int s = t->srv_state;
3610 int c = t->cli_state;
3611 struct buffer *req = t->req;
3612 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003613 int method_checked = 0;
3614 appsess *asession_temp = NULL;
3615 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003616
willy tarreau750a4722005-12-17 13:21:24 +01003617#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003618 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3619 cli_stnames[c], srv_stnames[s],
3620 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3621 t->crexpire.tv_sec, t->crexpire.tv_usec,
3622 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003623#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003624 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3625 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3626 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3627 //);
3628 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003629 /* now parse the partial (or complete) headers */
3630 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3631 char *ptr;
3632 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003633 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003634
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003636
willy tarreau0f7af912005-12-17 12:21:26 +01003637 /* look for the end of the current header */
3638 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3639 ptr++;
3640
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003643
3644 /*
3645 * first, let's check that it's not a leading empty line, in
3646 * which case we'll ignore and remove it (according to RFC2616).
3647 */
3648 if (req->h == req->data) {
3649 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3650 if (ptr > req->r - 2) {
3651 /* this is a partial header, let's wait for more to come */
3652 req->lr = ptr;
3653 break;
3654 }
3655
3656 /* now we know that *ptr is either \r or \n,
3657 * and that there are at least 1 char after it.
3658 */
3659 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3660 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3661 else
3662 req->lr = ptr + 2; /* \r\n or \n\r */
3663 /* ignore empty leading lines */
3664 buffer_replace2(req, req->h, req->lr, NULL, 0);
3665 req->h = req->lr;
3666 continue;
3667 }
3668
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 /* we can only get here after an end of headers */
3670 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003671
willy tarreaue39cd132005-12-17 13:00:18 +01003672 if (t->flags & SN_CLDENY) {
3673 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003674 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003675 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003676 if (!(t->flags & SN_ERR_MASK))
3677 t->flags |= SN_ERR_PRXCOND;
3678 if (!(t->flags & SN_FINST_MASK))
3679 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003680 return 1;
3681 }
3682
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003684 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3685 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003686 }
willy tarreau0f7af912005-12-17 12:21:26 +01003687
willy tarreau9fe663a2005-12-17 13:02:59 +01003688 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003689 if (t->cli_addr.ss_family == AF_INET) {
3690 unsigned char *pn;
3691 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3692 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3693 pn[0], pn[1], pn[2], pn[3]);
3694 buffer_replace2(req, req->h, req->h, trash, len);
3695 }
3696 else if (t->cli_addr.ss_family == AF_INET6) {
3697 char pn[INET6_ADDRSTRLEN];
3698 inet_ntop(AF_INET6,
3699 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3700 pn, sizeof(pn));
3701 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3702 buffer_replace2(req, req->h, req->h, trash, len);
3703 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003704 }
3705
willy tarreau25c4ea52005-12-18 00:49:49 +01003706 /* add a "connection: close" line if needed */
3707 if (t->proxy->options & PR_O_HTTP_CLOSE)
3708 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3709
willy tarreau982249e2005-12-18 00:57:06 +01003710 if (!memcmp(req->data, "POST ", 5)) {
3711 /* this is a POST request, which is not cacheable by default */
3712 t->flags |= SN_POST;
3713 }
willy tarreaucd878942005-12-17 13:27:43 +01003714
willy tarreau5cbea6f2005-12-17 12:48:26 +01003715 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003716 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003717
willy tarreau750a4722005-12-17 13:21:24 +01003718 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003719 /* FIXME: we'll set the client in a wait state while we try to
3720 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003721 * better to release the maximum of system buffers instead ?
3722 * The solution is to enable the FD but set its time-out to
3723 * eternity as long as the server-side does not enable data xfer.
3724 * CL_STDATA also has to take care of this, which is done below.
3725 */
willy tarreauef900ab2005-12-17 12:52:52 +01003726 //FD_CLR(t->cli_fd, StaticReadEvent);
3727 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003728
3729 /* FIXME: if we break here (as up to 1.1.23), having the client
3730 * shutdown its connection can lead to an abort further.
3731 * it's better to either return 1 or even jump directly to the
3732 * data state which will save one schedule.
3733 */
3734 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003735
3736 if (!t->proxy->clitimeout ||
3737 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3738 /* If the client has no timeout, or if the server is not ready yet,
3739 * and we know for sure that it can expire, then it's cleaner to
3740 * disable the timeout on the client side so that too low values
3741 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003742 *
3743 * FIXME-20050705: the server needs a way to re-enable this time-out
3744 * when it switches its state, otherwise a client can stay connected
3745 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003746 */
3747 tv_eternity(&t->crexpire);
3748
willy tarreau197e8ec2005-12-17 14:10:59 +01003749 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 }
willy tarreau0f7af912005-12-17 12:21:26 +01003751
Willy TARREAU13032e72006-03-12 17:31:45 +01003752 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3753 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 /* this is a partial header, let's wait for more to come */
3755 req->lr = ptr;
3756 break;
3757 }
willy tarreau0f7af912005-12-17 12:21:26 +01003758
willy tarreau5cbea6f2005-12-17 12:48:26 +01003759 /* now we know that *ptr is either \r or \n,
3760 * and that there are at least 1 char after it.
3761 */
3762 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3763 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3764 else
3765 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003766
willy tarreau5cbea6f2005-12-17 12:48:26 +01003767 /*
3768 * now we know that we have a full header ; we can do whatever
3769 * we want with these pointers :
3770 * req->h = beginning of header
3771 * ptr = end of header (first \r or \n)
3772 * req->lr = beginning of next line (next rep->h)
3773 * req->r = end of data (not used at this stage)
3774 */
willy tarreau0f7af912005-12-17 12:21:26 +01003775
willy tarreau12350152005-12-18 01:03:27 +01003776 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3777 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3778 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3779
3780 /* skip ; */
3781 request_line++;
3782
3783 /* look if we have a jsessionid */
3784
3785 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3786
3787 /* skip jsessionid= */
3788 request_line += t->proxy->appsession_name_len + 1;
3789
3790 /* First try if we allready have an appsession */
3791 asession_temp = &local_asession;
3792
3793 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3794 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3795 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3796 return 0;
3797 }
3798
3799 /* Copy the sessionid */
3800 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3801 asession_temp->sessid[t->proxy->appsession_len] = 0;
3802 asession_temp->serverid = NULL;
3803
3804 /* only do insert, if lookup fails */
3805 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3806 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3807 Alert("Not enough memory process_cli():asession:calloc().\n");
3808 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3809 return 0;
3810 }
3811 asession_temp->sessid = local_asession.sessid;
3812 asession_temp->serverid = local_asession.serverid;
3813 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003814 } /* end if (chtbl_lookup()) */
3815 else {
willy tarreau12350152005-12-18 01:03:27 +01003816 /*free wasted memory;*/
3817 pool_free_to(apools.sessid, local_asession.sessid);
3818 }
3819
3820 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3821 asession_temp->request_count++;
3822
3823#if defined(DEBUG_HASH)
3824 print_table(&(t->proxy->htbl_proxy));
3825#endif
3826
3827 if (asession_temp->serverid == NULL) {
3828 Alert("Found Application Session without matching server.\n");
3829 } else {
3830 struct server *srv = t->proxy->srv;
3831 while (srv) {
3832 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3833 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3834 /* we found the server and it's usable */
3835 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003836 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003837 t->srv = srv;
3838 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003839 } else {
willy tarreau12350152005-12-18 01:03:27 +01003840 t->flags &= ~SN_CK_MASK;
3841 t->flags |= SN_CK_DOWN;
3842 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003843 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003844 srv = srv->next;
3845 }/* end while(srv) */
3846 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003847 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003848 else {
3849 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3850 }
willy tarreau598da412005-12-18 01:07:29 +01003851 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003852 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003853 else{
3854 //printf("No Methode-Header with Session-String\n");
3855 }
3856
willy tarreau8337c6b2005-12-17 13:41:01 +01003857 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003858 /* we have a complete HTTP request that we must log */
3859 int urilen;
3860
willy tarreaua1598082005-12-17 13:08:06 +01003861 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003862 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003863 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003864 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003865 if (!(t->flags & SN_ERR_MASK))
3866 t->flags |= SN_ERR_PRXCOND;
3867 if (!(t->flags & SN_FINST_MASK))
3868 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003869 return 1;
3870 }
3871
3872 urilen = ptr - req->h;
3873 if (urilen >= REQURI_LEN)
3874 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003875 memcpy(t->logs.uri, req->h, urilen);
3876 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003877
willy tarreaua1598082005-12-17 13:08:06 +01003878 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003879 sess_log(t);
3880 }
willy tarreau4302f492005-12-18 01:00:37 +01003881 else if (t->logs.logwait & LW_REQHDR) {
3882 struct cap_hdr *h;
3883 int len;
3884 for (h = t->proxy->req_cap; h; h = h->next) {
3885 if ((h->namelen + 2 <= ptr - req->h) &&
3886 (req->h[h->namelen] == ':') &&
3887 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3888
3889 if (t->req_cap[h->index] == NULL)
3890 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3891
3892 len = ptr - (req->h + h->namelen + 2);
3893 if (len > h->len)
3894 len = h->len;
3895
3896 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3897 t->req_cap[h->index][len]=0;
3898 }
3899 }
3900
3901 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003902
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003904
willy tarreau982249e2005-12-18 00:57:06 +01003905 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003907 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 +01003908 max = ptr - req->h;
3909 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003910 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 trash[len++] = '\n';
3912 write(1, trash, len);
3913 }
willy tarreau0f7af912005-12-17 12:21:26 +01003914
willy tarreau25c4ea52005-12-18 00:49:49 +01003915
3916 /* remove "connection: " if needed */
3917 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3918 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3919 delete_header = 1;
3920 }
3921
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003923 if (!delete_header && t->proxy->req_exp != NULL
3924 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003925 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003926 char term;
3927
3928 term = *ptr;
3929 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003930 exp = t->proxy->req_exp;
3931 do {
3932 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3933 switch (exp->action) {
3934 case ACT_ALLOW:
3935 if (!(t->flags & SN_CLDENY))
3936 t->flags |= SN_CLALLOW;
3937 break;
3938 case ACT_REPLACE:
3939 if (!(t->flags & SN_CLDENY)) {
3940 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3941 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3942 }
3943 break;
3944 case ACT_REMOVE:
3945 if (!(t->flags & SN_CLDENY))
3946 delete_header = 1;
3947 break;
3948 case ACT_DENY:
3949 if (!(t->flags & SN_CLALLOW))
3950 t->flags |= SN_CLDENY;
3951 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003952 case ACT_PASS: /* we simply don't deny this one */
3953 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003954 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003955 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003956 }
willy tarreaue39cd132005-12-17 13:00:18 +01003957 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003958 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003959 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960
willy tarreau240afa62005-12-17 13:14:35 +01003961 /* Now look for cookies. Conforming to RFC2109, we have to support
3962 * attributes whose name begin with a '$', and associate them with
3963 * the right cookie, if we want to delete this cookie.
3964 * So there are 3 cases for each cookie read :
3965 * 1) it's a special attribute, beginning with a '$' : ignore it.
3966 * 2) it's a server id cookie that we *MAY* want to delete : save
3967 * some pointers on it (last semi-colon, beginning of cookie...)
3968 * 3) it's an application cookie : we *MAY* have to delete a previous
3969 * "special" cookie.
3970 * At the end of loop, if a "special" cookie remains, we may have to
3971 * remove it. If no application cookie persists in the header, we
3972 * *MUST* delete it
3973 */
willy tarreau12350152005-12-18 01:03:27 +01003974 if (!delete_header &&
3975 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003976 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003977 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003978 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003979 char *del_colon, *del_cookie, *colon;
3980 int app_cookies;
3981
willy tarreau5cbea6f2005-12-17 12:48:26 +01003982 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003983 colon = p1;
3984 /* del_cookie == NULL => nothing to be deleted */
3985 del_colon = del_cookie = NULL;
3986 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003987
3988 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003989 /* skip spaces and colons, but keep an eye on these ones */
3990 while (p1 < ptr) {
3991 if (*p1 == ';' || *p1 == ',')
3992 colon = p1;
3993 else if (!isspace((int)*p1))
3994 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003995 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003996 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003997
3998 if (p1 == ptr)
3999 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000
4001 /* p1 is at the beginning of the cookie name */
4002 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004003 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 p2++;
4005
4006 if (p2 == ptr)
4007 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004008
4009 p3 = p2 + 1; /* skips the '=' sign */
4010 if (p3 == ptr)
4011 break;
4012
willy tarreau240afa62005-12-17 13:14:35 +01004013 p4 = p3;
4014 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015 p4++;
4016
4017 /* here, we have the cookie name between p1 and p2,
4018 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004019 * we can process it :
4020 *
4021 * Cookie: NAME=VALUE;
4022 * | || || |
4023 * | || || +--> p4
4024 * | || |+-------> p3
4025 * | || +--------> p2
4026 * | |+------------> p1
4027 * | +-------------> colon
4028 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004029 */
4030
willy tarreau240afa62005-12-17 13:14:35 +01004031 if (*p1 == '$') {
4032 /* skip this one */
4033 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004034 else {
4035 /* first, let's see if we want to capture it */
4036 if (t->proxy->capture_name != NULL &&
4037 t->logs.cli_cookie == NULL &&
4038 (p4 - p1 >= t->proxy->capture_namelen) &&
4039 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4040 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004041
willy tarreau8337c6b2005-12-17 13:41:01 +01004042 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4043 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004044 } else {
4045 if (log_len > t->proxy->capture_len)
4046 log_len = t->proxy->capture_len;
4047 memcpy(t->logs.cli_cookie, p1, log_len);
4048 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004051
4052 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4053 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4054 /* Cool... it's the right one */
4055 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004056 char *delim;
4057
4058 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4059 * have the server ID betweek p3 and delim, and the original cookie between
4060 * delim+1 and p4. Otherwise, delim==p4 :
4061 *
4062 * Cookie: NAME=SRV~VALUE;
4063 * | || || | |
4064 * | || || | +--> p4
4065 * | || || +--------> delim
4066 * | || |+-----------> p3
4067 * | || +------------> p2
4068 * | |+----------------> p1
4069 * | +-----------------> colon
4070 * +------------------------> req->h
4071 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004072
willy tarreau0174f312005-12-18 01:02:42 +01004073 if (t->proxy->options & PR_O_COOK_PFX) {
4074 for (delim = p3; delim < p4; delim++)
4075 if (*delim == COOKIE_DELIM)
4076 break;
4077 }
4078 else
4079 delim = p4;
4080
4081
4082 /* Here, we'll look for the first running server which supports the cookie.
4083 * This allows to share a same cookie between several servers, for example
4084 * to dedicate backup servers to specific servers only.
4085 */
4086 while (srv) {
4087 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4088 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4089 /* we found the server and it's usable */
4090 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004091 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004092 t->srv = srv;
4093 break;
willy tarreau12350152005-12-18 01:03:27 +01004094 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004095 /* we found a server, but it's down */
4096 t->flags &= ~SN_CK_MASK;
4097 t->flags |= SN_CK_DOWN;
4098 }
4099 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004100 srv = srv->next;
4101 }
4102
willy tarreau0174f312005-12-18 01:02:42 +01004103 if (!srv && !(t->flags & SN_CK_DOWN)) {
4104 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004105 t->flags &= ~SN_CK_MASK;
4106 t->flags |= SN_CK_INVALID;
4107 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004108
willy tarreau0174f312005-12-18 01:02:42 +01004109 /* depending on the cookie mode, we may have to either :
4110 * - delete the complete cookie if we're in insert+indirect mode, so that
4111 * the server never sees it ;
4112 * - remove the server id from the cookie value, and tag the cookie as an
4113 * application cookie so that it does not get accidentely removed later,
4114 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004115 */
willy tarreau0174f312005-12-18 01:02:42 +01004116 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4117 buffer_replace2(req, p3, delim + 1, NULL, 0);
4118 p4 -= (delim + 1 - p3);
4119 ptr -= (delim + 1 - p3);
4120 del_cookie = del_colon = NULL;
4121 app_cookies++; /* protect the header from deletion */
4122 }
4123 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004124 (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 +01004125 del_cookie = p1;
4126 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004127 }
willy tarreau12350152005-12-18 01:03:27 +01004128 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004129 /* now we know that we must keep this cookie since it's
4130 * not ours. But if we wanted to delete our cookie
4131 * earlier, we cannot remove the complete header, but we
4132 * can remove the previous block itself.
4133 */
4134 app_cookies++;
4135
4136 if (del_cookie != NULL) {
4137 buffer_replace2(req, del_cookie, p1, NULL, 0);
4138 p4 -= (p1 - del_cookie);
4139 ptr -= (p1 - del_cookie);
4140 del_cookie = del_colon = NULL;
4141 }
willy tarreau240afa62005-12-17 13:14:35 +01004142 }
willy tarreau12350152005-12-18 01:03:27 +01004143
4144 if ((t->proxy->appsession_name != NULL) &&
4145 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4146 /* first, let's see if the cookie is our appcookie*/
4147
4148 /* Cool... it's the right one */
4149
4150 asession_temp = &local_asession;
4151
4152 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4153 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4154 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4155 return 0;
4156 }
4157
4158 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4159 asession_temp->sessid[t->proxy->appsession_len] = 0;
4160 asession_temp->serverid = NULL;
4161
4162 /* only do insert, if lookup fails */
4163 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4164 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4165 Alert("Not enough memory process_cli():asession:calloc().\n");
4166 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4167 return 0;
4168 }
4169
4170 asession_temp->sessid = local_asession.sessid;
4171 asession_temp->serverid = local_asession.serverid;
4172 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4173 }
4174 else{
4175 /* free wasted memory */
4176 pool_free_to(apools.sessid, local_asession.sessid);
4177 }
4178
4179 if (asession_temp->serverid == NULL) {
4180 Alert("Found Application Session without matching server.\n");
4181 } else {
4182 struct server *srv = t->proxy->srv;
4183 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004184 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004185 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4186 /* we found the server and it's usable */
4187 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004188 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004189 t->srv = srv;
4190 break;
4191 } else {
4192 t->flags &= ~SN_CK_MASK;
4193 t->flags |= SN_CK_DOWN;
4194 }
4195 }
4196 srv = srv->next;
4197 }/* end while(srv) */
4198 }/* end else if server == NULL */
4199
4200 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004201 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004202 }
willy tarreau240afa62005-12-17 13:14:35 +01004203
willy tarreau5cbea6f2005-12-17 12:48:26 +01004204 /* we'll have to look for another cookie ... */
4205 p1 = p4;
4206 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004207
4208 /* There's no more cookie on this line.
4209 * We may have marked the last one(s) for deletion.
4210 * We must do this now in two ways :
4211 * - if there is no app cookie, we simply delete the header ;
4212 * - if there are app cookies, we must delete the end of the
4213 * string properly, including the colon/semi-colon before
4214 * the cookie name.
4215 */
4216 if (del_cookie != NULL) {
4217 if (app_cookies) {
4218 buffer_replace2(req, del_colon, ptr, NULL, 0);
4219 /* WARNING! <ptr> becomes invalid for now. If some code
4220 * below needs to rely on it before the end of the global
4221 * header loop, we need to correct it with this code :
4222 * ptr = del_colon;
4223 */
4224 }
4225 else
4226 delete_header = 1;
4227 }
4228 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004229
4230 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004231 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004232 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004233 }
willy tarreau240afa62005-12-17 13:14:35 +01004234 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4235
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236 req->h = req->lr;
4237 } /* while (req->lr < req->r) */
4238
4239 /* end of header processing (even if incomplete) */
4240
willy tarreauef900ab2005-12-17 12:52:52 +01004241 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4242 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4243 * full. We cannot loop here since event_cli_read will disable it only if
4244 * req->l == rlim-data
4245 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004246 FD_SET(t->cli_fd, StaticReadEvent);
4247 if (t->proxy->clitimeout)
4248 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4249 else
4250 tv_eternity(&t->crexpire);
4251 }
4252
willy tarreaue39cd132005-12-17 13:00:18 +01004253 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004254 * won't be able to free more later, so the session will never terminate.
4255 */
willy tarreaue39cd132005-12-17 13:00:18 +01004256 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004257 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004258 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004259 if (!(t->flags & SN_ERR_MASK))
4260 t->flags |= SN_ERR_PRXCOND;
4261 if (!(t->flags & SN_FINST_MASK))
4262 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004263 return 1;
4264 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004265 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004266 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 tv_eternity(&t->crexpire);
4268 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004269 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004270 if (!(t->flags & SN_ERR_MASK))
4271 t->flags |= SN_ERR_CLICL;
4272 if (!(t->flags & SN_FINST_MASK))
4273 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004274 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004275 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004276 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4277
4278 /* read timeout : give up with an error message.
4279 */
4280 t->logs.status = 408;
4281 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004282 if (!(t->flags & SN_ERR_MASK))
4283 t->flags |= SN_ERR_CLITO;
4284 if (!(t->flags & SN_FINST_MASK))
4285 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004286 return 1;
4287 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004288
4289 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004290 }
4291 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004292 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004293 /* FIXME: this error handling is partly buggy because we always report
4294 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4295 * or HEADER phase. BTW, it's not logical to expire the client while
4296 * we're waiting for the server to connect.
4297 */
willy tarreau0f7af912005-12-17 12:21:26 +01004298 /* read or write error */
4299 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004300 tv_eternity(&t->crexpire);
4301 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004302 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004303 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004304 if (!(t->flags & SN_ERR_MASK))
4305 t->flags |= SN_ERR_CLICL;
4306 if (!(t->flags & SN_FINST_MASK))
4307 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004308 return 1;
4309 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004310 /* last read, or end of server write */
4311 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004312 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004313 tv_eternity(&t->crexpire);
4314 shutdown(t->cli_fd, SHUT_RD);
4315 t->cli_state = CL_STSHUTR;
4316 return 1;
4317 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004318 /* last server read and buffer empty */
4319 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004320 FD_CLR(t->cli_fd, StaticWriteEvent);
4321 tv_eternity(&t->cwexpire);
4322 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004323 /* We must ensure that the read part is still alive when switching
4324 * to shutw */
4325 FD_SET(t->cli_fd, StaticReadEvent);
4326 if (t->proxy->clitimeout)
4327 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004328 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004329 //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 +01004330 return 1;
4331 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004332 /* read timeout */
4333 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4334 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004335 tv_eternity(&t->crexpire);
4336 shutdown(t->cli_fd, SHUT_RD);
4337 t->cli_state = CL_STSHUTR;
4338 if (!(t->flags & SN_ERR_MASK))
4339 t->flags |= SN_ERR_CLITO;
4340 if (!(t->flags & SN_FINST_MASK))
4341 t->flags |= SN_FINST_D;
4342 return 1;
4343 }
4344 /* write timeout */
4345 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4346 FD_CLR(t->cli_fd, StaticWriteEvent);
4347 tv_eternity(&t->cwexpire);
4348 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004349 /* We must ensure that the read part is still alive when switching
4350 * to shutw */
4351 FD_SET(t->cli_fd, StaticReadEvent);
4352 if (t->proxy->clitimeout)
4353 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4354
willy tarreau036e1ce2005-12-17 13:46:33 +01004355 t->cli_state = CL_STSHUTW;
4356 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004357 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004358 if (!(t->flags & SN_FINST_MASK))
4359 t->flags |= SN_FINST_D;
4360 return 1;
4361 }
willy tarreau0f7af912005-12-17 12:21:26 +01004362
willy tarreauc58fc692005-12-17 14:13:08 +01004363 if (req->l >= req->rlim - req->data) {
4364 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004365 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004366 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004367 FD_CLR(t->cli_fd, StaticReadEvent);
4368 tv_eternity(&t->crexpire);
4369 }
4370 }
4371 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004372 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004373 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4374 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004375 if (!t->proxy->clitimeout ||
4376 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4377 /* If the client has no timeout, or if the server not ready yet, and we
4378 * know for sure that it can expire, then it's cleaner to disable the
4379 * timeout on the client side so that too low values cannot make the
4380 * sessions abort too early.
4381 */
willy tarreau0f7af912005-12-17 12:21:26 +01004382 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004383 else
4384 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004385 }
4386 }
4387
4388 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004389 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004390 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4391 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4392 tv_eternity(&t->cwexpire);
4393 }
4394 }
4395 else { /* buffer not empty */
4396 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4397 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004398 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004399 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004400 /* FIXME: to prevent the client from expiring read timeouts during writes,
4401 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004402 t->crexpire = t->cwexpire;
4403 }
willy tarreau0f7af912005-12-17 12:21:26 +01004404 else
4405 tv_eternity(&t->cwexpire);
4406 }
4407 }
4408 return 0; /* other cases change nothing */
4409 }
4410 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004411 if (t->res_cw == RES_ERROR) {
4412 tv_eternity(&t->cwexpire);
4413 fd_delete(t->cli_fd);
4414 t->cli_state = CL_STCLOSE;
4415 if (!(t->flags & SN_ERR_MASK))
4416 t->flags |= SN_ERR_CLICL;
4417 if (!(t->flags & SN_FINST_MASK))
4418 t->flags |= SN_FINST_D;
4419 return 1;
4420 }
4421 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004422 tv_eternity(&t->cwexpire);
4423 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004424 t->cli_state = CL_STCLOSE;
4425 return 1;
4426 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004427 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4428 tv_eternity(&t->cwexpire);
4429 fd_delete(t->cli_fd);
4430 t->cli_state = CL_STCLOSE;
4431 if (!(t->flags & SN_ERR_MASK))
4432 t->flags |= SN_ERR_CLITO;
4433 if (!(t->flags & SN_FINST_MASK))
4434 t->flags |= SN_FINST_D;
4435 return 1;
4436 }
willy tarreau0f7af912005-12-17 12:21:26 +01004437 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004438 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004439 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4440 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4441 tv_eternity(&t->cwexpire);
4442 }
4443 }
4444 else { /* buffer not empty */
4445 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4446 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004447 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004448 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004449 /* FIXME: to prevent the client from expiring read timeouts during writes,
4450 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004451 t->crexpire = t->cwexpire;
4452 }
willy tarreau0f7af912005-12-17 12:21:26 +01004453 else
4454 tv_eternity(&t->cwexpire);
4455 }
4456 }
4457 return 0;
4458 }
4459 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004460 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004461 tv_eternity(&t->crexpire);
4462 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004463 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004464 if (!(t->flags & SN_ERR_MASK))
4465 t->flags |= SN_ERR_CLICL;
4466 if (!(t->flags & SN_FINST_MASK))
4467 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004468 return 1;
4469 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004470 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4471 tv_eternity(&t->crexpire);
4472 fd_delete(t->cli_fd);
4473 t->cli_state = CL_STCLOSE;
4474 return 1;
4475 }
4476 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4477 tv_eternity(&t->crexpire);
4478 fd_delete(t->cli_fd);
4479 t->cli_state = CL_STCLOSE;
4480 if (!(t->flags & SN_ERR_MASK))
4481 t->flags |= SN_ERR_CLITO;
4482 if (!(t->flags & SN_FINST_MASK))
4483 t->flags |= SN_FINST_D;
4484 return 1;
4485 }
willy tarreauef900ab2005-12-17 12:52:52 +01004486 else if (req->l >= req->rlim - req->data) {
4487 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004488
4489 /* FIXME-20050705: is it possible for a client to maintain a session
4490 * after the timeout by sending more data after it receives a close ?
4491 */
4492
willy tarreau0f7af912005-12-17 12:21:26 +01004493 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004494 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004495 FD_CLR(t->cli_fd, StaticReadEvent);
4496 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004497 //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 +01004498 }
4499 }
4500 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004501 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004502 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4503 FD_SET(t->cli_fd, StaticReadEvent);
4504 if (t->proxy->clitimeout)
4505 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4506 else
4507 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004508 //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 +01004509 }
4510 }
4511 return 0;
4512 }
4513 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004514 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004515 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004516 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 +01004517 write(1, trash, len);
4518 }
4519 return 0;
4520 }
4521 return 0;
4522}
4523
willy tarreaudfece232006-05-02 00:19:57 +02004524/* This function turns the server state into the SV_STCLOSE, and sets
4525 * indicators accordingly. Note that if <status> is 0, no message is
4526 * returned.
4527 */
4528void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4529 t->srv_state = SV_STCLOSE;
4530 if (status > 0) {
4531 t->logs.status = status;
4532 if (t->proxy->mode == PR_MODE_HTTP)
4533 client_return(t, msglen, msg);
4534 }
4535 if (!(t->flags & SN_ERR_MASK))
4536 t->flags |= err;
4537 if (!(t->flags & SN_FINST_MASK))
4538 t->flags |= finst;
4539}
4540
4541/*
4542 * This function checks the retry count during the connect() job.
4543 * It updates the session's srv_state and retries, so that the caller knows
4544 * what it has to do. It uses the last connection error to set the log when
4545 * it expires. It returns 1 when it has expired, and 0 otherwise.
4546 */
4547int srv_count_retry_down(struct session *t, int conn_err) {
4548 /* we are in front of a retryable error */
4549 t->conn_retries--;
4550 if (t->conn_retries < 0) {
4551 /* if not retryable anymore, let's abort */
4552 tv_eternity(&t->cnexpire);
4553 srv_close_with_err(t, conn_err, SN_FINST_C,
4554 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4555
4556 /* We used to have a free connection slot. Since we'll never use it,
4557 * we have to pass it on to another session.
4558 */
4559 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004560 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004561 return 1;
4562 }
4563 return 0;
4564}
willy tarreau0f7af912005-12-17 12:21:26 +01004565
4566/*
willy tarreaudfece232006-05-02 00:19:57 +02004567 * This function performs the retryable part of the connect() job.
4568 * It updates the session's srv_state and retries, so that the caller knows
4569 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4570 * it needs to redispatch.
4571 */
4572int srv_retryable_connect(struct session *t) {
4573 int conn_err;
4574
4575 /* This loop ensures that we stop before the last retry in case of a
4576 * redispatchable server.
4577 */
4578 do {
4579 /* initiate a connection to the server */
4580 conn_err = connect_server(t);
4581 switch (conn_err) {
4582
4583 case SN_ERR_NONE:
4584 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4585 t->srv_state = SV_STCONN;
4586 return 1;
4587
4588 case SN_ERR_INTERNAL:
4589 tv_eternity(&t->cnexpire);
4590 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4591 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4592 /* release other sessions waiting for this server */
4593 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004594 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004595 return 1;
4596 }
4597 /* ensure that we have enough retries left */
4598 if (srv_count_retry_down(t, conn_err))
4599 return 1;
4600 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4601
4602 /* We're on our last chance, and the REDISP option was specified.
4603 * We will ignore cookie and force to balance or use the dispatcher.
4604 */
4605 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4606 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4607 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4608 t->flags &= ~SN_CK_MASK;
4609 t->flags |= SN_CK_DOWN;
4610 }
4611 return 0;
4612}
4613
4614/* This function performs the "redispatch" part of a connection attempt. It
4615 * will assign a server if required, queue the connection if required, and
4616 * handle errors that might arise at this level. It can change the server
4617 * state. It will return 1 if it encounters an error, switches the server
4618 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4619 * that the connection is ready to use.
4620 */
4621
4622int srv_redispatch_connect(struct session *t) {
4623 int conn_err;
4624
4625 /* We know that we don't have any connection pending, so we will
4626 * try to get a new one, and wait in this state if it's queued
4627 */
4628 conn_err = assign_server_and_queue(t);
4629 switch (conn_err) {
4630 case SRV_STATUS_OK:
4631 break;
4632
4633 case SRV_STATUS_NOSRV:
4634 tv_eternity(&t->cnexpire);
4635 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4636 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4637
4638 /* FIXME-20060501: we should not need this once we flush every session
4639 * when the last server goes down.
4640 */
4641 /* release other sessions waiting for this server */
4642 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004643 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004644 return 1;
4645
4646 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004647 /* FIXME-20060503 : we should use the queue timeout instead */
4648 if (t->proxy->contimeout)
4649 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4650 else
4651 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004652 t->srv_state = SV_STIDLE;
4653 /* do nothing else and do not wake any other session up */
4654 return 1;
4655
4656 case SRV_STATUS_FULL:
4657 case SRV_STATUS_INTERNAL:
4658 default:
4659 tv_eternity(&t->cnexpire);
4660 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4661 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4662 /* release other sessions waiting for this server */
4663 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004664 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004665 return 1;
4666 }
4667 /* if we get here, it's because we got SRV_STATUS_OK, which also
4668 * means that the connection has not been queued.
4669 */
4670 return 0;
4671}
4672
4673
4674/*
willy tarreau0f7af912005-12-17 12:21:26 +01004675 * manages the server FSM and its socket. It returns 1 if a state has changed
4676 * (and a resync may be needed), 0 else.
4677 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004678int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004679 int s = t->srv_state;
4680 int c = t->cli_state;
4681 struct buffer *req = t->req;
4682 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004683 appsess *asession_temp = NULL;
4684 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004685 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004686
willy tarreau750a4722005-12-17 13:21:24 +01004687#ifdef DEBUG_FULL
4688 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4689#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004690 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4691 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4692 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4693 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004694 if (s == SV_STIDLE) {
4695 if (c == CL_STHEADERS)
4696 return 0; /* stay in idle, waiting for data to reach the client side */
4697 else if (c == CL_STCLOSE ||
4698 c == CL_STSHUTW ||
4699 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4700 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004701 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
4702
4703 /* it might be possible that we have been granted an access to the
4704 * server while waiting for a free slot. Since we'll never use it,
4705 * we have to pass it on to another session.
4706 */
4707 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004708 offer_connection_slot(t->srv, t->proxy);
willy tarreau0f7af912005-12-17 12:21:26 +01004709 return 1;
4710 }
willy tarreaudfece232006-05-02 00:19:57 +02004711 else {
4712 /* Right now, we will need to create a connection to the server.
4713 * We might already have tried, and got a connection pending, in
4714 * which case we will not do anything till it's pending. It's up
4715 * to any other session to release it and wake us up again.
4716 */
willy tarreau45526ed2006-05-03 20:11:50 +02004717 if (t->pend_pos) {
4718 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4719 return 0;
4720 else {
4721 /* we've been waiting too long here */
4722 tv_eternity(&t->cnexpire);
4723 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4724 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4725 return 1;
4726 }
4727 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004728
willy tarreaudfece232006-05-02 00:19:57 +02004729 do {
4730 /* first, get a connection */
4731 if (srv_redispatch_connect(t))
4732 return t->srv_state != SV_STIDLE;
4733
4734 /* try to (re-)connect to the server, and fail if we expire the
4735 * number of retries.
4736 */
willy tarreauf32f5242006-05-02 22:54:52 +02004737 if (srv_retryable_connect(t)) {
4738 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004739 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004740 }
willy tarreaudfece232006-05-02 00:19:57 +02004741
4742 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004743 }
4744 }
4745 else if (s == SV_STCONN) { /* connection in progress */
4746 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004747 //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 +01004748 return 0; /* nothing changed */
4749 }
4750 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004751 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004752 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004753
willy tarreau0f7af912005-12-17 12:21:26 +01004754 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004755 if (t->srv)
4756 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004757
4758 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004759 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4760 else
willy tarreaudfece232006-05-02 00:19:57 +02004761 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004762
willy tarreaudfece232006-05-02 00:19:57 +02004763 /* ensure that we have enough retries left */
4764 if (srv_count_retry_down(t, conn_err))
4765 return 1;
4766
4767 do {
4768 /* Now we will try to either reconnect to the same server or
4769 * connect to another server. If the connection gets queued
4770 * because all servers are saturated, then we will go back to
4771 * the SV_STIDLE state.
4772 */
willy tarreauf32f5242006-05-02 22:54:52 +02004773 if (srv_retryable_connect(t)) {
4774 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004775 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004776 }
willy tarreaudfece232006-05-02 00:19:57 +02004777
4778 /* we need to redispatch the connection to another server */
4779 if (srv_redispatch_connect(t))
4780 return t->srv_state != SV_STCONN;
4781 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004782 }
4783 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004784 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004785
willy tarreau0f7af912005-12-17 12:21:26 +01004786 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004787 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004788 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004789 tv_eternity(&t->swexpire);
4790 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004791 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004792 if (t->proxy->srvtimeout) {
4793 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004794 /* FIXME: to prevent the server from expiring read timeouts during writes,
4795 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004796 t->srexpire = t->swexpire;
4797 }
4798 else
4799 tv_eternity(&t->swexpire);
4800 }
willy tarreau0f7af912005-12-17 12:21:26 +01004801
4802 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4803 FD_SET(t->srv_fd, StaticReadEvent);
4804 if (t->proxy->srvtimeout)
4805 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4806 else
4807 tv_eternity(&t->srexpire);
4808
4809 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004810 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004811 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004812
4813 /* if the user wants to log as soon as possible, without counting
4814 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004815 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004816 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4817 sess_log(t);
4818 }
willy tarreau0f7af912005-12-17 12:21:26 +01004819 }
willy tarreauef900ab2005-12-17 12:52:52 +01004820 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004821 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004822 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004823 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4824 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004825 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004826 return 1;
4827 }
4828 }
4829 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004830 /* now parse the partial (or complete) headers */
4831 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4832 char *ptr;
4833 int delete_header;
4834
4835 ptr = rep->lr;
4836
4837 /* look for the end of the current header */
4838 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4839 ptr++;
4840
4841 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004842 int line, len;
4843
4844 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004845
4846 /* first, we'll block if security checks have caught nasty things */
4847 if (t->flags & SN_CACHEABLE) {
4848 if ((t->flags & SN_CACHE_COOK) &&
4849 (t->flags & SN_SCK_ANY) &&
4850 (t->proxy->options & PR_O_CHK_CACHE)) {
4851
4852 /* we're in presence of a cacheable response containing
4853 * a set-cookie header. We'll block it as requested by
4854 * the 'checkcache' option, and send an alert.
4855 */
4856 tv_eternity(&t->srexpire);
4857 tv_eternity(&t->swexpire);
4858 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004859 if (t->srv)
4860 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004861 t->srv_state = SV_STCLOSE;
4862 t->logs.status = 502;
4863 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4864 if (!(t->flags & SN_ERR_MASK))
4865 t->flags |= SN_ERR_PRXCOND;
4866 if (!(t->flags & SN_FINST_MASK))
4867 t->flags |= SN_FINST_H;
4868
4869 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4870 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4871
willy tarreaudfece232006-05-02 00:19:57 +02004872 /* We used to have a free connection slot. Since we'll never use it,
4873 * we have to pass it on to another session.
4874 */
4875 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004876 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004877
willy tarreau97f58572005-12-18 00:53:44 +01004878 return 1;
4879 }
4880 }
4881
willy tarreau982249e2005-12-18 00:57:06 +01004882 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4883 if (t->flags & SN_SVDENY) {
4884 tv_eternity(&t->srexpire);
4885 tv_eternity(&t->swexpire);
4886 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004887 if (t->srv)
4888 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004889 t->srv_state = SV_STCLOSE;
4890 t->logs.status = 502;
4891 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4892 if (!(t->flags & SN_ERR_MASK))
4893 t->flags |= SN_ERR_PRXCOND;
4894 if (!(t->flags & SN_FINST_MASK))
4895 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004896 /* We used to have a free connection slot. Since we'll never use it,
4897 * we have to pass it on to another session.
4898 */
4899 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02004900 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02004901
willy tarreau982249e2005-12-18 00:57:06 +01004902 return 1;
4903 }
4904
willy tarreau5cbea6f2005-12-17 12:48:26 +01004905 /* we'll have something else to do here : add new headers ... */
4906
willy tarreaucd878942005-12-17 13:27:43 +01004907 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4908 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004909 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004910 * insert a set-cookie here, except if we want to insert only on POST
4911 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004912 */
willy tarreau750a4722005-12-17 13:21:24 +01004913 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004914 t->proxy->cookie_name,
4915 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004916
willy tarreau036e1ce2005-12-17 13:46:33 +01004917 t->flags |= SN_SCK_INSERTED;
4918
willy tarreau750a4722005-12-17 13:21:24 +01004919 /* Here, we will tell an eventual cache on the client side that we don't
4920 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4921 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4922 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4923 */
willy tarreau240afa62005-12-17 13:14:35 +01004924 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004925 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4926 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004927
4928 if (rep->data + rep->l < rep->h)
4929 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4930 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004931 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004932 }
4933
4934 /* headers to be added */
4935 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004936 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4937 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004938 }
4939
willy tarreau25c4ea52005-12-18 00:49:49 +01004940 /* add a "connection: close" line if needed */
4941 if (t->proxy->options & PR_O_HTTP_CLOSE)
4942 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4943
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004945 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004946 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004947
Willy TARREAU767ba712006-03-01 22:40:50 +01004948 /* client connection already closed or option 'httpclose' required :
4949 * we close the server's outgoing connection right now.
4950 */
4951 if ((req->l == 0) &&
4952 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4953 FD_CLR(t->srv_fd, StaticWriteEvent);
4954 tv_eternity(&t->swexpire);
4955
4956 /* We must ensure that the read part is still alive when switching
4957 * to shutw */
4958 FD_SET(t->srv_fd, StaticReadEvent);
4959 if (t->proxy->srvtimeout)
4960 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4961
4962 shutdown(t->srv_fd, SHUT_WR);
4963 t->srv_state = SV_STSHUTW;
4964 }
4965
willy tarreau25c4ea52005-12-18 00:49:49 +01004966 /* if the user wants to log as soon as possible, without counting
4967 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004968 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004969 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4970 t->logs.bytes = rep->h - rep->data;
4971 sess_log(t);
4972 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004973 break;
4974 }
4975
4976 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4977 if (ptr > rep->r - 2) {
4978 /* this is a partial header, let's wait for more to come */
4979 rep->lr = ptr;
4980 break;
4981 }
4982
4983 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4984 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4985
4986 /* now we know that *ptr is either \r or \n,
4987 * and that there are at least 1 char after it.
4988 */
4989 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4990 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4991 else
4992 rep->lr = ptr + 2; /* \r\n or \n\r */
4993
4994 /*
4995 * now we know that we have a full header ; we can do whatever
4996 * we want with these pointers :
4997 * rep->h = beginning of header
4998 * ptr = end of header (first \r or \n)
4999 * rep->lr = beginning of next line (next rep->h)
5000 * rep->r = end of data (not used at this stage)
5001 */
5002
willy tarreaua1598082005-12-17 13:08:06 +01005003
willy tarreau982249e2005-12-18 00:57:06 +01005004 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005005 t->logs.logwait &= ~LW_RESP;
5006 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005007 switch (t->logs.status) {
5008 case 200:
5009 case 203:
5010 case 206:
5011 case 300:
5012 case 301:
5013 case 410:
5014 /* RFC2616 @13.4:
5015 * "A response received with a status code of
5016 * 200, 203, 206, 300, 301 or 410 MAY be stored
5017 * by a cache (...) unless a cache-control
5018 * directive prohibits caching."
5019 *
5020 * RFC2616 @9.5: POST method :
5021 * "Responses to this method are not cacheable,
5022 * unless the response includes appropriate
5023 * Cache-Control or Expires header fields."
5024 */
5025 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5026 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5027 break;
5028 default:
5029 break;
5030 }
willy tarreau4302f492005-12-18 01:00:37 +01005031 }
5032 else if (t->logs.logwait & LW_RSPHDR) {
5033 struct cap_hdr *h;
5034 int len;
5035 for (h = t->proxy->rsp_cap; h; h = h->next) {
5036 if ((h->namelen + 2 <= ptr - rep->h) &&
5037 (rep->h[h->namelen] == ':') &&
5038 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5039
5040 if (t->rsp_cap[h->index] == NULL)
5041 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5042
5043 len = ptr - (rep->h + h->namelen + 2);
5044 if (len > h->len)
5045 len = h->len;
5046
5047 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5048 t->rsp_cap[h->index][len]=0;
5049 }
5050 }
5051
willy tarreaua1598082005-12-17 13:08:06 +01005052 }
5053
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 delete_header = 0;
5055
willy tarreau982249e2005-12-18 00:57:06 +01005056 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005057 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005058 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 +01005059 max = ptr - rep->h;
5060 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005061 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005062 trash[len++] = '\n';
5063 write(1, trash, len);
5064 }
5065
willy tarreau25c4ea52005-12-18 00:49:49 +01005066 /* remove "connection: " if needed */
5067 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5068 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5069 delete_header = 1;
5070 }
5071
willy tarreau5cbea6f2005-12-17 12:48:26 +01005072 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005073 if (!delete_header && t->proxy->rsp_exp != NULL
5074 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005075 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 char term;
5077
5078 term = *ptr;
5079 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005080 exp = t->proxy->rsp_exp;
5081 do {
5082 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5083 switch (exp->action) {
5084 case ACT_ALLOW:
5085 if (!(t->flags & SN_SVDENY))
5086 t->flags |= SN_SVALLOW;
5087 break;
5088 case ACT_REPLACE:
5089 if (!(t->flags & SN_SVDENY)) {
5090 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5091 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5092 }
5093 break;
5094 case ACT_REMOVE:
5095 if (!(t->flags & SN_SVDENY))
5096 delete_header = 1;
5097 break;
5098 case ACT_DENY:
5099 if (!(t->flags & SN_SVALLOW))
5100 t->flags |= SN_SVDENY;
5101 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005102 case ACT_PASS: /* we simply don't deny this one */
5103 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005104 }
5105 break;
5106 }
willy tarreaue39cd132005-12-17 13:00:18 +01005107 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005108 *ptr = term; /* restore the string terminator */
5109 }
5110
willy tarreau97f58572005-12-18 00:53:44 +01005111 /* check for cache-control: or pragma: headers */
5112 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5113 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5114 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5115 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5116 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005117 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005118 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5119 else {
5120 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005121 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005122 t->flags &= ~SN_CACHE_COOK;
5123 }
5124 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005125 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005126 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005127 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005128 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5129 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005130 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005131 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005132 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5133 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5134 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5135 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5136 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5137 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005138 }
5139 }
5140 }
5141
willy tarreau5cbea6f2005-12-17 12:48:26 +01005142 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005143 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005144 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005145 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005146 char *p1, *p2, *p3, *p4;
5147
willy tarreau97f58572005-12-18 00:53:44 +01005148 t->flags |= SN_SCK_ANY;
5149
willy tarreau5cbea6f2005-12-17 12:48:26 +01005150 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5151
5152 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005153 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154 p1++;
5155
5156 if (p1 == ptr || *p1 == ';') /* end of cookie */
5157 break;
5158
5159 /* p1 is at the beginning of the cookie name */
5160 p2 = p1;
5161
5162 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5163 p2++;
5164
5165 if (p2 == ptr || *p2 == ';') /* next cookie */
5166 break;
5167
5168 p3 = p2 + 1; /* skips the '=' sign */
5169 if (p3 == ptr)
5170 break;
5171
5172 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005173 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005174 p4++;
5175
5176 /* here, we have the cookie name between p1 and p2,
5177 * and its value between p3 and p4.
5178 * we can process it.
5179 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005180
5181 /* first, let's see if we want to capture it */
5182 if (t->proxy->capture_name != NULL &&
5183 t->logs.srv_cookie == NULL &&
5184 (p4 - p1 >= t->proxy->capture_namelen) &&
5185 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5186 int log_len = p4 - p1;
5187
5188 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5189 Alert("HTTP logging : out of memory.\n");
5190 }
5191
5192 if (log_len > t->proxy->capture_len)
5193 log_len = t->proxy->capture_len;
5194 memcpy(t->logs.srv_cookie, p1, log_len);
5195 t->logs.srv_cookie[log_len] = 0;
5196 }
5197
5198 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5199 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005201 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005202
5203 /* If the cookie is in insert mode on a known server, we'll delete
5204 * this occurrence because we'll insert another one later.
5205 * We'll delete it too if the "indirect" option is set and we're in
5206 * a direct access. */
5207 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005208 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005209 /* this header must be deleted */
5210 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005211 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005212 }
5213 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5214 /* replace bytes p3->p4 with the cookie name associated
5215 * with this server since we know it.
5216 */
5217 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005218 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005219 }
willy tarreau0174f312005-12-18 01:02:42 +01005220 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5221 /* insert the cookie name associated with this server
5222 * before existing cookie, and insert a delimitor between them..
5223 */
5224 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5225 p3[t->srv->cklen] = COOKIE_DELIM;
5226 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5227 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228 break;
5229 }
willy tarreau12350152005-12-18 01:03:27 +01005230
5231 /* first, let's see if the cookie is our appcookie*/
5232 if ((t->proxy->appsession_name != NULL) &&
5233 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5234
5235 /* Cool... it's the right one */
5236
willy tarreaub952e1d2005-12-18 01:31:20 +01005237 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005238 asession_temp = &local_asession;
5239
willy tarreaub952e1d2005-12-18 01:31:20 +01005240 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005241 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5242 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5243 }
5244 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5245 asession_temp->sessid[t->proxy->appsession_len] = 0;
5246 asession_temp->serverid = NULL;
5247
5248 /* only do insert, if lookup fails */
5249 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5250 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5251 Alert("Not enought Memory process_srv():asession:calloc().\n");
5252 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5253 return 0;
5254 }
5255 asession_temp->sessid = local_asession.sessid;
5256 asession_temp->serverid = local_asession.serverid;
5257 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005258 }/* end if (chtbl_lookup()) */
5259 else {
willy tarreau12350152005-12-18 01:03:27 +01005260 /* free wasted memory */
5261 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005262 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005263
willy tarreaub952e1d2005-12-18 01:31:20 +01005264 if (asession_temp->serverid == NULL) {
5265 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005266 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5267 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5268 }
5269 asession_temp->serverid[0] = '\0';
5270 }
5271
willy tarreaub952e1d2005-12-18 01:31:20 +01005272 if (asession_temp->serverid[0] == '\0')
5273 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005274
5275 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5276
5277#if defined(DEBUG_HASH)
5278 print_table(&(t->proxy->htbl_proxy));
5279#endif
5280 break;
5281 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005282 else {
5283 // fprintf(stderr,"Ignoring unknown cookie : ");
5284 // write(2, p1, p2-p1);
5285 // fprintf(stderr," = ");
5286 // write(2, p3, p4-p3);
5287 // fprintf(stderr,"\n");
5288 }
5289 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5290 } /* we're now at the end of the cookie value */
5291 } /* end of cookie processing */
5292
willy tarreau97f58572005-12-18 00:53:44 +01005293 /* check for any set-cookie in case we check for cacheability */
5294 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5295 (t->proxy->options & PR_O_CHK_CACHE) &&
5296 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5297 t->flags |= SN_SCK_ANY;
5298 }
5299
willy tarreau5cbea6f2005-12-17 12:48:26 +01005300 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005301 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005302 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005303
willy tarreau5cbea6f2005-12-17 12:48:26 +01005304 rep->h = rep->lr;
5305 } /* while (rep->lr < rep->r) */
5306
5307 /* end of header processing (even if incomplete) */
5308
willy tarreauef900ab2005-12-17 12:52:52 +01005309 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5310 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5311 * full. We cannot loop here since event_srv_read will disable it only if
5312 * rep->l == rlim-data
5313 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005314 FD_SET(t->srv_fd, StaticReadEvent);
5315 if (t->proxy->srvtimeout)
5316 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5317 else
5318 tv_eternity(&t->srexpire);
5319 }
willy tarreau0f7af912005-12-17 12:21:26 +01005320
willy tarreau8337c6b2005-12-17 13:41:01 +01005321 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005322 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005323 tv_eternity(&t->srexpire);
5324 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005325 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005326 if (t->srv)
5327 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005328 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005329 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005330 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005331 if (!(t->flags & SN_ERR_MASK))
5332 t->flags |= SN_ERR_SRVCL;
5333 if (!(t->flags & SN_FINST_MASK))
5334 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005335 /* We used to have a free connection slot. Since we'll never use it,
5336 * we have to pass it on to another session.
5337 */
5338 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005339 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005340
willy tarreau0f7af912005-12-17 12:21:26 +01005341 return 1;
5342 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005343 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005344 * since we are in header mode, if there's no space left for headers, we
5345 * won't be able to free more later, so the session will never terminate.
5346 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005347 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 +01005348 FD_CLR(t->srv_fd, StaticReadEvent);
5349 tv_eternity(&t->srexpire);
5350 shutdown(t->srv_fd, SHUT_RD);
5351 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005352 //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 +01005353 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005354 }
5355 /* read timeout : return a 504 to the client.
5356 */
5357 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5358 tv_eternity(&t->srexpire);
5359 tv_eternity(&t->swexpire);
5360 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005361 if (t->srv)
5362 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005363 t->srv_state = SV_STCLOSE;
5364 t->logs.status = 504;
5365 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005366 if (!(t->flags & SN_ERR_MASK))
5367 t->flags |= SN_ERR_SRVTO;
5368 if (!(t->flags & SN_FINST_MASK))
5369 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005370 /* We used to have a free connection slot. Since we'll never use it,
5371 * we have to pass it on to another session.
5372 */
5373 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005374 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005375
willy tarreau8337c6b2005-12-17 13:41:01 +01005376 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005377 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005378 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005379 /* FIXME!!! here, we don't want to switch to SHUTW if the
5380 * client shuts read too early, because we may still have
5381 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005382 * The side-effect is that if the client completely closes its
5383 * connection during SV_STHEADER, the connection to the server
5384 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005385 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005386 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005387 FD_CLR(t->srv_fd, StaticWriteEvent);
5388 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005389
5390 /* We must ensure that the read part is still alive when switching
5391 * to shutw */
5392 FD_SET(t->srv_fd, StaticReadEvent);
5393 if (t->proxy->srvtimeout)
5394 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5395
willy tarreau0f7af912005-12-17 12:21:26 +01005396 shutdown(t->srv_fd, SHUT_WR);
5397 t->srv_state = SV_STSHUTW;
5398 return 1;
5399 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005400 /* write timeout */
5401 /* FIXME!!! here, we don't want to switch to SHUTW if the
5402 * client shuts read too early, because we may still have
5403 * some work to do on the headers.
5404 */
5405 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5406 FD_CLR(t->srv_fd, StaticWriteEvent);
5407 tv_eternity(&t->swexpire);
5408 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005409 /* We must ensure that the read part is still alive when switching
5410 * to shutw */
5411 FD_SET(t->srv_fd, StaticReadEvent);
5412 if (t->proxy->srvtimeout)
5413 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5414
5415 /* We must ensure that the read part is still alive when switching
5416 * to shutw */
5417 FD_SET(t->srv_fd, StaticReadEvent);
5418 if (t->proxy->srvtimeout)
5419 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5420
willy tarreau036e1ce2005-12-17 13:46:33 +01005421 t->srv_state = SV_STSHUTW;
5422 if (!(t->flags & SN_ERR_MASK))
5423 t->flags |= SN_ERR_SRVTO;
5424 if (!(t->flags & SN_FINST_MASK))
5425 t->flags |= SN_FINST_H;
5426 return 1;
5427 }
willy tarreau0f7af912005-12-17 12:21:26 +01005428
5429 if (req->l == 0) {
5430 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5431 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5432 tv_eternity(&t->swexpire);
5433 }
5434 }
5435 else { /* client buffer not empty */
5436 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5437 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005438 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005439 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005440 /* FIXME: to prevent the server from expiring read timeouts during writes,
5441 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005442 t->srexpire = t->swexpire;
5443 }
willy tarreau0f7af912005-12-17 12:21:26 +01005444 else
5445 tv_eternity(&t->swexpire);
5446 }
5447 }
5448
willy tarreau5cbea6f2005-12-17 12:48:26 +01005449 /* be nice with the client side which would like to send a complete header
5450 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5451 * would read all remaining data at once ! The client should not write past rep->lr
5452 * when the server is in header state.
5453 */
5454 //return header_processed;
5455 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005456 }
5457 else if (s == SV_STDATA) {
5458 /* read or write error */
5459 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005460 tv_eternity(&t->srexpire);
5461 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005462 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005463 if (t->srv)
5464 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005465 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005466 if (!(t->flags & SN_ERR_MASK))
5467 t->flags |= SN_ERR_SRVCL;
5468 if (!(t->flags & SN_FINST_MASK))
5469 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005470 /* We used to have a free connection slot. Since we'll never use it,
5471 * we have to pass it on to another session.
5472 */
5473 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005474 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005475
willy tarreau0f7af912005-12-17 12:21:26 +01005476 return 1;
5477 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005478 /* last read, or end of client write */
5479 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005480 FD_CLR(t->srv_fd, StaticReadEvent);
5481 tv_eternity(&t->srexpire);
5482 shutdown(t->srv_fd, SHUT_RD);
5483 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005484 //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 +01005485 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005486 }
5487 /* end of client read and no more data to send */
5488 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5489 FD_CLR(t->srv_fd, StaticWriteEvent);
5490 tv_eternity(&t->swexpire);
5491 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005492 /* We must ensure that the read part is still alive when switching
5493 * to shutw */
5494 FD_SET(t->srv_fd, StaticReadEvent);
5495 if (t->proxy->srvtimeout)
5496 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5497
willy tarreaua41a8b42005-12-17 14:02:24 +01005498 t->srv_state = SV_STSHUTW;
5499 return 1;
5500 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005501 /* read timeout */
5502 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5503 FD_CLR(t->srv_fd, StaticReadEvent);
5504 tv_eternity(&t->srexpire);
5505 shutdown(t->srv_fd, SHUT_RD);
5506 t->srv_state = SV_STSHUTR;
5507 if (!(t->flags & SN_ERR_MASK))
5508 t->flags |= SN_ERR_SRVTO;
5509 if (!(t->flags & SN_FINST_MASK))
5510 t->flags |= SN_FINST_D;
5511 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005512 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005513 /* write timeout */
5514 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005515 FD_CLR(t->srv_fd, StaticWriteEvent);
5516 tv_eternity(&t->swexpire);
5517 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005518 /* We must ensure that the read part is still alive when switching
5519 * to shutw */
5520 FD_SET(t->srv_fd, StaticReadEvent);
5521 if (t->proxy->srvtimeout)
5522 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005523 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005524 if (!(t->flags & SN_ERR_MASK))
5525 t->flags |= SN_ERR_SRVTO;
5526 if (!(t->flags & SN_FINST_MASK))
5527 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005528 return 1;
5529 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005530
5531 /* recompute request time-outs */
5532 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005533 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5534 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5535 tv_eternity(&t->swexpire);
5536 }
5537 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005538 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005539 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5540 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005541 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005542 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005543 /* FIXME: to prevent the server from expiring read timeouts during writes,
5544 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005545 t->srexpire = t->swexpire;
5546 }
willy tarreau0f7af912005-12-17 12:21:26 +01005547 else
5548 tv_eternity(&t->swexpire);
5549 }
5550 }
5551
willy tarreaub1ff9db2005-12-17 13:51:03 +01005552 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005553 if (rep->l == BUFSIZE) { /* no room to read more data */
5554 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5555 FD_CLR(t->srv_fd, StaticReadEvent);
5556 tv_eternity(&t->srexpire);
5557 }
5558 }
5559 else {
5560 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5561 FD_SET(t->srv_fd, StaticReadEvent);
5562 if (t->proxy->srvtimeout)
5563 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5564 else
5565 tv_eternity(&t->srexpire);
5566 }
5567 }
5568
5569 return 0; /* other cases change nothing */
5570 }
5571 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005572 if (t->res_sw == RES_ERROR) {
5573 //FD_CLR(t->srv_fd, StaticWriteEvent);
5574 tv_eternity(&t->swexpire);
5575 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005576 if (t->srv)
5577 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005578 //close(t->srv_fd);
5579 t->srv_state = SV_STCLOSE;
5580 if (!(t->flags & SN_ERR_MASK))
5581 t->flags |= SN_ERR_SRVCL;
5582 if (!(t->flags & SN_FINST_MASK))
5583 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005584 /* We used to have a free connection slot. Since we'll never use it,
5585 * we have to pass it on to another session.
5586 */
5587 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005588 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005589
willy tarreau036e1ce2005-12-17 13:46:33 +01005590 return 1;
5591 }
5592 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005593 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005594 tv_eternity(&t->swexpire);
5595 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005596 if (t->srv)
5597 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005598 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005599 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005600 /* We used to have a free connection slot. Since we'll never use it,
5601 * we have to pass it on to another session.
5602 */
5603 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005604 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005605
willy tarreau0f7af912005-12-17 12:21:26 +01005606 return 1;
5607 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005608 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5609 //FD_CLR(t->srv_fd, StaticWriteEvent);
5610 tv_eternity(&t->swexpire);
5611 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005612 if (t->srv)
5613 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005614 //close(t->srv_fd);
5615 t->srv_state = SV_STCLOSE;
5616 if (!(t->flags & SN_ERR_MASK))
5617 t->flags |= SN_ERR_SRVTO;
5618 if (!(t->flags & SN_FINST_MASK))
5619 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005620 /* We used to have a free connection slot. Since we'll never use it,
5621 * we have to pass it on to another session.
5622 */
5623 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005624 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005625
willy tarreau036e1ce2005-12-17 13:46:33 +01005626 return 1;
5627 }
willy tarreau0f7af912005-12-17 12:21:26 +01005628 else if (req->l == 0) {
5629 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5630 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5631 tv_eternity(&t->swexpire);
5632 }
5633 }
5634 else { /* buffer not empty */
5635 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5636 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005637 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005638 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005639 /* FIXME: to prevent the server from expiring read timeouts during writes,
5640 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005641 t->srexpire = t->swexpire;
5642 }
willy tarreau0f7af912005-12-17 12:21:26 +01005643 else
5644 tv_eternity(&t->swexpire);
5645 }
5646 }
5647 return 0;
5648 }
5649 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005650 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005651 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005652 tv_eternity(&t->srexpire);
5653 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005654 if (t->srv)
5655 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005656 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005657 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005658 if (!(t->flags & SN_ERR_MASK))
5659 t->flags |= SN_ERR_SRVCL;
5660 if (!(t->flags & SN_FINST_MASK))
5661 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005662 /* We used to have a free connection slot. Since we'll never use it,
5663 * we have to pass it on to another session.
5664 */
5665 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005666 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005667
willy tarreau0f7af912005-12-17 12:21:26 +01005668 return 1;
5669 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005670 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5671 //FD_CLR(t->srv_fd, StaticReadEvent);
5672 tv_eternity(&t->srexpire);
5673 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005674 if (t->srv)
5675 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005676 //close(t->srv_fd);
5677 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005678 /* We used to have a free connection slot. Since we'll never use it,
5679 * we have to pass it on to another session.
5680 */
5681 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005682 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005683
willy tarreau036e1ce2005-12-17 13:46:33 +01005684 return 1;
5685 }
5686 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5687 //FD_CLR(t->srv_fd, StaticReadEvent);
5688 tv_eternity(&t->srexpire);
5689 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005690 if (t->srv)
5691 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005692 //close(t->srv_fd);
5693 t->srv_state = SV_STCLOSE;
5694 if (!(t->flags & SN_ERR_MASK))
5695 t->flags |= SN_ERR_SRVTO;
5696 if (!(t->flags & SN_FINST_MASK))
5697 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005698 /* We used to have a free connection slot. Since we'll never use it,
5699 * we have to pass it on to another session.
5700 */
5701 if (t->srv)
willy tarreaubc2eda62006-05-04 15:16:23 +02005702 offer_connection_slot(t->srv, t->proxy);
willy tarreaudfece232006-05-02 00:19:57 +02005703
willy tarreau036e1ce2005-12-17 13:46:33 +01005704 return 1;
5705 }
willy tarreau0f7af912005-12-17 12:21:26 +01005706 else if (rep->l == BUFSIZE) { /* no room to read more data */
5707 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5708 FD_CLR(t->srv_fd, StaticReadEvent);
5709 tv_eternity(&t->srexpire);
5710 }
5711 }
5712 else {
5713 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5714 FD_SET(t->srv_fd, StaticReadEvent);
5715 if (t->proxy->srvtimeout)
5716 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5717 else
5718 tv_eternity(&t->srexpire);
5719 }
5720 }
5721 return 0;
5722 }
5723 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005724 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005725 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005726 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 +01005727 write(1, trash, len);
5728 }
5729 return 0;
5730 }
5731 return 0;
5732}
5733
5734
willy tarreau5cbea6f2005-12-17 12:48:26 +01005735/* Processes the client and server jobs of a session task, then
5736 * puts it back to the wait queue in a clean state, or
5737 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005738 * the time the task accepts to wait, or TIME_ETERNITY for
5739 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005740 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005741int process_session(struct task *t) {
5742 struct session *s = t->context;
5743 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005744
willy tarreau5cbea6f2005-12-17 12:48:26 +01005745 do {
5746 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005747 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005748 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005749 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005750 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005751 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005752 } while (fsm_resync);
5753
5754 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005755 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005756 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005757
willy tarreau5cbea6f2005-12-17 12:48:26 +01005758 tv_min(&min1, &s->crexpire, &s->cwexpire);
5759 tv_min(&min2, &s->srexpire, &s->swexpire);
5760 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005761 tv_min(&t->expire, &min1, &min2);
5762
5763 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005764 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005765
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005766#ifdef DEBUG_FULL
5767 /* DEBUG code : this should never ever happen, otherwise it indicates
5768 * that a task still has something to do and will provoke a quick loop.
5769 */
5770 if (tv_remain2(&now, &t->expire) <= 0)
5771 exit(100);
5772#endif
5773
willy tarreaub952e1d2005-12-18 01:31:20 +01005774 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005775 }
5776
willy tarreau5cbea6f2005-12-17 12:48:26 +01005777 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005778 actconn--;
5779
willy tarreau982249e2005-12-18 00:57:06 +01005780 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005781 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005782 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 +01005783 write(1, trash, len);
5784 }
5785
willy tarreau750a4722005-12-17 13:21:24 +01005786 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005787 if (s->rep != NULL)
5788 s->logs.bytes = s->rep->total;
5789
willy tarreau9fe663a2005-12-17 13:02:59 +01005790 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005791 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005792 sess_log(s);
5793
willy tarreau0f7af912005-12-17 12:21:26 +01005794 /* the task MUST not be in the run queue anymore */
5795 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005796 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005797 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005798 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005799}
5800
5801
willy tarreau2812edc2006-05-04 12:09:37 +02005802/* Sets server <s> down, notifies by all available means, recounts the
5803 * remaining servers on the proxy and transfers queued sessions whenever
5804 * possible to other servers.
5805 */
5806void set_server_down(struct server *s) {
5807 struct pendconn *pc, *pc_bck, *pc_end;
5808 struct session *sess;
5809 int xferred;
5810
5811 s->state &= ~SRV_RUNNING;
5812
5813 if (s->health == s->rise) {
5814 recount_servers(s->proxy);
5815 recalc_server_map(s->proxy);
5816
5817 /* we might have sessions queued on this server and waiting for
5818 * a connection. Those which are redispatchable will be queued
5819 * to another server or to the proxy itself.
5820 */
5821 xferred = 0;
5822 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5823 sess = pc->sess;
5824 if ((sess->proxy->options & PR_O_REDISP)) {
5825 /* The REDISP option was specified. We will ignore
5826 * cookie and force to balance or use the dispatcher.
5827 */
5828 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5829 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5830 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5831 sess->flags &= ~SN_CK_MASK;
5832 sess->flags |= SN_CK_DOWN;
5833 }
5834 pendconn_free(pc);
5835 task_wakeup(&rq, sess->task);
5836 xferred++;
5837 }
5838 }
5839
5840 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5841 " %d sessions active, %d requeued, %d remaining in queue.\n",
5842 s->state & SRV_BACKUP ? "Backup " : "",
5843 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5844 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5845 s->cur_sess, xferred, s->nbpend);
5846
willy tarreaubc2eda62006-05-04 15:16:23 +02005847 Warning("%s", trash);
5848 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005849
5850 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5851 Alert("Proxy %s has no server available !\n", s->proxy->id);
5852 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5853 }
5854 }
5855 s->health = 0; /* failure */
5856}
5857
5858
willy tarreau5cbea6f2005-12-17 12:48:26 +01005859
5860/*
5861 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005862 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005863 */
5864int process_chk(struct task *t) {
5865 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005866 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005867 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005868
willy tarreauef900ab2005-12-17 12:52:52 +01005869 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005870
willy tarreau25424f82006-03-19 19:37:48 +01005871 new_chk:
5872 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005873 if (fd < 0) { /* no check currently running */
5874 //fprintf(stderr, "process_chk: 2\n");
5875 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5876 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005877 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005878 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005879
5880 /* we don't send any health-checks when the proxy is stopped or when
5881 * the server should not be checked.
5882 */
5883 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005884 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5885 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005886 task_queue(t); /* restore t to its place in the task list */
5887 return tv_remain2(&now, &t->expire);
5888 }
5889
willy tarreau5cbea6f2005-12-17 12:48:26 +01005890 /* we'll initiate a new check */
5891 s->result = 0; /* no result yet */
5892 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005893 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005894 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5895 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5896 //fprintf(stderr, "process_chk: 3\n");
5897
willy tarreaua41a8b42005-12-17 14:02:24 +01005898 /* we'll connect to the check port on the server */
5899 sa = s->addr;
5900 sa.sin_port = htons(s->check_port);
5901
willy tarreau0174f312005-12-18 01:02:42 +01005902 /* allow specific binding :
5903 * - server-specific at first
5904 * - proxy-specific next
5905 */
5906 if (s->state & SRV_BIND_SRC) {
5907 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5908 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5909 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5910 s->proxy->id, s->id);
5911 s->result = -1;
5912 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005913 }
willy tarreau0174f312005-12-18 01:02:42 +01005914 else if (s->proxy->options & PR_O_BIND_SRC) {
5915 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5916 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5917 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5918 s->proxy->id);
5919 s->result = -1;
5920 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005921 }
willy tarreau0174f312005-12-18 01:02:42 +01005922
5923 if (!s->result) {
5924 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5925 /* OK, connection in progress or established */
5926
5927 //fprintf(stderr, "process_chk: 4\n");
5928
5929 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5930 fdtab[fd].owner = t;
5931 fdtab[fd].read = &event_srv_chk_r;
5932 fdtab[fd].write = &event_srv_chk_w;
5933 fdtab[fd].state = FD_STCONN; /* connection in progress */
5934 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005935#ifdef DEBUG_FULL
5936 assert (!FD_ISSET(fd, StaticReadEvent));
5937#endif
willy tarreau0174f312005-12-18 01:02:42 +01005938 fd_insert(fd);
5939 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5940 tv_delayfrom(&t->expire, &now, s->inter);
5941 task_queue(t); /* restore t to its place in the task list */
5942 return tv_remain(&now, &t->expire);
5943 }
5944 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5945 s->result = -1; /* a real error */
5946 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005947 }
5948 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005949 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005950 }
5951
5952 if (!s->result) { /* nothing done */
5953 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005954 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5955 tv_delayfrom(&t->expire, &t->expire, s->inter);
5956 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005957 }
5958
5959 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005960 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005961 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02005962 else
5963 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005964
5965 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005966 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005967 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5968 tv_delayfrom(&t->expire, &t->expire, s->inter);
5969 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005970 }
5971 else {
5972 //fprintf(stderr, "process_chk: 8\n");
5973 /* there was a test running */
5974 if (s->result > 0) { /* good server detected */
5975 //fprintf(stderr, "process_chk: 9\n");
5976 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005977 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005978 s->state |= SRV_RUNNING;
5979
willy tarreau535ae7a2005-12-17 12:58:00 +01005980 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02005981 int xferred;
5982
willy tarreau62084d42006-03-24 18:57:41 +01005983 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005984 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02005985
5986 /* check if we can handle some connections queued at the proxy. We
5987 * will take as many as we can handle.
5988 */
5989 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
5990 struct session *sess;
5991 struct pendconn *p;
5992
5993 p = pendconn_from_px(s->proxy);
5994 if (!p)
5995 break;
5996 p->sess->srv = s;
5997 sess = p->sess;
5998 pendconn_free(p);
5999 task_wakeup(&rq, sess->task);
6000 }
6001
6002 sprintf(trash,
6003 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6004 " %d sessions requeued, %d total in queue.\n",
6005 s->state & SRV_BACKUP ? "Backup " : "",
6006 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6007 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6008 xferred, s->nbpend);
6009
6010 Warning("%s", trash);
6011 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006012 }
willy tarreauef900ab2005-12-17 12:52:52 +01006013
willy tarreaue47c8d72005-12-17 12:55:52 +01006014 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006015 }
willy tarreauef900ab2005-12-17 12:52:52 +01006016 s->curfd = -1; /* no check running anymore */
6017 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006018 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006019 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6020 tv_delayfrom(&t->expire, &t->expire, s->inter);
6021 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006022 }
6023 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6024 //fprintf(stderr, "process_chk: 10\n");
6025 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006026 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006027 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006028 else
6029 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006030 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006031 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006032 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006033 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6034 tv_delayfrom(&t->expire, &t->expire, s->inter);
6035 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006036 }
6037 /* if result is 0 and there's no timeout, we have to wait again */
6038 }
6039 //fprintf(stderr, "process_chk: 11\n");
6040 s->result = 0;
6041 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006042 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006043}
6044
6045
willy tarreau5cbea6f2005-12-17 12:48:26 +01006046
willy tarreau0f7af912005-12-17 12:21:26 +01006047#if STATTIME > 0
6048int stats(void);
6049#endif
6050
6051/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006052 * This does 4 things :
6053 * - wake up all expired tasks
6054 * - call all runnable tasks
6055 * - call maintain_proxies() to enable/disable the listeners
6056 * - return the delay till next event in ms, -1 = wait indefinitely
6057 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6058 *
willy tarreau0f7af912005-12-17 12:21:26 +01006059 */
6060
willy tarreau1c2ad212005-12-18 01:11:29 +01006061int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006062 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006063 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006064 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006065
willy tarreaub952e1d2005-12-18 01:31:20 +01006066 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006067
willy tarreau1c2ad212005-12-18 01:11:29 +01006068 /* look for expired tasks and add them to the run queue.
6069 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006070 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6071 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006072 tnext = t->next;
6073 if (t->state & TASK_RUNNING)
6074 continue;
6075
willy tarreaub952e1d2005-12-18 01:31:20 +01006076 if (tv_iseternity(&t->expire))
6077 continue;
6078
willy tarreau1c2ad212005-12-18 01:11:29 +01006079 /* wakeup expired entries. It doesn't matter if they are
6080 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006081 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006082 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006083 task_wakeup(&rq, t);
6084 }
6085 else {
6086 /* first non-runnable task. Use its expiration date as an upper bound */
6087 int temp_time = tv_remain(&now, &t->expire);
6088 if (temp_time)
6089 next_time = temp_time;
6090 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006091 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006092 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006093
willy tarreau1c2ad212005-12-18 01:11:29 +01006094 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006095 * since we only use the run queue's head. Note that any task can be
6096 * woken up by any other task and it will be processed immediately
6097 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006098 */
willy tarreau7feab592006-04-22 15:13:16 +02006099 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006100 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006101
willy tarreau1c2ad212005-12-18 01:11:29 +01006102 task_sleep(&rq, t);
6103 temp_time = t->process(t);
6104 next_time = MINTIME(temp_time, next_time);
6105 }
6106
6107 /* maintain all proxies in a consistent state. This should quickly become a task */
6108 time2 = maintain_proxies();
6109 return MINTIME(time2, next_time);
6110}
6111
6112
6113#if defined(ENABLE_EPOLL)
6114
6115/*
6116 * Main epoll() loop.
6117 */
6118
6119/* does 3 actions :
6120 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6121 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6122 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6123 *
6124 * returns 0 if initialization failed, !0 otherwise.
6125 */
6126
6127int epoll_loop(int action) {
6128 int next_time;
6129 int status;
6130 int fd;
6131
6132 int fds, count;
6133 int pr, pw, sr, sw;
6134 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6135 struct epoll_event ev;
6136
6137 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006138 static struct epoll_event *epoll_events = NULL;
6139 static int epoll_fd;
6140
6141 if (action == POLL_LOOP_ACTION_INIT) {
6142 epoll_fd = epoll_create(global.maxsock + 1);
6143 if (epoll_fd < 0)
6144 return 0;
6145 else {
6146 epoll_events = (struct epoll_event*)
6147 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6148 PrevReadEvent = (fd_set *)
6149 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6150 PrevWriteEvent = (fd_set *)
6151 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006152 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006153 return 1;
6154 }
6155 else if (action == POLL_LOOP_ACTION_CLEAN) {
6156 if (PrevWriteEvent) free(PrevWriteEvent);
6157 if (PrevReadEvent) free(PrevReadEvent);
6158 if (epoll_events) free(epoll_events);
6159 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006160 epoll_fd = 0;
6161 return 1;
6162 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006163
willy tarreau1c2ad212005-12-18 01:11:29 +01006164 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006165
willy tarreau1c2ad212005-12-18 01:11:29 +01006166 tv_now(&now);
6167
6168 while (1) {
6169 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006170
6171 /* stop when there's no connection left and we don't allow them anymore */
6172 if (!actconn && listeners == 0)
6173 break;
6174
willy tarreau0f7af912005-12-17 12:21:26 +01006175#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006176 {
6177 int time2;
6178 time2 = stats();
6179 next_time = MINTIME(time2, next_time);
6180 }
willy tarreau0f7af912005-12-17 12:21:26 +01006181#endif
6182
willy tarreau1c2ad212005-12-18 01:11:29 +01006183 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6184
6185 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6186 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6187
6188 if ((ro^rn) | (wo^wn)) {
6189 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6190#define FDSETS_ARE_INT_ALIGNED
6191#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006192
willy tarreauad90a0c2005-12-18 01:09:15 +01006193#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6194#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006195 pr = (ro >> count) & 1;
6196 pw = (wo >> count) & 1;
6197 sr = (rn >> count) & 1;
6198 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006199#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006200 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6201 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6202 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6203 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006204#endif
6205#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006206 pr = FD_ISSET(fd, PrevReadEvent);
6207 pw = FD_ISSET(fd, PrevWriteEvent);
6208 sr = FD_ISSET(fd, StaticReadEvent);
6209 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006210#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006211 if (!((sr^pr) | (sw^pw)))
6212 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006213
willy tarreau1c2ad212005-12-18 01:11:29 +01006214 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6215 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006216
willy tarreaub952e1d2005-12-18 01:31:20 +01006217#ifdef EPOLL_CTL_MOD_WORKAROUND
6218 /* I encountered a rarely reproducible problem with
6219 * EPOLL_CTL_MOD where a modified FD (systematically
6220 * the one in epoll_events[0], fd#7) would sometimes
6221 * be set EPOLL_OUT while asked for a read ! This is
6222 * with the 2.4 epoll patch. The workaround is to
6223 * delete then recreate in case of modification.
6224 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6225 * nor RHEL kernels.
6226 */
6227
6228 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6229 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6230
6231 if ((sr | sw))
6232 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6233#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006234 if ((pr | pw)) {
6235 /* the file-descriptor already exists... */
6236 if ((sr | sw)) {
6237 /* ...and it will still exist */
6238 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6239 // perror("epoll_ctl(MOD)");
6240 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006241 }
6242 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006243 /* ...and it will be removed */
6244 if (fdtab[fd].state != FD_STCLOSE &&
6245 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6246 // perror("epoll_ctl(DEL)");
6247 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006248 }
6249 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006250 } else {
6251 /* the file-descriptor did not exist, let's add it */
6252 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6253 // perror("epoll_ctl(ADD)");
6254 // exit(1);
6255 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006256 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006257#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006258 }
6259 ((int*)PrevReadEvent)[fds] = rn;
6260 ((int*)PrevWriteEvent)[fds] = wn;
6261 }
6262 }
6263
6264 /* now let's wait for events */
6265 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6266 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006267
willy tarreau1c2ad212005-12-18 01:11:29 +01006268 for (count = 0; count < status; count++) {
6269 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006270
6271 if (FD_ISSET(fd, StaticReadEvent)) {
6272 if (fdtab[fd].state == FD_STCLOSE)
6273 continue;
6274 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6275 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006276 }
willy tarreau05be12b2006-03-19 19:35:00 +01006277
6278 if (FD_ISSET(fd, StaticWriteEvent)) {
6279 if (fdtab[fd].state == FD_STCLOSE)
6280 continue;
6281 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6282 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006283 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006284 }
6285 }
6286 return 1;
6287}
6288#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006289
willy tarreauad90a0c2005-12-18 01:09:15 +01006290
willy tarreau5cbea6f2005-12-17 12:48:26 +01006291
willy tarreau1c2ad212005-12-18 01:11:29 +01006292#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006293
willy tarreau1c2ad212005-12-18 01:11:29 +01006294/*
6295 * Main poll() loop.
6296 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006297
willy tarreau1c2ad212005-12-18 01:11:29 +01006298/* does 3 actions :
6299 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6300 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6301 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6302 *
6303 * returns 0 if initialization failed, !0 otherwise.
6304 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006305
willy tarreau1c2ad212005-12-18 01:11:29 +01006306int poll_loop(int action) {
6307 int next_time;
6308 int status;
6309 int fd, nbfd;
6310
6311 int fds, count;
6312 int sr, sw;
6313 unsigned rn, wn; /* read new, write new */
6314
6315 /* private data */
6316 static struct pollfd *poll_events = NULL;
6317
6318 if (action == POLL_LOOP_ACTION_INIT) {
6319 poll_events = (struct pollfd*)
6320 calloc(1, sizeof(struct pollfd) * global.maxsock);
6321 return 1;
6322 }
6323 else if (action == POLL_LOOP_ACTION_CLEAN) {
6324 if (poll_events)
6325 free(poll_events);
6326 return 1;
6327 }
6328
6329 /* OK, it's POLL_LOOP_ACTION_RUN */
6330
6331 tv_now(&now);
6332
6333 while (1) {
6334 next_time = process_runnable_tasks();
6335
6336 /* stop when there's no connection left and we don't allow them anymore */
6337 if (!actconn && listeners == 0)
6338 break;
6339
6340#if STATTIME > 0
6341 {
6342 int time2;
6343 time2 = stats();
6344 next_time = MINTIME(time2, next_time);
6345 }
6346#endif
6347
6348
6349 nbfd = 0;
6350 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6351
6352 rn = ((int*)StaticReadEvent)[fds];
6353 wn = ((int*)StaticWriteEvent)[fds];
6354
6355 if ((rn|wn)) {
6356 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6357#define FDSETS_ARE_INT_ALIGNED
6358#ifdef FDSETS_ARE_INT_ALIGNED
6359
6360#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6361#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6362 sr = (rn >> count) & 1;
6363 sw = (wn >> count) & 1;
6364#else
6365 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6366 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6367#endif
6368#else
6369 sr = FD_ISSET(fd, StaticReadEvent);
6370 sw = FD_ISSET(fd, StaticWriteEvent);
6371#endif
6372 if ((sr|sw)) {
6373 poll_events[nbfd].fd = fd;
6374 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6375 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006376 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006377 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006378 }
6379 }
6380
6381 /* now let's wait for events */
6382 status = poll(poll_events, nbfd, next_time);
6383 tv_now(&now);
6384
6385 for (count = 0; status > 0 && count < nbfd; count++) {
6386 fd = poll_events[count].fd;
6387
6388 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6389 continue;
6390
6391 /* ok, we found one active fd */
6392 status--;
6393
willy tarreau05be12b2006-03-19 19:35:00 +01006394 if (FD_ISSET(fd, StaticReadEvent)) {
6395 if (fdtab[fd].state == FD_STCLOSE)
6396 continue;
6397 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6398 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006399 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006400
willy tarreau05be12b2006-03-19 19:35:00 +01006401 if (FD_ISSET(fd, StaticWriteEvent)) {
6402 if (fdtab[fd].state == FD_STCLOSE)
6403 continue;
6404 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6405 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006406 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006407 }
6408 }
6409 return 1;
6410}
willy tarreauad90a0c2005-12-18 01:09:15 +01006411#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006412
willy tarreauad90a0c2005-12-18 01:09:15 +01006413
willy tarreauad90a0c2005-12-18 01:09:15 +01006414
willy tarreau1c2ad212005-12-18 01:11:29 +01006415/*
6416 * Main select() loop.
6417 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006418
willy tarreau1c2ad212005-12-18 01:11:29 +01006419/* does 3 actions :
6420 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6421 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6422 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6423 *
6424 * returns 0 if initialization failed, !0 otherwise.
6425 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006426
willy tarreauad90a0c2005-12-18 01:09:15 +01006427
willy tarreau1c2ad212005-12-18 01:11:29 +01006428int select_loop(int action) {
6429 int next_time;
6430 int status;
6431 int fd,i;
6432 struct timeval delta;
6433 int readnotnull, writenotnull;
6434 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006435
willy tarreau1c2ad212005-12-18 01:11:29 +01006436 if (action == POLL_LOOP_ACTION_INIT) {
6437 ReadEvent = (fd_set *)
6438 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6439 WriteEvent = (fd_set *)
6440 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6441 return 1;
6442 }
6443 else if (action == POLL_LOOP_ACTION_CLEAN) {
6444 if (WriteEvent) free(WriteEvent);
6445 if (ReadEvent) free(ReadEvent);
6446 return 1;
6447 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006448
willy tarreau1c2ad212005-12-18 01:11:29 +01006449 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006450
willy tarreau1c2ad212005-12-18 01:11:29 +01006451 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006452
willy tarreau1c2ad212005-12-18 01:11:29 +01006453 while (1) {
6454 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006455
willy tarreau1c2ad212005-12-18 01:11:29 +01006456 /* stop when there's no connection left and we don't allow them anymore */
6457 if (!actconn && listeners == 0)
6458 break;
6459
6460#if STATTIME > 0
6461 {
6462 int time2;
6463 time2 = stats();
6464 next_time = MINTIME(time2, next_time);
6465 }
6466#endif
6467
willy tarreau1c2ad212005-12-18 01:11:29 +01006468 if (next_time > 0) { /* FIXME */
6469 /* Convert to timeval */
6470 /* to avoid eventual select loops due to timer precision */
6471 next_time += SCHEDULER_RESOLUTION;
6472 delta.tv_sec = next_time / 1000;
6473 delta.tv_usec = (next_time % 1000) * 1000;
6474 }
6475 else if (next_time == 0) { /* allow select to return immediately when needed */
6476 delta.tv_sec = delta.tv_usec = 0;
6477 }
6478
6479
6480 /* let's restore fdset state */
6481
6482 readnotnull = 0; writenotnull = 0;
6483 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6484 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6485 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6486 }
6487
6488 // /* just a verification code, needs to be removed for performance */
6489 // for (i=0; i<maxfd; i++) {
6490 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6491 // abort();
6492 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6493 // abort();
6494 //
6495 // }
6496
6497 status = select(maxfd,
6498 readnotnull ? ReadEvent : NULL,
6499 writenotnull ? WriteEvent : NULL,
6500 NULL,
6501 (next_time >= 0) ? &delta : NULL);
6502
6503 /* this is an experiment on the separation of the select work */
6504 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6505 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6506
6507 tv_now(&now);
6508
6509 if (status > 0) { /* must proceed with events */
6510
6511 int fds;
6512 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006513
willy tarreau1c2ad212005-12-18 01:11:29 +01006514 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6515 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6516 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6517
6518 /* if we specify read first, the accepts and zero reads will be
6519 * seen first. Moreover, system buffers will be flushed faster.
6520 */
willy tarreau05be12b2006-03-19 19:35:00 +01006521 if (FD_ISSET(fd, ReadEvent)) {
6522 if (fdtab[fd].state == FD_STCLOSE)
6523 continue;
6524 fdtab[fd].read(fd);
6525 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006526
willy tarreau05be12b2006-03-19 19:35:00 +01006527 if (FD_ISSET(fd, WriteEvent)) {
6528 if (fdtab[fd].state == FD_STCLOSE)
6529 continue;
6530 fdtab[fd].write(fd);
6531 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006532 }
6533 }
6534 else {
6535 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006536 }
willy tarreau0f7af912005-12-17 12:21:26 +01006537 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006538 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006539}
6540
6541
6542#if STATTIME > 0
6543/*
6544 * Display proxy statistics regularly. It is designed to be called from the
6545 * select_loop().
6546 */
6547int stats(void) {
6548 static int lines;
6549 static struct timeval nextevt;
6550 static struct timeval lastevt;
6551 static struct timeval starttime = {0,0};
6552 unsigned long totaltime, deltatime;
6553 int ret;
6554
willy tarreau750a4722005-12-17 13:21:24 +01006555 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006556 deltatime = (tv_diff(&lastevt, &now)?:1);
6557 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006558
willy tarreau9fe663a2005-12-17 13:02:59 +01006559 if (global.mode & MODE_STATS) {
6560 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006561 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006562 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6563 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006564 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006565 actconn, totalconn,
6566 stats_tsk_new, stats_tsk_good,
6567 stats_tsk_left, stats_tsk_right,
6568 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6569 }
6570 }
6571
6572 tv_delayfrom(&nextevt, &now, STATTIME);
6573
6574 lastevt=now;
6575 }
6576 ret = tv_remain(&now, &nextevt);
6577 return ret;
6578}
6579#endif
6580
6581
6582/*
6583 * this function enables proxies when there are enough free sessions,
6584 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006585 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006586 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006587 */
6588static int maintain_proxies(void) {
6589 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006590 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006591 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006592
6593 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006594 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006595
6596 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006597 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006598 while (p) {
6599 if (p->nbconn < p->maxconn) {
6600 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006601 for (l = p->listen; l != NULL; l = l->next) {
6602 FD_SET(l->fd, StaticReadEvent);
6603 }
willy tarreau0f7af912005-12-17 12:21:26 +01006604 p->state = PR_STRUN;
6605 }
6606 }
6607 else {
6608 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006609 for (l = p->listen; l != NULL; l = l->next) {
6610 FD_CLR(l->fd, StaticReadEvent);
6611 }
willy tarreau0f7af912005-12-17 12:21:26 +01006612 p->state = PR_STIDLE;
6613 }
6614 }
6615 p = p->next;
6616 }
6617 }
6618 else { /* block all proxies */
6619 while (p) {
6620 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006621 for (l = p->listen; l != NULL; l = l->next) {
6622 FD_CLR(l->fd, StaticReadEvent);
6623 }
willy tarreau0f7af912005-12-17 12:21:26 +01006624 p->state = PR_STIDLE;
6625 }
6626 p = p->next;
6627 }
6628 }
6629
willy tarreau5cbea6f2005-12-17 12:48:26 +01006630 if (stopping) {
6631 p = proxy;
6632 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006633 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006634 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006635 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006636 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006637 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006638 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006639
willy tarreaua41a8b42005-12-17 14:02:24 +01006640 for (l = p->listen; l != NULL; l = l->next) {
6641 fd_delete(l->fd);
6642 listeners--;
6643 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006644 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006645 }
6646 else {
6647 tleft = MINTIME(t, tleft);
6648 }
6649 }
6650 p = p->next;
6651 }
6652 }
6653 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006654}
6655
6656/*
6657 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006658 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6659 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006660 */
6661static void soft_stop(void) {
6662 struct proxy *p;
6663
6664 stopping = 1;
6665 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006666 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006667 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006668 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006669 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006671 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006672 }
willy tarreau0f7af912005-12-17 12:21:26 +01006673 p = p->next;
6674 }
6675}
6676
willy tarreaudbd3bef2006-01-20 19:35:18 +01006677static void pause_proxy(struct proxy *p) {
6678 struct listener *l;
6679 for (l = p->listen; l != NULL; l = l->next) {
6680 shutdown(l->fd, SHUT_RD);
6681 FD_CLR(l->fd, StaticReadEvent);
6682 p->state = PR_STPAUSED;
6683 }
6684}
6685
6686/*
6687 * This function temporarily disables listening so that another new instance
6688 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006689 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006690 * the proxy, or a SIGTTIN can be sent to listen again.
6691 */
6692static void pause_proxies(void) {
6693 struct proxy *p;
6694
6695 p = proxy;
6696 tv_now(&now); /* else, the old time before select will be used */
6697 while (p) {
6698 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6699 Warning("Pausing proxy %s.\n", p->id);
6700 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6701 pause_proxy(p);
6702 }
6703 p = p->next;
6704 }
6705}
6706
6707
6708/*
6709 * This function reactivates listening. This can be used after a call to
6710 * sig_pause(), for example when a new instance has failed starting up.
6711 * It is designed to be called upon reception of a SIGTTIN.
6712 */
6713static void listen_proxies(void) {
6714 struct proxy *p;
6715 struct listener *l;
6716
6717 p = proxy;
6718 tv_now(&now); /* else, the old time before select will be used */
6719 while (p) {
6720 if (p->state == PR_STPAUSED) {
6721 Warning("Enabling proxy %s.\n", p->id);
6722 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6723
6724 for (l = p->listen; l != NULL; l = l->next) {
6725 if (listen(l->fd, p->maxconn) == 0) {
6726 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6727 FD_SET(l->fd, StaticReadEvent);
6728 p->state = PR_STRUN;
6729 }
6730 else
6731 p->state = PR_STIDLE;
6732 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006733 int port;
6734
6735 if (l->addr.ss_family == AF_INET6)
6736 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6737 else
6738 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6739
willy tarreaudbd3bef2006-01-20 19:35:18 +01006740 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006741 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006742 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006743 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006744 /* Another port might have been enabled. Let's stop everything. */
6745 pause_proxy(p);
6746 break;
6747 }
6748 }
6749 }
6750 p = p->next;
6751 }
6752}
6753
6754
willy tarreau0f7af912005-12-17 12:21:26 +01006755/*
6756 * upon SIGUSR1, let's have a soft stop.
6757 */
6758void sig_soft_stop(int sig) {
6759 soft_stop();
6760 signal(sig, SIG_IGN);
6761}
6762
willy tarreaudbd3bef2006-01-20 19:35:18 +01006763/*
6764 * upon SIGTTOU, we pause everything
6765 */
6766void sig_pause(int sig) {
6767 pause_proxies();
6768 signal(sig, sig_pause);
6769}
willy tarreau0f7af912005-12-17 12:21:26 +01006770
willy tarreau8337c6b2005-12-17 13:41:01 +01006771/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006772 * upon SIGTTIN, let's have a soft stop.
6773 */
6774void sig_listen(int sig) {
6775 listen_proxies();
6776 signal(sig, sig_listen);
6777}
6778
6779/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006780 * this function dumps every server's state when the process receives SIGHUP.
6781 */
6782void sig_dump_state(int sig) {
6783 struct proxy *p = proxy;
6784
6785 Warning("SIGHUP received, dumping servers states.\n");
6786 while (p) {
6787 struct server *s = p->srv;
6788
willy tarreau4632c212006-05-02 23:32:51 +02006789 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006790 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006791 snprintf(trash, sizeof(trash),
6792 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6793 p->id, s->id,
6794 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6795 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006796 Warning("%s\n", trash);
6797 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006798 s = s->next;
6799 }
willy tarreaudd07e972005-12-18 00:48:48 +01006800
willy tarreau62084d42006-03-24 18:57:41 +01006801 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006802 snprintf(trash, sizeof(trash),
6803 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6804 p->id,
6805 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6806 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006807 } else {
6808 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006809 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6810 " Conn: %d act, %d pend (%d unass), %d tot.",
6811 p->id, p->srv_act, p->srv_bck,
6812 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006813 }
6814 Warning("%s\n", trash);
6815 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006816
willy tarreau8337c6b2005-12-17 13:41:01 +01006817 p = p->next;
6818 }
6819 signal(sig, sig_dump_state);
6820}
6821
willy tarreau0f7af912005-12-17 12:21:26 +01006822void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006823 struct task *t, *tnext;
6824 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006825
willy tarreau5e698ef2006-05-02 14:51:00 +02006826 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6827 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006828 tnext = t->next;
6829 s = t->context;
6830 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6831 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6832 "req=%d, rep=%d, clifd=%d\n",
6833 s, tv_remain(&now, &t->expire),
6834 s->cli_state,
6835 s->srv_state,
6836 FD_ISSET(s->cli_fd, StaticReadEvent),
6837 FD_ISSET(s->cli_fd, StaticWriteEvent),
6838 FD_ISSET(s->srv_fd, StaticReadEvent),
6839 FD_ISSET(s->srv_fd, StaticWriteEvent),
6840 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6841 );
willy tarreau0f7af912005-12-17 12:21:26 +01006842 }
willy tarreau12350152005-12-18 01:03:27 +01006843}
6844
willy tarreau64a3cc32005-12-18 01:13:11 +01006845#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006846static void fast_stop(void)
6847{
6848 struct proxy *p;
6849 p = proxy;
6850 while (p) {
6851 p->grace = 0;
6852 p = p->next;
6853 }
6854 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006855}
6856
willy tarreau12350152005-12-18 01:03:27 +01006857void sig_int(int sig) {
6858 /* This would normally be a hard stop,
6859 but we want to be sure about deallocation,
6860 and so on, so we do a soft stop with
6861 0 GRACE time
6862 */
6863 fast_stop();
6864 /* If we are killed twice, we decide to die*/
6865 signal(sig, SIG_DFL);
6866}
6867
6868void sig_term(int sig) {
6869 /* This would normally be a hard stop,
6870 but we want to be sure about deallocation,
6871 and so on, so we do a soft stop with
6872 0 GRACE time
6873 */
6874 fast_stop();
6875 /* If we are killed twice, we decide to die*/
6876 signal(sig, SIG_DFL);
6877}
willy tarreau64a3cc32005-12-18 01:13:11 +01006878#endif
willy tarreau12350152005-12-18 01:03:27 +01006879
willy tarreauc1f47532005-12-18 01:08:26 +01006880/* returns the pointer to an error in the replacement string, or NULL if OK */
6881char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006882 struct hdr_exp *exp;
6883
willy tarreauc1f47532005-12-18 01:08:26 +01006884 if (replace != NULL) {
6885 char *err;
6886 err = check_replace_string(replace);
6887 if (err)
6888 return err;
6889 }
6890
willy tarreaue39cd132005-12-17 13:00:18 +01006891 while (*head != NULL)
6892 head = &(*head)->next;
6893
6894 exp = calloc(1, sizeof(struct hdr_exp));
6895
6896 exp->preg = preg;
6897 exp->replace = replace;
6898 exp->action = action;
6899 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006900
6901 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006902}
6903
willy tarreau9fe663a2005-12-17 13:02:59 +01006904
willy tarreau0f7af912005-12-17 12:21:26 +01006905/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006906 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006907 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006908int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006909
willy tarreau9fe663a2005-12-17 13:02:59 +01006910 if (!strcmp(args[0], "global")) { /* new section */
6911 /* no option, nothing special to do */
6912 return 0;
6913 }
6914 else if (!strcmp(args[0], "daemon")) {
6915 global.mode |= MODE_DAEMON;
6916 }
6917 else if (!strcmp(args[0], "debug")) {
6918 global.mode |= MODE_DEBUG;
6919 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006920 else if (!strcmp(args[0], "noepoll")) {
6921 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6922 }
6923 else if (!strcmp(args[0], "nopoll")) {
6924 cfg_polling_mechanism &= ~POLL_USE_POLL;
6925 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006926 else if (!strcmp(args[0], "quiet")) {
6927 global.mode |= MODE_QUIET;
6928 }
6929 else if (!strcmp(args[0], "stats")) {
6930 global.mode |= MODE_STATS;
6931 }
6932 else if (!strcmp(args[0], "uid")) {
6933 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006934 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006935 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006936 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006937 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006938 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006939 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 global.uid = atol(args[1]);
6942 }
6943 else if (!strcmp(args[0], "gid")) {
6944 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006945 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006946 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006947 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006948 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006949 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006950 return -1;
6951 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006952 global.gid = atol(args[1]);
6953 }
6954 else if (!strcmp(args[0], "nbproc")) {
6955 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006956 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006958 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006959 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006960 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006961 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006962 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 global.nbproc = atol(args[1]);
6964 }
6965 else if (!strcmp(args[0], "maxconn")) {
6966 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006967 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006969 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006971 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006972 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006973 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006974 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006975#ifdef SYSTEM_MAXCONN
6976 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6977 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);
6978 global.maxconn = DEFAULT_MAXCONN;
6979 }
6980#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006981 }
willy tarreaub1285d52005-12-18 01:20:14 +01006982 else if (!strcmp(args[0], "ulimit-n")) {
6983 if (global.rlimit_nofile != 0) {
6984 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6985 return 0;
6986 }
6987 if (*(args[1]) == 0) {
6988 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6989 return -1;
6990 }
6991 global.rlimit_nofile = atol(args[1]);
6992 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 else if (!strcmp(args[0], "chroot")) {
6994 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006995 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 return 0;
6997 }
6998 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006999 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007000 return -1;
7001 }
7002 global.chroot = strdup(args[1]);
7003 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007004 else if (!strcmp(args[0], "pidfile")) {
7005 if (global.pidfile != NULL) {
7006 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7007 return 0;
7008 }
7009 if (*(args[1]) == 0) {
7010 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7011 return -1;
7012 }
7013 global.pidfile = strdup(args[1]);
7014 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007015 else if (!strcmp(args[0], "log")) { /* syslog server address */
7016 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007017 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007018
7019 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007020 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007021 return -1;
7022 }
7023
7024 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7025 if (!strcmp(log_facilities[facility], args[2]))
7026 break;
7027
7028 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007029 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007030 exit(1);
7031 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007032
7033 level = 7; /* max syslog level = debug */
7034 if (*(args[3])) {
7035 while (level >= 0 && strcmp(log_levels[level], args[3]))
7036 level--;
7037 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007038 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007039 exit(1);
7040 }
7041 }
7042
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 sa = str2sa(args[1]);
7044 if (!sa->sin_port)
7045 sa->sin_port = htons(SYSLOG_PORT);
7046
7047 if (global.logfac1 == -1) {
7048 global.logsrv1 = *sa;
7049 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007050 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007051 }
7052 else if (global.logfac2 == -1) {
7053 global.logsrv2 = *sa;
7054 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007055 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007056 }
7057 else {
7058 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7059 return -1;
7060 }
7061
7062 }
7063 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007064 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007065 return -1;
7066 }
7067 return 0;
7068}
7069
7070
willy tarreaua41a8b42005-12-17 14:02:24 +01007071void init_default_instance() {
7072 memset(&defproxy, 0, sizeof(defproxy));
7073 defproxy.mode = PR_MODE_TCP;
7074 defproxy.state = PR_STNEW;
7075 defproxy.maxconn = cfg_maxpconn;
7076 defproxy.conn_retries = CONN_RETRIES;
7077 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7078}
7079
willy tarreau9fe663a2005-12-17 13:02:59 +01007080/*
7081 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7082 */
7083int cfg_parse_listen(char *file, int linenum, char **args) {
7084 static struct proxy *curproxy = NULL;
7085 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007086 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007087 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007088
7089 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007090 if (!*args[1]) {
7091 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7092 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007093 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 return -1;
7095 }
7096
7097 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007098 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 return -1;
7100 }
willy tarreaudfece232006-05-02 00:19:57 +02007101
willy tarreau9fe663a2005-12-17 13:02:59 +01007102 curproxy->next = proxy;
7103 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007104 LIST_INIT(&curproxy->pendconns);
7105
willy tarreau9fe663a2005-12-17 13:02:59 +01007106 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007107
7108 /* parse the listener address if any */
7109 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007110 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007111 if (!curproxy->listen)
7112 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007113 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007114 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007115
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007117 curproxy->state = defproxy.state;
7118 curproxy->maxconn = defproxy.maxconn;
7119 curproxy->conn_retries = defproxy.conn_retries;
7120 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007121
7122 if (defproxy.check_req)
7123 curproxy->check_req = strdup(defproxy.check_req);
7124 curproxy->check_len = defproxy.check_len;
7125
7126 if (defproxy.cookie_name)
7127 curproxy->cookie_name = strdup(defproxy.cookie_name);
7128 curproxy->cookie_len = defproxy.cookie_len;
7129
7130 if (defproxy.capture_name)
7131 curproxy->capture_name = strdup(defproxy.capture_name);
7132 curproxy->capture_namelen = defproxy.capture_namelen;
7133 curproxy->capture_len = defproxy.capture_len;
7134
7135 if (defproxy.errmsg.msg400)
7136 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7137 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7138
7139 if (defproxy.errmsg.msg403)
7140 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7141 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7142
7143 if (defproxy.errmsg.msg408)
7144 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7145 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7146
7147 if (defproxy.errmsg.msg500)
7148 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7149 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7150
7151 if (defproxy.errmsg.msg502)
7152 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7153 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7154
7155 if (defproxy.errmsg.msg503)
7156 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7157 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7158
7159 if (defproxy.errmsg.msg504)
7160 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7161 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7162
willy tarreaua41a8b42005-12-17 14:02:24 +01007163 curproxy->clitimeout = defproxy.clitimeout;
7164 curproxy->contimeout = defproxy.contimeout;
7165 curproxy->srvtimeout = defproxy.srvtimeout;
7166 curproxy->mode = defproxy.mode;
7167 curproxy->logfac1 = defproxy.logfac1;
7168 curproxy->logsrv1 = defproxy.logsrv1;
7169 curproxy->loglev1 = defproxy.loglev1;
7170 curproxy->logfac2 = defproxy.logfac2;
7171 curproxy->logsrv2 = defproxy.logsrv2;
7172 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007173 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007174 curproxy->grace = defproxy.grace;
7175 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007176 curproxy->mon_net = defproxy.mon_net;
7177 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007178 return 0;
7179 }
7180 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007181 /* some variables may have already been initialized earlier */
7182 if (defproxy.check_req) free(defproxy.check_req);
7183 if (defproxy.cookie_name) free(defproxy.cookie_name);
7184 if (defproxy.capture_name) free(defproxy.capture_name);
7185 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7186 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7187 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7188 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7189 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7190 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7191 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7192
7193 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007194 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 return 0;
7196 }
7197 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007198 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 return -1;
7200 }
7201
willy tarreaua41a8b42005-12-17 14:02:24 +01007202 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7203 if (curproxy == &defproxy) {
7204 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7205 return -1;
7206 }
7207
7208 if (strchr(args[1], ':') == NULL) {
7209 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7210 file, linenum, args[0]);
7211 return -1;
7212 }
7213 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007214 if (!curproxy->listen)
7215 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007216 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007217 return 0;
7218 }
willy tarreaub1285d52005-12-18 01:20:14 +01007219 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7220 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7221 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7222 file, linenum, args[0]);
7223 return -1;
7224 }
7225 /* flush useless bits */
7226 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7227 return 0;
7228 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007229 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007230 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7231 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7232 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7233 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007234 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 return -1;
7236 }
7237 }
7238 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007239 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007241 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7242 curproxy->state = PR_STNEW;
7243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007244 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7245 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007246// if (curproxy == &defproxy) {
7247// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7248// return -1;
7249// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007250
willy tarreau9fe663a2005-12-17 13:02:59 +01007251 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007252// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7253// file, linenum);
7254// return 0;
7255 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007256 }
7257
7258 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007259 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7260 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007261 return -1;
7262 }
7263 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007264 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007265
7266 cur_arg = 2;
7267 while (*(args[cur_arg])) {
7268 if (!strcmp(args[cur_arg], "rewrite")) {
7269 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007270 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007271 else if (!strcmp(args[cur_arg], "indirect")) {
7272 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007273 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 else if (!strcmp(args[cur_arg], "insert")) {
7275 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007276 }
willy tarreau240afa62005-12-17 13:14:35 +01007277 else if (!strcmp(args[cur_arg], "nocache")) {
7278 curproxy->options |= PR_O_COOK_NOC;
7279 }
willy tarreaucd878942005-12-17 13:27:43 +01007280 else if (!strcmp(args[cur_arg], "postonly")) {
7281 curproxy->options |= PR_O_COOK_POST;
7282 }
willy tarreau0174f312005-12-18 01:02:42 +01007283 else if (!strcmp(args[cur_arg], "prefix")) {
7284 curproxy->options |= PR_O_COOK_PFX;
7285 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 else {
willy tarreau0174f312005-12-18 01:02:42 +01007287 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007288 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007289 return -1;
7290 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007291 cur_arg++;
7292 }
willy tarreau0174f312005-12-18 01:02:42 +01007293 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7294 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7295 file, linenum);
7296 return -1;
7297 }
7298
7299 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7300 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 file, linenum);
7302 return -1;
7303 }
willy tarreau12350152005-12-18 01:03:27 +01007304 }/* end else if (!strcmp(args[0], "cookie")) */
7305 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7306// if (curproxy == &defproxy) {
7307// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7308// return -1;
7309// }
7310
7311 if (curproxy->appsession_name != NULL) {
7312// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7313// file, linenum);
7314// return 0;
7315 free(curproxy->appsession_name);
7316 }
7317
7318 if (*(args[5]) == 0) {
7319 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7320 file, linenum, args[0]);
7321 return -1;
7322 }
7323 have_appsession = 1;
7324 curproxy->appsession_name = strdup(args[1]);
7325 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7326 curproxy->appsession_len = atoi(args[3]);
7327 curproxy->appsession_timeout = atoi(args[5]);
7328 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7329 if (rc) {
7330 Alert("Error Init Appsession Hashtable.\n");
7331 return -1;
7332 }
7333 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007334 else if (!strcmp(args[0], "capture")) {
7335 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7336 // if (curproxy == &defproxy) {
7337 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7338 // return -1;
7339 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007340
willy tarreau4302f492005-12-18 01:00:37 +01007341 if (curproxy->capture_name != NULL) {
7342 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7343 // file, linenum, args[0]);
7344 // return 0;
7345 free(curproxy->capture_name);
7346 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007347
willy tarreau4302f492005-12-18 01:00:37 +01007348 if (*(args[4]) == 0) {
7349 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7350 file, linenum, args[0]);
7351 return -1;
7352 }
7353 curproxy->capture_name = strdup(args[2]);
7354 curproxy->capture_namelen = strlen(curproxy->capture_name);
7355 curproxy->capture_len = atol(args[4]);
7356 if (curproxy->capture_len >= CAPTURE_LEN) {
7357 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7358 file, linenum, CAPTURE_LEN - 1);
7359 curproxy->capture_len = CAPTURE_LEN - 1;
7360 }
7361 curproxy->to_log |= LW_COOKIE;
7362 }
7363 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7364 struct cap_hdr *hdr;
7365
7366 if (curproxy == &defproxy) {
7367 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7368 return -1;
7369 }
7370
7371 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7372 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7373 file, linenum, args[0], args[1]);
7374 return -1;
7375 }
7376
7377 hdr = calloc(sizeof(struct cap_hdr), 1);
7378 hdr->next = curproxy->req_cap;
7379 hdr->name = strdup(args[3]);
7380 hdr->namelen = strlen(args[3]);
7381 hdr->len = atol(args[5]);
7382 hdr->index = curproxy->nb_req_cap++;
7383 curproxy->req_cap = hdr;
7384 curproxy->to_log |= LW_REQHDR;
7385 }
7386 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7387 struct cap_hdr *hdr;
7388
7389 if (curproxy == &defproxy) {
7390 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7391 return -1;
7392 }
7393
7394 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7395 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7396 file, linenum, args[0], args[1]);
7397 return -1;
7398 }
7399 hdr = calloc(sizeof(struct cap_hdr), 1);
7400 hdr->next = curproxy->rsp_cap;
7401 hdr->name = strdup(args[3]);
7402 hdr->namelen = strlen(args[3]);
7403 hdr->len = atol(args[5]);
7404 hdr->index = curproxy->nb_rsp_cap++;
7405 curproxy->rsp_cap = hdr;
7406 curproxy->to_log |= LW_RSPHDR;
7407 }
7408 else {
7409 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007410 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007411 return -1;
7412 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007413 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007414 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007415 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007416 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007417 return 0;
7418 }
7419 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007420 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7421 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007422 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007424 curproxy->contimeout = atol(args[1]);
7425 }
7426 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007427 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007428 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7429 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007430 return 0;
7431 }
7432 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007433 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7434 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007435 return -1;
7436 }
7437 curproxy->clitimeout = atol(args[1]);
7438 }
7439 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007440 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007441 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007442 return 0;
7443 }
7444 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007445 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7446 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007447 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007448 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007449 curproxy->srvtimeout = atol(args[1]);
7450 }
7451 else if (!strcmp(args[0], "retries")) { /* connection retries */
7452 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007453 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7454 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007455 return -1;
7456 }
7457 curproxy->conn_retries = atol(args[1]);
7458 }
7459 else if (!strcmp(args[0], "option")) {
7460 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007461 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007462 return -1;
7463 }
7464 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007465 /* enable reconnections to dispatch */
7466 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007467#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007468 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007469 /* enable transparent proxy connections */
7470 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007471#endif
7472 else if (!strcmp(args[1], "keepalive"))
7473 /* enable keep-alive */
7474 curproxy->options |= PR_O_KEEPALIVE;
7475 else if (!strcmp(args[1], "forwardfor"))
7476 /* insert x-forwarded-for field */
7477 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007478 else if (!strcmp(args[1], "logasap"))
7479 /* log as soon as possible, without waiting for the session to complete */
7480 curproxy->options |= PR_O_LOGASAP;
7481 else if (!strcmp(args[1], "httpclose"))
7482 /* force connection: close in both directions in HTTP mode */
7483 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007484 else if (!strcmp(args[1], "forceclose"))
7485 /* force connection: close in both directions in HTTP mode and enforce end of session */
7486 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007487 else if (!strcmp(args[1], "checkcache"))
7488 /* require examination of cacheability of the 'set-cookie' field */
7489 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007490 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007492 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007493 else if (!strcmp(args[1], "tcplog"))
7494 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007495 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007496 else if (!strcmp(args[1], "dontlognull")) {
7497 /* don't log empty requests */
7498 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007499 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007500 else if (!strcmp(args[1], "tcpka")) {
7501 /* enable TCP keep-alives on client and server sessions */
7502 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7503 }
7504 else if (!strcmp(args[1], "clitcpka")) {
7505 /* enable TCP keep-alives on client sessions */
7506 curproxy->options |= PR_O_TCP_CLI_KA;
7507 }
7508 else if (!strcmp(args[1], "srvtcpka")) {
7509 /* enable TCP keep-alives on server sessions */
7510 curproxy->options |= PR_O_TCP_SRV_KA;
7511 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007512 else if (!strcmp(args[1], "allbackups")) {
7513 /* Use all backup servers simultaneously */
7514 curproxy->options |= PR_O_USE_ALL_BK;
7515 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007516 else if (!strcmp(args[1], "httpchk")) {
7517 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007518 if (curproxy->check_req != NULL) {
7519 free(curproxy->check_req);
7520 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007521 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007522 if (!*args[2]) { /* no argument */
7523 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7524 curproxy->check_len = strlen(DEF_CHECK_REQ);
7525 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007526 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7527 curproxy->check_req = (char *)malloc(reqlen);
7528 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7529 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007530 } else { /* more arguments : METHOD URI [HTTP_VER] */
7531 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7532 if (*args[4])
7533 reqlen += strlen(args[4]);
7534 else
7535 reqlen += strlen("HTTP/1.0");
7536
7537 curproxy->check_req = (char *)malloc(reqlen);
7538 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7539 "%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 +01007540 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007541 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007542 else if (!strcmp(args[1], "persist")) {
7543 /* persist on using the server specified by the cookie, even when it's down */
7544 curproxy->options |= PR_O_PERSIST;
7545 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007546 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007547 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007548 return -1;
7549 }
7550 return 0;
7551 }
7552 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7553 /* enable reconnections to dispatch */
7554 curproxy->options |= PR_O_REDISP;
7555 }
willy tarreaua1598082005-12-17 13:08:06 +01007556#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007557 else if (!strcmp(args[0], "transparent")) {
7558 /* enable transparent proxy connections */
7559 curproxy->options |= PR_O_TRANSP;
7560 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007561#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007562 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7563 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007564 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007566 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007567 curproxy->maxconn = atol(args[1]);
7568 }
7569 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7570 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007571 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007573 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007574 curproxy->grace = atol(args[1]);
7575 }
7576 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007577 if (curproxy == &defproxy) {
7578 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7579 return -1;
7580 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007581 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007582 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007583 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007584 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007585 curproxy->dispatch_addr = *str2sa(args[1]);
7586 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007587 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007588 if (*(args[1])) {
7589 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007590 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007592 else if (!strcmp(args[1], "source")) {
7593 curproxy->options |= PR_O_BALANCE_SH;
7594 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007595 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007596 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007597 return -1;
7598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007599 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007600 else /* if no option is set, use round-robin by default */
7601 curproxy->options |= PR_O_BALANCE_RR;
7602 }
7603 else if (!strcmp(args[0], "server")) { /* server address */
7604 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007605 char *rport;
7606 char *raddr;
7607 short realport;
7608 int do_check;
7609
7610 if (curproxy == &defproxy) {
7611 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7612 return -1;
7613 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007614
willy tarreaua41a8b42005-12-17 14:02:24 +01007615 if (!*args[2]) {
7616 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007617 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007618 return -1;
7619 }
7620 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7621 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7622 return -1;
7623 }
willy tarreau0174f312005-12-18 01:02:42 +01007624
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007625 /* the servers are linked backwards first */
7626 newsrv->next = curproxy->srv;
7627 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007628 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007629
willy tarreau18a957c2006-04-12 19:26:23 +02007630 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007631 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007632 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007633 newsrv->id = strdup(args[1]);
7634
7635 /* several ways to check the port component :
7636 * - IP => port=+0, relative
7637 * - IP: => port=+0, relative
7638 * - IP:N => port=N, absolute
7639 * - IP:+N => port=+N, relative
7640 * - IP:-N => port=-N, relative
7641 */
7642 raddr = strdup(args[2]);
7643 rport = strchr(raddr, ':');
7644 if (rport) {
7645 *rport++ = 0;
7646 realport = atol(rport);
7647 if (!isdigit((int)*rport))
7648 newsrv->state |= SRV_MAPPORTS;
7649 } else {
7650 realport = 0;
7651 newsrv->state |= SRV_MAPPORTS;
7652 }
7653
7654 newsrv->addr = *str2sa(raddr);
7655 newsrv->addr.sin_port = htons(realport);
7656 free(raddr);
7657
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 newsrv->curfd = -1; /* no health-check in progress */
7659 newsrv->inter = DEF_CHKINTR;
7660 newsrv->rise = DEF_RISETIME;
7661 newsrv->fall = DEF_FALLTIME;
7662 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7663 cur_arg = 3;
7664 while (*args[cur_arg]) {
7665 if (!strcmp(args[cur_arg], "cookie")) {
7666 newsrv->cookie = strdup(args[cur_arg + 1]);
7667 newsrv->cklen = strlen(args[cur_arg + 1]);
7668 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007670 else if (!strcmp(args[cur_arg], "rise")) {
7671 newsrv->rise = atol(args[cur_arg + 1]);
7672 newsrv->health = newsrv->rise;
7673 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007675 else if (!strcmp(args[cur_arg], "fall")) {
7676 newsrv->fall = atol(args[cur_arg + 1]);
7677 cur_arg += 2;
7678 }
7679 else if (!strcmp(args[cur_arg], "inter")) {
7680 newsrv->inter = atol(args[cur_arg + 1]);
7681 cur_arg += 2;
7682 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007683 else if (!strcmp(args[cur_arg], "port")) {
7684 newsrv->check_port = atol(args[cur_arg + 1]);
7685 cur_arg += 2;
7686 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007687 else if (!strcmp(args[cur_arg], "backup")) {
7688 newsrv->state |= SRV_BACKUP;
7689 cur_arg ++;
7690 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007691 else if (!strcmp(args[cur_arg], "weight")) {
7692 int w;
7693 w = atol(args[cur_arg + 1]);
7694 if (w < 1 || w > 256) {
7695 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7696 file, linenum, newsrv->id, w);
7697 return -1;
7698 }
7699 newsrv->uweight = w - 1;
7700 cur_arg += 2;
7701 }
willy tarreau18a957c2006-04-12 19:26:23 +02007702 else if (!strcmp(args[cur_arg], "maxconn")) {
7703 newsrv->maxconn = atol(args[cur_arg + 1]);
7704 cur_arg += 2;
7705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007706 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007707 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007708 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007709 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007710 }
willy tarreau0174f312005-12-18 01:02:42 +01007711 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7712 if (!*args[cur_arg + 1]) {
7713 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7714 file, linenum, "source");
7715 return -1;
7716 }
7717 newsrv->state |= SRV_BIND_SRC;
7718 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7719 cur_arg += 2;
7720 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007721 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007722 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port', 'source', and 'weight'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01007723 file, linenum, newsrv->id);
7724 return -1;
7725 }
7726 }
7727
7728 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007729 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7730 newsrv->check_port = realport; /* by default */
7731 if (!newsrv->check_port) {
7732 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 +01007733 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007734 return -1;
7735 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007736 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007737 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007738
willy tarreau62084d42006-03-24 18:57:41 +01007739 if (newsrv->state & SRV_BACKUP)
7740 curproxy->srv_bck++;
7741 else
7742 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007743 }
7744 else if (!strcmp(args[0], "log")) { /* syslog server address */
7745 struct sockaddr_in *sa;
7746 int facility;
7747
7748 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7749 curproxy->logfac1 = global.logfac1;
7750 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007751 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007752 curproxy->logfac2 = global.logfac2;
7753 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007754 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 }
7756 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007757 int level;
7758
willy tarreau0f7af912005-12-17 12:21:26 +01007759 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7760 if (!strcmp(log_facilities[facility], args[2]))
7761 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007762
willy tarreau0f7af912005-12-17 12:21:26 +01007763 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007764 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007765 exit(1);
7766 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007767
willy tarreau8337c6b2005-12-17 13:41:01 +01007768 level = 7; /* max syslog level = debug */
7769 if (*(args[3])) {
7770 while (level >= 0 && strcmp(log_levels[level], args[3]))
7771 level--;
7772 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007773 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007774 exit(1);
7775 }
7776 }
7777
willy tarreau0f7af912005-12-17 12:21:26 +01007778 sa = str2sa(args[1]);
7779 if (!sa->sin_port)
7780 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007781
willy tarreau0f7af912005-12-17 12:21:26 +01007782 if (curproxy->logfac1 == -1) {
7783 curproxy->logsrv1 = *sa;
7784 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007785 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007786 }
7787 else if (curproxy->logfac2 == -1) {
7788 curproxy->logsrv2 = *sa;
7789 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007790 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007791 }
7792 else {
7793 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007794 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007795 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 }
7797 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007798 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007799 file, linenum);
7800 return -1;
7801 }
7802 }
willy tarreaua1598082005-12-17 13:08:06 +01007803 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007804 if (!*args[1]) {
7805 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007806 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007807 return -1;
7808 }
7809
7810 curproxy->source_addr = *str2sa(args[1]);
7811 curproxy->options |= PR_O_BIND_SRC;
7812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007813 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7814 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007815 if (curproxy == &defproxy) {
7816 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7817 return -1;
7818 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007819
7820 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007821 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7822 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007823 return -1;
7824 }
7825
7826 preg = calloc(1, sizeof(regex_t));
7827 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007828 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007829 return -1;
7830 }
7831
willy tarreauc1f47532005-12-18 01:08:26 +01007832 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7833 if (err) {
7834 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7835 file, linenum, *err);
7836 return -1;
7837 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007838 }
7839 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7840 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007841 if (curproxy == &defproxy) {
7842 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7843 return -1;
7844 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007845
7846 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007847 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007848 return -1;
7849 }
7850
7851 preg = calloc(1, sizeof(regex_t));
7852 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007853 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007854 return -1;
7855 }
7856
7857 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7858 }
7859 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7860 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007861 if (curproxy == &defproxy) {
7862 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7863 return -1;
7864 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007865
7866 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007867 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007868 return -1;
7869 }
7870
7871 preg = calloc(1, sizeof(regex_t));
7872 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007873 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007874 return -1;
7875 }
7876
7877 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7878 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007879 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7880 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007881 if (curproxy == &defproxy) {
7882 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7883 return -1;
7884 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007885
7886 if (*(args[1]) == 0) {
7887 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7888 return -1;
7889 }
7890
7891 preg = calloc(1, sizeof(regex_t));
7892 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7893 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7894 return -1;
7895 }
7896
7897 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7898 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007899 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7900 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007901 if (curproxy == &defproxy) {
7902 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7903 return -1;
7904 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007905
7906 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007907 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007908 return -1;
7909 }
7910
7911 preg = calloc(1, sizeof(regex_t));
7912 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007913 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007914 return -1;
7915 }
7916
7917 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7918 }
7919 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7920 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007921 if (curproxy == &defproxy) {
7922 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7923 return -1;
7924 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007925
7926 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007927 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7928 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007929 return -1;
7930 }
7931
7932 preg = calloc(1, sizeof(regex_t));
7933 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007934 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007935 return -1;
7936 }
7937
willy tarreauc1f47532005-12-18 01:08:26 +01007938 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7939 if (err) {
7940 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7941 file, linenum, *err);
7942 return -1;
7943 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007944 }
7945 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7946 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007947 if (curproxy == &defproxy) {
7948 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7949 return -1;
7950 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007951
7952 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007953 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007954 return -1;
7955 }
7956
7957 preg = calloc(1, sizeof(regex_t));
7958 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007959 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007960 return -1;
7961 }
7962
7963 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7964 }
7965 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7966 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007967 if (curproxy == &defproxy) {
7968 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7969 return -1;
7970 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007971
7972 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007973 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007974 return -1;
7975 }
7976
7977 preg = calloc(1, sizeof(regex_t));
7978 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007979 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007980 return -1;
7981 }
7982
7983 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7984 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007985 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7986 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007987 if (curproxy == &defproxy) {
7988 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7989 return -1;
7990 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007991
7992 if (*(args[1]) == 0) {
7993 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7994 return -1;
7995 }
7996
7997 preg = calloc(1, sizeof(regex_t));
7998 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7999 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8000 return -1;
8001 }
8002
8003 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8004 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008005 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8006 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008007 if (curproxy == &defproxy) {
8008 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8009 return -1;
8010 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008011
8012 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008013 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008014 return -1;
8015 }
8016
8017 preg = calloc(1, sizeof(regex_t));
8018 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008019 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008020 return -1;
8021 }
8022
8023 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8024 }
8025 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008026 if (curproxy == &defproxy) {
8027 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8028 return -1;
8029 }
8030
willy tarreau9fe663a2005-12-17 13:02:59 +01008031 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008032 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008033 return 0;
8034 }
8035
8036 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008037 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008038 return -1;
8039 }
8040
willy tarreau4302f492005-12-18 01:00:37 +01008041 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8042 }
8043 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8044 regex_t *preg;
8045
8046 if (*(args[1]) == 0 || *(args[2]) == 0) {
8047 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8048 file, linenum, args[0]);
8049 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008050 }
willy tarreau4302f492005-12-18 01:00:37 +01008051
8052 preg = calloc(1, sizeof(regex_t));
8053 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8054 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8055 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008056 }
willy tarreau4302f492005-12-18 01:00:37 +01008057
willy tarreauc1f47532005-12-18 01:08:26 +01008058 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8059 if (err) {
8060 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8061 file, linenum, *err);
8062 return -1;
8063 }
willy tarreau4302f492005-12-18 01:00:37 +01008064 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008065 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8066 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008067 if (curproxy == &defproxy) {
8068 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8069 return -1;
8070 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008071
8072 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008073 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008074 return -1;
8075 }
willy tarreaue39cd132005-12-17 13:00:18 +01008076
willy tarreau9fe663a2005-12-17 13:02:59 +01008077 preg = calloc(1, sizeof(regex_t));
8078 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008079 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008080 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008081 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008082
willy tarreauc1f47532005-12-18 01:08:26 +01008083 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8084 if (err) {
8085 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8086 file, linenum, *err);
8087 return -1;
8088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008089 }
willy tarreau982249e2005-12-18 00:57:06 +01008090 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8091 regex_t *preg;
8092 if (curproxy == &defproxy) {
8093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8094 return -1;
8095 }
8096
8097 if (*(args[1]) == 0) {
8098 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8099 return -1;
8100 }
8101
8102 preg = calloc(1, sizeof(regex_t));
8103 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8105 return -1;
8106 }
8107
willy tarreauc1f47532005-12-18 01:08:26 +01008108 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8109 if (err) {
8110 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8111 file, linenum, *err);
8112 return -1;
8113 }
willy tarreau982249e2005-12-18 00:57:06 +01008114 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008115 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008116 regex_t *preg;
8117 if (curproxy == &defproxy) {
8118 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8119 return -1;
8120 }
willy tarreaue39cd132005-12-17 13:00:18 +01008121
willy tarreaua41a8b42005-12-17 14:02:24 +01008122 if (*(args[1]) == 0 || *(args[2]) == 0) {
8123 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8124 file, linenum, args[0]);
8125 return -1;
8126 }
willy tarreaue39cd132005-12-17 13:00:18 +01008127
willy tarreaua41a8b42005-12-17 14:02:24 +01008128 preg = calloc(1, sizeof(regex_t));
8129 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8130 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8131 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008132 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008133
willy tarreauc1f47532005-12-18 01:08:26 +01008134 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8135 if (err) {
8136 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8137 file, linenum, *err);
8138 return -1;
8139 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008140 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008141 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8142 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008143 if (curproxy == &defproxy) {
8144 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8145 return -1;
8146 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008147
8148 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008149 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008150 return -1;
8151 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008152
willy tarreau9fe663a2005-12-17 13:02:59 +01008153 preg = calloc(1, sizeof(regex_t));
8154 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008155 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008156 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008157 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008158
willy tarreauc1f47532005-12-18 01:08:26 +01008159 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8160 if (err) {
8161 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8162 file, linenum, *err);
8163 return -1;
8164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008165 }
willy tarreau982249e2005-12-18 00:57:06 +01008166 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8167 regex_t *preg;
8168 if (curproxy == &defproxy) {
8169 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8170 return -1;
8171 }
8172
8173 if (*(args[1]) == 0) {
8174 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8175 return -1;
8176 }
8177
8178 preg = calloc(1, sizeof(regex_t));
8179 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8180 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8181 return -1;
8182 }
8183
willy tarreauc1f47532005-12-18 01:08:26 +01008184 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8185 if (err) {
8186 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8187 file, linenum, *err);
8188 return -1;
8189 }
willy tarreau982249e2005-12-18 00:57:06 +01008190 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008191 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008192 if (curproxy == &defproxy) {
8193 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8194 return -1;
8195 }
8196
willy tarreau9fe663a2005-12-17 13:02:59 +01008197 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008198 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008199 return 0;
8200 }
8201
8202 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008203 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008204 return -1;
8205 }
8206
8207 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8208 }
willy tarreauc1f47532005-12-18 01:08:26 +01008209 else if (!strcmp(args[0], "errorloc") ||
8210 !strcmp(args[0], "errorloc302") ||
8211 !strcmp(args[0], "errorloc303")) { /* error location */
8212 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008213 char *err;
8214
willy tarreaueedaa9f2005-12-17 14:08:03 +01008215 // if (curproxy == &defproxy) {
8216 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8217 // return -1;
8218 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008219
willy tarreau8337c6b2005-12-17 13:41:01 +01008220 if (*(args[2]) == 0) {
8221 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8222 return -1;
8223 }
8224
8225 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008226 if (!strcmp(args[0], "errorloc303")) {
8227 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8228 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8229 } else {
8230 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8231 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8232 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008233
8234 if (errnum == 400) {
8235 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008236 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008237 free(curproxy->errmsg.msg400);
8238 }
8239 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008240 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008241 }
8242 else if (errnum == 403) {
8243 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008244 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008245 free(curproxy->errmsg.msg403);
8246 }
8247 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008248 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008249 }
8250 else if (errnum == 408) {
8251 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008252 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008253 free(curproxy->errmsg.msg408);
8254 }
8255 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008256 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008257 }
8258 else if (errnum == 500) {
8259 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008260 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008261 free(curproxy->errmsg.msg500);
8262 }
8263 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008264 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008265 }
8266 else if (errnum == 502) {
8267 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008268 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008269 free(curproxy->errmsg.msg502);
8270 }
8271 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008272 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008273 }
8274 else if (errnum == 503) {
8275 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008276 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008277 free(curproxy->errmsg.msg503);
8278 }
8279 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008280 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008281 }
8282 else if (errnum == 504) {
8283 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008284 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008285 free(curproxy->errmsg.msg504);
8286 }
8287 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008288 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008289 }
8290 else {
8291 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8292 free(err);
8293 }
8294 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008295 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008296 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008297 return -1;
8298 }
8299 return 0;
8300}
willy tarreaue39cd132005-12-17 13:00:18 +01008301
willy tarreau5cbea6f2005-12-17 12:48:26 +01008302
willy tarreau9fe663a2005-12-17 13:02:59 +01008303/*
8304 * This function reads and parses the configuration file given in the argument.
8305 * returns 0 if OK, -1 if error.
8306 */
8307int readcfgfile(char *file) {
8308 char thisline[256];
8309 char *line;
8310 FILE *f;
8311 int linenum = 0;
8312 char *end;
8313 char *args[MAX_LINE_ARGS];
8314 int arg;
8315 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008316 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008317 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008318
willy tarreau9fe663a2005-12-17 13:02:59 +01008319 struct proxy *curproxy = NULL;
8320 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008321
willy tarreau9fe663a2005-12-17 13:02:59 +01008322 if ((f=fopen(file,"r")) == NULL)
8323 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008324
willy tarreaueedaa9f2005-12-17 14:08:03 +01008325 init_default_instance();
8326
willy tarreau9fe663a2005-12-17 13:02:59 +01008327 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8328 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008329
willy tarreau9fe663a2005-12-17 13:02:59 +01008330 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008331
willy tarreau9fe663a2005-12-17 13:02:59 +01008332 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008333 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008334 line++;
8335
8336 arg = 0;
8337 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008338
willy tarreau9fe663a2005-12-17 13:02:59 +01008339 while (*line && arg < MAX_LINE_ARGS) {
8340 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8341 * C equivalent value. Other combinations left unchanged (eg: \1).
8342 */
8343 if (*line == '\\') {
8344 int skip = 0;
8345 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8346 *line = line[1];
8347 skip = 1;
8348 }
8349 else if (line[1] == 'r') {
8350 *line = '\r';
8351 skip = 1;
8352 }
8353 else if (line[1] == 'n') {
8354 *line = '\n';
8355 skip = 1;
8356 }
8357 else if (line[1] == 't') {
8358 *line = '\t';
8359 skip = 1;
8360 }
willy tarreauc1f47532005-12-18 01:08:26 +01008361 else if (line[1] == 'x') {
8362 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8363 unsigned char hex1, hex2;
8364 hex1 = toupper(line[2]) - '0';
8365 hex2 = toupper(line[3]) - '0';
8366 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8367 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8368 *line = (hex1<<4) + hex2;
8369 skip = 3;
8370 }
8371 else {
8372 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8373 return -1;
8374 }
8375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008376 if (skip) {
8377 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8378 end -= skip;
8379 }
8380 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008381 }
willy tarreaua1598082005-12-17 13:08:06 +01008382 else if (*line == '#' || *line == '\n' || *line == '\r') {
8383 /* end of string, end of loop */
8384 *line = 0;
8385 break;
8386 }
willy tarreauc29948c2005-12-17 13:10:27 +01008387 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008388 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008389 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008390 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008391 line++;
8392 args[++arg] = line;
8393 }
8394 else {
8395 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008396 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008397 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008398
willy tarreau9fe663a2005-12-17 13:02:59 +01008399 /* empty line */
8400 if (!**args)
8401 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008402
willy tarreau9fe663a2005-12-17 13:02:59 +01008403 /* zero out remaining args */
8404 while (++arg < MAX_LINE_ARGS) {
8405 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008406 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008407
willy tarreaua41a8b42005-12-17 14:02:24 +01008408 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008409 confsect = CFG_LISTEN;
8410 else if (!strcmp(args[0], "global")) /* global config */
8411 confsect = CFG_GLOBAL;
8412 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008413
willy tarreau9fe663a2005-12-17 13:02:59 +01008414 switch (confsect) {
8415 case CFG_LISTEN:
8416 if (cfg_parse_listen(file, linenum, args) < 0)
8417 return -1;
8418 break;
8419 case CFG_GLOBAL:
8420 if (cfg_parse_global(file, linenum, args) < 0)
8421 return -1;
8422 break;
8423 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008424 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008425 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008427
8428
willy tarreau0f7af912005-12-17 12:21:26 +01008429 }
8430 fclose(f);
8431
8432 /*
8433 * Now, check for the integrity of all that we have collected.
8434 */
8435
Willy TARREAU3759f982006-03-01 22:44:17 +01008436 /* will be needed further to delay some tasks */
8437 tv_now(&now);
8438
willy tarreau0f7af912005-12-17 12:21:26 +01008439 if ((curproxy = proxy) == NULL) {
8440 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8441 file);
8442 return -1;
8443 }
8444
8445 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008446 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008447 curproxy = curproxy->next;
8448 continue;
8449 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008450
8451 if (curproxy->listen == NULL) {
8452 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);
8453 cfgerr++;
8454 }
8455 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008456 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008457 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008458 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8459 file, curproxy->id);
8460 cfgerr++;
8461 }
8462 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8463 if (curproxy->options & PR_O_TRANSP) {
8464 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8465 file, curproxy->id);
8466 cfgerr++;
8467 }
8468 else if (curproxy->srv == NULL) {
8469 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8470 file, curproxy->id);
8471 cfgerr++;
8472 }
willy tarreaua1598082005-12-17 13:08:06 +01008473 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008474 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8475 file, curproxy->id);
8476 }
8477 }
8478 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008479 if (curproxy->cookie_name != NULL) {
8480 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8481 file, curproxy->id);
8482 }
8483 if ((newsrv = curproxy->srv) != NULL) {
8484 Warning("parsing %s : servers will be ignored for listener %s.\n",
8485 file, curproxy->id);
8486 }
willy tarreaue39cd132005-12-17 13:00:18 +01008487 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008488 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8489 file, curproxy->id);
8490 }
willy tarreaue39cd132005-12-17 13:00:18 +01008491 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008492 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8493 file, curproxy->id);
8494 }
8495 }
8496 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8497 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8498 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8499 file, curproxy->id);
8500 cfgerr++;
8501 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008502 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008503
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008504 /* first, we will invert the servers list order */
8505 newsrv = NULL;
8506 while (curproxy->srv) {
8507 struct server *next;
8508
8509 next = curproxy->srv->next;
8510 curproxy->srv->next = newsrv;
8511 newsrv = curproxy->srv;
8512 if (!next)
8513 break;
8514 curproxy->srv = next;
8515 }
8516
8517 /* now, newsrv == curproxy->srv */
8518 if (newsrv) {
8519 struct server *srv;
8520 int pgcd;
8521 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008522
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008523 /* We will factor the weights to reduce the table,
8524 * using Euclide's largest common divisor algorithm
8525 */
8526 pgcd = newsrv->uweight + 1;
8527 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8528 int t, w;
8529
8530 w = srv->uweight + 1;
8531 while (w) {
8532 t = pgcd % w;
8533 pgcd = w;
8534 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008535 }
willy tarreau0f7af912005-12-17 12:21:26 +01008536 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008537
8538 act = bck = 0;
8539 for (srv = newsrv; srv; srv = srv->next) {
8540 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8541 if (srv->state & SRV_BACKUP)
8542 bck += srv->eweight + 1;
8543 else
8544 act += srv->eweight + 1;
8545 }
8546
8547 /* this is the largest map we will ever need for this servers list */
8548 if (act < bck)
8549 act = bck;
8550
8551 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8552 /* recounts servers and their weights */
8553 recount_servers(curproxy);
8554 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008555 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008556
8557 if (curproxy->options & PR_O_LOGASAP)
8558 curproxy->to_log &= ~LW_BYTES;
8559
willy tarreau8337c6b2005-12-17 13:41:01 +01008560 if (curproxy->errmsg.msg400 == NULL) {
8561 curproxy->errmsg.msg400 = (char *)HTTP_400;
8562 curproxy->errmsg.len400 = strlen(HTTP_400);
8563 }
8564 if (curproxy->errmsg.msg403 == NULL) {
8565 curproxy->errmsg.msg403 = (char *)HTTP_403;
8566 curproxy->errmsg.len403 = strlen(HTTP_403);
8567 }
8568 if (curproxy->errmsg.msg408 == NULL) {
8569 curproxy->errmsg.msg408 = (char *)HTTP_408;
8570 curproxy->errmsg.len408 = strlen(HTTP_408);
8571 }
8572 if (curproxy->errmsg.msg500 == NULL) {
8573 curproxy->errmsg.msg500 = (char *)HTTP_500;
8574 curproxy->errmsg.len500 = strlen(HTTP_500);
8575 }
8576 if (curproxy->errmsg.msg502 == NULL) {
8577 curproxy->errmsg.msg502 = (char *)HTTP_502;
8578 curproxy->errmsg.len502 = strlen(HTTP_502);
8579 }
8580 if (curproxy->errmsg.msg503 == NULL) {
8581 curproxy->errmsg.msg503 = (char *)HTTP_503;
8582 curproxy->errmsg.len503 = strlen(HTTP_503);
8583 }
8584 if (curproxy->errmsg.msg504 == NULL) {
8585 curproxy->errmsg.msg504 = (char *)HTTP_504;
8586 curproxy->errmsg.len504 = strlen(HTTP_504);
8587 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008588
8589 /* now we'll start this proxy's health checks if any */
8590 /* 1- count the checkers to run simultaneously */
8591 nbchk = 0;
8592 mininter = 0;
8593 newsrv = curproxy->srv;
8594 while (newsrv != NULL) {
8595 if (newsrv->state & SRV_CHECKED) {
8596 if (!mininter || mininter > newsrv->inter)
8597 mininter = newsrv->inter;
8598 nbchk++;
8599 }
8600 newsrv = newsrv->next;
8601 }
8602
8603 /* 2- start them as far as possible from each others while respecting
8604 * their own intervals. For this, we will start them after their own
8605 * interval added to the min interval divided by the number of servers,
8606 * weighted by the server's position in the list.
8607 */
8608 if (nbchk > 0) {
8609 struct task *t;
8610 int srvpos;
8611
8612 newsrv = curproxy->srv;
8613 srvpos = 0;
8614 while (newsrv != NULL) {
8615 /* should this server be checked ? */
8616 if (newsrv->state & SRV_CHECKED) {
8617 if ((t = pool_alloc(task)) == NULL) {
8618 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8619 return -1;
8620 }
8621
8622 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008623 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008624 t->state = TASK_IDLE;
8625 t->process = process_chk;
8626 t->context = newsrv;
8627
8628 /* check this every ms */
8629 tv_delayfrom(&t->expire, &now,
8630 newsrv->inter + mininter * srvpos / nbchk);
8631 task_queue(t);
8632 //task_wakeup(&rq, t);
8633 srvpos++;
8634 }
8635 newsrv = newsrv->next;
8636 }
8637 }
8638
willy tarreau0f7af912005-12-17 12:21:26 +01008639 curproxy = curproxy->next;
8640 }
8641 if (cfgerr > 0) {
8642 Alert("Errors found in configuration file, aborting.\n");
8643 return -1;
8644 }
8645 else
8646 return 0;
8647}
8648
8649
8650/*
8651 * This function initializes all the necessary variables. It only returns
8652 * if everything is OK. If something fails, it exits.
8653 */
8654void init(int argc, char **argv) {
8655 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008656 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008657 char *old_argv = *argv;
8658 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008659 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008660
8661 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008662 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008663 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008664 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008665 exit(1);
8666 }
8667
willy tarreau746e26b2006-03-25 11:14:35 +01008668#ifdef HAPROXY_MEMMAX
8669 global.rlimit_memmax = HAPROXY_MEMMAX;
8670#endif
8671
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008672 /* initialize the libc's localtime structures once for all so that we
8673 * won't be missing memory if we want to send alerts under OOM conditions.
8674 */
8675 tv_now(&now);
8676 localtime(&now.tv_sec);
8677
willy tarreau4302f492005-12-18 01:00:37 +01008678 /* initialize the log header encoding map : '{|}"#' should be encoded with
8679 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8680 * URL encoding only requires '"', '#' to be encoded as well as non-
8681 * printable characters above.
8682 */
8683 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8684 memset(url_encode_map, 0, sizeof(url_encode_map));
8685 for (i = 0; i < 32; i++) {
8686 FD_SET(i, hdr_encode_map);
8687 FD_SET(i, url_encode_map);
8688 }
8689 for (i = 127; i < 256; i++) {
8690 FD_SET(i, hdr_encode_map);
8691 FD_SET(i, url_encode_map);
8692 }
8693
8694 tmp = "\"#{|}";
8695 while (*tmp) {
8696 FD_SET(*tmp, hdr_encode_map);
8697 tmp++;
8698 }
8699
8700 tmp = "\"#";
8701 while (*tmp) {
8702 FD_SET(*tmp, url_encode_map);
8703 tmp++;
8704 }
8705
willy tarreau64a3cc32005-12-18 01:13:11 +01008706 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8707#if defined(ENABLE_POLL)
8708 cfg_polling_mechanism |= POLL_USE_POLL;
8709#endif
8710#if defined(ENABLE_EPOLL)
8711 cfg_polling_mechanism |= POLL_USE_EPOLL;
8712#endif
8713
willy tarreau0f7af912005-12-17 12:21:26 +01008714 pid = getpid();
8715 progname = *argv;
8716 while ((tmp = strchr(progname, '/')) != NULL)
8717 progname = tmp + 1;
8718
8719 argc--; argv++;
8720 while (argc > 0) {
8721 char *flag;
8722
8723 if (**argv == '-') {
8724 flag = *argv+1;
8725
8726 /* 1 arg */
8727 if (*flag == 'v') {
8728 display_version();
8729 exit(0);
8730 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008731#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008732 else if (*flag == 'd' && flag[1] == 'e')
8733 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008734#endif
8735#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008736 else if (*flag == 'd' && flag[1] == 'p')
8737 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008738#endif
willy tarreau982249e2005-12-18 00:57:06 +01008739 else if (*flag == 'V')
8740 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008741 else if (*flag == 'd' && flag[1] == 'b')
8742 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008743 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008744 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008745 else if (*flag == 'c')
8746 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008747 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008748 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008749 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008750 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008751 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8752 /* list of pids to finish ('f') or terminate ('t') */
8753
8754 if (flag[1] == 'f')
8755 oldpids_sig = SIGUSR1; /* finish then exit */
8756 else
8757 oldpids_sig = SIGTERM; /* terminate immediately */
8758 argv++; argc--;
8759
8760 if (argc > 0) {
8761 oldpids = calloc(argc, sizeof(int));
8762 while (argc > 0) {
8763 oldpids[nb_oldpids] = atol(*argv);
8764 if (oldpids[nb_oldpids] <= 0)
8765 usage(old_argv);
8766 argc--; argv++;
8767 nb_oldpids++;
8768 }
8769 }
8770 }
willy tarreau2c513732006-04-15 19:25:16 +02008771#if STATTIME > 0
8772 else if (*flag == 's')
8773 arg_mode |= MODE_STATS;
8774 else if (*flag == 'l')
8775 arg_mode |= MODE_LOG;
8776#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008777 else { /* >=2 args */
8778 argv++; argc--;
8779 if (argc == 0)
8780 usage(old_argv);
8781
8782 switch (*flag) {
8783 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008784 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008785 case 'N' : cfg_maxpconn = atol(*argv); break;
8786 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008787 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008788 default: usage(old_argv);
8789 }
8790 }
8791 }
8792 else
8793 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008794 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008795 }
8796
willy tarreaud0fb4652005-12-18 01:32:04 +01008797 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008798 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8799 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008800
willy tarreau0f7af912005-12-17 12:21:26 +01008801 if (!cfg_cfgfile)
8802 usage(old_argv);
8803
8804 gethostname(hostname, MAX_HOSTNAME_LEN);
8805
willy tarreau12350152005-12-18 01:03:27 +01008806 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008807 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008808 if (readcfgfile(cfg_cfgfile) < 0) {
8809 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8810 exit(1);
8811 }
willy tarreau12350152005-12-18 01:03:27 +01008812 if (have_appsession)
8813 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008814
willy tarreau982249e2005-12-18 00:57:06 +01008815 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008816 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8817 exit(0);
8818 }
8819
willy tarreau9fe663a2005-12-17 13:02:59 +01008820 if (cfg_maxconn > 0)
8821 global.maxconn = cfg_maxconn;
8822
willy tarreaufe2c5c12005-12-17 14:14:34 +01008823 if (cfg_pidfile) {
8824 if (global.pidfile)
8825 free(global.pidfile);
8826 global.pidfile = strdup(cfg_pidfile);
8827 }
8828
willy tarreau9fe663a2005-12-17 13:02:59 +01008829 if (global.maxconn == 0)
8830 global.maxconn = DEFAULT_MAXCONN;
8831
Willy TARREAU203b0b62006-03-12 18:00:28 +01008832 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008833
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008834 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008835 /* command line debug mode inhibits configuration mode */
8836 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8837 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008838 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8839 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008840
8841 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8842 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8843 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8844 }
8845
8846 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008847 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8848 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008849 global.nbproc = 1;
8850 }
8851
8852 if (global.nbproc < 1)
8853 global.nbproc = 1;
8854
willy tarreau0f7af912005-12-17 12:21:26 +01008855 StaticReadEvent = (fd_set *)calloc(1,
8856 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008857 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008858 StaticWriteEvent = (fd_set *)calloc(1,
8859 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008860 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008861
8862 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008863 sizeof(struct fdtab) * (global.maxsock));
8864 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008865 fdtab[i].state = FD_STCLOSE;
8866 }
8867}
8868
8869/*
willy tarreau41310e72006-03-25 18:17:56 +01008870 * this function starts all the proxies. Its return value is composed from
8871 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8872 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008873 */
willy tarreau41310e72006-03-25 18:17:56 +01008874int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008875 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008876 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008877 int err = ERR_NONE;
8878 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008879
8880 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008881 if (curproxy->state != PR_STNEW)
8882 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008883
willy tarreau41310e72006-03-25 18:17:56 +01008884 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008885 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008886 if (listener->fd != -1)
8887 continue; /* already initialized */
8888
8889 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8890 if (verbose)
8891 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8892 curproxy->id);
8893 err |= ERR_RETRYABLE;
8894 pxerr |= 1;
8895 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008896 }
willy tarreau0f7af912005-12-17 12:21:26 +01008897
willy tarreaua41a8b42005-12-17 14:02:24 +01008898 if (fd >= global.maxsock) {
8899 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8900 curproxy->id);
8901 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008902 err |= ERR_FATAL;
8903 pxerr |= 1;
8904 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008905 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008906
willy tarreaua41a8b42005-12-17 14:02:24 +01008907 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8908 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8909 (char *) &one, sizeof(one)) == -1)) {
8910 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8911 curproxy->id);
8912 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008913 err |= ERR_FATAL;
8914 pxerr |= 1;
8915 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008916 }
willy tarreau0f7af912005-12-17 12:21:26 +01008917
willy tarreaua41a8b42005-12-17 14:02:24 +01008918 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8919 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8920 curproxy->id);
8921 }
willy tarreau0f7af912005-12-17 12:21:26 +01008922
willy tarreaua41a8b42005-12-17 14:02:24 +01008923 if (bind(fd,
8924 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008925 listener->addr.ss_family == AF_INET6 ?
8926 sizeof(struct sockaddr_in6) :
8927 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008928 if (verbose)
8929 Alert("cannot bind socket for proxy %s. Aborting.\n",
8930 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008931 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008932 err |= ERR_RETRYABLE;
8933 pxerr |= 1;
8934 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008935 }
willy tarreau0f7af912005-12-17 12:21:26 +01008936
willy tarreaua41a8b42005-12-17 14:02:24 +01008937 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008938 if (verbose)
8939 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8940 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008941 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008942 err |= ERR_RETRYABLE;
8943 pxerr |= 1;
8944 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008945 }
willy tarreau0f7af912005-12-17 12:21:26 +01008946
willy tarreau41310e72006-03-25 18:17:56 +01008947 /* the socket is ready */
8948 listener->fd = fd;
8949
willy tarreaua41a8b42005-12-17 14:02:24 +01008950 /* the function for the accept() event */
8951 fdtab[fd].read = &event_accept;
8952 fdtab[fd].write = NULL; /* never called */
8953 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008954 fdtab[fd].state = FD_STLISTEN;
8955 FD_SET(fd, StaticReadEvent);
8956 fd_insert(fd);
8957 listeners++;
8958 }
willy tarreau41310e72006-03-25 18:17:56 +01008959
8960 if (!pxerr) {
8961 curproxy->state = PR_STRUN;
8962 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8963 }
willy tarreau0f7af912005-12-17 12:21:26 +01008964 }
willy tarreau41310e72006-03-25 18:17:56 +01008965
8966 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008967}
8968
willy tarreaub952e1d2005-12-18 01:31:20 +01008969int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008970
8971 appsess *temp1,*temp2;
8972 temp1 = (appsess *)key1;
8973 temp2 = (appsess *)key2;
8974
8975 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8976 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8977
8978 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8979}/* end match_str */
8980
willy tarreaub952e1d2005-12-18 01:31:20 +01008981void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008982 appsess *temp1;
8983
8984 //printf("destroy called\n");
8985 temp1 = (appsess *)data;
8986
8987 if (temp1->sessid)
8988 pool_free_to(apools.sessid, temp1->sessid);
8989
8990 if (temp1->serverid)
8991 pool_free_to(apools.serverid, temp1->serverid);
8992
8993 pool_free(appsess, temp1);
8994} /* end destroy */
8995
8996void appsession_cleanup( void )
8997{
8998 struct proxy *p = proxy;
8999
9000 while(p) {
9001 chtbl_destroy(&(p->htbl_proxy));
9002 p = p->next;
9003 }
9004}/* end appsession_cleanup() */
9005
9006void pool_destroy(void **pool)
9007{
9008 void *temp, *next;
9009 next = pool;
9010 while (next) {
9011 temp = next;
9012 next = *(void **)temp;
9013 free(temp);
9014 }
9015}/* end pool_destroy() */
9016
willy tarreaub952e1d2005-12-18 01:31:20 +01009017void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009018 struct proxy *p = proxy;
9019 struct cap_hdr *h,*h_next;
9020 struct server *s,*s_next;
9021 struct listener *l,*l_next;
9022
9023 while (p) {
9024 if (p->id)
9025 free(p->id);
9026
9027 if (p->check_req)
9028 free(p->check_req);
9029
9030 if (p->cookie_name)
9031 free(p->cookie_name);
9032
9033 if (p->capture_name)
9034 free(p->capture_name);
9035
9036 /* only strup if the user have set in config.
9037 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009038 if (p->errmsg.msg400) free(p->errmsg.msg400);
9039 if (p->errmsg.msg403) free(p->errmsg.msg403);
9040 if (p->errmsg.msg408) free(p->errmsg.msg408);
9041 if (p->errmsg.msg500) free(p->errmsg.msg500);
9042 if (p->errmsg.msg502) free(p->errmsg.msg502);
9043 if (p->errmsg.msg503) free(p->errmsg.msg503);
9044 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009045 */
9046 if (p->appsession_name)
9047 free(p->appsession_name);
9048
9049 h = p->req_cap;
9050 while (h) {
9051 h_next = h->next;
9052 if (h->name)
9053 free(h->name);
9054 pool_destroy(h->pool);
9055 free(h);
9056 h = h_next;
9057 }/* end while(h) */
9058
9059 h = p->rsp_cap;
9060 while (h) {
9061 h_next = h->next;
9062 if (h->name)
9063 free(h->name);
9064
9065 pool_destroy(h->pool);
9066 free(h);
9067 h = h_next;
9068 }/* end while(h) */
9069
9070 s = p->srv;
9071 while (s) {
9072 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009073 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009074 free(s->id);
9075
willy tarreaub952e1d2005-12-18 01:31:20 +01009076 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009077 free(s->cookie);
9078
9079 free(s);
9080 s = s_next;
9081 }/* end while(s) */
9082
9083 l = p->listen;
9084 while (l) {
9085 l_next = l->next;
9086 free(l);
9087 l = l_next;
9088 }/* end while(l) */
9089
9090 pool_destroy((void **) p->req_cap_pool);
9091 pool_destroy((void **) p->rsp_cap_pool);
9092 p = p->next;
9093 }/* end while(p) */
9094
9095 if (global.chroot) free(global.chroot);
9096 if (global.pidfile) free(global.pidfile);
9097
willy tarreau12350152005-12-18 01:03:27 +01009098 if (StaticReadEvent) free(StaticReadEvent);
9099 if (StaticWriteEvent) free(StaticWriteEvent);
9100 if (fdtab) free(fdtab);
9101
9102 pool_destroy(pool_session);
9103 pool_destroy(pool_buffer);
9104 pool_destroy(pool_fdtab);
9105 pool_destroy(pool_requri);
9106 pool_destroy(pool_task);
9107 pool_destroy(pool_capture);
9108 pool_destroy(pool_appsess);
9109
9110 if (have_appsession) {
9111 pool_destroy(apools.serverid);
9112 pool_destroy(apools.sessid);
9113 }
9114} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009115
willy tarreau41310e72006-03-25 18:17:56 +01009116/* sends the signal <sig> to all pids found in <oldpids> */
9117static void tell_old_pids(int sig) {
9118 int p;
9119 for (p = 0; p < nb_oldpids; p++)
9120 kill(oldpids[p], sig);
9121}
9122
willy tarreau0f7af912005-12-17 12:21:26 +01009123int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009124 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009125 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009126 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009127 init(argc, argv);
9128
willy tarreau0f7af912005-12-17 12:21:26 +01009129 signal(SIGQUIT, dump);
9130 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009131 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009132#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009133 signal(SIGINT, sig_int);
9134 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009135#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009136
9137 /* on very high loads, a sigpipe sometimes happen just between the
9138 * getsockopt() which tells "it's OK to write", and the following write :-(
9139 */
willy tarreau3242e862005-12-17 12:27:53 +01009140#ifndef MSG_NOSIGNAL
9141 signal(SIGPIPE, SIG_IGN);
9142#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009143
willy tarreau41310e72006-03-25 18:17:56 +01009144 /* We will loop at most 100 times with 10 ms delay each time.
9145 * That's at most 1 second. We only send a signal to old pids
9146 * if we cannot grab at least one port.
9147 */
9148 retry = MAX_START_RETRIES;
9149 err = ERR_NONE;
9150 while (retry >= 0) {
9151 struct timeval w;
9152 err = start_proxies(retry == 0 || nb_oldpids == 0);
9153 if (err != ERR_RETRYABLE)
9154 break;
9155 if (nb_oldpids == 0)
9156 break;
9157
9158 tell_old_pids(SIGTTOU);
9159 /* give some time to old processes to stop listening */
9160 w.tv_sec = 0;
9161 w.tv_usec = 10*1000;
9162 select(0, NULL, NULL, NULL, &w);
9163 retry--;
9164 }
9165
9166 /* Note: start_proxies() sends an alert when it fails. */
9167 if (err != ERR_NONE) {
9168 if (retry != MAX_START_RETRIES && nb_oldpids)
9169 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009170 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009171 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009172
9173 if (listeners == 0) {
9174 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009175 /* Note: we don't have to send anything to the old pids because we
9176 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009177 exit(1);
9178 }
9179
willy tarreaudbd3bef2006-01-20 19:35:18 +01009180 /* prepare pause/play signals */
9181 signal(SIGTTOU, sig_pause);
9182 signal(SIGTTIN, sig_listen);
9183
Willy TARREAUe3283d12006-03-01 22:15:29 +01009184 if (global.mode & MODE_DAEMON) {
9185 global.mode &= ~MODE_VERBOSE;
9186 global.mode |= MODE_QUIET;
9187 }
9188
willy tarreaud0fb4652005-12-18 01:32:04 +01009189 /* MODE_QUIET can inhibit alerts and warnings below this line */
9190
9191 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009192 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009193 /* detach from the tty */
9194 fclose(stdin); fclose(stdout); fclose(stderr);
9195 close(0); close(1); close(2);
9196 }
willy tarreau0f7af912005-12-17 12:21:26 +01009197
willy tarreaufe2c5c12005-12-17 14:14:34 +01009198 /* open log & pid files before the chroot */
9199 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9200 int pidfd;
9201 unlink(global.pidfile);
9202 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9203 if (pidfd < 0) {
9204 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009205 if (nb_oldpids)
9206 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009207 exit(1);
9208 }
9209 pidfile = fdopen(pidfd, "w");
9210 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009211
9212 /* chroot if needed */
9213 if (global.chroot != NULL) {
9214 if (chroot(global.chroot) == -1) {
9215 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009216 if (nb_oldpids)
9217 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009218 }
9219 chdir("/");
9220 }
9221
willy tarreaub1285d52005-12-18 01:20:14 +01009222 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009223 if (!global.rlimit_nofile)
9224 global.rlimit_nofile = global.maxsock;
9225
willy tarreaub1285d52005-12-18 01:20:14 +01009226 if (global.rlimit_nofile) {
9227 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9228 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9229 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9230 }
willy tarreau746e26b2006-03-25 11:14:35 +01009231 }
9232
9233 if (global.rlimit_memmax) {
9234 limit.rlim_cur = limit.rlim_max =
9235 global.rlimit_memmax * 1048576 / global.nbproc;
9236#ifdef RLIMIT_AS
9237 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9238 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9239 argv[0], global.rlimit_memmax);
9240 }
9241#else
9242 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9243 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9244 argv[0], global.rlimit_memmax);
9245 }
9246#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009247 }
9248
willy tarreau41310e72006-03-25 18:17:56 +01009249 if (nb_oldpids)
9250 tell_old_pids(oldpids_sig);
9251
9252 /* Note that any error at this stage will be fatal because we will not
9253 * be able to restart the old pids.
9254 */
9255
willy tarreau9fe663a2005-12-17 13:02:59 +01009256 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009257 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009258 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9259 exit(1);
9260 }
9261
willy tarreau036e1ce2005-12-17 13:46:33 +01009262 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009263 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9264 exit(1);
9265 }
9266
willy tarreaub1285d52005-12-18 01:20:14 +01009267 /* check ulimits */
9268 limit.rlim_cur = limit.rlim_max = 0;
9269 getrlimit(RLIMIT_NOFILE, &limit);
9270 if (limit.rlim_cur < global.maxsock) {
9271 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",
9272 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9273 }
9274
willy tarreau9fe663a2005-12-17 13:02:59 +01009275 if (global.mode & MODE_DAEMON) {
9276 int ret = 0;
9277 int proc;
9278
9279 /* the father launches the required number of processes */
9280 for (proc = 0; proc < global.nbproc; proc++) {
9281 ret = fork();
9282 if (ret < 0) {
9283 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009284 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009285 exit(1); /* there has been an error */
9286 }
9287 else if (ret == 0) /* child breaks here */
9288 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009289 if (pidfile != NULL) {
9290 fprintf(pidfile, "%d\n", ret);
9291 fflush(pidfile);
9292 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009293 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009294 /* close the pidfile both in children and father */
9295 if (pidfile != NULL)
9296 fclose(pidfile);
9297 free(global.pidfile);
9298
willy tarreau9fe663a2005-12-17 13:02:59 +01009299 if (proc == global.nbproc)
9300 exit(0); /* parent must leave */
9301
willy tarreau750a4722005-12-17 13:21:24 +01009302 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9303 * that we can detach from the TTY. We MUST NOT do it in other cases since
9304 * it would have already be done, and 0-2 would have been affected to listening
9305 * sockets
9306 */
9307 if (!(global.mode & MODE_QUIET)) {
9308 /* detach from the tty */
9309 fclose(stdin); fclose(stdout); fclose(stderr);
9310 close(0); close(1); close(2); /* close all fd's */
9311 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9312 }
willy tarreaua1598082005-12-17 13:08:06 +01009313 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009314 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009315 }
9316
willy tarreau1c2ad212005-12-18 01:11:29 +01009317#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009318 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009319 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9320 epoll_loop(POLL_LOOP_ACTION_RUN);
9321 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009322 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009323 }
9324 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009325 Warning("epoll() is not available. Using poll()/select() instead.\n");
9326 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009327 }
9328 }
9329#endif
9330
9331#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009332 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009333 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9334 poll_loop(POLL_LOOP_ACTION_RUN);
9335 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009336 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009337 }
9338 else {
9339 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009340 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009341 }
9342 }
9343#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009344 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009345 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9346 select_loop(POLL_LOOP_ACTION_RUN);
9347 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009348 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009349 }
9350 }
9351
willy tarreau0f7af912005-12-17 12:21:26 +01009352
willy tarreau12350152005-12-18 01:03:27 +01009353 /* Free all Hash Keys and all Hash elements */
9354 appsession_cleanup();
9355 /* Do some cleanup */
9356 deinit();
9357
willy tarreau0f7af912005-12-17 12:21:26 +01009358 exit(0);
9359}
willy tarreau12350152005-12-18 01:03:27 +01009360
9361#if defined(DEBUG_HASH)
9362static void print_table(const CHTbl *htbl) {
9363
9364 ListElmt *element;
9365 int i;
9366 appsess *asession;
9367
9368 /*****************************************************************************
9369 * *
9370 * Display the chained hash table. *
9371 * *
9372 *****************************************************************************/
9373
9374 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9375
9376 for (i = 0; i < TBLSIZ; i++) {
9377 fprintf(stdout, "Bucket[%03d]\n", i);
9378
9379 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9380 //fprintf(stdout, "%c", *(char *)list_data(element));
9381 asession = (appsess *)list_data(element);
9382 fprintf(stdout, "ELEM :%s:", asession->sessid);
9383 fprintf(stdout, " Server :%s: \n", asession->serverid);
9384 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9385 }
9386
9387 fprintf(stdout, "\n");
9388 }
9389 return;
9390} /* end print_table */
9391#endif
9392
9393static int appsession_init(void)
9394{
9395 static int initialized = 0;
9396 int idlen;
9397 struct server *s;
9398 struct proxy *p = proxy;
9399
9400 if (!initialized) {
9401 if (!appsession_task_init()) {
9402 apools.sessid = NULL;
9403 apools.serverid = NULL;
9404 apools.ser_waste = 0;
9405 apools.ser_use = 0;
9406 apools.ser_msize = sizeof(void *);
9407 apools.ses_waste = 0;
9408 apools.ses_use = 0;
9409 apools.ses_msize = sizeof(void *);
9410 while (p) {
9411 s = p->srv;
9412 if (apools.ses_msize < p->appsession_len)
9413 apools.ses_msize = p->appsession_len;
9414 while (s) {
9415 idlen = strlen(s->id);
9416 if (apools.ser_msize < idlen)
9417 apools.ser_msize = idlen;
9418 s = s->next;
9419 }
9420 p = p->next;
9421 }
9422 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9423 apools.ses_msize ++;
9424 }
9425 else {
9426 fprintf(stderr, "appsession_task_init failed\n");
9427 return -1;
9428 }
9429 initialized ++;
9430 }
9431 return 0;
9432}
9433
9434static int appsession_task_init(void)
9435{
9436 static int initialized = 0;
9437 struct task *t;
9438 if (!initialized) {
9439 if ((t = pool_alloc(task)) == NULL)
9440 return -1;
9441 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009442 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009443 t->state = TASK_IDLE;
9444 t->context = NULL;
9445 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9446 task_queue(t);
9447 t->process = appsession_refresh;
9448 initialized ++;
9449 }
9450 return 0;
9451}
9452
9453static int appsession_refresh(struct task *t) {
9454 struct proxy *p = proxy;
9455 CHTbl *htbl;
9456 ListElmt *element, *last;
9457 int i;
9458 appsess *asession;
9459 void *data;
9460
9461 while (p) {
9462 if (p->appsession_name != NULL) {
9463 htbl = &p->htbl_proxy;
9464 /* if we ever give up the use of TBLSIZ, we need to change this */
9465 for (i = 0; i < TBLSIZ; i++) {
9466 last = NULL;
9467 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9468 asession = (appsess *)list_data(element);
9469 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9470 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9471 int len;
9472 /*
9473 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9474 */
9475 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9476 asession->sessid, asession->serverid?asession->serverid:"(null)");
9477 write(1, trash, len);
9478 }
9479 /* delete the expired element from within the hash table */
9480 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9481 && (htbl->table[i].destroy != NULL)) {
9482 htbl->table[i].destroy(data);
9483 }
9484 if (last == NULL) {/* patient lost his head, get a new one */
9485 element = list_head(&htbl->table[i]);
9486 if (element == NULL) break; /* no heads left, go to next patient */
9487 }
9488 else
9489 element = last;
9490 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9491 else
9492 last = element;
9493 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9494 }
9495 }
9496 p = p->next;
9497 }
9498 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9499 return TBLCHKINT;
9500} /* end appsession_refresh */
9501
willy tarreau18a957c2006-04-12 19:26:23 +02009502
9503/*
9504 * Local variables:
9505 * c-indent-level: 4
9506 * c-basic-offset: 4
9507 * End:
9508 */