blob: 948fa8d7ac12b1c962d20855362e177ab9627351 [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 tarreaudfece232006-05-02 00:19:57 +02001862/* Detaches the next pending connection for either current session's server or
1863 * current session's proxy, and returns its associated session. If no pending
1864 * connection is found, NULL is returned. Note that cur->srv cannot be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001865 */
willy tarreaudfece232006-05-02 00:19:57 +02001866static struct session *pendconn_get_next_sess(struct session *cur) {
willy tarreau18a957c2006-04-12 19:26:23 +02001867 struct pendconn *p;
1868 struct session *sess;
1869
willy tarreaudfece232006-05-02 00:19:57 +02001870 p = pendconn_from_srv(cur->srv);
1871 if (!p) {
1872 p = pendconn_from_px(cur->proxy);
1873 if (!p)
1874 return NULL;
1875 p->sess->srv = cur->srv;
1876 }
willy tarreau18a957c2006-04-12 19:26:23 +02001877 sess = p->sess;
1878 pendconn_free(p);
1879 return sess;
1880}
1881
willy tarreaudfece232006-05-02 00:19:57 +02001882/* Checks if other sessions are waiting for the same server, and wakes the
1883 * first one up. Note that cur->srv cannot be NULL.
1884 */
1885void offer_connection_slot(struct session *cur) {
1886 struct session *sess;
1887
1888 sess = pendconn_get_next_sess(cur);
1889 if (sess == NULL)
1890 return;
1891 task_wakeup(&rq, sess->task);
1892}
1893
1894/* Adds the session <sess> to the pending connection list of server <sess>->srv
1895 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1896 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1897 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001898 */
willy tarreaudfece232006-05-02 00:19:57 +02001899static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001900 struct pendconn *p;
1901
1902 p = pool_alloc(pendconn);
1903 if (!p)
1904 return NULL;
1905
willy tarreau18a957c2006-04-12 19:26:23 +02001906 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001907 p->sess = sess;
1908 p->srv = sess->srv;
1909 if (sess->srv) {
1910 LIST_ADDQ(&sess->srv->pendconns, &p->list);
1911 sess->srv->nbpend++;
1912 } else {
1913 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
1914 sess->proxy->nbpend++;
1915 }
willy tarreauf32f5242006-05-02 22:54:52 +02001916 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001917 return p;
1918}
1919
1920/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001921/* more specific functions ***************************************/
1922/*********************************************************************/
1923
1924/* some prototypes */
1925static int maintain_proxies(void);
1926
willy tarreaub952e1d2005-12-18 01:31:20 +01001927/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1929 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001930static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001931#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001932 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1933#else
willy tarreaua1598082005-12-17 13:08:06 +01001934#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001935 return getsockname(fd, (struct sockaddr *)sa, salen);
1936#else
1937 return -1;
1938#endif
1939#endif
1940}
1941
1942/*
1943 * frees the context associated to a session. It must have been removed first.
1944 */
willy tarreaudfece232006-05-02 00:19:57 +02001945static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001946 if (s->pend_pos)
1947 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001948 if (s->req)
1949 pool_free(buffer, s->req);
1950 if (s->rep)
1951 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001952
1953 if (s->rsp_cap != NULL) {
1954 struct cap_hdr *h;
1955 for (h = s->proxy->rsp_cap; h; h = h->next) {
1956 if (s->rsp_cap[h->index] != NULL)
1957 pool_free_to(h->pool, s->rsp_cap[h->index]);
1958 }
1959 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1960 }
1961 if (s->req_cap != NULL) {
1962 struct cap_hdr *h;
1963 for (h = s->proxy->req_cap; h; h = h->next) {
1964 if (s->req_cap[h->index] != NULL)
1965 pool_free_to(h->pool, s->req_cap[h->index]);
1966 }
1967 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1968 }
1969
willy tarreaua1598082005-12-17 13:08:06 +01001970 if (s->logs.uri)
1971 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001972 if (s->logs.cli_cookie)
1973 pool_free(capture, s->logs.cli_cookie);
1974 if (s->logs.srv_cookie)
1975 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001976
willy tarreau5cbea6f2005-12-17 12:48:26 +01001977 pool_free(session, s);
1978}
1979
willy tarreau0f7af912005-12-17 12:21:26 +01001980
1981/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001982 * This function recounts the number of usable active and backup servers for
1983 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001984 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001985 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001986static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001987 struct server *srv;
1988
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001989 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001990 for (srv = px->srv; srv != NULL; srv = srv->next) {
1991 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001992 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001993 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001994 px->tot_wbck += srv->eweight + 1;
1995 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001996 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001997 px->tot_wact += srv->eweight + 1;
1998 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001999 }
2000 }
2001}
2002
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002003/* This function recomputes the server map for proxy px. It
2004 * relies on px->tot_wact and px->tot_wbck, so it must be
2005 * called after recount_servers(). It also expects px->srv_map
2006 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002007 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002008static void recalc_server_map(struct proxy *px) {
2009 int o, tot, flag;
2010 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002011
willy tarreau4c8c2b52006-03-24 19:36:41 +01002012 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002013 flag = SRV_RUNNING;
2014 tot = px->tot_wact;
2015 } else if (px->srv_bck) {
2016 flag = SRV_RUNNING | SRV_BACKUP;
2017 if (px->options & PR_O_USE_ALL_BK)
2018 tot = px->tot_wbck;
2019 else
2020 tot = 1; /* the first server is enough */
2021 } else {
2022 px->srv_map_sz = 0;
2023 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002024 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002025
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002026 /* this algorithm gives priority to the first server, which means that
2027 * it will respect the declaration order for equivalent weights, and
2028 * that whatever the weights, the first server called will always be
2029 * the first declard. This is an important asumption for the backup
2030 * case, where we want the first server only.
2031 */
2032 for (cur = px->srv; cur; cur = cur->next)
2033 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002034
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002035 for (o = 0; o < tot; o++) {
2036 int max = 0;
2037 best = NULL;
2038 for (cur = px->srv; cur; cur = cur->next) {
2039 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2040 int v;
2041
2042 /* If we are forced to return only one server, we don't want to
2043 * go further, because we would return the wrong one due to
2044 * divide overflow.
2045 */
2046 if (tot == 1) {
2047 best = cur;
2048 break;
2049 }
2050
2051 cur->wscore += cur->eweight + 1;
2052 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2053 if (best == NULL || v > max) {
2054 max = v;
2055 best = cur;
2056 }
2057 }
2058 }
2059 px->srv_map[o] = best;
2060 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002061 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002062 px->srv_map_sz = tot;
2063}
Willy TARREAU3481c462006-03-01 22:37:57 +01002064
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002065/*
willy tarreau898db9d2006-04-12 20:29:08 +02002066 * This function tries to find a running server with free connection slots for
2067 * the proxy <px> following the round-robin method.
2068 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2069 * to point to the next server. If no valid server is found, NULL is returned.
2070 */
2071static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2072 int newidx;
2073 struct server *srv;
2074
2075 if (px->srv_map_sz == 0)
2076 return NULL;
2077
2078 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2079 px->srv_rr_idx = 0;
2080 newidx = px->srv_rr_idx;
2081
2082 do {
2083 srv = px->srv_map[newidx++];
2084 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2085 px->srv_rr_idx = newidx;
2086 return srv;
2087 }
2088 if (newidx == px->srv_map_sz)
2089 newidx = 0;
2090 } while (newidx != px->srv_rr_idx);
2091
2092 return NULL;
2093}
2094
2095
2096/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002097 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002098 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002099 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2100 * to point to the next server. If no valid server is found, NULL is returned.
2101 */
2102static inline struct server *get_server_rr(struct proxy *px) {
2103 if (px->srv_map_sz == 0)
2104 return NULL;
2105
2106 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2107 px->srv_rr_idx = 0;
2108 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002109}
2110
willy tarreau62084d42006-03-24 18:57:41 +01002111
2112/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002113 * This function tries to find a running server for the proxy <px> following
2114 * the source hash method. Depending on the number of active/backup servers,
2115 * it will either look for active servers, or for backup servers.
2116 * If any server is found, it will be returned. If no valid server is found,
2117 * NULL is returned.
2118 */
2119static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002120 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002121
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002122 if (px->srv_map_sz == 0)
2123 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002124
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002125 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002126 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002127 while ((l + sizeof (int)) <= len) {
2128 h ^= ntohl(*(unsigned int *)(&addr[l]));
2129 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002130 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002131 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002132 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002133 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002134}
2135
2136
2137/*
willy tarreaudfece232006-05-02 00:19:57 +02002138 * This function marks the session as 'assigned' in direct or dispatch modes,
2139 * or tries to assign one in balance mode, according to the algorithm. It does
2140 * nothing if the session had already been assigned a server.
2141 *
2142 * It may return :
2143 * SRV_STATUS_OK if everything is OK.
2144 * SRV_STATUS_NOSRV if no server is available
2145 * SRV_STATUS_FULL if all servers are saturated
2146 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2147 *
2148 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2149 * not need to be called anymore. This usually means that s->srv can be trusted
2150 * in balance and direct modes. This flag is not cleared, so it's to the caller
2151 * to clear it if required (eg: redispatch).
2152 *
willy tarreau0f7af912005-12-17 12:21:26 +01002153 */
willy tarreau0f7af912005-12-17 12:21:26 +01002154
willy tarreaudfece232006-05-02 00:19:57 +02002155int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002156#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002157 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002158#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002159
willy tarreaudfece232006-05-02 00:19:57 +02002160 if (s->pend_pos)
2161 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002162
willy tarreaudfece232006-05-02 00:19:57 +02002163 if (!(s->flags & SN_ASSIGNED)) {
2164 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2165 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2166 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167
willy tarreaudfece232006-05-02 00:19:57 +02002168 if (s->proxy->options & PR_O_BALANCE_RR) {
2169 s->srv = get_server_rr_with_conns(s->proxy);
2170 if (!s->srv)
2171 return SRV_STATUS_FULL;
2172 }
2173 else if (s->proxy->options & PR_O_BALANCE_SH) {
2174 int len;
2175
2176 if (s->cli_addr.ss_family == AF_INET)
2177 len = 4;
2178 else if (s->cli_addr.ss_family == AF_INET6)
2179 len = 16;
2180 else /* unknown IP family */
2181 return SRV_STATUS_INTERNAL;
2182
2183 s->srv = get_server_sh(s->proxy,
2184 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2185 len);
2186 }
2187 else /* unknown balancing algorithm */
2188 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002189 }
willy tarreaudfece232006-05-02 00:19:57 +02002190 s->flags |= SN_ASSIGNED;
2191 }
2192 return SRV_STATUS_OK;
2193}
willy tarreau1a3442d2006-03-24 21:03:20 +01002194
willy tarreaudfece232006-05-02 00:19:57 +02002195/*
2196 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2197 * The address is taken from the currently assigned server, or from the
2198 * dispatch or transparent address.
2199 *
2200 * It may return :
2201 * SRV_STATUS_OK if everything is OK.
2202 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2203 *
2204 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2205 * not cleared, so it's to the caller to clear it if required.
2206 *
2207 */
2208int assign_server_address(struct session *s) {
2209#ifdef DEBUG_FULL
2210 fprintf(stderr,"assign_server_address : s=%p\n",s);
2211#endif
2212
2213 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2214 /* A server is necessarily known for this session */
2215 if (!(s->flags & SN_ASSIGNED))
2216 return SRV_STATUS_INTERNAL;
2217
2218 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002219
willy tarreaudfece232006-05-02 00:19:57 +02002220 /* if this server remaps proxied ports, we'll use
2221 * the port the client connected to with an offset. */
2222 if (s->srv->state & SRV_MAPPORTS) {
2223 struct sockaddr_in sockname;
2224 socklen_t namelen = sizeof(sockname);
2225
2226 if (!(s->proxy->options & PR_O_TRANSP) ||
2227 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2228 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2229 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002230 }
willy tarreau0f7af912005-12-17 12:21:26 +01002231 }
willy tarreaua1598082005-12-17 13:08:06 +01002232 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002233 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002234 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 }
2236 else if (s->proxy->options & PR_O_TRANSP) {
2237 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002238 socklen_t salen = sizeof(s->srv_addr);
2239
willy tarreau5cbea6f2005-12-17 12:48:26 +01002240 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2241 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002242 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002243 }
2244 }
willy tarreau0f7af912005-12-17 12:21:26 +01002245
willy tarreaudfece232006-05-02 00:19:57 +02002246 s->flags |= SN_ADDR_SET;
2247 return SRV_STATUS_OK;
2248}
willy tarreaua41a8b42005-12-17 14:02:24 +01002249
willy tarreaudfece232006-05-02 00:19:57 +02002250/* This function assigns a server to session <s> if required, and can add the
2251 * connection to either the assigned server's queue or to the proxy's queue.
2252 *
2253 * Returns :
2254 *
2255 * SRV_STATUS_OK if everything is OK.
2256 * SRV_STATUS_NOSRV if no server is available
2257 * SRV_STATUS_QUEUED if the connection has been queued.
2258 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2259 * connection could not be queued.
2260 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2261 *
2262 */
2263int assign_server_and_queue(struct session *s) {
2264 struct pendconn *p;
2265 int err;
2266
2267 if (s->pend_pos)
2268 return SRV_STATUS_INTERNAL;
2269
2270 if (s->flags & SN_ASSIGNED) {
2271 /* a server does not need to be assigned, perhaps because we're in
2272 * direct mode, or in dispatch or transparent modes where the server
2273 * is not needed.
2274 */
2275 if (s->srv &&
2276 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2277 p = pendconn_add(s);
2278 if (p)
2279 return SRV_STATUS_QUEUED;
2280 else
2281 return SRV_STATUS_FULL;
2282 }
2283 return SRV_STATUS_OK;
2284 }
2285
2286 /* a server needs to be assigned */
2287 err = assign_server(s);
2288 switch (err) {
2289 case SRV_STATUS_OK:
2290 /* in balance mode, we might have servers with connection limits */
2291 if (s->srv != NULL &&
2292 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2293 p = pendconn_add(s);
2294 if (p)
2295 return SRV_STATUS_QUEUED;
2296 else
2297 return SRV_STATUS_FULL;
2298 }
2299 return SRV_STATUS_OK;
2300
2301 case SRV_STATUS_FULL:
2302 /* queue this session into the proxy's queue */
2303 p = pendconn_add(s);
2304 if (p)
2305 return SRV_STATUS_QUEUED;
2306 else
2307 return SRV_STATUS_FULL;
2308
2309 case SRV_STATUS_NOSRV:
2310 case SRV_STATUS_INTERNAL:
2311 return err;
2312 default:
2313 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002314 }
willy tarreaudfece232006-05-02 00:19:57 +02002315}
2316
2317
2318/*
2319 * This function initiates a connection to the server assigned to this session
2320 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2321 * It can return one of :
2322 * - SN_ERR_NONE if everything's OK
2323 * - SN_ERR_SRVTO if there are no more servers
2324 * - SN_ERR_SRVCL if the connection was refused by the server
2325 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2326 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2327 * - SN_ERR_INTERNAL for any other purely internal errors
2328 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2329 */
2330int connect_server(struct session *s) {
2331 int fd, err;
2332
2333 if (!(s->flags & SN_ADDR_SET)) {
2334 err = assign_server_address(s);
2335 if (err != SRV_STATUS_OK)
2336 return SN_ERR_INTERNAL;
2337 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002338
willy tarreau0f7af912005-12-17 12:21:26 +01002339 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002341
2342 if (errno == ENFILE)
2343 send_log(s->proxy, LOG_EMERG,
2344 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2345 s->proxy->id, maxfd);
2346 else if (errno == EMFILE)
2347 send_log(s->proxy, LOG_EMERG,
2348 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2349 s->proxy->id, maxfd);
2350 else if (errno == ENOBUFS || errno == ENOMEM)
2351 send_log(s->proxy, LOG_EMERG,
2352 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2353 s->proxy->id, maxfd);
2354 /* this is a resource error */
2355 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002356 }
2357
willy tarreau9fe663a2005-12-17 13:02:59 +01002358 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002359 /* do not log anything there, it's a normal condition when this option
2360 * is used to serialize connections to a server !
2361 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002362 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2363 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002364 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002365 }
2366
willy tarreau0f7af912005-12-17 12:21:26 +01002367 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2368 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002369 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002370 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002371 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002372 }
2373
willy tarreaub952e1d2005-12-18 01:31:20 +01002374 if (s->proxy->options & PR_O_TCP_SRV_KA)
2375 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2376
willy tarreau0174f312005-12-18 01:02:42 +01002377 /* allow specific binding :
2378 * - server-specific at first
2379 * - proxy-specific next
2380 */
2381 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2382 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2383 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2384 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2385 s->proxy->id, s->srv->id);
2386 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002387 send_log(s->proxy, LOG_EMERG,
2388 "Cannot bind to source address before connect() for server %s/%s.\n",
2389 s->proxy->id, s->srv->id);
2390 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002391 }
2392 }
2393 else if (s->proxy->options & PR_O_BIND_SRC) {
2394 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2395 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2396 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2397 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002398 send_log(s->proxy, LOG_EMERG,
2399 "Cannot bind to source address before connect() for server %s/%s.\n",
2400 s->proxy->id, s->srv->id);
2401 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002402 }
willy tarreaua1598082005-12-17 13:08:06 +01002403 }
2404
willy tarreaub1285d52005-12-18 01:20:14 +01002405 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2406 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2407
2408 if (errno == EAGAIN || errno == EADDRINUSE) {
2409 char *msg;
2410 if (errno == EAGAIN) /* no free ports left, try again later */
2411 msg = "no free ports";
2412 else
2413 msg = "local address already in use";
2414
2415 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002416 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002417 send_log(s->proxy, LOG_EMERG,
2418 "Connect() failed for server %s/%s: %s.\n",
2419 s->proxy->id, s->srv->id, msg);
2420 return SN_ERR_RESOURCE;
2421 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002422 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002423 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002424 return SN_ERR_SRVTO;
2425 } else {
2426 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002427 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002428 close(fd);
2429 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002430 }
2431 }
2432
willy tarreau5cbea6f2005-12-17 12:48:26 +01002433 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002434 fdtab[fd].read = &event_srv_read;
2435 fdtab[fd].write = &event_srv_write;
2436 fdtab[fd].state = FD_STCONN; /* connection in progress */
2437
2438 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002439#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2440 if (PrevReadEvent) {
2441 assert(!(FD_ISSET(fd, PrevReadEvent)));
2442 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2443 }
2444#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002445
2446 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002447 if (s->srv)
2448 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002449
2450 if (s->proxy->contimeout)
2451 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2452 else
2453 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002454 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002455}
2456
2457/*
2458 * this function is called on a read event from a client socket.
2459 * It returns 0.
2460 */
2461int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002462 struct task *t = fdtab[fd].owner;
2463 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002464 struct buffer *b = s->req;
2465 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002466
willy tarreau12350152005-12-18 01:03:27 +01002467#ifdef DEBUG_FULL
2468 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2469#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002470
willy tarreau0f7af912005-12-17 12:21:26 +01002471 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002472#ifdef FILL_BUFFERS
2473 while (1)
2474#else
2475 do
2476#endif
2477 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002478 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2479 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002480 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002481 }
2482 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002483 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002484 }
2485 else {
2486 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002487 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2488 * since it means that the rewrite protection has been removed. This
2489 * implies that the if statement can be removed.
2490 */
2491 if (max > b->rlim - b->data)
2492 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002493 }
2494
2495 if (max == 0) { /* not anymore room to store data */
2496 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002497 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002498 }
2499
willy tarreau3242e862005-12-17 12:27:53 +01002500#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002502 int skerr;
2503 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002504
willy tarreau5cbea6f2005-12-17 12:48:26 +01002505 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2506 if (skerr)
2507 ret = -1;
2508 else
2509 ret = recv(fd, b->r, max, 0);
2510 }
willy tarreau3242e862005-12-17 12:27:53 +01002511#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002513#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002514 if (ret > 0) {
2515 b->r += ret;
2516 b->l += ret;
2517 s->res_cr = RES_DATA;
2518
2519 if (b->r == b->data + BUFSIZE) {
2520 b->r = b->data; /* wrap around the buffer */
2521 }
willy tarreaua1598082005-12-17 13:08:06 +01002522
2523 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002524 /* we hope to read more data or to get a close on next round */
2525 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002526 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002527 else if (ret == 0) {
2528 s->res_cr = RES_NULL;
2529 break;
2530 }
2531 else if (errno == EAGAIN) {/* ignore EAGAIN */
2532 break;
2533 }
2534 else {
2535 s->res_cr = RES_ERROR;
2536 fdtab[fd].state = FD_STERROR;
2537 break;
2538 }
2539 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002540#ifndef FILL_BUFFERS
2541 while (0);
2542#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002543 }
2544 else {
2545 s->res_cr = RES_ERROR;
2546 fdtab[fd].state = FD_STERROR;
2547 }
2548
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002550 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2552 else
2553 tv_eternity(&s->crexpire);
2554
2555 task_wakeup(&rq, t);
2556 }
willy tarreau0f7af912005-12-17 12:21:26 +01002557
willy tarreau0f7af912005-12-17 12:21:26 +01002558 return 0;
2559}
2560
2561
2562/*
2563 * this function is called on a read event from a server socket.
2564 * It returns 0.
2565 */
2566int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 struct task *t = fdtab[fd].owner;
2568 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002569 struct buffer *b = s->rep;
2570 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002571
willy tarreau12350152005-12-18 01:03:27 +01002572#ifdef DEBUG_FULL
2573 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2574#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002575
willy tarreau0f7af912005-12-17 12:21:26 +01002576 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002577#ifdef FILL_BUFFERS
2578 while (1)
2579#else
2580 do
2581#endif
2582 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2584 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002585 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002586 }
2587 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002588 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002589 }
2590 else {
2591 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002592 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2593 * since it means that the rewrite protection has been removed. This
2594 * implies that the if statement can be removed.
2595 */
2596 if (max > b->rlim - b->data)
2597 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 }
2599
2600 if (max == 0) { /* not anymore room to store data */
2601 FD_CLR(fd, StaticReadEvent);
2602 break;
2603 }
2604
willy tarreau3242e862005-12-17 12:27:53 +01002605#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002607 int skerr;
2608 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002609
willy tarreau5cbea6f2005-12-17 12:48:26 +01002610 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2611 if (skerr)
2612 ret = -1;
2613 else
2614 ret = recv(fd, b->r, max, 0);
2615 }
willy tarreau3242e862005-12-17 12:27:53 +01002616#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002617 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002618#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002619 if (ret > 0) {
2620 b->r += ret;
2621 b->l += ret;
2622 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002623
willy tarreau5cbea6f2005-12-17 12:48:26 +01002624 if (b->r == b->data + BUFSIZE) {
2625 b->r = b->data; /* wrap around the buffer */
2626 }
willy tarreaua1598082005-12-17 13:08:06 +01002627
2628 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002629 /* we hope to read more data or to get a close on next round */
2630 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002631 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 else if (ret == 0) {
2633 s->res_sr = RES_NULL;
2634 break;
2635 }
2636 else if (errno == EAGAIN) {/* ignore EAGAIN */
2637 break;
2638 }
2639 else {
2640 s->res_sr = RES_ERROR;
2641 fdtab[fd].state = FD_STERROR;
2642 break;
2643 }
2644 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002645#ifndef FILL_BUFFERS
2646 while (0);
2647#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002648 }
2649 else {
2650 s->res_sr = RES_ERROR;
2651 fdtab[fd].state = FD_STERROR;
2652 }
2653
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002655 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2657 else
2658 tv_eternity(&s->srexpire);
2659
2660 task_wakeup(&rq, t);
2661 }
willy tarreau0f7af912005-12-17 12:21:26 +01002662
willy tarreau0f7af912005-12-17 12:21:26 +01002663 return 0;
2664}
2665
2666/*
2667 * this function is called on a write event from a client socket.
2668 * It returns 0.
2669 */
2670int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002671 struct task *t = fdtab[fd].owner;
2672 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002673 struct buffer *b = s->rep;
2674 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002675
willy tarreau12350152005-12-18 01:03:27 +01002676#ifdef DEBUG_FULL
2677 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2678#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002679
2680 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002681 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002682 // max = BUFSIZE; BUG !!!!
2683 max = 0;
2684 }
2685 else if (b->r > b->w) {
2686 max = b->r - b->w;
2687 }
2688 else
2689 max = b->data + BUFSIZE - b->w;
2690
willy tarreau0f7af912005-12-17 12:21:26 +01002691 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002692 if (max == 0) {
2693 s->res_cw = RES_NULL;
2694 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002695 tv_eternity(&s->cwexpire);
2696 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002697 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002698 }
2699
willy tarreau3242e862005-12-17 12:27:53 +01002700#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002701 {
2702 int skerr;
2703 socklen_t lskerr = sizeof(skerr);
2704
2705 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2706 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002707 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002708 else
willy tarreau3242e862005-12-17 12:27:53 +01002709 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002710 }
willy tarreau3242e862005-12-17 12:27:53 +01002711#else
willy tarreau0f7af912005-12-17 12:21:26 +01002712 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002713#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002714
2715 if (ret > 0) {
2716 b->l -= ret;
2717 b->w += ret;
2718
2719 s->res_cw = RES_DATA;
2720
2721 if (b->w == b->data + BUFSIZE) {
2722 b->w = b->data; /* wrap around the buffer */
2723 }
2724 }
2725 else if (ret == 0) {
2726 /* nothing written, just make as if we were never called */
2727// s->res_cw = RES_NULL;
2728 return 0;
2729 }
2730 else if (errno == EAGAIN) /* ignore EAGAIN */
2731 return 0;
2732 else {
2733 s->res_cw = RES_ERROR;
2734 fdtab[fd].state = FD_STERROR;
2735 }
2736 }
2737 else {
2738 s->res_cw = RES_ERROR;
2739 fdtab[fd].state = FD_STERROR;
2740 }
2741
willy tarreaub1ff9db2005-12-17 13:51:03 +01002742 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002743 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002744 /* FIXME: to prevent the client from expiring read timeouts during writes,
2745 * we refresh it. A solution would be to merge read+write timeouts into a
2746 * unique one, although that needs some study particularly on full-duplex
2747 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002748 s->crexpire = s->cwexpire;
2749 }
willy tarreau0f7af912005-12-17 12:21:26 +01002750 else
2751 tv_eternity(&s->cwexpire);
2752
willy tarreau5cbea6f2005-12-17 12:48:26 +01002753 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002754 return 0;
2755}
2756
2757
2758/*
2759 * this function is called on a write event from a server socket.
2760 * It returns 0.
2761 */
2762int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002763 struct task *t = fdtab[fd].owner;
2764 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002765 struct buffer *b = s->req;
2766 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002767
willy tarreau12350152005-12-18 01:03:27 +01002768#ifdef DEBUG_FULL
2769 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2770#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002771
2772 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002773 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002774 // max = BUFSIZE; BUG !!!!
2775 max = 0;
2776 }
2777 else if (b->r > b->w) {
2778 max = b->r - b->w;
2779 }
2780 else
2781 max = b->data + BUFSIZE - b->w;
2782
willy tarreau0f7af912005-12-17 12:21:26 +01002783 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002784 if (max == 0) {
2785 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002786 if (s->srv_state == SV_STCONN) {
2787 int skerr;
2788 socklen_t lskerr = sizeof(skerr);
2789 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2790 if (skerr) {
2791 s->res_sw = RES_ERROR;
2792 fdtab[fd].state = FD_STERROR;
2793 task_wakeup(&rq, t);
2794 tv_eternity(&s->swexpire);
2795 FD_CLR(fd, StaticWriteEvent);
2796 return 0;
2797 }
2798 }
2799
willy tarreau0f7af912005-12-17 12:21:26 +01002800 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002801 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002802 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002803 tv_eternity(&s->swexpire);
2804 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002805 return 0;
2806 }
2807
willy tarreau3242e862005-12-17 12:27:53 +01002808#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002809 {
2810 int skerr;
2811 socklen_t lskerr = sizeof(skerr);
2812 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2813 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002814 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002815 else
willy tarreau3242e862005-12-17 12:27:53 +01002816 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002817 }
willy tarreau3242e862005-12-17 12:27:53 +01002818#else
willy tarreau0f7af912005-12-17 12:21:26 +01002819 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002820#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002821 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002822 if (ret > 0) {
2823 b->l -= ret;
2824 b->w += ret;
2825
2826 s->res_sw = RES_DATA;
2827
2828 if (b->w == b->data + BUFSIZE) {
2829 b->w = b->data; /* wrap around the buffer */
2830 }
2831 }
2832 else if (ret == 0) {
2833 /* nothing written, just make as if we were never called */
2834 // s->res_sw = RES_NULL;
2835 return 0;
2836 }
2837 else if (errno == EAGAIN) /* ignore EAGAIN */
2838 return 0;
2839 else {
2840 s->res_sw = RES_ERROR;
2841 fdtab[fd].state = FD_STERROR;
2842 }
2843 }
2844 else {
2845 s->res_sw = RES_ERROR;
2846 fdtab[fd].state = FD_STERROR;
2847 }
2848
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002849 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2850 * otherwise it could loop indefinitely !
2851 */
2852 if (s->srv_state != SV_STCONN) {
2853 if (s->proxy->srvtimeout) {
2854 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002855 /* FIXME: to prevent the server from expiring read timeouts during writes,
2856 * we refresh it. A solution would be to merge read+write+connect timeouts
2857 * into a unique one since we don't mind expiring on read or write, and none
2858 * of them is enabled while waiting for connect(), although that needs some
2859 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002860 s->srexpire = s->swexpire;
2861 }
2862 else
2863 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002864 }
willy tarreau0f7af912005-12-17 12:21:26 +01002865
willy tarreau5cbea6f2005-12-17 12:48:26 +01002866 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002867 return 0;
2868}
2869
2870
2871/*
willy tarreaue39cd132005-12-17 13:00:18 +01002872 * returns a message to the client ; the connection is shut down for read,
2873 * and the request is cleared so that no server connection can be initiated.
2874 * The client must be in a valid state for this (HEADER, DATA ...).
2875 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002876 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002877 */
2878void client_retnclose(struct session *s, int len, const char *msg) {
2879 FD_CLR(s->cli_fd, StaticReadEvent);
2880 FD_SET(s->cli_fd, StaticWriteEvent);
2881 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002882 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002883 shutdown(s->cli_fd, SHUT_RD);
2884 s->cli_state = CL_STSHUTR;
2885 strcpy(s->rep->data, msg);
2886 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002887 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002888 s->rep->r += len;
2889 s->req->l = 0;
2890}
2891
2892
2893/*
2894 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002895 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002896 */
2897void client_return(struct session *s, int len, const char *msg) {
2898 strcpy(s->rep->data, msg);
2899 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002900 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002901 s->rep->r += len;
2902 s->req->l = 0;
2903}
2904
willy tarreau9fe663a2005-12-17 13:02:59 +01002905/*
2906 * send a log for the session when we have enough info about it
2907 */
2908void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002909 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002910 struct proxy *p = s->proxy;
2911 int log;
2912 char *uri;
2913 char *pxid;
2914 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002915 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002916
2917 /* This is a first attempt at a better logging system.
2918 * For now, we rely on send_log() to provide the date, although it obviously
2919 * is the date of the log and not of the request, and most fields are not
2920 * computed.
2921 */
2922
willy tarreaua1598082005-12-17 13:08:06 +01002923 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002924
willy tarreau8a86dbf2005-12-18 00:45:59 +01002925 if (s->cli_addr.ss_family == AF_INET)
2926 inet_ntop(AF_INET,
2927 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2928 pn, sizeof(pn));
2929 else
2930 inet_ntop(AF_INET6,
2931 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2932 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002933
willy tarreauc1cae632005-12-17 14:12:23 +01002934 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002935 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002936 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002937
willy tarreauc1cae632005-12-17 14:12:23 +01002938 tm = localtime(&s->logs.tv_accept.tv_sec);
2939 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002940 char tmpline[MAX_SYSLOG_LEN], *h;
2941 int hdr;
2942
2943 h = tmpline;
2944 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2945 *(h++) = ' ';
2946 *(h++) = '{';
2947 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2948 if (hdr)
2949 *(h++) = '|';
2950 if (s->req_cap[hdr] != NULL)
2951 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2952 }
2953 *(h++) = '}';
2954 }
2955
2956 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2957 *(h++) = ' ';
2958 *(h++) = '{';
2959 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2960 if (hdr)
2961 *(h++) = '|';
2962 if (s->rsp_cap[hdr] != NULL)
2963 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2964 }
2965 *(h++) = '}';
2966 }
2967
2968 if (h < tmpline + sizeof(tmpline) - 4) {
2969 *(h++) = ' ';
2970 *(h++) = '"';
2971 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2972 *(h++) = '"';
2973 }
2974 *h = '\0';
2975
willy tarreauf32f5242006-05-02 22:54:52 +02002976 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 +01002977 pn,
2978 (s->cli_addr.ss_family == AF_INET) ?
2979 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2980 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002981 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2982 tm->tm_hour, tm->tm_min, tm->tm_sec,
2983 pxid, srv,
2984 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002985 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2986 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002987 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002988 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2989 s->logs.status,
2990 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002991 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2992 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002993 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2994 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2995 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2996 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauf32f5242006-05-02 22:54:52 +02002997 s->srv ? s->srv->cur_sess : 0, s->logs.queue_size,
2998 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002999 }
3000 else {
willy tarreauf32f5242006-05-02 22:54:52 +02003001 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 +01003002 pn,
3003 (s->cli_addr.ss_family == AF_INET) ?
3004 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3005 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003006 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3007 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003008 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003009 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003010 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3011 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003012 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003013 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauf32f5242006-05-02 22:54:52 +02003014 s->srv ? s->srv->cur_sess : 0, s->logs.queue_size,
3015 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01003016 }
3017
3018 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003019}
3020
willy tarreaue39cd132005-12-17 13:00:18 +01003021
3022/*
willy tarreau0f7af912005-12-17 12:21:26 +01003023 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003024 * to an accept. It tries to accept as many connections as possible.
3025 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003026 */
3027int event_accept(int fd) {
3028 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 struct session *s;
3030 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003031 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003032 int max_accept;
3033
3034 if (global.nbproc > 1)
3035 max_accept = 8; /* let other processes catch some connections too */
3036 else
3037 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003038
willy tarreauc2becdc2006-03-19 19:36:48 +01003039 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003040 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003041 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003042
willy tarreaub1285d52005-12-18 01:20:14 +01003043 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3044 switch (errno) {
3045 case EAGAIN:
3046 case EINTR:
3047 case ECONNABORTED:
3048 return 0; /* nothing more to accept */
3049 case ENFILE:
3050 send_log(p, LOG_EMERG,
3051 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3052 p->id, maxfd);
3053 return 0;
3054 case EMFILE:
3055 send_log(p, LOG_EMERG,
3056 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3057 p->id, maxfd);
3058 return 0;
3059 case ENOBUFS:
3060 case ENOMEM:
3061 send_log(p, LOG_EMERG,
3062 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3063 p->id, maxfd);
3064 return 0;
3065 default:
3066 return 0;
3067 }
3068 }
willy tarreau0f7af912005-12-17 12:21:26 +01003069
willy tarreau5cbea6f2005-12-17 12:48:26 +01003070 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3071 Alert("out of memory in event_accept().\n");
3072 FD_CLR(fd, StaticReadEvent);
3073 p->state = PR_STIDLE;
3074 close(cfd);
3075 return 0;
3076 }
willy tarreau0f7af912005-12-17 12:21:26 +01003077
willy tarreaub1285d52005-12-18 01:20:14 +01003078 /* if this session comes from a known monitoring system, we want to ignore
3079 * it as soon as possible, which means closing it immediately for TCP.
3080 */
3081 s->flags = 0;
3082 if (addr.ss_family == AF_INET &&
3083 p->mon_mask.s_addr &&
3084 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3085 if (p->mode == PR_MODE_TCP) {
3086 close(cfd);
3087 pool_free(session, s);
3088 continue;
3089 }
3090 s->flags |= SN_MONITOR;
3091 }
3092
willy tarreau5cbea6f2005-12-17 12:48:26 +01003093 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3094 Alert("out of memory in event_accept().\n");
3095 FD_CLR(fd, StaticReadEvent);
3096 p->state = PR_STIDLE;
3097 close(cfd);
3098 pool_free(session, s);
3099 return 0;
3100 }
willy tarreau0f7af912005-12-17 12:21:26 +01003101
willy tarreau5cbea6f2005-12-17 12:48:26 +01003102 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003103 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3105 close(cfd);
3106 pool_free(task, t);
3107 pool_free(session, s);
3108 return 0;
3109 }
willy tarreau0f7af912005-12-17 12:21:26 +01003110
willy tarreau5cbea6f2005-12-17 12:48:26 +01003111 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3112 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3113 (char *) &one, sizeof(one)) == -1)) {
3114 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3115 close(cfd);
3116 pool_free(task, t);
3117 pool_free(session, s);
3118 return 0;
3119 }
willy tarreau0f7af912005-12-17 12:21:26 +01003120
willy tarreaub952e1d2005-12-18 01:31:20 +01003121 if (p->options & PR_O_TCP_CLI_KA)
3122 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3123
willy tarreau9fe663a2005-12-17 13:02:59 +01003124 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003125 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003126 t->state = TASK_IDLE;
3127 t->process = process_session;
3128 t->context = s;
3129
3130 s->task = t;
3131 s->proxy = p;
3132 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3133 s->srv_state = SV_STIDLE;
3134 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003135
willy tarreau9fe663a2005-12-17 13:02:59 +01003136 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3137 s->cli_fd = cfd;
3138 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003139 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003140 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003141
willy tarreaub1285d52005-12-18 01:20:14 +01003142 if (s->flags & SN_MONITOR)
3143 s->logs.logwait = 0;
3144 else
3145 s->logs.logwait = p->to_log;
3146
willy tarreaua1598082005-12-17 13:08:06 +01003147 s->logs.tv_accept = now;
3148 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003149 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003150 s->logs.t_connect = -1;
3151 s->logs.t_data = -1;
3152 s->logs.t_close = 0;
3153 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003154 s->logs.cli_cookie = NULL;
3155 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003156 s->logs.status = -1;
3157 s->logs.bytes = 0;
willy tarreauf32f5242006-05-02 22:54:52 +02003158 s->logs.queue_size = p->totpend; /* we get the number of pending conns before us */
willy tarreau9fe663a2005-12-17 13:02:59 +01003159
willy tarreau2f6ba652005-12-17 13:57:42 +01003160 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003161 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003162
willy tarreau4302f492005-12-18 01:00:37 +01003163 if (p->nb_req_cap > 0) {
3164 if ((s->req_cap =
3165 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3166 == NULL) { /* no memory */
3167 close(cfd); /* nothing can be done for this fd without memory */
3168 pool_free(task, t);
3169 pool_free(session, s);
3170 return 0;
3171 }
3172 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3173 }
3174 else
3175 s->req_cap = NULL;
3176
3177 if (p->nb_rsp_cap > 0) {
3178 if ((s->rsp_cap =
3179 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3180 == NULL) { /* no memory */
3181 if (s->req_cap != NULL)
3182 pool_free_to(p->req_cap_pool, s->req_cap);
3183 close(cfd); /* nothing can be done for this fd without memory */
3184 pool_free(task, t);
3185 pool_free(session, s);
3186 return 0;
3187 }
3188 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3189 }
3190 else
3191 s->rsp_cap = NULL;
3192
willy tarreau5cbea6f2005-12-17 12:48:26 +01003193 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3194 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003195 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003196 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003197
willy tarreau8a86dbf2005-12-18 00:45:59 +01003198 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003199 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003201 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003202
willy tarreau9fe663a2005-12-17 13:02:59 +01003203 if (p->to_log) {
3204 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003205 if (s->logs.logwait & LW_CLIP)
3206 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003207 sess_log(s);
3208 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003209 else if (s->cli_addr.ss_family == AF_INET) {
3210 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3211 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3212 sn, sizeof(sn)) &&
3213 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3214 pn, sizeof(pn))) {
3215 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3216 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3217 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3218 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3219 }
3220 }
3221 else {
3222 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3223 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3224 sn, sizeof(sn)) &&
3225 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3226 pn, sizeof(pn))) {
3227 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3228 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3229 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3230 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3231 }
3232 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 }
willy tarreau0f7af912005-12-17 12:21:26 +01003234
willy tarreau982249e2005-12-18 00:57:06 +01003235 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003236 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003237 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003238 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003239 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003240 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003241 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003242 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003243
willy tarreau8a86dbf2005-12-18 00:45:59 +01003244 if (s->cli_addr.ss_family == AF_INET) {
3245 char pn[INET_ADDRSTRLEN];
3246 inet_ntop(AF_INET,
3247 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3248 pn, sizeof(pn));
3249
3250 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3251 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3252 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3253 }
3254 else {
3255 char pn[INET6_ADDRSTRLEN];
3256 inet_ntop(AF_INET6,
3257 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3258 pn, sizeof(pn));
3259
3260 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3261 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3262 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3263 }
3264
willy tarreauef900ab2005-12-17 12:52:52 +01003265 write(1, trash, len);
3266 }
willy tarreau0f7af912005-12-17 12:21:26 +01003267
willy tarreau5cbea6f2005-12-17 12:48:26 +01003268 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003269 if (s->rsp_cap != NULL)
3270 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3271 if (s->req_cap != NULL)
3272 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003273 close(cfd); /* nothing can be done for this fd without memory */
3274 pool_free(task, t);
3275 pool_free(session, s);
3276 return 0;
3277 }
willy tarreau4302f492005-12-18 01:00:37 +01003278
willy tarreau5cbea6f2005-12-17 12:48:26 +01003279 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003280 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003281 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3282 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003283 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003284 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003285
willy tarreau5cbea6f2005-12-17 12:48:26 +01003286 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3287 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003288 if (s->rsp_cap != NULL)
3289 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3290 if (s->req_cap != NULL)
3291 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003292 close(cfd); /* nothing can be done for this fd without memory */
3293 pool_free(task, t);
3294 pool_free(session, s);
3295 return 0;
3296 }
3297 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003298 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003299 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 +01003300
willy tarreau5cbea6f2005-12-17 12:48:26 +01003301 fdtab[cfd].read = &event_cli_read;
3302 fdtab[cfd].write = &event_cli_write;
3303 fdtab[cfd].owner = t;
3304 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003305
willy tarreaub1285d52005-12-18 01:20:14 +01003306 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3307 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3308 /* Either we got a request from a monitoring system on an HTTP instance,
3309 * or we're in health check mode with the 'httpchk' option enabled. In
3310 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3311 */
3312 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3313 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3314 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003315 }
3316 else {
3317 FD_SET(cfd, StaticReadEvent);
3318 }
3319
willy tarreaub952e1d2005-12-18 01:31:20 +01003320#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3321 if (PrevReadEvent) {
3322 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3323 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3324 }
3325#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003326 fd_insert(cfd);
3327
3328 tv_eternity(&s->cnexpire);
3329 tv_eternity(&s->srexpire);
3330 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003331 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003332 tv_eternity(&s->cwexpire);
3333
willy tarreaub1285d52005-12-18 01:20:14 +01003334 if (s->proxy->clitimeout) {
3335 if (FD_ISSET(cfd, StaticReadEvent))
3336 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3337 if (FD_ISSET(cfd, StaticWriteEvent))
3338 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3339 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003340
willy tarreaub1285d52005-12-18 01:20:14 +01003341 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342
3343 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003344
3345 if (p->mode != PR_MODE_HEALTH)
3346 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347
3348 p->nbconn++;
3349 actconn++;
3350 totalconn++;
3351
willy tarreaub952e1d2005-12-18 01:31:20 +01003352 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 } /* end of while (p->nbconn < p->maxconn) */
3354 return 0;
3355}
willy tarreau0f7af912005-12-17 12:21:26 +01003356
willy tarreau0f7af912005-12-17 12:21:26 +01003357
willy tarreau5cbea6f2005-12-17 12:48:26 +01003358/*
3359 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003360 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3361 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003362 * or -1 if an error occured.
3363 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003364int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 struct task *t = fdtab[fd].owner;
3366 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003367 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003368 socklen_t lskerr = sizeof(skerr);
3369
willy tarreau05be12b2006-03-19 19:35:00 +01003370 skerr = 1;
3371 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3372 || (skerr != 0)) {
3373 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003375 fdtab[fd].state = FD_STERROR;
3376 FD_CLR(fd, StaticWriteEvent);
3377 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003378 else if (s->result != -1) {
3379 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003380 if (s->proxy->options & PR_O_HTTP_CHK) {
3381 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003382 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003383 * so we'll send the request, and won't wake the checker up now.
3384 */
3385#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003386 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003387#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003388 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003389#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003390 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003391 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3392 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3393 return 0;
3394 }
willy tarreau05be12b2006-03-19 19:35:00 +01003395 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003396 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003397 FD_CLR(fd, StaticWriteEvent);
3398 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003399 }
3400 else {
3401 /* good TCP connection is enough */
3402 s->result = 1;
3403 }
3404 }
3405
3406 task_wakeup(&rq, t);
3407 return 0;
3408}
3409
willy tarreau0f7af912005-12-17 12:21:26 +01003410
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003411/*
3412 * This function is used only for server health-checks. It handles
3413 * the server's reply to an HTTP request. It returns 1 if the server replies
3414 * 2xx or 3xx (valid responses), or -1 in other cases.
3415 */
3416int event_srv_chk_r(int fd) {
3417 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003418 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003419 struct task *t = fdtab[fd].owner;
3420 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003421 int skerr;
3422 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003423
willy tarreaua4a583a2005-12-18 01:39:19 +01003424 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003425
willy tarreau05be12b2006-03-19 19:35:00 +01003426 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3427 if (!skerr) {
3428#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003429 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003430#else
willy tarreau05be12b2006-03-19 19:35:00 +01003431 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3432 * but the connection was closed on the remote end. Fortunately, recv still
3433 * works correctly and we don't need to do the getsockopt() on linux.
3434 */
3435 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003436#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003437
3438 if ((len >= sizeof("HTTP/1.0 000")) &&
3439 !memcmp(reply, "HTTP/1.", 7) &&
3440 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3441 result = 1;
3442 }
3443
3444 if (result == -1)
3445 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003446
3447 if (s->result != -1)
3448 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003449
3450 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003451 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003452 return 0;
3453}
3454
3455
3456/*
3457 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3458 * and moves <end> just after the end of <str>.
3459 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3460 * the shift value (positive or negative) is returned.
3461 * If there's no space left, the move is not done.
3462 *
3463 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003464int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003465 int delta;
3466 int len;
3467
3468 len = strlen(str);
3469 delta = len - (end - pos);
3470
3471 if (delta + b->r >= b->data + BUFSIZE)
3472 return 0; /* no space left */
3473
3474 /* first, protect the end of the buffer */
3475 memmove(end + delta, end, b->data + b->l - end);
3476
3477 /* now, copy str over pos */
3478 memcpy(pos, str,len);
3479
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480 /* we only move data after the displaced zone */
3481 if (b->r > pos) b->r += delta;
3482 if (b->w > pos) b->w += delta;
3483 if (b->h > pos) b->h += delta;
3484 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003485 b->l += delta;
3486
3487 return delta;
3488}
3489
willy tarreau8337c6b2005-12-17 13:41:01 +01003490/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003491 * len is 0.
3492 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003493int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003494 int delta;
3495
3496 delta = len - (end - pos);
3497
3498 if (delta + b->r >= b->data + BUFSIZE)
3499 return 0; /* no space left */
3500
Willy TARREAUe78ae262006-01-08 01:24:12 +01003501 if (b->data + b->l < end)
3502 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3503 return 0;
3504
willy tarreau0f7af912005-12-17 12:21:26 +01003505 /* first, protect the end of the buffer */
3506 memmove(end + delta, end, b->data + b->l - end);
3507
3508 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003509 if (len)
3510 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003511
willy tarreau5cbea6f2005-12-17 12:48:26 +01003512 /* we only move data after the displaced zone */
3513 if (b->r > pos) b->r += delta;
3514 if (b->w > pos) b->w += delta;
3515 if (b->h > pos) b->h += delta;
3516 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003517 b->l += delta;
3518
3519 return delta;
3520}
3521
3522
3523int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3524 char *old_dst = dst;
3525
3526 while (*str) {
3527 if (*str == '\\') {
3528 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003529 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003530 int len, num;
3531
3532 num = *str - '0';
3533 str++;
3534
willy tarreau8a86dbf2005-12-18 00:45:59 +01003535 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003536 len = matches[num].rm_eo - matches[num].rm_so;
3537 memcpy(dst, src + matches[num].rm_so, len);
3538 dst += len;
3539 }
3540
3541 }
3542 else if (*str == 'x') {
3543 unsigned char hex1, hex2;
3544 str++;
3545
willy tarreauc1f47532005-12-18 01:08:26 +01003546 hex1 = toupper(*str++) - '0';
3547 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003548
3549 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3550 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3551 *dst++ = (hex1<<4) + hex2;
3552 }
3553 else
3554 *dst++ = *str++;
3555 }
3556 else
3557 *dst++ = *str++;
3558 }
3559 *dst = 0;
3560 return dst - old_dst;
3561}
3562
willy tarreauc1f47532005-12-18 01:08:26 +01003563static int ishex(char s)
3564{
3565 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3566}
3567
3568/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3569char *check_replace_string(char *str)
3570{
3571 char *err = NULL;
3572 while (*str) {
3573 if (*str == '\\') {
3574 err = str; /* in case of a backslash, we return the pointer to it */
3575 str++;
3576 if (!*str)
3577 return err;
3578 else if (isdigit((int)*str))
3579 err = NULL;
3580 else if (*str == 'x') {
3581 str++;
3582 if (!ishex(*str))
3583 return err;
3584 str++;
3585 if (!ishex(*str))
3586 return err;
3587 err = NULL;
3588 }
3589 else {
3590 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3591 err = NULL;
3592 }
3593 }
3594 str++;
3595 }
3596 return err;
3597}
3598
3599
willy tarreau9fe663a2005-12-17 13:02:59 +01003600
willy tarreau0f7af912005-12-17 12:21:26 +01003601/*
3602 * manages the client FSM and its socket. BTW, it also tries to handle the
3603 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3604 * 0 else.
3605 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003607 int s = t->srv_state;
3608 int c = t->cli_state;
3609 struct buffer *req = t->req;
3610 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003611 int method_checked = 0;
3612 appsess *asession_temp = NULL;
3613 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003614
willy tarreau750a4722005-12-17 13:21:24 +01003615#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003616 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3617 cli_stnames[c], srv_stnames[s],
3618 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3619 t->crexpire.tv_sec, t->crexpire.tv_usec,
3620 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003621#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003622 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3623 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3624 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3625 //);
3626 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003627 /* now parse the partial (or complete) headers */
3628 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3629 char *ptr;
3630 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003631 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003632
willy tarreau5cbea6f2005-12-17 12:48:26 +01003633 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003634
willy tarreau0f7af912005-12-17 12:21:26 +01003635 /* look for the end of the current header */
3636 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3637 ptr++;
3638
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003640 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003641
3642 /*
3643 * first, let's check that it's not a leading empty line, in
3644 * which case we'll ignore and remove it (according to RFC2616).
3645 */
3646 if (req->h == req->data) {
3647 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3648 if (ptr > req->r - 2) {
3649 /* this is a partial header, let's wait for more to come */
3650 req->lr = ptr;
3651 break;
3652 }
3653
3654 /* now we know that *ptr is either \r or \n,
3655 * and that there are at least 1 char after it.
3656 */
3657 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3658 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3659 else
3660 req->lr = ptr + 2; /* \r\n or \n\r */
3661 /* ignore empty leading lines */
3662 buffer_replace2(req, req->h, req->lr, NULL, 0);
3663 req->h = req->lr;
3664 continue;
3665 }
3666
willy tarreau5cbea6f2005-12-17 12:48:26 +01003667 /* we can only get here after an end of headers */
3668 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003669
willy tarreaue39cd132005-12-17 13:00:18 +01003670 if (t->flags & SN_CLDENY) {
3671 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003672 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003673 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003674 if (!(t->flags & SN_ERR_MASK))
3675 t->flags |= SN_ERR_PRXCOND;
3676 if (!(t->flags & SN_FINST_MASK))
3677 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003678 return 1;
3679 }
3680
willy tarreau5cbea6f2005-12-17 12:48:26 +01003681 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003682 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3683 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003684 }
willy tarreau0f7af912005-12-17 12:21:26 +01003685
willy tarreau9fe663a2005-12-17 13:02:59 +01003686 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003687 if (t->cli_addr.ss_family == AF_INET) {
3688 unsigned char *pn;
3689 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3690 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3691 pn[0], pn[1], pn[2], pn[3]);
3692 buffer_replace2(req, req->h, req->h, trash, len);
3693 }
3694 else if (t->cli_addr.ss_family == AF_INET6) {
3695 char pn[INET6_ADDRSTRLEN];
3696 inet_ntop(AF_INET6,
3697 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3698 pn, sizeof(pn));
3699 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3700 buffer_replace2(req, req->h, req->h, trash, len);
3701 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003702 }
3703
willy tarreau25c4ea52005-12-18 00:49:49 +01003704 /* add a "connection: close" line if needed */
3705 if (t->proxy->options & PR_O_HTTP_CLOSE)
3706 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3707
willy tarreau982249e2005-12-18 00:57:06 +01003708 if (!memcmp(req->data, "POST ", 5)) {
3709 /* this is a POST request, which is not cacheable by default */
3710 t->flags |= SN_POST;
3711 }
willy tarreaucd878942005-12-17 13:27:43 +01003712
willy tarreau5cbea6f2005-12-17 12:48:26 +01003713 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003714 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003715
willy tarreau750a4722005-12-17 13:21:24 +01003716 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003717 /* FIXME: we'll set the client in a wait state while we try to
3718 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003719 * better to release the maximum of system buffers instead ?
3720 * The solution is to enable the FD but set its time-out to
3721 * eternity as long as the server-side does not enable data xfer.
3722 * CL_STDATA also has to take care of this, which is done below.
3723 */
willy tarreauef900ab2005-12-17 12:52:52 +01003724 //FD_CLR(t->cli_fd, StaticReadEvent);
3725 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003726
3727 /* FIXME: if we break here (as up to 1.1.23), having the client
3728 * shutdown its connection can lead to an abort further.
3729 * it's better to either return 1 or even jump directly to the
3730 * data state which will save one schedule.
3731 */
3732 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003733
3734 if (!t->proxy->clitimeout ||
3735 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3736 /* If the client has no timeout, or if the server is not ready yet,
3737 * and we know for sure that it can expire, then it's cleaner to
3738 * disable the timeout on the client side so that too low values
3739 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003740 *
3741 * FIXME-20050705: the server needs a way to re-enable this time-out
3742 * when it switches its state, otherwise a client can stay connected
3743 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003744 */
3745 tv_eternity(&t->crexpire);
3746
willy tarreau197e8ec2005-12-17 14:10:59 +01003747 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003748 }
willy tarreau0f7af912005-12-17 12:21:26 +01003749
Willy TARREAU13032e72006-03-12 17:31:45 +01003750 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3751 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003752 /* this is a partial header, let's wait for more to come */
3753 req->lr = ptr;
3754 break;
3755 }
willy tarreau0f7af912005-12-17 12:21:26 +01003756
willy tarreau5cbea6f2005-12-17 12:48:26 +01003757 /* now we know that *ptr is either \r or \n,
3758 * and that there are at least 1 char after it.
3759 */
3760 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3761 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3762 else
3763 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003764
willy tarreau5cbea6f2005-12-17 12:48:26 +01003765 /*
3766 * now we know that we have a full header ; we can do whatever
3767 * we want with these pointers :
3768 * req->h = beginning of header
3769 * ptr = end of header (first \r or \n)
3770 * req->lr = beginning of next line (next rep->h)
3771 * req->r = end of data (not used at this stage)
3772 */
willy tarreau0f7af912005-12-17 12:21:26 +01003773
willy tarreau12350152005-12-18 01:03:27 +01003774 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3775 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3776 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3777
3778 /* skip ; */
3779 request_line++;
3780
3781 /* look if we have a jsessionid */
3782
3783 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3784
3785 /* skip jsessionid= */
3786 request_line += t->proxy->appsession_name_len + 1;
3787
3788 /* First try if we allready have an appsession */
3789 asession_temp = &local_asession;
3790
3791 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3792 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3793 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3794 return 0;
3795 }
3796
3797 /* Copy the sessionid */
3798 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3799 asession_temp->sessid[t->proxy->appsession_len] = 0;
3800 asession_temp->serverid = NULL;
3801
3802 /* only do insert, if lookup fails */
3803 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3804 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3805 Alert("Not enough memory process_cli():asession:calloc().\n");
3806 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3807 return 0;
3808 }
3809 asession_temp->sessid = local_asession.sessid;
3810 asession_temp->serverid = local_asession.serverid;
3811 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003812 } /* end if (chtbl_lookup()) */
3813 else {
willy tarreau12350152005-12-18 01:03:27 +01003814 /*free wasted memory;*/
3815 pool_free_to(apools.sessid, local_asession.sessid);
3816 }
3817
3818 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3819 asession_temp->request_count++;
3820
3821#if defined(DEBUG_HASH)
3822 print_table(&(t->proxy->htbl_proxy));
3823#endif
3824
3825 if (asession_temp->serverid == NULL) {
3826 Alert("Found Application Session without matching server.\n");
3827 } else {
3828 struct server *srv = t->proxy->srv;
3829 while (srv) {
3830 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3831 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3832 /* we found the server and it's usable */
3833 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003834 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003835 t->srv = srv;
3836 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003837 } else {
willy tarreau12350152005-12-18 01:03:27 +01003838 t->flags &= ~SN_CK_MASK;
3839 t->flags |= SN_CK_DOWN;
3840 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003841 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003842 srv = srv->next;
3843 }/* end while(srv) */
3844 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003845 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003846 else {
3847 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3848 }
willy tarreau598da412005-12-18 01:07:29 +01003849 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003850 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003851 else{
3852 //printf("No Methode-Header with Session-String\n");
3853 }
3854
willy tarreau8337c6b2005-12-17 13:41:01 +01003855 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003856 /* we have a complete HTTP request that we must log */
3857 int urilen;
3858
willy tarreaua1598082005-12-17 13:08:06 +01003859 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003860 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003861 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003862 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003863 if (!(t->flags & SN_ERR_MASK))
3864 t->flags |= SN_ERR_PRXCOND;
3865 if (!(t->flags & SN_FINST_MASK))
3866 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003867 return 1;
3868 }
3869
3870 urilen = ptr - req->h;
3871 if (urilen >= REQURI_LEN)
3872 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003873 memcpy(t->logs.uri, req->h, urilen);
3874 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003875
willy tarreaua1598082005-12-17 13:08:06 +01003876 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003877 sess_log(t);
3878 }
willy tarreau4302f492005-12-18 01:00:37 +01003879 else if (t->logs.logwait & LW_REQHDR) {
3880 struct cap_hdr *h;
3881 int len;
3882 for (h = t->proxy->req_cap; h; h = h->next) {
3883 if ((h->namelen + 2 <= ptr - req->h) &&
3884 (req->h[h->namelen] == ':') &&
3885 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3886
3887 if (t->req_cap[h->index] == NULL)
3888 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3889
3890 len = ptr - (req->h + h->namelen + 2);
3891 if (len > h->len)
3892 len = h->len;
3893
3894 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3895 t->req_cap[h->index][len]=0;
3896 }
3897 }
3898
3899 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003900
willy tarreau5cbea6f2005-12-17 12:48:26 +01003901 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003902
willy tarreau982249e2005-12-18 00:57:06 +01003903 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003904 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003905 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 +01003906 max = ptr - req->h;
3907 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003908 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 trash[len++] = '\n';
3910 write(1, trash, len);
3911 }
willy tarreau0f7af912005-12-17 12:21:26 +01003912
willy tarreau25c4ea52005-12-18 00:49:49 +01003913
3914 /* remove "connection: " if needed */
3915 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3916 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3917 delete_header = 1;
3918 }
3919
willy tarreau5cbea6f2005-12-17 12:48:26 +01003920 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003921 if (!delete_header && t->proxy->req_exp != NULL
3922 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003923 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003924 char term;
3925
3926 term = *ptr;
3927 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003928 exp = t->proxy->req_exp;
3929 do {
3930 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3931 switch (exp->action) {
3932 case ACT_ALLOW:
3933 if (!(t->flags & SN_CLDENY))
3934 t->flags |= SN_CLALLOW;
3935 break;
3936 case ACT_REPLACE:
3937 if (!(t->flags & SN_CLDENY)) {
3938 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3939 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3940 }
3941 break;
3942 case ACT_REMOVE:
3943 if (!(t->flags & SN_CLDENY))
3944 delete_header = 1;
3945 break;
3946 case ACT_DENY:
3947 if (!(t->flags & SN_CLALLOW))
3948 t->flags |= SN_CLDENY;
3949 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003950 case ACT_PASS: /* we simply don't deny this one */
3951 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003952 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003953 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003954 }
willy tarreaue39cd132005-12-17 13:00:18 +01003955 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003957 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003958
willy tarreau240afa62005-12-17 13:14:35 +01003959 /* Now look for cookies. Conforming to RFC2109, we have to support
3960 * attributes whose name begin with a '$', and associate them with
3961 * the right cookie, if we want to delete this cookie.
3962 * So there are 3 cases for each cookie read :
3963 * 1) it's a special attribute, beginning with a '$' : ignore it.
3964 * 2) it's a server id cookie that we *MAY* want to delete : save
3965 * some pointers on it (last semi-colon, beginning of cookie...)
3966 * 3) it's an application cookie : we *MAY* have to delete a previous
3967 * "special" cookie.
3968 * At the end of loop, if a "special" cookie remains, we may have to
3969 * remove it. If no application cookie persists in the header, we
3970 * *MUST* delete it
3971 */
willy tarreau12350152005-12-18 01:03:27 +01003972 if (!delete_header &&
3973 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003974 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003975 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003976 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003977 char *del_colon, *del_cookie, *colon;
3978 int app_cookies;
3979
willy tarreau5cbea6f2005-12-17 12:48:26 +01003980 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003981 colon = p1;
3982 /* del_cookie == NULL => nothing to be deleted */
3983 del_colon = del_cookie = NULL;
3984 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003985
3986 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003987 /* skip spaces and colons, but keep an eye on these ones */
3988 while (p1 < ptr) {
3989 if (*p1 == ';' || *p1 == ',')
3990 colon = p1;
3991 else if (!isspace((int)*p1))
3992 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003994 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003995
3996 if (p1 == ptr)
3997 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998
3999 /* p1 is at the beginning of the cookie name */
4000 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004001 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004002 p2++;
4003
4004 if (p2 == ptr)
4005 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006
4007 p3 = p2 + 1; /* skips the '=' sign */
4008 if (p3 == ptr)
4009 break;
4010
willy tarreau240afa62005-12-17 13:14:35 +01004011 p4 = p3;
4012 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004013 p4++;
4014
4015 /* here, we have the cookie name between p1 and p2,
4016 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004017 * we can process it :
4018 *
4019 * Cookie: NAME=VALUE;
4020 * | || || |
4021 * | || || +--> p4
4022 * | || |+-------> p3
4023 * | || +--------> p2
4024 * | |+------------> p1
4025 * | +-------------> colon
4026 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027 */
4028
willy tarreau240afa62005-12-17 13:14:35 +01004029 if (*p1 == '$') {
4030 /* skip this one */
4031 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004032 else {
4033 /* first, let's see if we want to capture it */
4034 if (t->proxy->capture_name != NULL &&
4035 t->logs.cli_cookie == NULL &&
4036 (p4 - p1 >= t->proxy->capture_namelen) &&
4037 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4038 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004039
willy tarreau8337c6b2005-12-17 13:41:01 +01004040 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4041 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004042 } else {
4043 if (log_len > t->proxy->capture_len)
4044 log_len = t->proxy->capture_len;
4045 memcpy(t->logs.cli_cookie, p1, log_len);
4046 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004047 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004048 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004049
4050 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4051 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4052 /* Cool... it's the right one */
4053 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004054 char *delim;
4055
4056 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4057 * have the server ID betweek p3 and delim, and the original cookie between
4058 * delim+1 and p4. Otherwise, delim==p4 :
4059 *
4060 * Cookie: NAME=SRV~VALUE;
4061 * | || || | |
4062 * | || || | +--> p4
4063 * | || || +--------> delim
4064 * | || |+-----------> p3
4065 * | || +------------> p2
4066 * | |+----------------> p1
4067 * | +-----------------> colon
4068 * +------------------------> req->h
4069 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004070
willy tarreau0174f312005-12-18 01:02:42 +01004071 if (t->proxy->options & PR_O_COOK_PFX) {
4072 for (delim = p3; delim < p4; delim++)
4073 if (*delim == COOKIE_DELIM)
4074 break;
4075 }
4076 else
4077 delim = p4;
4078
4079
4080 /* Here, we'll look for the first running server which supports the cookie.
4081 * This allows to share a same cookie between several servers, for example
4082 * to dedicate backup servers to specific servers only.
4083 */
4084 while (srv) {
4085 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4086 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4087 /* we found the server and it's usable */
4088 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004089 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004090 t->srv = srv;
4091 break;
willy tarreau12350152005-12-18 01:03:27 +01004092 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004093 /* we found a server, but it's down */
4094 t->flags &= ~SN_CK_MASK;
4095 t->flags |= SN_CK_DOWN;
4096 }
4097 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004098 srv = srv->next;
4099 }
4100
willy tarreau0174f312005-12-18 01:02:42 +01004101 if (!srv && !(t->flags & SN_CK_DOWN)) {
4102 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004103 t->flags &= ~SN_CK_MASK;
4104 t->flags |= SN_CK_INVALID;
4105 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004106
willy tarreau0174f312005-12-18 01:02:42 +01004107 /* depending on the cookie mode, we may have to either :
4108 * - delete the complete cookie if we're in insert+indirect mode, so that
4109 * the server never sees it ;
4110 * - remove the server id from the cookie value, and tag the cookie as an
4111 * application cookie so that it does not get accidentely removed later,
4112 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004113 */
willy tarreau0174f312005-12-18 01:02:42 +01004114 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4115 buffer_replace2(req, p3, delim + 1, NULL, 0);
4116 p4 -= (delim + 1 - p3);
4117 ptr -= (delim + 1 - p3);
4118 del_cookie = del_colon = NULL;
4119 app_cookies++; /* protect the header from deletion */
4120 }
4121 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004122 (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 +01004123 del_cookie = p1;
4124 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004125 }
willy tarreau12350152005-12-18 01:03:27 +01004126 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004127 /* now we know that we must keep this cookie since it's
4128 * not ours. But if we wanted to delete our cookie
4129 * earlier, we cannot remove the complete header, but we
4130 * can remove the previous block itself.
4131 */
4132 app_cookies++;
4133
4134 if (del_cookie != NULL) {
4135 buffer_replace2(req, del_cookie, p1, NULL, 0);
4136 p4 -= (p1 - del_cookie);
4137 ptr -= (p1 - del_cookie);
4138 del_cookie = del_colon = NULL;
4139 }
willy tarreau240afa62005-12-17 13:14:35 +01004140 }
willy tarreau12350152005-12-18 01:03:27 +01004141
4142 if ((t->proxy->appsession_name != NULL) &&
4143 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4144 /* first, let's see if the cookie is our appcookie*/
4145
4146 /* Cool... it's the right one */
4147
4148 asession_temp = &local_asession;
4149
4150 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4151 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4152 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4153 return 0;
4154 }
4155
4156 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4157 asession_temp->sessid[t->proxy->appsession_len] = 0;
4158 asession_temp->serverid = NULL;
4159
4160 /* only do insert, if lookup fails */
4161 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4162 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4163 Alert("Not enough memory process_cli():asession:calloc().\n");
4164 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4165 return 0;
4166 }
4167
4168 asession_temp->sessid = local_asession.sessid;
4169 asession_temp->serverid = local_asession.serverid;
4170 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4171 }
4172 else{
4173 /* free wasted memory */
4174 pool_free_to(apools.sessid, local_asession.sessid);
4175 }
4176
4177 if (asession_temp->serverid == NULL) {
4178 Alert("Found Application Session without matching server.\n");
4179 } else {
4180 struct server *srv = t->proxy->srv;
4181 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004182 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004183 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4184 /* we found the server and it's usable */
4185 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004186 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004187 t->srv = srv;
4188 break;
4189 } else {
4190 t->flags &= ~SN_CK_MASK;
4191 t->flags |= SN_CK_DOWN;
4192 }
4193 }
4194 srv = srv->next;
4195 }/* end while(srv) */
4196 }/* end else if server == NULL */
4197
4198 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004199 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004200 }
willy tarreau240afa62005-12-17 13:14:35 +01004201
willy tarreau5cbea6f2005-12-17 12:48:26 +01004202 /* we'll have to look for another cookie ... */
4203 p1 = p4;
4204 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004205
4206 /* There's no more cookie on this line.
4207 * We may have marked the last one(s) for deletion.
4208 * We must do this now in two ways :
4209 * - if there is no app cookie, we simply delete the header ;
4210 * - if there are app cookies, we must delete the end of the
4211 * string properly, including the colon/semi-colon before
4212 * the cookie name.
4213 */
4214 if (del_cookie != NULL) {
4215 if (app_cookies) {
4216 buffer_replace2(req, del_colon, ptr, NULL, 0);
4217 /* WARNING! <ptr> becomes invalid for now. If some code
4218 * below needs to rely on it before the end of the global
4219 * header loop, we need to correct it with this code :
4220 * ptr = del_colon;
4221 */
4222 }
4223 else
4224 delete_header = 1;
4225 }
4226 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227
4228 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004229 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004230 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004231 }
willy tarreau240afa62005-12-17 13:14:35 +01004232 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4233
willy tarreau5cbea6f2005-12-17 12:48:26 +01004234 req->h = req->lr;
4235 } /* while (req->lr < req->r) */
4236
4237 /* end of header processing (even if incomplete) */
4238
willy tarreauef900ab2005-12-17 12:52:52 +01004239 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4240 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4241 * full. We cannot loop here since event_cli_read will disable it only if
4242 * req->l == rlim-data
4243 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004244 FD_SET(t->cli_fd, StaticReadEvent);
4245 if (t->proxy->clitimeout)
4246 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4247 else
4248 tv_eternity(&t->crexpire);
4249 }
4250
willy tarreaue39cd132005-12-17 13:00:18 +01004251 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004252 * won't be able to free more later, so the session will never terminate.
4253 */
willy tarreaue39cd132005-12-17 13:00:18 +01004254 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004255 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004256 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004257 if (!(t->flags & SN_ERR_MASK))
4258 t->flags |= SN_ERR_PRXCOND;
4259 if (!(t->flags & SN_FINST_MASK))
4260 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004261 return 1;
4262 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004263 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004264 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004265 tv_eternity(&t->crexpire);
4266 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004267 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004268 if (!(t->flags & SN_ERR_MASK))
4269 t->flags |= SN_ERR_CLICL;
4270 if (!(t->flags & SN_FINST_MASK))
4271 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004272 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004273 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004274 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4275
4276 /* read timeout : give up with an error message.
4277 */
4278 t->logs.status = 408;
4279 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004280 if (!(t->flags & SN_ERR_MASK))
4281 t->flags |= SN_ERR_CLITO;
4282 if (!(t->flags & SN_FINST_MASK))
4283 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004284 return 1;
4285 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004286
4287 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004288 }
4289 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004290 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004291 /* FIXME: this error handling is partly buggy because we always report
4292 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4293 * or HEADER phase. BTW, it's not logical to expire the client while
4294 * we're waiting for the server to connect.
4295 */
willy tarreau0f7af912005-12-17 12:21:26 +01004296 /* read or write error */
4297 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004298 tv_eternity(&t->crexpire);
4299 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004300 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004301 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004302 if (!(t->flags & SN_ERR_MASK))
4303 t->flags |= SN_ERR_CLICL;
4304 if (!(t->flags & SN_FINST_MASK))
4305 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004306 return 1;
4307 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004308 /* last read, or end of server write */
4309 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004310 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004311 tv_eternity(&t->crexpire);
4312 shutdown(t->cli_fd, SHUT_RD);
4313 t->cli_state = CL_STSHUTR;
4314 return 1;
4315 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004316 /* last server read and buffer empty */
4317 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004318 FD_CLR(t->cli_fd, StaticWriteEvent);
4319 tv_eternity(&t->cwexpire);
4320 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004321 /* We must ensure that the read part is still alive when switching
4322 * to shutw */
4323 FD_SET(t->cli_fd, StaticReadEvent);
4324 if (t->proxy->clitimeout)
4325 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004326 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004327 //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 +01004328 return 1;
4329 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004330 /* read timeout */
4331 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4332 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004333 tv_eternity(&t->crexpire);
4334 shutdown(t->cli_fd, SHUT_RD);
4335 t->cli_state = CL_STSHUTR;
4336 if (!(t->flags & SN_ERR_MASK))
4337 t->flags |= SN_ERR_CLITO;
4338 if (!(t->flags & SN_FINST_MASK))
4339 t->flags |= SN_FINST_D;
4340 return 1;
4341 }
4342 /* write timeout */
4343 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4344 FD_CLR(t->cli_fd, StaticWriteEvent);
4345 tv_eternity(&t->cwexpire);
4346 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004347 /* We must ensure that the read part is still alive when switching
4348 * to shutw */
4349 FD_SET(t->cli_fd, StaticReadEvent);
4350 if (t->proxy->clitimeout)
4351 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4352
willy tarreau036e1ce2005-12-17 13:46:33 +01004353 t->cli_state = CL_STSHUTW;
4354 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004355 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004356 if (!(t->flags & SN_FINST_MASK))
4357 t->flags |= SN_FINST_D;
4358 return 1;
4359 }
willy tarreau0f7af912005-12-17 12:21:26 +01004360
willy tarreauc58fc692005-12-17 14:13:08 +01004361 if (req->l >= req->rlim - req->data) {
4362 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004363 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004364 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004365 FD_CLR(t->cli_fd, StaticReadEvent);
4366 tv_eternity(&t->crexpire);
4367 }
4368 }
4369 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004370 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004371 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4372 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004373 if (!t->proxy->clitimeout ||
4374 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4375 /* If the client has no timeout, or if the server not ready yet, and we
4376 * know for sure that it can expire, then it's cleaner to disable the
4377 * timeout on the client side so that too low values cannot make the
4378 * sessions abort too early.
4379 */
willy tarreau0f7af912005-12-17 12:21:26 +01004380 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004381 else
4382 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004383 }
4384 }
4385
4386 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004387 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004388 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4389 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4390 tv_eternity(&t->cwexpire);
4391 }
4392 }
4393 else { /* buffer not empty */
4394 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4395 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004396 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004397 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004398 /* FIXME: to prevent the client from expiring read timeouts during writes,
4399 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004400 t->crexpire = t->cwexpire;
4401 }
willy tarreau0f7af912005-12-17 12:21:26 +01004402 else
4403 tv_eternity(&t->cwexpire);
4404 }
4405 }
4406 return 0; /* other cases change nothing */
4407 }
4408 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004409 if (t->res_cw == RES_ERROR) {
4410 tv_eternity(&t->cwexpire);
4411 fd_delete(t->cli_fd);
4412 t->cli_state = CL_STCLOSE;
4413 if (!(t->flags & SN_ERR_MASK))
4414 t->flags |= SN_ERR_CLICL;
4415 if (!(t->flags & SN_FINST_MASK))
4416 t->flags |= SN_FINST_D;
4417 return 1;
4418 }
4419 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004420 tv_eternity(&t->cwexpire);
4421 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004422 t->cli_state = CL_STCLOSE;
4423 return 1;
4424 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004425 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4426 tv_eternity(&t->cwexpire);
4427 fd_delete(t->cli_fd);
4428 t->cli_state = CL_STCLOSE;
4429 if (!(t->flags & SN_ERR_MASK))
4430 t->flags |= SN_ERR_CLITO;
4431 if (!(t->flags & SN_FINST_MASK))
4432 t->flags |= SN_FINST_D;
4433 return 1;
4434 }
willy tarreau0f7af912005-12-17 12:21:26 +01004435 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004436 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004437 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4438 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4439 tv_eternity(&t->cwexpire);
4440 }
4441 }
4442 else { /* buffer not empty */
4443 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4444 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004445 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004446 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004447 /* FIXME: to prevent the client from expiring read timeouts during writes,
4448 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004449 t->crexpire = t->cwexpire;
4450 }
willy tarreau0f7af912005-12-17 12:21:26 +01004451 else
4452 tv_eternity(&t->cwexpire);
4453 }
4454 }
4455 return 0;
4456 }
4457 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004458 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004459 tv_eternity(&t->crexpire);
4460 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004461 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004462 if (!(t->flags & SN_ERR_MASK))
4463 t->flags |= SN_ERR_CLICL;
4464 if (!(t->flags & SN_FINST_MASK))
4465 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004466 return 1;
4467 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004468 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4469 tv_eternity(&t->crexpire);
4470 fd_delete(t->cli_fd);
4471 t->cli_state = CL_STCLOSE;
4472 return 1;
4473 }
4474 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4475 tv_eternity(&t->crexpire);
4476 fd_delete(t->cli_fd);
4477 t->cli_state = CL_STCLOSE;
4478 if (!(t->flags & SN_ERR_MASK))
4479 t->flags |= SN_ERR_CLITO;
4480 if (!(t->flags & SN_FINST_MASK))
4481 t->flags |= SN_FINST_D;
4482 return 1;
4483 }
willy tarreauef900ab2005-12-17 12:52:52 +01004484 else if (req->l >= req->rlim - req->data) {
4485 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004486
4487 /* FIXME-20050705: is it possible for a client to maintain a session
4488 * after the timeout by sending more data after it receives a close ?
4489 */
4490
willy tarreau0f7af912005-12-17 12:21:26 +01004491 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004492 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004493 FD_CLR(t->cli_fd, StaticReadEvent);
4494 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004495 //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 +01004496 }
4497 }
4498 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004499 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004500 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4501 FD_SET(t->cli_fd, StaticReadEvent);
4502 if (t->proxy->clitimeout)
4503 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4504 else
4505 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004506 //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 +01004507 }
4508 }
4509 return 0;
4510 }
4511 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004512 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004513 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004514 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 +01004515 write(1, trash, len);
4516 }
4517 return 0;
4518 }
4519 return 0;
4520}
4521
willy tarreaudfece232006-05-02 00:19:57 +02004522/* This function turns the server state into the SV_STCLOSE, and sets
4523 * indicators accordingly. Note that if <status> is 0, no message is
4524 * returned.
4525 */
4526void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4527 t->srv_state = SV_STCLOSE;
4528 if (status > 0) {
4529 t->logs.status = status;
4530 if (t->proxy->mode == PR_MODE_HTTP)
4531 client_return(t, msglen, msg);
4532 }
4533 if (!(t->flags & SN_ERR_MASK))
4534 t->flags |= err;
4535 if (!(t->flags & SN_FINST_MASK))
4536 t->flags |= finst;
4537}
4538
4539/*
4540 * This function checks the retry count during the connect() job.
4541 * It updates the session's srv_state and retries, so that the caller knows
4542 * what it has to do. It uses the last connection error to set the log when
4543 * it expires. It returns 1 when it has expired, and 0 otherwise.
4544 */
4545int srv_count_retry_down(struct session *t, int conn_err) {
4546 /* we are in front of a retryable error */
4547 t->conn_retries--;
4548 if (t->conn_retries < 0) {
4549 /* if not retryable anymore, let's abort */
4550 tv_eternity(&t->cnexpire);
4551 srv_close_with_err(t, conn_err, SN_FINST_C,
4552 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4553
4554 /* We used to have a free connection slot. Since we'll never use it,
4555 * we have to pass it on to another session.
4556 */
4557 if (t->srv)
4558 offer_connection_slot(t);
4559 return 1;
4560 }
4561 return 0;
4562}
willy tarreau0f7af912005-12-17 12:21:26 +01004563
4564/*
willy tarreaudfece232006-05-02 00:19:57 +02004565 * This function performs the retryable part of the connect() job.
4566 * It updates the session's srv_state and retries, so that the caller knows
4567 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4568 * it needs to redispatch.
4569 */
4570int srv_retryable_connect(struct session *t) {
4571 int conn_err;
4572
4573 /* This loop ensures that we stop before the last retry in case of a
4574 * redispatchable server.
4575 */
4576 do {
4577 /* initiate a connection to the server */
4578 conn_err = connect_server(t);
4579 switch (conn_err) {
4580
4581 case SN_ERR_NONE:
4582 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4583 t->srv_state = SV_STCONN;
4584 return 1;
4585
4586 case SN_ERR_INTERNAL:
4587 tv_eternity(&t->cnexpire);
4588 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4589 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4590 /* release other sessions waiting for this server */
4591 if (t->srv)
4592 offer_connection_slot(t);
4593 return 1;
4594 }
4595 /* ensure that we have enough retries left */
4596 if (srv_count_retry_down(t, conn_err))
4597 return 1;
4598 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4599
4600 /* We're on our last chance, and the REDISP option was specified.
4601 * We will ignore cookie and force to balance or use the dispatcher.
4602 */
4603 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4604 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4605 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4606 t->flags &= ~SN_CK_MASK;
4607 t->flags |= SN_CK_DOWN;
4608 }
4609 return 0;
4610}
4611
4612/* This function performs the "redispatch" part of a connection attempt. It
4613 * will assign a server if required, queue the connection if required, and
4614 * handle errors that might arise at this level. It can change the server
4615 * state. It will return 1 if it encounters an error, switches the server
4616 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4617 * that the connection is ready to use.
4618 */
4619
4620int srv_redispatch_connect(struct session *t) {
4621 int conn_err;
4622
4623 /* We know that we don't have any connection pending, so we will
4624 * try to get a new one, and wait in this state if it's queued
4625 */
4626 conn_err = assign_server_and_queue(t);
4627 switch (conn_err) {
4628 case SRV_STATUS_OK:
4629 break;
4630
4631 case SRV_STATUS_NOSRV:
4632 tv_eternity(&t->cnexpire);
4633 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4634 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4635
4636 /* FIXME-20060501: we should not need this once we flush every session
4637 * when the last server goes down.
4638 */
4639 /* release other sessions waiting for this server */
4640 if (t->srv)
4641 offer_connection_slot(t);
4642 return 1;
4643
4644 case SRV_STATUS_QUEUED:
4645 t->srv_state = SV_STIDLE;
4646 /* do nothing else and do not wake any other session up */
4647 return 1;
4648
4649 case SRV_STATUS_FULL:
4650 case SRV_STATUS_INTERNAL:
4651 default:
4652 tv_eternity(&t->cnexpire);
4653 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4654 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4655 /* release other sessions waiting for this server */
4656 if (t->srv)
4657 offer_connection_slot(t);
4658 return 1;
4659 }
4660 /* if we get here, it's because we got SRV_STATUS_OK, which also
4661 * means that the connection has not been queued.
4662 */
4663 return 0;
4664}
4665
4666
4667/*
willy tarreau0f7af912005-12-17 12:21:26 +01004668 * manages the server FSM and its socket. It returns 1 if a state has changed
4669 * (and a resync may be needed), 0 else.
4670 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004671int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004672 int s = t->srv_state;
4673 int c = t->cli_state;
4674 struct buffer *req = t->req;
4675 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004676 appsess *asession_temp = NULL;
4677 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004678 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004679
willy tarreau750a4722005-12-17 13:21:24 +01004680#ifdef DEBUG_FULL
4681 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4682#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004683 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4684 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4685 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4686 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004687 if (s == SV_STIDLE) {
4688 if (c == CL_STHEADERS)
4689 return 0; /* stay in idle, waiting for data to reach the client side */
4690 else if (c == CL_STCLOSE ||
4691 c == CL_STSHUTW ||
4692 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4693 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004694 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
4695
4696 /* it might be possible that we have been granted an access to the
4697 * server while waiting for a free slot. Since we'll never use it,
4698 * we have to pass it on to another session.
4699 */
4700 if (t->srv)
4701 offer_connection_slot(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004702 return 1;
4703 }
willy tarreaudfece232006-05-02 00:19:57 +02004704 else {
4705 /* Right now, we will need to create a connection to the server.
4706 * We might already have tried, and got a connection pending, in
4707 * which case we will not do anything till it's pending. It's up
4708 * to any other session to release it and wake us up again.
4709 */
4710 if (t->pend_pos)
4711 return 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004712
willy tarreaudfece232006-05-02 00:19:57 +02004713 do {
4714 /* first, get a connection */
4715 if (srv_redispatch_connect(t))
4716 return t->srv_state != SV_STIDLE;
4717
4718 /* try to (re-)connect to the server, and fail if we expire the
4719 * number of retries.
4720 */
willy tarreauf32f5242006-05-02 22:54:52 +02004721 if (srv_retryable_connect(t)) {
4722 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004723 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004724 }
willy tarreaudfece232006-05-02 00:19:57 +02004725
4726 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004727 }
4728 }
4729 else if (s == SV_STCONN) { /* connection in progress */
4730 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004731 //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 +01004732 return 0; /* nothing changed */
4733 }
4734 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004735 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004736 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004737
willy tarreau0f7af912005-12-17 12:21:26 +01004738 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004739 if (t->srv)
4740 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004741
4742 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004743 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4744 else
willy tarreaudfece232006-05-02 00:19:57 +02004745 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004746
willy tarreaudfece232006-05-02 00:19:57 +02004747 /* ensure that we have enough retries left */
4748 if (srv_count_retry_down(t, conn_err))
4749 return 1;
4750
4751 do {
4752 /* Now we will try to either reconnect to the same server or
4753 * connect to another server. If the connection gets queued
4754 * because all servers are saturated, then we will go back to
4755 * the SV_STIDLE state.
4756 */
willy tarreauf32f5242006-05-02 22:54:52 +02004757 if (srv_retryable_connect(t)) {
4758 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004759 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004760 }
willy tarreaudfece232006-05-02 00:19:57 +02004761
4762 /* we need to redispatch the connection to another server */
4763 if (srv_redispatch_connect(t))
4764 return t->srv_state != SV_STCONN;
4765 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004766 }
4767 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004768 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004769
willy tarreau0f7af912005-12-17 12:21:26 +01004770 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004771 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004772 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004773 tv_eternity(&t->swexpire);
4774 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004775 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004776 if (t->proxy->srvtimeout) {
4777 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004778 /* FIXME: to prevent the server from expiring read timeouts during writes,
4779 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004780 t->srexpire = t->swexpire;
4781 }
4782 else
4783 tv_eternity(&t->swexpire);
4784 }
willy tarreau0f7af912005-12-17 12:21:26 +01004785
4786 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4787 FD_SET(t->srv_fd, StaticReadEvent);
4788 if (t->proxy->srvtimeout)
4789 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4790 else
4791 tv_eternity(&t->srexpire);
4792
4793 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004794 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004795 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004796
4797 /* if the user wants to log as soon as possible, without counting
4798 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004799 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004800 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4801 sess_log(t);
4802 }
willy tarreau0f7af912005-12-17 12:21:26 +01004803 }
willy tarreauef900ab2005-12-17 12:52:52 +01004804 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004805 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004806 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004807 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4808 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004809 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004810 return 1;
4811 }
4812 }
4813 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004814 /* now parse the partial (or complete) headers */
4815 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4816 char *ptr;
4817 int delete_header;
4818
4819 ptr = rep->lr;
4820
4821 /* look for the end of the current header */
4822 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4823 ptr++;
4824
4825 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004826 int line, len;
4827
4828 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004829
4830 /* first, we'll block if security checks have caught nasty things */
4831 if (t->flags & SN_CACHEABLE) {
4832 if ((t->flags & SN_CACHE_COOK) &&
4833 (t->flags & SN_SCK_ANY) &&
4834 (t->proxy->options & PR_O_CHK_CACHE)) {
4835
4836 /* we're in presence of a cacheable response containing
4837 * a set-cookie header. We'll block it as requested by
4838 * the 'checkcache' option, and send an alert.
4839 */
4840 tv_eternity(&t->srexpire);
4841 tv_eternity(&t->swexpire);
4842 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004843 if (t->srv)
4844 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004845 t->srv_state = SV_STCLOSE;
4846 t->logs.status = 502;
4847 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4848 if (!(t->flags & SN_ERR_MASK))
4849 t->flags |= SN_ERR_PRXCOND;
4850 if (!(t->flags & SN_FINST_MASK))
4851 t->flags |= SN_FINST_H;
4852
4853 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4854 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4855
willy tarreaudfece232006-05-02 00:19:57 +02004856 /* We used to have a free connection slot. Since we'll never use it,
4857 * we have to pass it on to another session.
4858 */
4859 if (t->srv)
4860 offer_connection_slot(t);
4861
willy tarreau97f58572005-12-18 00:53:44 +01004862 return 1;
4863 }
4864 }
4865
willy tarreau982249e2005-12-18 00:57:06 +01004866 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4867 if (t->flags & SN_SVDENY) {
4868 tv_eternity(&t->srexpire);
4869 tv_eternity(&t->swexpire);
4870 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004871 if (t->srv)
4872 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004873 t->srv_state = SV_STCLOSE;
4874 t->logs.status = 502;
4875 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4876 if (!(t->flags & SN_ERR_MASK))
4877 t->flags |= SN_ERR_PRXCOND;
4878 if (!(t->flags & SN_FINST_MASK))
4879 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004880 /* We used to have a free connection slot. Since we'll never use it,
4881 * we have to pass it on to another session.
4882 */
4883 if (t->srv)
4884 offer_connection_slot(t);
4885
willy tarreau982249e2005-12-18 00:57:06 +01004886 return 1;
4887 }
4888
willy tarreau5cbea6f2005-12-17 12:48:26 +01004889 /* we'll have something else to do here : add new headers ... */
4890
willy tarreaucd878942005-12-17 13:27:43 +01004891 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4892 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004893 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004894 * insert a set-cookie here, except if we want to insert only on POST
4895 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004896 */
willy tarreau750a4722005-12-17 13:21:24 +01004897 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004898 t->proxy->cookie_name,
4899 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004900
willy tarreau036e1ce2005-12-17 13:46:33 +01004901 t->flags |= SN_SCK_INSERTED;
4902
willy tarreau750a4722005-12-17 13:21:24 +01004903 /* Here, we will tell an eventual cache on the client side that we don't
4904 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4905 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4906 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4907 */
willy tarreau240afa62005-12-17 13:14:35 +01004908 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004909 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4910 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004911
4912 if (rep->data + rep->l < rep->h)
4913 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4914 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004915 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004916 }
4917
4918 /* headers to be added */
4919 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004920 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4921 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004922 }
4923
willy tarreau25c4ea52005-12-18 00:49:49 +01004924 /* add a "connection: close" line if needed */
4925 if (t->proxy->options & PR_O_HTTP_CLOSE)
4926 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4927
willy tarreau5cbea6f2005-12-17 12:48:26 +01004928 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004929 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004930 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004931
Willy TARREAU767ba712006-03-01 22:40:50 +01004932 /* client connection already closed or option 'httpclose' required :
4933 * we close the server's outgoing connection right now.
4934 */
4935 if ((req->l == 0) &&
4936 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4937 FD_CLR(t->srv_fd, StaticWriteEvent);
4938 tv_eternity(&t->swexpire);
4939
4940 /* We must ensure that the read part is still alive when switching
4941 * to shutw */
4942 FD_SET(t->srv_fd, StaticReadEvent);
4943 if (t->proxy->srvtimeout)
4944 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4945
4946 shutdown(t->srv_fd, SHUT_WR);
4947 t->srv_state = SV_STSHUTW;
4948 }
4949
willy tarreau25c4ea52005-12-18 00:49:49 +01004950 /* if the user wants to log as soon as possible, without counting
4951 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004952 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004953 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4954 t->logs.bytes = rep->h - rep->data;
4955 sess_log(t);
4956 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004957 break;
4958 }
4959
4960 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4961 if (ptr > rep->r - 2) {
4962 /* this is a partial header, let's wait for more to come */
4963 rep->lr = ptr;
4964 break;
4965 }
4966
4967 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4968 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4969
4970 /* now we know that *ptr is either \r or \n,
4971 * and that there are at least 1 char after it.
4972 */
4973 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4974 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4975 else
4976 rep->lr = ptr + 2; /* \r\n or \n\r */
4977
4978 /*
4979 * now we know that we have a full header ; we can do whatever
4980 * we want with these pointers :
4981 * rep->h = beginning of header
4982 * ptr = end of header (first \r or \n)
4983 * rep->lr = beginning of next line (next rep->h)
4984 * rep->r = end of data (not used at this stage)
4985 */
4986
willy tarreaua1598082005-12-17 13:08:06 +01004987
willy tarreau982249e2005-12-18 00:57:06 +01004988 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004989 t->logs.logwait &= ~LW_RESP;
4990 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004991 switch (t->logs.status) {
4992 case 200:
4993 case 203:
4994 case 206:
4995 case 300:
4996 case 301:
4997 case 410:
4998 /* RFC2616 @13.4:
4999 * "A response received with a status code of
5000 * 200, 203, 206, 300, 301 or 410 MAY be stored
5001 * by a cache (...) unless a cache-control
5002 * directive prohibits caching."
5003 *
5004 * RFC2616 @9.5: POST method :
5005 * "Responses to this method are not cacheable,
5006 * unless the response includes appropriate
5007 * Cache-Control or Expires header fields."
5008 */
5009 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5010 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5011 break;
5012 default:
5013 break;
5014 }
willy tarreau4302f492005-12-18 01:00:37 +01005015 }
5016 else if (t->logs.logwait & LW_RSPHDR) {
5017 struct cap_hdr *h;
5018 int len;
5019 for (h = t->proxy->rsp_cap; h; h = h->next) {
5020 if ((h->namelen + 2 <= ptr - rep->h) &&
5021 (rep->h[h->namelen] == ':') &&
5022 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5023
5024 if (t->rsp_cap[h->index] == NULL)
5025 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5026
5027 len = ptr - (rep->h + h->namelen + 2);
5028 if (len > h->len)
5029 len = h->len;
5030
5031 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5032 t->rsp_cap[h->index][len]=0;
5033 }
5034 }
5035
willy tarreaua1598082005-12-17 13:08:06 +01005036 }
5037
willy tarreau5cbea6f2005-12-17 12:48:26 +01005038 delete_header = 0;
5039
willy tarreau982249e2005-12-18 00:57:06 +01005040 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005041 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005042 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 +01005043 max = ptr - rep->h;
5044 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005045 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005046 trash[len++] = '\n';
5047 write(1, trash, len);
5048 }
5049
willy tarreau25c4ea52005-12-18 00:49:49 +01005050 /* remove "connection: " if needed */
5051 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5052 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5053 delete_header = 1;
5054 }
5055
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005057 if (!delete_header && t->proxy->rsp_exp != NULL
5058 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005059 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 char term;
5061
5062 term = *ptr;
5063 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005064 exp = t->proxy->rsp_exp;
5065 do {
5066 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5067 switch (exp->action) {
5068 case ACT_ALLOW:
5069 if (!(t->flags & SN_SVDENY))
5070 t->flags |= SN_SVALLOW;
5071 break;
5072 case ACT_REPLACE:
5073 if (!(t->flags & SN_SVDENY)) {
5074 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5075 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5076 }
5077 break;
5078 case ACT_REMOVE:
5079 if (!(t->flags & SN_SVDENY))
5080 delete_header = 1;
5081 break;
5082 case ACT_DENY:
5083 if (!(t->flags & SN_SVALLOW))
5084 t->flags |= SN_SVDENY;
5085 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005086 case ACT_PASS: /* we simply don't deny this one */
5087 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005088 }
5089 break;
5090 }
willy tarreaue39cd132005-12-17 13:00:18 +01005091 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005092 *ptr = term; /* restore the string terminator */
5093 }
5094
willy tarreau97f58572005-12-18 00:53:44 +01005095 /* check for cache-control: or pragma: headers */
5096 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5097 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5098 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5099 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5100 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005101 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005102 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5103 else {
5104 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005105 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005106 t->flags &= ~SN_CACHE_COOK;
5107 }
5108 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005109 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005110 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005111 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005112 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5113 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005114 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005115 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005116 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5117 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5118 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5119 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5120 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5121 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005122 }
5123 }
5124 }
5125
willy tarreau5cbea6f2005-12-17 12:48:26 +01005126 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005127 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005128 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005129 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005130 char *p1, *p2, *p3, *p4;
5131
willy tarreau97f58572005-12-18 00:53:44 +01005132 t->flags |= SN_SCK_ANY;
5133
willy tarreau5cbea6f2005-12-17 12:48:26 +01005134 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5135
5136 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005137 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005138 p1++;
5139
5140 if (p1 == ptr || *p1 == ';') /* end of cookie */
5141 break;
5142
5143 /* p1 is at the beginning of the cookie name */
5144 p2 = p1;
5145
5146 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5147 p2++;
5148
5149 if (p2 == ptr || *p2 == ';') /* next cookie */
5150 break;
5151
5152 p3 = p2 + 1; /* skips the '=' sign */
5153 if (p3 == ptr)
5154 break;
5155
5156 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005157 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158 p4++;
5159
5160 /* here, we have the cookie name between p1 and p2,
5161 * and its value between p3 and p4.
5162 * we can process it.
5163 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005164
5165 /* first, let's see if we want to capture it */
5166 if (t->proxy->capture_name != NULL &&
5167 t->logs.srv_cookie == NULL &&
5168 (p4 - p1 >= t->proxy->capture_namelen) &&
5169 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5170 int log_len = p4 - p1;
5171
5172 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5173 Alert("HTTP logging : out of memory.\n");
5174 }
5175
5176 if (log_len > t->proxy->capture_len)
5177 log_len = t->proxy->capture_len;
5178 memcpy(t->logs.srv_cookie, p1, log_len);
5179 t->logs.srv_cookie[log_len] = 0;
5180 }
5181
5182 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5183 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005184 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005185 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005186
5187 /* If the cookie is in insert mode on a known server, we'll delete
5188 * this occurrence because we'll insert another one later.
5189 * We'll delete it too if the "indirect" option is set and we're in
5190 * a direct access. */
5191 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005192 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005193 /* this header must be deleted */
5194 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005195 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 }
5197 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5198 /* replace bytes p3->p4 with the cookie name associated
5199 * with this server since we know it.
5200 */
5201 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005202 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005203 }
willy tarreau0174f312005-12-18 01:02:42 +01005204 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5205 /* insert the cookie name associated with this server
5206 * before existing cookie, and insert a delimitor between them..
5207 */
5208 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5209 p3[t->srv->cklen] = COOKIE_DELIM;
5210 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5211 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005212 break;
5213 }
willy tarreau12350152005-12-18 01:03:27 +01005214
5215 /* first, let's see if the cookie is our appcookie*/
5216 if ((t->proxy->appsession_name != NULL) &&
5217 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5218
5219 /* Cool... it's the right one */
5220
willy tarreaub952e1d2005-12-18 01:31:20 +01005221 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005222 asession_temp = &local_asession;
5223
willy tarreaub952e1d2005-12-18 01:31:20 +01005224 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005225 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5226 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5227 }
5228 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5229 asession_temp->sessid[t->proxy->appsession_len] = 0;
5230 asession_temp->serverid = NULL;
5231
5232 /* only do insert, if lookup fails */
5233 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5234 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5235 Alert("Not enought Memory process_srv():asession:calloc().\n");
5236 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5237 return 0;
5238 }
5239 asession_temp->sessid = local_asession.sessid;
5240 asession_temp->serverid = local_asession.serverid;
5241 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005242 }/* end if (chtbl_lookup()) */
5243 else {
willy tarreau12350152005-12-18 01:03:27 +01005244 /* free wasted memory */
5245 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005246 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005247
willy tarreaub952e1d2005-12-18 01:31:20 +01005248 if (asession_temp->serverid == NULL) {
5249 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005250 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5251 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5252 }
5253 asession_temp->serverid[0] = '\0';
5254 }
5255
willy tarreaub952e1d2005-12-18 01:31:20 +01005256 if (asession_temp->serverid[0] == '\0')
5257 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005258
5259 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5260
5261#if defined(DEBUG_HASH)
5262 print_table(&(t->proxy->htbl_proxy));
5263#endif
5264 break;
5265 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005266 else {
5267 // fprintf(stderr,"Ignoring unknown cookie : ");
5268 // write(2, p1, p2-p1);
5269 // fprintf(stderr," = ");
5270 // write(2, p3, p4-p3);
5271 // fprintf(stderr,"\n");
5272 }
5273 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5274 } /* we're now at the end of the cookie value */
5275 } /* end of cookie processing */
5276
willy tarreau97f58572005-12-18 00:53:44 +01005277 /* check for any set-cookie in case we check for cacheability */
5278 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5279 (t->proxy->options & PR_O_CHK_CACHE) &&
5280 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5281 t->flags |= SN_SCK_ANY;
5282 }
5283
willy tarreau5cbea6f2005-12-17 12:48:26 +01005284 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005285 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005286 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005287
willy tarreau5cbea6f2005-12-17 12:48:26 +01005288 rep->h = rep->lr;
5289 } /* while (rep->lr < rep->r) */
5290
5291 /* end of header processing (even if incomplete) */
5292
willy tarreauef900ab2005-12-17 12:52:52 +01005293 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5294 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5295 * full. We cannot loop here since event_srv_read will disable it only if
5296 * rep->l == rlim-data
5297 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005298 FD_SET(t->srv_fd, StaticReadEvent);
5299 if (t->proxy->srvtimeout)
5300 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5301 else
5302 tv_eternity(&t->srexpire);
5303 }
willy tarreau0f7af912005-12-17 12:21:26 +01005304
willy tarreau8337c6b2005-12-17 13:41:01 +01005305 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005306 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005307 tv_eternity(&t->srexpire);
5308 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005309 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005310 if (t->srv)
5311 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005312 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005313 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005314 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005315 if (!(t->flags & SN_ERR_MASK))
5316 t->flags |= SN_ERR_SRVCL;
5317 if (!(t->flags & SN_FINST_MASK))
5318 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005319 /* We used to have a free connection slot. Since we'll never use it,
5320 * we have to pass it on to another session.
5321 */
5322 if (t->srv)
5323 offer_connection_slot(t);
5324
willy tarreau0f7af912005-12-17 12:21:26 +01005325 return 1;
5326 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005327 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005328 * since we are in header mode, if there's no space left for headers, we
5329 * won't be able to free more later, so the session will never terminate.
5330 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005331 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 +01005332 FD_CLR(t->srv_fd, StaticReadEvent);
5333 tv_eternity(&t->srexpire);
5334 shutdown(t->srv_fd, SHUT_RD);
5335 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005336 //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 +01005337 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005338 }
5339 /* read timeout : return a 504 to the client.
5340 */
5341 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5342 tv_eternity(&t->srexpire);
5343 tv_eternity(&t->swexpire);
5344 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005345 if (t->srv)
5346 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005347 t->srv_state = SV_STCLOSE;
5348 t->logs.status = 504;
5349 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005350 if (!(t->flags & SN_ERR_MASK))
5351 t->flags |= SN_ERR_SRVTO;
5352 if (!(t->flags & SN_FINST_MASK))
5353 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005354 /* We used to have a free connection slot. Since we'll never use it,
5355 * we have to pass it on to another session.
5356 */
5357 if (t->srv)
5358 offer_connection_slot(t);
5359
willy tarreau8337c6b2005-12-17 13:41:01 +01005360 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005361 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005362 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005363 /* FIXME!!! here, we don't want to switch to SHUTW if the
5364 * client shuts read too early, because we may still have
5365 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005366 * The side-effect is that if the client completely closes its
5367 * connection during SV_STHEADER, the connection to the server
5368 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005369 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005370 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005371 FD_CLR(t->srv_fd, StaticWriteEvent);
5372 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005373
5374 /* We must ensure that the read part is still alive when switching
5375 * to shutw */
5376 FD_SET(t->srv_fd, StaticReadEvent);
5377 if (t->proxy->srvtimeout)
5378 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5379
willy tarreau0f7af912005-12-17 12:21:26 +01005380 shutdown(t->srv_fd, SHUT_WR);
5381 t->srv_state = SV_STSHUTW;
5382 return 1;
5383 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005384 /* write timeout */
5385 /* FIXME!!! here, we don't want to switch to SHUTW if the
5386 * client shuts read too early, because we may still have
5387 * some work to do on the headers.
5388 */
5389 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5390 FD_CLR(t->srv_fd, StaticWriteEvent);
5391 tv_eternity(&t->swexpire);
5392 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005393 /* We must ensure that the read part is still alive when switching
5394 * to shutw */
5395 FD_SET(t->srv_fd, StaticReadEvent);
5396 if (t->proxy->srvtimeout)
5397 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5398
5399 /* We must ensure that the read part is still alive when switching
5400 * to shutw */
5401 FD_SET(t->srv_fd, StaticReadEvent);
5402 if (t->proxy->srvtimeout)
5403 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5404
willy tarreau036e1ce2005-12-17 13:46:33 +01005405 t->srv_state = SV_STSHUTW;
5406 if (!(t->flags & SN_ERR_MASK))
5407 t->flags |= SN_ERR_SRVTO;
5408 if (!(t->flags & SN_FINST_MASK))
5409 t->flags |= SN_FINST_H;
5410 return 1;
5411 }
willy tarreau0f7af912005-12-17 12:21:26 +01005412
5413 if (req->l == 0) {
5414 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5415 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5416 tv_eternity(&t->swexpire);
5417 }
5418 }
5419 else { /* client buffer not empty */
5420 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5421 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005422 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005423 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005424 /* FIXME: to prevent the server from expiring read timeouts during writes,
5425 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005426 t->srexpire = t->swexpire;
5427 }
willy tarreau0f7af912005-12-17 12:21:26 +01005428 else
5429 tv_eternity(&t->swexpire);
5430 }
5431 }
5432
willy tarreau5cbea6f2005-12-17 12:48:26 +01005433 /* be nice with the client side which would like to send a complete header
5434 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5435 * would read all remaining data at once ! The client should not write past rep->lr
5436 * when the server is in header state.
5437 */
5438 //return header_processed;
5439 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005440 }
5441 else if (s == SV_STDATA) {
5442 /* read or write error */
5443 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005444 tv_eternity(&t->srexpire);
5445 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005446 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005447 if (t->srv)
5448 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005449 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005450 if (!(t->flags & SN_ERR_MASK))
5451 t->flags |= SN_ERR_SRVCL;
5452 if (!(t->flags & SN_FINST_MASK))
5453 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005454 /* We used to have a free connection slot. Since we'll never use it,
5455 * we have to pass it on to another session.
5456 */
5457 if (t->srv)
5458 offer_connection_slot(t);
5459
willy tarreau0f7af912005-12-17 12:21:26 +01005460 return 1;
5461 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005462 /* last read, or end of client write */
5463 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005464 FD_CLR(t->srv_fd, StaticReadEvent);
5465 tv_eternity(&t->srexpire);
5466 shutdown(t->srv_fd, SHUT_RD);
5467 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005468 //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 +01005469 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005470 }
5471 /* end of client read and no more data to send */
5472 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5473 FD_CLR(t->srv_fd, StaticWriteEvent);
5474 tv_eternity(&t->swexpire);
5475 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005476 /* We must ensure that the read part is still alive when switching
5477 * to shutw */
5478 FD_SET(t->srv_fd, StaticReadEvent);
5479 if (t->proxy->srvtimeout)
5480 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5481
willy tarreaua41a8b42005-12-17 14:02:24 +01005482 t->srv_state = SV_STSHUTW;
5483 return 1;
5484 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005485 /* read timeout */
5486 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5487 FD_CLR(t->srv_fd, StaticReadEvent);
5488 tv_eternity(&t->srexpire);
5489 shutdown(t->srv_fd, SHUT_RD);
5490 t->srv_state = SV_STSHUTR;
5491 if (!(t->flags & SN_ERR_MASK))
5492 t->flags |= SN_ERR_SRVTO;
5493 if (!(t->flags & SN_FINST_MASK))
5494 t->flags |= SN_FINST_D;
5495 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005496 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005497 /* write timeout */
5498 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005499 FD_CLR(t->srv_fd, StaticWriteEvent);
5500 tv_eternity(&t->swexpire);
5501 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005502 /* We must ensure that the read part is still alive when switching
5503 * to shutw */
5504 FD_SET(t->srv_fd, StaticReadEvent);
5505 if (t->proxy->srvtimeout)
5506 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005507 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005508 if (!(t->flags & SN_ERR_MASK))
5509 t->flags |= SN_ERR_SRVTO;
5510 if (!(t->flags & SN_FINST_MASK))
5511 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005512 return 1;
5513 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005514
5515 /* recompute request time-outs */
5516 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005517 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5518 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5519 tv_eternity(&t->swexpire);
5520 }
5521 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005522 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005523 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5524 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005525 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005526 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005527 /* FIXME: to prevent the server from expiring read timeouts during writes,
5528 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005529 t->srexpire = t->swexpire;
5530 }
willy tarreau0f7af912005-12-17 12:21:26 +01005531 else
5532 tv_eternity(&t->swexpire);
5533 }
5534 }
5535
willy tarreaub1ff9db2005-12-17 13:51:03 +01005536 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005537 if (rep->l == BUFSIZE) { /* no room to read more data */
5538 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5539 FD_CLR(t->srv_fd, StaticReadEvent);
5540 tv_eternity(&t->srexpire);
5541 }
5542 }
5543 else {
5544 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5545 FD_SET(t->srv_fd, StaticReadEvent);
5546 if (t->proxy->srvtimeout)
5547 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5548 else
5549 tv_eternity(&t->srexpire);
5550 }
5551 }
5552
5553 return 0; /* other cases change nothing */
5554 }
5555 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005556 if (t->res_sw == RES_ERROR) {
5557 //FD_CLR(t->srv_fd, StaticWriteEvent);
5558 tv_eternity(&t->swexpire);
5559 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005560 if (t->srv)
5561 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005562 //close(t->srv_fd);
5563 t->srv_state = SV_STCLOSE;
5564 if (!(t->flags & SN_ERR_MASK))
5565 t->flags |= SN_ERR_SRVCL;
5566 if (!(t->flags & SN_FINST_MASK))
5567 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005568 /* We used to have a free connection slot. Since we'll never use it,
5569 * we have to pass it on to another session.
5570 */
5571 if (t->srv)
5572 offer_connection_slot(t);
5573
willy tarreau036e1ce2005-12-17 13:46:33 +01005574 return 1;
5575 }
5576 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005577 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005578 tv_eternity(&t->swexpire);
5579 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005580 if (t->srv)
5581 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005582 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005583 t->srv_state = SV_STCLOSE;
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)
5588 offer_connection_slot(t);
5589
willy tarreau0f7af912005-12-17 12:21:26 +01005590 return 1;
5591 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005592 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5593 //FD_CLR(t->srv_fd, StaticWriteEvent);
5594 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 tarreau036e1ce2005-12-17 13:46:33 +01005598 //close(t->srv_fd);
5599 t->srv_state = SV_STCLOSE;
5600 if (!(t->flags & SN_ERR_MASK))
5601 t->flags |= SN_ERR_SRVTO;
5602 if (!(t->flags & SN_FINST_MASK))
5603 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005604 /* We used to have a free connection slot. Since we'll never use it,
5605 * we have to pass it on to another session.
5606 */
5607 if (t->srv)
5608 offer_connection_slot(t);
5609
willy tarreau036e1ce2005-12-17 13:46:33 +01005610 return 1;
5611 }
willy tarreau0f7af912005-12-17 12:21:26 +01005612 else if (req->l == 0) {
5613 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5614 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5615 tv_eternity(&t->swexpire);
5616 }
5617 }
5618 else { /* buffer not empty */
5619 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5620 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005621 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005622 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005623 /* FIXME: to prevent the server from expiring read timeouts during writes,
5624 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005625 t->srexpire = t->swexpire;
5626 }
willy tarreau0f7af912005-12-17 12:21:26 +01005627 else
5628 tv_eternity(&t->swexpire);
5629 }
5630 }
5631 return 0;
5632 }
5633 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005634 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005635 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005636 tv_eternity(&t->srexpire);
5637 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005638 if (t->srv)
5639 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005640 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005641 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005642 if (!(t->flags & SN_ERR_MASK))
5643 t->flags |= SN_ERR_SRVCL;
5644 if (!(t->flags & SN_FINST_MASK))
5645 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005646 /* We used to have a free connection slot. Since we'll never use it,
5647 * we have to pass it on to another session.
5648 */
5649 if (t->srv)
5650 offer_connection_slot(t);
5651
willy tarreau0f7af912005-12-17 12:21:26 +01005652 return 1;
5653 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005654 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5655 //FD_CLR(t->srv_fd, StaticReadEvent);
5656 tv_eternity(&t->srexpire);
5657 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005658 if (t->srv)
5659 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005660 //close(t->srv_fd);
5661 t->srv_state = SV_STCLOSE;
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)
5666 offer_connection_slot(t);
5667
willy tarreau036e1ce2005-12-17 13:46:33 +01005668 return 1;
5669 }
5670 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
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;
5678 if (!(t->flags & SN_ERR_MASK))
5679 t->flags |= SN_ERR_SRVTO;
5680 if (!(t->flags & SN_FINST_MASK))
5681 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005682 /* We used to have a free connection slot. Since we'll never use it,
5683 * we have to pass it on to another session.
5684 */
5685 if (t->srv)
5686 offer_connection_slot(t);
5687
willy tarreau036e1ce2005-12-17 13:46:33 +01005688 return 1;
5689 }
willy tarreau0f7af912005-12-17 12:21:26 +01005690 else if (rep->l == BUFSIZE) { /* no room to read more data */
5691 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5692 FD_CLR(t->srv_fd, StaticReadEvent);
5693 tv_eternity(&t->srexpire);
5694 }
5695 }
5696 else {
5697 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5698 FD_SET(t->srv_fd, StaticReadEvent);
5699 if (t->proxy->srvtimeout)
5700 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5701 else
5702 tv_eternity(&t->srexpire);
5703 }
5704 }
5705 return 0;
5706 }
5707 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005708 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005709 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005710 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 +01005711 write(1, trash, len);
5712 }
5713 return 0;
5714 }
5715 return 0;
5716}
5717
5718
willy tarreau5cbea6f2005-12-17 12:48:26 +01005719/* Processes the client and server jobs of a session task, then
5720 * puts it back to the wait queue in a clean state, or
5721 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005722 * the time the task accepts to wait, or TIME_ETERNITY for
5723 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005724 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005725int process_session(struct task *t) {
5726 struct session *s = t->context;
5727 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005728
willy tarreau5cbea6f2005-12-17 12:48:26 +01005729 do {
5730 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005731 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005732 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005733 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005734 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005735 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005736 } while (fsm_resync);
5737
5738 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005739 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005740 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005741
willy tarreau5cbea6f2005-12-17 12:48:26 +01005742 tv_min(&min1, &s->crexpire, &s->cwexpire);
5743 tv_min(&min2, &s->srexpire, &s->swexpire);
5744 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005745 tv_min(&t->expire, &min1, &min2);
5746
5747 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005748 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005749
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005750#ifdef DEBUG_FULL
5751 /* DEBUG code : this should never ever happen, otherwise it indicates
5752 * that a task still has something to do and will provoke a quick loop.
5753 */
5754 if (tv_remain2(&now, &t->expire) <= 0)
5755 exit(100);
5756#endif
5757
willy tarreaub952e1d2005-12-18 01:31:20 +01005758 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005759 }
5760
willy tarreau5cbea6f2005-12-17 12:48:26 +01005761 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005762 actconn--;
5763
willy tarreau982249e2005-12-18 00:57:06 +01005764 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005765 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005766 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 +01005767 write(1, trash, len);
5768 }
5769
willy tarreau750a4722005-12-17 13:21:24 +01005770 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005771 if (s->rep != NULL)
5772 s->logs.bytes = s->rep->total;
5773
willy tarreau9fe663a2005-12-17 13:02:59 +01005774 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005775 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005776 sess_log(s);
5777
willy tarreau0f7af912005-12-17 12:21:26 +01005778 /* the task MUST not be in the run queue anymore */
5779 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005780 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005781 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005782 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005783}
5784
5785
5786
5787/*
5788 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005789 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005790 */
5791int process_chk(struct task *t) {
5792 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005793 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005794 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005795
willy tarreauef900ab2005-12-17 12:52:52 +01005796 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005797
willy tarreau25424f82006-03-19 19:37:48 +01005798 new_chk:
5799 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005800 if (fd < 0) { /* no check currently running */
5801 //fprintf(stderr, "process_chk: 2\n");
5802 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5803 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005804 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005805 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005806
5807 /* we don't send any health-checks when the proxy is stopped or when
5808 * the server should not be checked.
5809 */
5810 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005811 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5812 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005813 task_queue(t); /* restore t to its place in the task list */
5814 return tv_remain2(&now, &t->expire);
5815 }
5816
willy tarreau5cbea6f2005-12-17 12:48:26 +01005817 /* we'll initiate a new check */
5818 s->result = 0; /* no result yet */
5819 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005820 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005821 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5822 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5823 //fprintf(stderr, "process_chk: 3\n");
5824
willy tarreaua41a8b42005-12-17 14:02:24 +01005825 /* we'll connect to the check port on the server */
5826 sa = s->addr;
5827 sa.sin_port = htons(s->check_port);
5828
willy tarreau0174f312005-12-18 01:02:42 +01005829 /* allow specific binding :
5830 * - server-specific at first
5831 * - proxy-specific next
5832 */
5833 if (s->state & SRV_BIND_SRC) {
5834 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5835 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5836 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5837 s->proxy->id, s->id);
5838 s->result = -1;
5839 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005840 }
willy tarreau0174f312005-12-18 01:02:42 +01005841 else if (s->proxy->options & PR_O_BIND_SRC) {
5842 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5843 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5844 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5845 s->proxy->id);
5846 s->result = -1;
5847 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005848 }
willy tarreau0174f312005-12-18 01:02:42 +01005849
5850 if (!s->result) {
5851 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5852 /* OK, connection in progress or established */
5853
5854 //fprintf(stderr, "process_chk: 4\n");
5855
5856 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5857 fdtab[fd].owner = t;
5858 fdtab[fd].read = &event_srv_chk_r;
5859 fdtab[fd].write = &event_srv_chk_w;
5860 fdtab[fd].state = FD_STCONN; /* connection in progress */
5861 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005862#ifdef DEBUG_FULL
5863 assert (!FD_ISSET(fd, StaticReadEvent));
5864#endif
willy tarreau0174f312005-12-18 01:02:42 +01005865 fd_insert(fd);
5866 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5867 tv_delayfrom(&t->expire, &now, s->inter);
5868 task_queue(t); /* restore t to its place in the task list */
5869 return tv_remain(&now, &t->expire);
5870 }
5871 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5872 s->result = -1; /* a real error */
5873 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005874 }
5875 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005876 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005877 }
5878
5879 if (!s->result) { /* nothing done */
5880 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005881 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5882 tv_delayfrom(&t->expire, &t->expire, s->inter);
5883 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005884 }
5885
5886 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005887 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005888 s->health--; /* still good */
5889 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005890 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005891 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005892 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005893 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005894 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5895 s->state & SRV_BACKUP ? "Backup " : "",
5896 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5897 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5898 send_log(s->proxy, LOG_ALERT,
5899 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5900 s->state & SRV_BACKUP ? "Backup " : "",
5901 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5902 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005903
willy tarreau62084d42006-03-24 18:57:41 +01005904 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005905 Alert("Proxy %s has no server available !\n", s->proxy->id);
5906 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5907 }
5908 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005909 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005910 }
5911
5912 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005913 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005914 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5915 tv_delayfrom(&t->expire, &t->expire, s->inter);
5916 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005917 }
5918 else {
5919 //fprintf(stderr, "process_chk: 8\n");
5920 /* there was a test running */
5921 if (s->result > 0) { /* good server detected */
5922 //fprintf(stderr, "process_chk: 9\n");
5923 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005924 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005925 s->state |= SRV_RUNNING;
5926
willy tarreau535ae7a2005-12-17 12:58:00 +01005927 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005928 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005929 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005930 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5931 s->state & SRV_BACKUP ? "Backup " : "",
5932 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5933 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5934 send_log(s->proxy, LOG_NOTICE,
5935 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5936 s->state & SRV_BACKUP ? "Backup " : "",
5937 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5938 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005939 }
willy tarreauef900ab2005-12-17 12:52:52 +01005940
willy tarreaue47c8d72005-12-17 12:55:52 +01005941 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005942 }
willy tarreauef900ab2005-12-17 12:52:52 +01005943 s->curfd = -1; /* no check running anymore */
5944 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005945 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005946 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5947 tv_delayfrom(&t->expire, &t->expire, s->inter);
5948 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005949 }
5950 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5951 //fprintf(stderr, "process_chk: 10\n");
5952 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005953 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005954 s->health--; /* still good */
5955 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005956 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005957
willy tarreau62084d42006-03-24 18:57:41 +01005958 if (s->health == s->rise) {
5959 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005960 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005961 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5962 s->state & SRV_BACKUP ? "Backup " : "",
5963 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5964 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5965 send_log(s->proxy, LOG_ALERT,
5966 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5967 s->state & SRV_BACKUP ? "Backup " : "",
5968 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5969 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5970
5971 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5972 Alert("Proxy %s has no server available !\n", s->proxy->id);
5973 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5974 }
5975 }
willy tarreauef900ab2005-12-17 12:52:52 +01005976
willy tarreau5cbea6f2005-12-17 12:48:26 +01005977 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005978 }
5979 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005980 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005981 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005982 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5983 tv_delayfrom(&t->expire, &t->expire, s->inter);
5984 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005985 }
5986 /* if result is 0 and there's no timeout, we have to wait again */
5987 }
5988 //fprintf(stderr, "process_chk: 11\n");
5989 s->result = 0;
5990 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005991 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005992}
5993
5994
willy tarreau5cbea6f2005-12-17 12:48:26 +01005995
willy tarreau0f7af912005-12-17 12:21:26 +01005996#if STATTIME > 0
5997int stats(void);
5998#endif
5999
6000/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006001 * This does 4 things :
6002 * - wake up all expired tasks
6003 * - call all runnable tasks
6004 * - call maintain_proxies() to enable/disable the listeners
6005 * - return the delay till next event in ms, -1 = wait indefinitely
6006 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6007 *
willy tarreau0f7af912005-12-17 12:21:26 +01006008 */
6009
willy tarreau1c2ad212005-12-18 01:11:29 +01006010int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006011 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006012 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006013 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006014
willy tarreaub952e1d2005-12-18 01:31:20 +01006015 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006016
willy tarreau1c2ad212005-12-18 01:11:29 +01006017 /* look for expired tasks and add them to the run queue.
6018 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006019 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6020 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006021 tnext = t->next;
6022 if (t->state & TASK_RUNNING)
6023 continue;
6024
willy tarreaub952e1d2005-12-18 01:31:20 +01006025 if (tv_iseternity(&t->expire))
6026 continue;
6027
willy tarreau1c2ad212005-12-18 01:11:29 +01006028 /* wakeup expired entries. It doesn't matter if they are
6029 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006030 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006031 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006032 task_wakeup(&rq, t);
6033 }
6034 else {
6035 /* first non-runnable task. Use its expiration date as an upper bound */
6036 int temp_time = tv_remain(&now, &t->expire);
6037 if (temp_time)
6038 next_time = temp_time;
6039 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006040 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006041 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006042
willy tarreau1c2ad212005-12-18 01:11:29 +01006043 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006044 * since we only use the run queue's head. Note that any task can be
6045 * woken up by any other task and it will be processed immediately
6046 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006047 */
willy tarreau7feab592006-04-22 15:13:16 +02006048 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006049 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006050
willy tarreau1c2ad212005-12-18 01:11:29 +01006051 task_sleep(&rq, t);
6052 temp_time = t->process(t);
6053 next_time = MINTIME(temp_time, next_time);
6054 }
6055
6056 /* maintain all proxies in a consistent state. This should quickly become a task */
6057 time2 = maintain_proxies();
6058 return MINTIME(time2, next_time);
6059}
6060
6061
6062#if defined(ENABLE_EPOLL)
6063
6064/*
6065 * Main epoll() loop.
6066 */
6067
6068/* does 3 actions :
6069 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6070 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6071 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6072 *
6073 * returns 0 if initialization failed, !0 otherwise.
6074 */
6075
6076int epoll_loop(int action) {
6077 int next_time;
6078 int status;
6079 int fd;
6080
6081 int fds, count;
6082 int pr, pw, sr, sw;
6083 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6084 struct epoll_event ev;
6085
6086 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006087 static struct epoll_event *epoll_events = NULL;
6088 static int epoll_fd;
6089
6090 if (action == POLL_LOOP_ACTION_INIT) {
6091 epoll_fd = epoll_create(global.maxsock + 1);
6092 if (epoll_fd < 0)
6093 return 0;
6094 else {
6095 epoll_events = (struct epoll_event*)
6096 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6097 PrevReadEvent = (fd_set *)
6098 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6099 PrevWriteEvent = (fd_set *)
6100 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006101 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006102 return 1;
6103 }
6104 else if (action == POLL_LOOP_ACTION_CLEAN) {
6105 if (PrevWriteEvent) free(PrevWriteEvent);
6106 if (PrevReadEvent) free(PrevReadEvent);
6107 if (epoll_events) free(epoll_events);
6108 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006109 epoll_fd = 0;
6110 return 1;
6111 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006112
willy tarreau1c2ad212005-12-18 01:11:29 +01006113 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006114
willy tarreau1c2ad212005-12-18 01:11:29 +01006115 tv_now(&now);
6116
6117 while (1) {
6118 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006119
6120 /* stop when there's no connection left and we don't allow them anymore */
6121 if (!actconn && listeners == 0)
6122 break;
6123
willy tarreau0f7af912005-12-17 12:21:26 +01006124#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006125 {
6126 int time2;
6127 time2 = stats();
6128 next_time = MINTIME(time2, next_time);
6129 }
willy tarreau0f7af912005-12-17 12:21:26 +01006130#endif
6131
willy tarreau1c2ad212005-12-18 01:11:29 +01006132 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6133
6134 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6135 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6136
6137 if ((ro^rn) | (wo^wn)) {
6138 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6139#define FDSETS_ARE_INT_ALIGNED
6140#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006141
willy tarreauad90a0c2005-12-18 01:09:15 +01006142#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6143#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006144 pr = (ro >> count) & 1;
6145 pw = (wo >> count) & 1;
6146 sr = (rn >> count) & 1;
6147 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006148#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006149 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6150 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6151 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6152 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006153#endif
6154#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006155 pr = FD_ISSET(fd, PrevReadEvent);
6156 pw = FD_ISSET(fd, PrevWriteEvent);
6157 sr = FD_ISSET(fd, StaticReadEvent);
6158 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006159#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006160 if (!((sr^pr) | (sw^pw)))
6161 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006162
willy tarreau1c2ad212005-12-18 01:11:29 +01006163 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6164 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006165
willy tarreaub952e1d2005-12-18 01:31:20 +01006166#ifdef EPOLL_CTL_MOD_WORKAROUND
6167 /* I encountered a rarely reproducible problem with
6168 * EPOLL_CTL_MOD where a modified FD (systematically
6169 * the one in epoll_events[0], fd#7) would sometimes
6170 * be set EPOLL_OUT while asked for a read ! This is
6171 * with the 2.4 epoll patch. The workaround is to
6172 * delete then recreate in case of modification.
6173 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6174 * nor RHEL kernels.
6175 */
6176
6177 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6178 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6179
6180 if ((sr | sw))
6181 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6182#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006183 if ((pr | pw)) {
6184 /* the file-descriptor already exists... */
6185 if ((sr | sw)) {
6186 /* ...and it will still exist */
6187 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6188 // perror("epoll_ctl(MOD)");
6189 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006190 }
6191 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006192 /* ...and it will be removed */
6193 if (fdtab[fd].state != FD_STCLOSE &&
6194 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6195 // perror("epoll_ctl(DEL)");
6196 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006197 }
6198 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006199 } else {
6200 /* the file-descriptor did not exist, let's add it */
6201 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6202 // perror("epoll_ctl(ADD)");
6203 // exit(1);
6204 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006205 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006206#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006207 }
6208 ((int*)PrevReadEvent)[fds] = rn;
6209 ((int*)PrevWriteEvent)[fds] = wn;
6210 }
6211 }
6212
6213 /* now let's wait for events */
6214 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6215 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006216
willy tarreau1c2ad212005-12-18 01:11:29 +01006217 for (count = 0; count < status; count++) {
6218 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006219
6220 if (FD_ISSET(fd, StaticReadEvent)) {
6221 if (fdtab[fd].state == FD_STCLOSE)
6222 continue;
6223 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6224 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006225 }
willy tarreau05be12b2006-03-19 19:35:00 +01006226
6227 if (FD_ISSET(fd, StaticWriteEvent)) {
6228 if (fdtab[fd].state == FD_STCLOSE)
6229 continue;
6230 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6231 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006232 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006233 }
6234 }
6235 return 1;
6236}
6237#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006238
willy tarreauad90a0c2005-12-18 01:09:15 +01006239
willy tarreau5cbea6f2005-12-17 12:48:26 +01006240
willy tarreau1c2ad212005-12-18 01:11:29 +01006241#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006242
willy tarreau1c2ad212005-12-18 01:11:29 +01006243/*
6244 * Main poll() loop.
6245 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006246
willy tarreau1c2ad212005-12-18 01:11:29 +01006247/* does 3 actions :
6248 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6249 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6250 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6251 *
6252 * returns 0 if initialization failed, !0 otherwise.
6253 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006254
willy tarreau1c2ad212005-12-18 01:11:29 +01006255int poll_loop(int action) {
6256 int next_time;
6257 int status;
6258 int fd, nbfd;
6259
6260 int fds, count;
6261 int sr, sw;
6262 unsigned rn, wn; /* read new, write new */
6263
6264 /* private data */
6265 static struct pollfd *poll_events = NULL;
6266
6267 if (action == POLL_LOOP_ACTION_INIT) {
6268 poll_events = (struct pollfd*)
6269 calloc(1, sizeof(struct pollfd) * global.maxsock);
6270 return 1;
6271 }
6272 else if (action == POLL_LOOP_ACTION_CLEAN) {
6273 if (poll_events)
6274 free(poll_events);
6275 return 1;
6276 }
6277
6278 /* OK, it's POLL_LOOP_ACTION_RUN */
6279
6280 tv_now(&now);
6281
6282 while (1) {
6283 next_time = process_runnable_tasks();
6284
6285 /* stop when there's no connection left and we don't allow them anymore */
6286 if (!actconn && listeners == 0)
6287 break;
6288
6289#if STATTIME > 0
6290 {
6291 int time2;
6292 time2 = stats();
6293 next_time = MINTIME(time2, next_time);
6294 }
6295#endif
6296
6297
6298 nbfd = 0;
6299 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6300
6301 rn = ((int*)StaticReadEvent)[fds];
6302 wn = ((int*)StaticWriteEvent)[fds];
6303
6304 if ((rn|wn)) {
6305 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6306#define FDSETS_ARE_INT_ALIGNED
6307#ifdef FDSETS_ARE_INT_ALIGNED
6308
6309#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6310#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6311 sr = (rn >> count) & 1;
6312 sw = (wn >> count) & 1;
6313#else
6314 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6315 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6316#endif
6317#else
6318 sr = FD_ISSET(fd, StaticReadEvent);
6319 sw = FD_ISSET(fd, StaticWriteEvent);
6320#endif
6321 if ((sr|sw)) {
6322 poll_events[nbfd].fd = fd;
6323 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6324 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006325 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006326 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006327 }
6328 }
6329
6330 /* now let's wait for events */
6331 status = poll(poll_events, nbfd, next_time);
6332 tv_now(&now);
6333
6334 for (count = 0; status > 0 && count < nbfd; count++) {
6335 fd = poll_events[count].fd;
6336
6337 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6338 continue;
6339
6340 /* ok, we found one active fd */
6341 status--;
6342
willy tarreau05be12b2006-03-19 19:35:00 +01006343 if (FD_ISSET(fd, StaticReadEvent)) {
6344 if (fdtab[fd].state == FD_STCLOSE)
6345 continue;
6346 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6347 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006348 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006349
willy tarreau05be12b2006-03-19 19:35:00 +01006350 if (FD_ISSET(fd, StaticWriteEvent)) {
6351 if (fdtab[fd].state == FD_STCLOSE)
6352 continue;
6353 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6354 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006355 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006356 }
6357 }
6358 return 1;
6359}
willy tarreauad90a0c2005-12-18 01:09:15 +01006360#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006361
willy tarreauad90a0c2005-12-18 01:09:15 +01006362
willy tarreauad90a0c2005-12-18 01:09:15 +01006363
willy tarreau1c2ad212005-12-18 01:11:29 +01006364/*
6365 * Main select() loop.
6366 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006367
willy tarreau1c2ad212005-12-18 01:11:29 +01006368/* does 3 actions :
6369 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6370 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6371 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6372 *
6373 * returns 0 if initialization failed, !0 otherwise.
6374 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006375
willy tarreauad90a0c2005-12-18 01:09:15 +01006376
willy tarreau1c2ad212005-12-18 01:11:29 +01006377int select_loop(int action) {
6378 int next_time;
6379 int status;
6380 int fd,i;
6381 struct timeval delta;
6382 int readnotnull, writenotnull;
6383 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006384
willy tarreau1c2ad212005-12-18 01:11:29 +01006385 if (action == POLL_LOOP_ACTION_INIT) {
6386 ReadEvent = (fd_set *)
6387 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6388 WriteEvent = (fd_set *)
6389 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6390 return 1;
6391 }
6392 else if (action == POLL_LOOP_ACTION_CLEAN) {
6393 if (WriteEvent) free(WriteEvent);
6394 if (ReadEvent) free(ReadEvent);
6395 return 1;
6396 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006397
willy tarreau1c2ad212005-12-18 01:11:29 +01006398 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006399
willy tarreau1c2ad212005-12-18 01:11:29 +01006400 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006401
willy tarreau1c2ad212005-12-18 01:11:29 +01006402 while (1) {
6403 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006404
willy tarreau1c2ad212005-12-18 01:11:29 +01006405 /* stop when there's no connection left and we don't allow them anymore */
6406 if (!actconn && listeners == 0)
6407 break;
6408
6409#if STATTIME > 0
6410 {
6411 int time2;
6412 time2 = stats();
6413 next_time = MINTIME(time2, next_time);
6414 }
6415#endif
6416
willy tarreau1c2ad212005-12-18 01:11:29 +01006417 if (next_time > 0) { /* FIXME */
6418 /* Convert to timeval */
6419 /* to avoid eventual select loops due to timer precision */
6420 next_time += SCHEDULER_RESOLUTION;
6421 delta.tv_sec = next_time / 1000;
6422 delta.tv_usec = (next_time % 1000) * 1000;
6423 }
6424 else if (next_time == 0) { /* allow select to return immediately when needed */
6425 delta.tv_sec = delta.tv_usec = 0;
6426 }
6427
6428
6429 /* let's restore fdset state */
6430
6431 readnotnull = 0; writenotnull = 0;
6432 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6433 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6434 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6435 }
6436
6437 // /* just a verification code, needs to be removed for performance */
6438 // for (i=0; i<maxfd; i++) {
6439 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6440 // abort();
6441 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6442 // abort();
6443 //
6444 // }
6445
6446 status = select(maxfd,
6447 readnotnull ? ReadEvent : NULL,
6448 writenotnull ? WriteEvent : NULL,
6449 NULL,
6450 (next_time >= 0) ? &delta : NULL);
6451
6452 /* this is an experiment on the separation of the select work */
6453 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6454 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6455
6456 tv_now(&now);
6457
6458 if (status > 0) { /* must proceed with events */
6459
6460 int fds;
6461 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006462
willy tarreau1c2ad212005-12-18 01:11:29 +01006463 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6464 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6465 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6466
6467 /* if we specify read first, the accepts and zero reads will be
6468 * seen first. Moreover, system buffers will be flushed faster.
6469 */
willy tarreau05be12b2006-03-19 19:35:00 +01006470 if (FD_ISSET(fd, ReadEvent)) {
6471 if (fdtab[fd].state == FD_STCLOSE)
6472 continue;
6473 fdtab[fd].read(fd);
6474 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006475
willy tarreau05be12b2006-03-19 19:35:00 +01006476 if (FD_ISSET(fd, WriteEvent)) {
6477 if (fdtab[fd].state == FD_STCLOSE)
6478 continue;
6479 fdtab[fd].write(fd);
6480 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006481 }
6482 }
6483 else {
6484 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006485 }
willy tarreau0f7af912005-12-17 12:21:26 +01006486 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006487 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006488}
6489
6490
6491#if STATTIME > 0
6492/*
6493 * Display proxy statistics regularly. It is designed to be called from the
6494 * select_loop().
6495 */
6496int stats(void) {
6497 static int lines;
6498 static struct timeval nextevt;
6499 static struct timeval lastevt;
6500 static struct timeval starttime = {0,0};
6501 unsigned long totaltime, deltatime;
6502 int ret;
6503
willy tarreau750a4722005-12-17 13:21:24 +01006504 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006505 deltatime = (tv_diff(&lastevt, &now)?:1);
6506 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006507
willy tarreau9fe663a2005-12-17 13:02:59 +01006508 if (global.mode & MODE_STATS) {
6509 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006510 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006511 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6512 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006513 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006514 actconn, totalconn,
6515 stats_tsk_new, stats_tsk_good,
6516 stats_tsk_left, stats_tsk_right,
6517 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6518 }
6519 }
6520
6521 tv_delayfrom(&nextevt, &now, STATTIME);
6522
6523 lastevt=now;
6524 }
6525 ret = tv_remain(&now, &nextevt);
6526 return ret;
6527}
6528#endif
6529
6530
6531/*
6532 * this function enables proxies when there are enough free sessions,
6533 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006534 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006535 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006536 */
6537static int maintain_proxies(void) {
6538 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006539 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006540 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006541
6542 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006543 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006544
6545 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006546 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006547 while (p) {
6548 if (p->nbconn < p->maxconn) {
6549 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006550 for (l = p->listen; l != NULL; l = l->next) {
6551 FD_SET(l->fd, StaticReadEvent);
6552 }
willy tarreau0f7af912005-12-17 12:21:26 +01006553 p->state = PR_STRUN;
6554 }
6555 }
6556 else {
6557 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006558 for (l = p->listen; l != NULL; l = l->next) {
6559 FD_CLR(l->fd, StaticReadEvent);
6560 }
willy tarreau0f7af912005-12-17 12:21:26 +01006561 p->state = PR_STIDLE;
6562 }
6563 }
6564 p = p->next;
6565 }
6566 }
6567 else { /* block all proxies */
6568 while (p) {
6569 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006570 for (l = p->listen; l != NULL; l = l->next) {
6571 FD_CLR(l->fd, StaticReadEvent);
6572 }
willy tarreau0f7af912005-12-17 12:21:26 +01006573 p->state = PR_STIDLE;
6574 }
6575 p = p->next;
6576 }
6577 }
6578
willy tarreau5cbea6f2005-12-17 12:48:26 +01006579 if (stopping) {
6580 p = proxy;
6581 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006582 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006583 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006584 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006585 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006586 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006587 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006588
willy tarreaua41a8b42005-12-17 14:02:24 +01006589 for (l = p->listen; l != NULL; l = l->next) {
6590 fd_delete(l->fd);
6591 listeners--;
6592 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006593 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006594 }
6595 else {
6596 tleft = MINTIME(t, tleft);
6597 }
6598 }
6599 p = p->next;
6600 }
6601 }
6602 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006603}
6604
6605/*
6606 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006607 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6608 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006609 */
6610static void soft_stop(void) {
6611 struct proxy *p;
6612
6613 stopping = 1;
6614 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006615 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006616 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006617 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006618 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006619 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006620 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006621 }
willy tarreau0f7af912005-12-17 12:21:26 +01006622 p = p->next;
6623 }
6624}
6625
willy tarreaudbd3bef2006-01-20 19:35:18 +01006626static void pause_proxy(struct proxy *p) {
6627 struct listener *l;
6628 for (l = p->listen; l != NULL; l = l->next) {
6629 shutdown(l->fd, SHUT_RD);
6630 FD_CLR(l->fd, StaticReadEvent);
6631 p->state = PR_STPAUSED;
6632 }
6633}
6634
6635/*
6636 * This function temporarily disables listening so that another new instance
6637 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006638 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006639 * the proxy, or a SIGTTIN can be sent to listen again.
6640 */
6641static void pause_proxies(void) {
6642 struct proxy *p;
6643
6644 p = proxy;
6645 tv_now(&now); /* else, the old time before select will be used */
6646 while (p) {
6647 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6648 Warning("Pausing proxy %s.\n", p->id);
6649 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6650 pause_proxy(p);
6651 }
6652 p = p->next;
6653 }
6654}
6655
6656
6657/*
6658 * This function reactivates listening. This can be used after a call to
6659 * sig_pause(), for example when a new instance has failed starting up.
6660 * It is designed to be called upon reception of a SIGTTIN.
6661 */
6662static void listen_proxies(void) {
6663 struct proxy *p;
6664 struct listener *l;
6665
6666 p = proxy;
6667 tv_now(&now); /* else, the old time before select will be used */
6668 while (p) {
6669 if (p->state == PR_STPAUSED) {
6670 Warning("Enabling proxy %s.\n", p->id);
6671 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6672
6673 for (l = p->listen; l != NULL; l = l->next) {
6674 if (listen(l->fd, p->maxconn) == 0) {
6675 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6676 FD_SET(l->fd, StaticReadEvent);
6677 p->state = PR_STRUN;
6678 }
6679 else
6680 p->state = PR_STIDLE;
6681 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006682 int port;
6683
6684 if (l->addr.ss_family == AF_INET6)
6685 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6686 else
6687 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6688
willy tarreaudbd3bef2006-01-20 19:35:18 +01006689 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006690 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006691 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006692 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006693 /* Another port might have been enabled. Let's stop everything. */
6694 pause_proxy(p);
6695 break;
6696 }
6697 }
6698 }
6699 p = p->next;
6700 }
6701}
6702
6703
willy tarreau0f7af912005-12-17 12:21:26 +01006704/*
6705 * upon SIGUSR1, let's have a soft stop.
6706 */
6707void sig_soft_stop(int sig) {
6708 soft_stop();
6709 signal(sig, SIG_IGN);
6710}
6711
willy tarreaudbd3bef2006-01-20 19:35:18 +01006712/*
6713 * upon SIGTTOU, we pause everything
6714 */
6715void sig_pause(int sig) {
6716 pause_proxies();
6717 signal(sig, sig_pause);
6718}
willy tarreau0f7af912005-12-17 12:21:26 +01006719
willy tarreau8337c6b2005-12-17 13:41:01 +01006720/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006721 * upon SIGTTIN, let's have a soft stop.
6722 */
6723void sig_listen(int sig) {
6724 listen_proxies();
6725 signal(sig, sig_listen);
6726}
6727
6728/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006729 * this function dumps every server's state when the process receives SIGHUP.
6730 */
6731void sig_dump_state(int sig) {
6732 struct proxy *p = proxy;
6733
6734 Warning("SIGHUP received, dumping servers states.\n");
6735 while (p) {
6736 struct server *s = p->srv;
6737
willy tarreau4632c212006-05-02 23:32:51 +02006738 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006739 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006740 snprintf(trash, sizeof(trash),
6741 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6742 p->id, s->id,
6743 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6744 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006745 Warning("%s\n", trash);
6746 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006747 s = s->next;
6748 }
willy tarreaudd07e972005-12-18 00:48:48 +01006749
willy tarreau62084d42006-03-24 18:57:41 +01006750 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006751 snprintf(trash, sizeof(trash),
6752 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6753 p->id,
6754 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6755 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006756 } else {
6757 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006758 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6759 " Conn: %d act, %d pend (%d unass), %d tot.",
6760 p->id, p->srv_act, p->srv_bck,
6761 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006762 }
6763 Warning("%s\n", trash);
6764 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006765
willy tarreau8337c6b2005-12-17 13:41:01 +01006766 p = p->next;
6767 }
6768 signal(sig, sig_dump_state);
6769}
6770
willy tarreau0f7af912005-12-17 12:21:26 +01006771void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006772 struct task *t, *tnext;
6773 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006774
willy tarreau5e698ef2006-05-02 14:51:00 +02006775 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6776 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006777 tnext = t->next;
6778 s = t->context;
6779 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6780 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6781 "req=%d, rep=%d, clifd=%d\n",
6782 s, tv_remain(&now, &t->expire),
6783 s->cli_state,
6784 s->srv_state,
6785 FD_ISSET(s->cli_fd, StaticReadEvent),
6786 FD_ISSET(s->cli_fd, StaticWriteEvent),
6787 FD_ISSET(s->srv_fd, StaticReadEvent),
6788 FD_ISSET(s->srv_fd, StaticWriteEvent),
6789 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6790 );
willy tarreau0f7af912005-12-17 12:21:26 +01006791 }
willy tarreau12350152005-12-18 01:03:27 +01006792}
6793
willy tarreau64a3cc32005-12-18 01:13:11 +01006794#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006795static void fast_stop(void)
6796{
6797 struct proxy *p;
6798 p = proxy;
6799 while (p) {
6800 p->grace = 0;
6801 p = p->next;
6802 }
6803 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006804}
6805
willy tarreau12350152005-12-18 01:03:27 +01006806void sig_int(int sig) {
6807 /* This would normally be a hard stop,
6808 but we want to be sure about deallocation,
6809 and so on, so we do a soft stop with
6810 0 GRACE time
6811 */
6812 fast_stop();
6813 /* If we are killed twice, we decide to die*/
6814 signal(sig, SIG_DFL);
6815}
6816
6817void sig_term(int sig) {
6818 /* This would normally be a hard stop,
6819 but we want to be sure about deallocation,
6820 and so on, so we do a soft stop with
6821 0 GRACE time
6822 */
6823 fast_stop();
6824 /* If we are killed twice, we decide to die*/
6825 signal(sig, SIG_DFL);
6826}
willy tarreau64a3cc32005-12-18 01:13:11 +01006827#endif
willy tarreau12350152005-12-18 01:03:27 +01006828
willy tarreauc1f47532005-12-18 01:08:26 +01006829/* returns the pointer to an error in the replacement string, or NULL if OK */
6830char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006831 struct hdr_exp *exp;
6832
willy tarreauc1f47532005-12-18 01:08:26 +01006833 if (replace != NULL) {
6834 char *err;
6835 err = check_replace_string(replace);
6836 if (err)
6837 return err;
6838 }
6839
willy tarreaue39cd132005-12-17 13:00:18 +01006840 while (*head != NULL)
6841 head = &(*head)->next;
6842
6843 exp = calloc(1, sizeof(struct hdr_exp));
6844
6845 exp->preg = preg;
6846 exp->replace = replace;
6847 exp->action = action;
6848 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006849
6850 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006851}
6852
willy tarreau9fe663a2005-12-17 13:02:59 +01006853
willy tarreau0f7af912005-12-17 12:21:26 +01006854/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006855 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006856 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006857int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006858
willy tarreau9fe663a2005-12-17 13:02:59 +01006859 if (!strcmp(args[0], "global")) { /* new section */
6860 /* no option, nothing special to do */
6861 return 0;
6862 }
6863 else if (!strcmp(args[0], "daemon")) {
6864 global.mode |= MODE_DAEMON;
6865 }
6866 else if (!strcmp(args[0], "debug")) {
6867 global.mode |= MODE_DEBUG;
6868 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006869 else if (!strcmp(args[0], "noepoll")) {
6870 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6871 }
6872 else if (!strcmp(args[0], "nopoll")) {
6873 cfg_polling_mechanism &= ~POLL_USE_POLL;
6874 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006875 else if (!strcmp(args[0], "quiet")) {
6876 global.mode |= MODE_QUIET;
6877 }
6878 else if (!strcmp(args[0], "stats")) {
6879 global.mode |= MODE_STATS;
6880 }
6881 else if (!strcmp(args[0], "uid")) {
6882 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006883 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006884 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006886 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006887 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006889 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006890 global.uid = atol(args[1]);
6891 }
6892 else if (!strcmp(args[0], "gid")) {
6893 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006894 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006895 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006896 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006897 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006898 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006899 return -1;
6900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006901 global.gid = atol(args[1]);
6902 }
6903 else if (!strcmp(args[0], "nbproc")) {
6904 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006905 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006906 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006907 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006908 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006909 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006910 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 global.nbproc = atol(args[1]);
6913 }
6914 else if (!strcmp(args[0], "maxconn")) {
6915 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006916 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006917 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006920 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006921 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006922 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006923 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006924#ifdef SYSTEM_MAXCONN
6925 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6926 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);
6927 global.maxconn = DEFAULT_MAXCONN;
6928 }
6929#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 }
willy tarreaub1285d52005-12-18 01:20:14 +01006931 else if (!strcmp(args[0], "ulimit-n")) {
6932 if (global.rlimit_nofile != 0) {
6933 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6934 return 0;
6935 }
6936 if (*(args[1]) == 0) {
6937 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6938 return -1;
6939 }
6940 global.rlimit_nofile = atol(args[1]);
6941 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006942 else if (!strcmp(args[0], "chroot")) {
6943 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006944 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006945 return 0;
6946 }
6947 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006948 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 return -1;
6950 }
6951 global.chroot = strdup(args[1]);
6952 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006953 else if (!strcmp(args[0], "pidfile")) {
6954 if (global.pidfile != NULL) {
6955 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6956 return 0;
6957 }
6958 if (*(args[1]) == 0) {
6959 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6960 return -1;
6961 }
6962 global.pidfile = strdup(args[1]);
6963 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 else if (!strcmp(args[0], "log")) { /* syslog server address */
6965 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006966 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006967
6968 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006969 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 return -1;
6971 }
6972
6973 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6974 if (!strcmp(log_facilities[facility], args[2]))
6975 break;
6976
6977 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006978 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006979 exit(1);
6980 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006981
6982 level = 7; /* max syslog level = debug */
6983 if (*(args[3])) {
6984 while (level >= 0 && strcmp(log_levels[level], args[3]))
6985 level--;
6986 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006987 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006988 exit(1);
6989 }
6990 }
6991
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 sa = str2sa(args[1]);
6993 if (!sa->sin_port)
6994 sa->sin_port = htons(SYSLOG_PORT);
6995
6996 if (global.logfac1 == -1) {
6997 global.logsrv1 = *sa;
6998 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006999 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007000 }
7001 else if (global.logfac2 == -1) {
7002 global.logsrv2 = *sa;
7003 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007004 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007005 }
7006 else {
7007 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7008 return -1;
7009 }
7010
7011 }
7012 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007013 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007014 return -1;
7015 }
7016 return 0;
7017}
7018
7019
willy tarreaua41a8b42005-12-17 14:02:24 +01007020void init_default_instance() {
7021 memset(&defproxy, 0, sizeof(defproxy));
7022 defproxy.mode = PR_MODE_TCP;
7023 defproxy.state = PR_STNEW;
7024 defproxy.maxconn = cfg_maxpconn;
7025 defproxy.conn_retries = CONN_RETRIES;
7026 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7027}
7028
willy tarreau9fe663a2005-12-17 13:02:59 +01007029/*
7030 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7031 */
7032int cfg_parse_listen(char *file, int linenum, char **args) {
7033 static struct proxy *curproxy = NULL;
7034 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007035 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007036 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007037
7038 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007039 if (!*args[1]) {
7040 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7041 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007042 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 return -1;
7044 }
7045
7046 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007047 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007048 return -1;
7049 }
willy tarreaudfece232006-05-02 00:19:57 +02007050
willy tarreau9fe663a2005-12-17 13:02:59 +01007051 curproxy->next = proxy;
7052 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007053 LIST_INIT(&curproxy->pendconns);
7054
willy tarreau9fe663a2005-12-17 13:02:59 +01007055 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007056
7057 /* parse the listener address if any */
7058 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007059 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007060 if (!curproxy->listen)
7061 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007062 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007063 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007064
willy tarreau9fe663a2005-12-17 13:02:59 +01007065 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007066 curproxy->state = defproxy.state;
7067 curproxy->maxconn = defproxy.maxconn;
7068 curproxy->conn_retries = defproxy.conn_retries;
7069 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007070
7071 if (defproxy.check_req)
7072 curproxy->check_req = strdup(defproxy.check_req);
7073 curproxy->check_len = defproxy.check_len;
7074
7075 if (defproxy.cookie_name)
7076 curproxy->cookie_name = strdup(defproxy.cookie_name);
7077 curproxy->cookie_len = defproxy.cookie_len;
7078
7079 if (defproxy.capture_name)
7080 curproxy->capture_name = strdup(defproxy.capture_name);
7081 curproxy->capture_namelen = defproxy.capture_namelen;
7082 curproxy->capture_len = defproxy.capture_len;
7083
7084 if (defproxy.errmsg.msg400)
7085 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7086 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7087
7088 if (defproxy.errmsg.msg403)
7089 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7090 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7091
7092 if (defproxy.errmsg.msg408)
7093 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7094 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7095
7096 if (defproxy.errmsg.msg500)
7097 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7098 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7099
7100 if (defproxy.errmsg.msg502)
7101 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7102 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7103
7104 if (defproxy.errmsg.msg503)
7105 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7106 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7107
7108 if (defproxy.errmsg.msg504)
7109 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7110 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7111
willy tarreaua41a8b42005-12-17 14:02:24 +01007112 curproxy->clitimeout = defproxy.clitimeout;
7113 curproxy->contimeout = defproxy.contimeout;
7114 curproxy->srvtimeout = defproxy.srvtimeout;
7115 curproxy->mode = defproxy.mode;
7116 curproxy->logfac1 = defproxy.logfac1;
7117 curproxy->logsrv1 = defproxy.logsrv1;
7118 curproxy->loglev1 = defproxy.loglev1;
7119 curproxy->logfac2 = defproxy.logfac2;
7120 curproxy->logsrv2 = defproxy.logsrv2;
7121 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007122 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007123 curproxy->grace = defproxy.grace;
7124 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007125 curproxy->mon_net = defproxy.mon_net;
7126 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007127 return 0;
7128 }
7129 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007130 /* some variables may have already been initialized earlier */
7131 if (defproxy.check_req) free(defproxy.check_req);
7132 if (defproxy.cookie_name) free(defproxy.cookie_name);
7133 if (defproxy.capture_name) free(defproxy.capture_name);
7134 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7135 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7136 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7137 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7138 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7139 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7140 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7141
7142 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007143 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 return 0;
7145 }
7146 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007147 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007148 return -1;
7149 }
7150
willy tarreaua41a8b42005-12-17 14:02:24 +01007151 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7152 if (curproxy == &defproxy) {
7153 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7154 return -1;
7155 }
7156
7157 if (strchr(args[1], ':') == NULL) {
7158 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7159 file, linenum, args[0]);
7160 return -1;
7161 }
7162 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007163 if (!curproxy->listen)
7164 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007165 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007166 return 0;
7167 }
willy tarreaub1285d52005-12-18 01:20:14 +01007168 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7169 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7170 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7171 file, linenum, args[0]);
7172 return -1;
7173 }
7174 /* flush useless bits */
7175 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7176 return 0;
7177 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007178 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007179 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7180 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7181 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7182 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007183 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007184 return -1;
7185 }
7186 }
7187 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007188 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007189 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007190 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7191 curproxy->state = PR_STNEW;
7192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007193 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7194 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007195// if (curproxy == &defproxy) {
7196// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7197// return -1;
7198// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007199
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007201// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7202// file, linenum);
7203// return 0;
7204 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007205 }
7206
7207 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007208 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7209 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007210 return -1;
7211 }
7212 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007213 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007214
7215 cur_arg = 2;
7216 while (*(args[cur_arg])) {
7217 if (!strcmp(args[cur_arg], "rewrite")) {
7218 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007219 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007220 else if (!strcmp(args[cur_arg], "indirect")) {
7221 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007222 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007223 else if (!strcmp(args[cur_arg], "insert")) {
7224 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007225 }
willy tarreau240afa62005-12-17 13:14:35 +01007226 else if (!strcmp(args[cur_arg], "nocache")) {
7227 curproxy->options |= PR_O_COOK_NOC;
7228 }
willy tarreaucd878942005-12-17 13:27:43 +01007229 else if (!strcmp(args[cur_arg], "postonly")) {
7230 curproxy->options |= PR_O_COOK_POST;
7231 }
willy tarreau0174f312005-12-18 01:02:42 +01007232 else if (!strcmp(args[cur_arg], "prefix")) {
7233 curproxy->options |= PR_O_COOK_PFX;
7234 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 else {
willy tarreau0174f312005-12-18 01:02:42 +01007236 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007237 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007238 return -1;
7239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007240 cur_arg++;
7241 }
willy tarreau0174f312005-12-18 01:02:42 +01007242 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7243 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7244 file, linenum);
7245 return -1;
7246 }
7247
7248 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7249 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007250 file, linenum);
7251 return -1;
7252 }
willy tarreau12350152005-12-18 01:03:27 +01007253 }/* end else if (!strcmp(args[0], "cookie")) */
7254 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7255// if (curproxy == &defproxy) {
7256// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7257// return -1;
7258// }
7259
7260 if (curproxy->appsession_name != NULL) {
7261// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7262// file, linenum);
7263// return 0;
7264 free(curproxy->appsession_name);
7265 }
7266
7267 if (*(args[5]) == 0) {
7268 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7269 file, linenum, args[0]);
7270 return -1;
7271 }
7272 have_appsession = 1;
7273 curproxy->appsession_name = strdup(args[1]);
7274 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7275 curproxy->appsession_len = atoi(args[3]);
7276 curproxy->appsession_timeout = atoi(args[5]);
7277 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7278 if (rc) {
7279 Alert("Error Init Appsession Hashtable.\n");
7280 return -1;
7281 }
7282 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007283 else if (!strcmp(args[0], "capture")) {
7284 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7285 // if (curproxy == &defproxy) {
7286 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7287 // return -1;
7288 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007289
willy tarreau4302f492005-12-18 01:00:37 +01007290 if (curproxy->capture_name != NULL) {
7291 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7292 // file, linenum, args[0]);
7293 // return 0;
7294 free(curproxy->capture_name);
7295 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007296
willy tarreau4302f492005-12-18 01:00:37 +01007297 if (*(args[4]) == 0) {
7298 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7299 file, linenum, args[0]);
7300 return -1;
7301 }
7302 curproxy->capture_name = strdup(args[2]);
7303 curproxy->capture_namelen = strlen(curproxy->capture_name);
7304 curproxy->capture_len = atol(args[4]);
7305 if (curproxy->capture_len >= CAPTURE_LEN) {
7306 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7307 file, linenum, CAPTURE_LEN - 1);
7308 curproxy->capture_len = CAPTURE_LEN - 1;
7309 }
7310 curproxy->to_log |= LW_COOKIE;
7311 }
7312 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7313 struct cap_hdr *hdr;
7314
7315 if (curproxy == &defproxy) {
7316 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7317 return -1;
7318 }
7319
7320 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7321 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7322 file, linenum, args[0], args[1]);
7323 return -1;
7324 }
7325
7326 hdr = calloc(sizeof(struct cap_hdr), 1);
7327 hdr->next = curproxy->req_cap;
7328 hdr->name = strdup(args[3]);
7329 hdr->namelen = strlen(args[3]);
7330 hdr->len = atol(args[5]);
7331 hdr->index = curproxy->nb_req_cap++;
7332 curproxy->req_cap = hdr;
7333 curproxy->to_log |= LW_REQHDR;
7334 }
7335 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7336 struct cap_hdr *hdr;
7337
7338 if (curproxy == &defproxy) {
7339 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7340 return -1;
7341 }
7342
7343 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7344 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7345 file, linenum, args[0], args[1]);
7346 return -1;
7347 }
7348 hdr = calloc(sizeof(struct cap_hdr), 1);
7349 hdr->next = curproxy->rsp_cap;
7350 hdr->name = strdup(args[3]);
7351 hdr->namelen = strlen(args[3]);
7352 hdr->len = atol(args[5]);
7353 hdr->index = curproxy->nb_rsp_cap++;
7354 curproxy->rsp_cap = hdr;
7355 curproxy->to_log |= LW_RSPHDR;
7356 }
7357 else {
7358 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007360 return -1;
7361 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007362 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007363 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007364 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007365 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 return 0;
7367 }
7368 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007369 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7370 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007371 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007372 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007373 curproxy->contimeout = atol(args[1]);
7374 }
7375 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007376 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007377 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7378 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007379 return 0;
7380 }
7381 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007382 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7383 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007384 return -1;
7385 }
7386 curproxy->clitimeout = atol(args[1]);
7387 }
7388 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007389 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007390 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007391 return 0;
7392 }
7393 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007394 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7395 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007396 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007397 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007398 curproxy->srvtimeout = atol(args[1]);
7399 }
7400 else if (!strcmp(args[0], "retries")) { /* connection retries */
7401 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007402 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7403 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007404 return -1;
7405 }
7406 curproxy->conn_retries = atol(args[1]);
7407 }
7408 else if (!strcmp(args[0], "option")) {
7409 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007410 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007411 return -1;
7412 }
7413 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007414 /* enable reconnections to dispatch */
7415 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007416#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007417 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007418 /* enable transparent proxy connections */
7419 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007420#endif
7421 else if (!strcmp(args[1], "keepalive"))
7422 /* enable keep-alive */
7423 curproxy->options |= PR_O_KEEPALIVE;
7424 else if (!strcmp(args[1], "forwardfor"))
7425 /* insert x-forwarded-for field */
7426 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007427 else if (!strcmp(args[1], "logasap"))
7428 /* log as soon as possible, without waiting for the session to complete */
7429 curproxy->options |= PR_O_LOGASAP;
7430 else if (!strcmp(args[1], "httpclose"))
7431 /* force connection: close in both directions in HTTP mode */
7432 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007433 else if (!strcmp(args[1], "forceclose"))
7434 /* force connection: close in both directions in HTTP mode and enforce end of session */
7435 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007436 else if (!strcmp(args[1], "checkcache"))
7437 /* require examination of cacheability of the 'set-cookie' field */
7438 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007439 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007440 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007441 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007442 else if (!strcmp(args[1], "tcplog"))
7443 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007444 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007445 else if (!strcmp(args[1], "dontlognull")) {
7446 /* don't log empty requests */
7447 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007448 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007449 else if (!strcmp(args[1], "tcpka")) {
7450 /* enable TCP keep-alives on client and server sessions */
7451 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7452 }
7453 else if (!strcmp(args[1], "clitcpka")) {
7454 /* enable TCP keep-alives on client sessions */
7455 curproxy->options |= PR_O_TCP_CLI_KA;
7456 }
7457 else if (!strcmp(args[1], "srvtcpka")) {
7458 /* enable TCP keep-alives on server sessions */
7459 curproxy->options |= PR_O_TCP_SRV_KA;
7460 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007461 else if (!strcmp(args[1], "allbackups")) {
7462 /* Use all backup servers simultaneously */
7463 curproxy->options |= PR_O_USE_ALL_BK;
7464 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007465 else if (!strcmp(args[1], "httpchk")) {
7466 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007467 if (curproxy->check_req != NULL) {
7468 free(curproxy->check_req);
7469 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007470 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007471 if (!*args[2]) { /* no argument */
7472 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7473 curproxy->check_len = strlen(DEF_CHECK_REQ);
7474 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007475 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7476 curproxy->check_req = (char *)malloc(reqlen);
7477 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7478 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007479 } else { /* more arguments : METHOD URI [HTTP_VER] */
7480 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7481 if (*args[4])
7482 reqlen += strlen(args[4]);
7483 else
7484 reqlen += strlen("HTTP/1.0");
7485
7486 curproxy->check_req = (char *)malloc(reqlen);
7487 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7488 "%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 +01007489 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007490 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007491 else if (!strcmp(args[1], "persist")) {
7492 /* persist on using the server specified by the cookie, even when it's down */
7493 curproxy->options |= PR_O_PERSIST;
7494 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007495 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007496 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007497 return -1;
7498 }
7499 return 0;
7500 }
7501 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7502 /* enable reconnections to dispatch */
7503 curproxy->options |= PR_O_REDISP;
7504 }
willy tarreaua1598082005-12-17 13:08:06 +01007505#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007506 else if (!strcmp(args[0], "transparent")) {
7507 /* enable transparent proxy connections */
7508 curproxy->options |= PR_O_TRANSP;
7509 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007510#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007511 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7512 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007513 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007514 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007515 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007516 curproxy->maxconn = atol(args[1]);
7517 }
7518 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7519 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007520 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007521 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007522 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007523 curproxy->grace = atol(args[1]);
7524 }
7525 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007526 if (curproxy == &defproxy) {
7527 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7528 return -1;
7529 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007531 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007532 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007533 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007534 curproxy->dispatch_addr = *str2sa(args[1]);
7535 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007536 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 if (*(args[1])) {
7538 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007539 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007540 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007541 else if (!strcmp(args[1], "source")) {
7542 curproxy->options |= PR_O_BALANCE_SH;
7543 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007544 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007545 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007546 return -1;
7547 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007548 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007549 else /* if no option is set, use round-robin by default */
7550 curproxy->options |= PR_O_BALANCE_RR;
7551 }
7552 else if (!strcmp(args[0], "server")) { /* server address */
7553 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007554 char *rport;
7555 char *raddr;
7556 short realport;
7557 int do_check;
7558
7559 if (curproxy == &defproxy) {
7560 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7561 return -1;
7562 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007563
willy tarreaua41a8b42005-12-17 14:02:24 +01007564 if (!*args[2]) {
7565 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007566 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007567 return -1;
7568 }
7569 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7570 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7571 return -1;
7572 }
willy tarreau0174f312005-12-18 01:02:42 +01007573
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007574 /* the servers are linked backwards first */
7575 newsrv->next = curproxy->srv;
7576 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007577 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007578
willy tarreau18a957c2006-04-12 19:26:23 +02007579 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007580 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007581 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007582 newsrv->id = strdup(args[1]);
7583
7584 /* several ways to check the port component :
7585 * - IP => port=+0, relative
7586 * - IP: => port=+0, relative
7587 * - IP:N => port=N, absolute
7588 * - IP:+N => port=+N, relative
7589 * - IP:-N => port=-N, relative
7590 */
7591 raddr = strdup(args[2]);
7592 rport = strchr(raddr, ':');
7593 if (rport) {
7594 *rport++ = 0;
7595 realport = atol(rport);
7596 if (!isdigit((int)*rport))
7597 newsrv->state |= SRV_MAPPORTS;
7598 } else {
7599 realport = 0;
7600 newsrv->state |= SRV_MAPPORTS;
7601 }
7602
7603 newsrv->addr = *str2sa(raddr);
7604 newsrv->addr.sin_port = htons(realport);
7605 free(raddr);
7606
willy tarreau9fe663a2005-12-17 13:02:59 +01007607 newsrv->curfd = -1; /* no health-check in progress */
7608 newsrv->inter = DEF_CHKINTR;
7609 newsrv->rise = DEF_RISETIME;
7610 newsrv->fall = DEF_FALLTIME;
7611 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7612 cur_arg = 3;
7613 while (*args[cur_arg]) {
7614 if (!strcmp(args[cur_arg], "cookie")) {
7615 newsrv->cookie = strdup(args[cur_arg + 1]);
7616 newsrv->cklen = strlen(args[cur_arg + 1]);
7617 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007618 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007619 else if (!strcmp(args[cur_arg], "rise")) {
7620 newsrv->rise = atol(args[cur_arg + 1]);
7621 newsrv->health = newsrv->rise;
7622 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007623 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007624 else if (!strcmp(args[cur_arg], "fall")) {
7625 newsrv->fall = atol(args[cur_arg + 1]);
7626 cur_arg += 2;
7627 }
7628 else if (!strcmp(args[cur_arg], "inter")) {
7629 newsrv->inter = atol(args[cur_arg + 1]);
7630 cur_arg += 2;
7631 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007632 else if (!strcmp(args[cur_arg], "port")) {
7633 newsrv->check_port = atol(args[cur_arg + 1]);
7634 cur_arg += 2;
7635 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007636 else if (!strcmp(args[cur_arg], "backup")) {
7637 newsrv->state |= SRV_BACKUP;
7638 cur_arg ++;
7639 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007640 else if (!strcmp(args[cur_arg], "weight")) {
7641 int w;
7642 w = atol(args[cur_arg + 1]);
7643 if (w < 1 || w > 256) {
7644 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7645 file, linenum, newsrv->id, w);
7646 return -1;
7647 }
7648 newsrv->uweight = w - 1;
7649 cur_arg += 2;
7650 }
willy tarreau18a957c2006-04-12 19:26:23 +02007651 else if (!strcmp(args[cur_arg], "maxconn")) {
7652 newsrv->maxconn = atol(args[cur_arg + 1]);
7653 cur_arg += 2;
7654 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007655 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007656 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007657 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007658 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007659 }
willy tarreau0174f312005-12-18 01:02:42 +01007660 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7661 if (!*args[cur_arg + 1]) {
7662 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7663 file, linenum, "source");
7664 return -1;
7665 }
7666 newsrv->state |= SRV_BIND_SRC;
7667 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7668 cur_arg += 2;
7669 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007670 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007671 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 +01007672 file, linenum, newsrv->id);
7673 return -1;
7674 }
7675 }
7676
7677 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007678 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7679 newsrv->check_port = realport; /* by default */
7680 if (!newsrv->check_port) {
7681 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 +01007682 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007683 return -1;
7684 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007685 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007686 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007687
willy tarreau62084d42006-03-24 18:57:41 +01007688 if (newsrv->state & SRV_BACKUP)
7689 curproxy->srv_bck++;
7690 else
7691 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007692 }
7693 else if (!strcmp(args[0], "log")) { /* syslog server address */
7694 struct sockaddr_in *sa;
7695 int facility;
7696
7697 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7698 curproxy->logfac1 = global.logfac1;
7699 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007700 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007701 curproxy->logfac2 = global.logfac2;
7702 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007703 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007704 }
7705 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007706 int level;
7707
willy tarreau0f7af912005-12-17 12:21:26 +01007708 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7709 if (!strcmp(log_facilities[facility], args[2]))
7710 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007711
willy tarreau0f7af912005-12-17 12:21:26 +01007712 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007713 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007714 exit(1);
7715 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007716
willy tarreau8337c6b2005-12-17 13:41:01 +01007717 level = 7; /* max syslog level = debug */
7718 if (*(args[3])) {
7719 while (level >= 0 && strcmp(log_levels[level], args[3]))
7720 level--;
7721 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007722 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007723 exit(1);
7724 }
7725 }
7726
willy tarreau0f7af912005-12-17 12:21:26 +01007727 sa = str2sa(args[1]);
7728 if (!sa->sin_port)
7729 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007730
willy tarreau0f7af912005-12-17 12:21:26 +01007731 if (curproxy->logfac1 == -1) {
7732 curproxy->logsrv1 = *sa;
7733 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007734 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007735 }
7736 else if (curproxy->logfac2 == -1) {
7737 curproxy->logsrv2 = *sa;
7738 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007739 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007740 }
7741 else {
7742 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007743 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007745 }
7746 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007747 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 file, linenum);
7749 return -1;
7750 }
7751 }
willy tarreaua1598082005-12-17 13:08:06 +01007752 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007753 if (!*args[1]) {
7754 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007755 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007756 return -1;
7757 }
7758
7759 curproxy->source_addr = *str2sa(args[1]);
7760 curproxy->options |= PR_O_BIND_SRC;
7761 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007762 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7763 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007764 if (curproxy == &defproxy) {
7765 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7766 return -1;
7767 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007768
7769 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007770 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7771 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007772 return -1;
7773 }
7774
7775 preg = calloc(1, sizeof(regex_t));
7776 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007777 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007778 return -1;
7779 }
7780
willy tarreauc1f47532005-12-18 01:08:26 +01007781 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7782 if (err) {
7783 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7784 file, linenum, *err);
7785 return -1;
7786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007787 }
7788 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7789 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007790 if (curproxy == &defproxy) {
7791 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7792 return -1;
7793 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007794
7795 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007796 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007797 return -1;
7798 }
7799
7800 preg = calloc(1, sizeof(regex_t));
7801 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007802 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007803 return -1;
7804 }
7805
7806 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7807 }
7808 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7809 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007810 if (curproxy == &defproxy) {
7811 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7812 return -1;
7813 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007814
7815 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007816 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007817 return -1;
7818 }
7819
7820 preg = calloc(1, sizeof(regex_t));
7821 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007822 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007823 return -1;
7824 }
7825
7826 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7827 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007828 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7829 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007830 if (curproxy == &defproxy) {
7831 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7832 return -1;
7833 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007834
7835 if (*(args[1]) == 0) {
7836 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7837 return -1;
7838 }
7839
7840 preg = calloc(1, sizeof(regex_t));
7841 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7842 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7843 return -1;
7844 }
7845
7846 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7847 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007848 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7849 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007850 if (curproxy == &defproxy) {
7851 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7852 return -1;
7853 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007854
7855 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007856 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007857 return -1;
7858 }
7859
7860 preg = calloc(1, sizeof(regex_t));
7861 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007862 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007863 return -1;
7864 }
7865
7866 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7867 }
7868 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7869 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007870 if (curproxy == &defproxy) {
7871 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7872 return -1;
7873 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007874
7875 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007876 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7877 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007878 return -1;
7879 }
7880
7881 preg = calloc(1, sizeof(regex_t));
7882 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007883 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007884 return -1;
7885 }
7886
willy tarreauc1f47532005-12-18 01:08:26 +01007887 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7888 if (err) {
7889 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7890 file, linenum, *err);
7891 return -1;
7892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007893 }
7894 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7895 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007896 if (curproxy == &defproxy) {
7897 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7898 return -1;
7899 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007900
7901 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007902 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007903 return -1;
7904 }
7905
7906 preg = calloc(1, sizeof(regex_t));
7907 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007908 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007909 return -1;
7910 }
7911
7912 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7913 }
7914 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7915 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007916 if (curproxy == &defproxy) {
7917 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7918 return -1;
7919 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007920
7921 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007922 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007923 return -1;
7924 }
7925
7926 preg = calloc(1, sizeof(regex_t));
7927 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007928 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007929 return -1;
7930 }
7931
7932 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7933 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007934 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7935 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007936 if (curproxy == &defproxy) {
7937 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7938 return -1;
7939 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007940
7941 if (*(args[1]) == 0) {
7942 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7943 return -1;
7944 }
7945
7946 preg = calloc(1, sizeof(regex_t));
7947 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7948 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7949 return -1;
7950 }
7951
7952 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007954 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7955 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007956 if (curproxy == &defproxy) {
7957 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7958 return -1;
7959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007960
7961 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007962 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007963 return -1;
7964 }
7965
7966 preg = calloc(1, sizeof(regex_t));
7967 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007968 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007969 return -1;
7970 }
7971
7972 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7973 }
7974 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007975 if (curproxy == &defproxy) {
7976 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7977 return -1;
7978 }
7979
willy tarreau9fe663a2005-12-17 13:02:59 +01007980 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007981 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007982 return 0;
7983 }
7984
7985 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007986 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007987 return -1;
7988 }
7989
willy tarreau4302f492005-12-18 01:00:37 +01007990 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7991 }
7992 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7993 regex_t *preg;
7994
7995 if (*(args[1]) == 0 || *(args[2]) == 0) {
7996 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7997 file, linenum, args[0]);
7998 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007999 }
willy tarreau4302f492005-12-18 01:00:37 +01008000
8001 preg = calloc(1, sizeof(regex_t));
8002 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8003 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8004 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008005 }
willy tarreau4302f492005-12-18 01:00:37 +01008006
willy tarreauc1f47532005-12-18 01:08:26 +01008007 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8008 if (err) {
8009 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8010 file, linenum, *err);
8011 return -1;
8012 }
willy tarreau4302f492005-12-18 01:00:37 +01008013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008014 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8015 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008016 if (curproxy == &defproxy) {
8017 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8018 return -1;
8019 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008020
8021 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008022 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008023 return -1;
8024 }
willy tarreaue39cd132005-12-17 13:00:18 +01008025
willy tarreau9fe663a2005-12-17 13:02:59 +01008026 preg = calloc(1, sizeof(regex_t));
8027 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008028 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008029 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008031
willy tarreauc1f47532005-12-18 01:08:26 +01008032 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8033 if (err) {
8034 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8035 file, linenum, *err);
8036 return -1;
8037 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008038 }
willy tarreau982249e2005-12-18 00:57:06 +01008039 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8040 regex_t *preg;
8041 if (curproxy == &defproxy) {
8042 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8043 return -1;
8044 }
8045
8046 if (*(args[1]) == 0) {
8047 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8048 return -1;
8049 }
8050
8051 preg = calloc(1, sizeof(regex_t));
8052 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8053 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8054 return -1;
8055 }
8056
willy tarreauc1f47532005-12-18 01:08:26 +01008057 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8058 if (err) {
8059 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8060 file, linenum, *err);
8061 return -1;
8062 }
willy tarreau982249e2005-12-18 00:57:06 +01008063 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008064 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008065 regex_t *preg;
8066 if (curproxy == &defproxy) {
8067 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8068 return -1;
8069 }
willy tarreaue39cd132005-12-17 13:00:18 +01008070
willy tarreaua41a8b42005-12-17 14:02:24 +01008071 if (*(args[1]) == 0 || *(args[2]) == 0) {
8072 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8073 file, linenum, args[0]);
8074 return -1;
8075 }
willy tarreaue39cd132005-12-17 13:00:18 +01008076
willy tarreaua41a8b42005-12-17 14:02:24 +01008077 preg = calloc(1, sizeof(regex_t));
8078 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8079 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8080 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008081 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008082
willy tarreauc1f47532005-12-18 01:08:26 +01008083 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, 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 tarreaua41a8b42005-12-17 14:02:24 +01008089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8091 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008092 if (curproxy == &defproxy) {
8093 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8094 return -1;
8095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008096
8097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008098 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008099 return -1;
8100 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008101
willy tarreau9fe663a2005-12-17 13:02:59 +01008102 preg = calloc(1, sizeof(regex_t));
8103 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008104 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008107
willy tarreauc1f47532005-12-18 01:08:26 +01008108 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, 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 tarreau9fe663a2005-12-17 13:02:59 +01008114 }
willy tarreau982249e2005-12-18 00:57:06 +01008115 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8116 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 }
8121
8122 if (*(args[1]) == 0) {
8123 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8124 return -1;
8125 }
8126
8127 preg = calloc(1, sizeof(regex_t));
8128 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8129 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8130 return -1;
8131 }
8132
willy tarreauc1f47532005-12-18 01:08:26 +01008133 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8134 if (err) {
8135 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8136 file, linenum, *err);
8137 return -1;
8138 }
willy tarreau982249e2005-12-18 00:57:06 +01008139 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008140 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008141 if (curproxy == &defproxy) {
8142 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8143 return -1;
8144 }
8145
willy tarreau9fe663a2005-12-17 13:02:59 +01008146 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008147 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008148 return 0;
8149 }
8150
8151 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008152 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008153 return -1;
8154 }
8155
8156 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8157 }
willy tarreauc1f47532005-12-18 01:08:26 +01008158 else if (!strcmp(args[0], "errorloc") ||
8159 !strcmp(args[0], "errorloc302") ||
8160 !strcmp(args[0], "errorloc303")) { /* error location */
8161 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008162 char *err;
8163
willy tarreaueedaa9f2005-12-17 14:08:03 +01008164 // if (curproxy == &defproxy) {
8165 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8166 // return -1;
8167 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008168
willy tarreau8337c6b2005-12-17 13:41:01 +01008169 if (*(args[2]) == 0) {
8170 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8171 return -1;
8172 }
8173
8174 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008175 if (!strcmp(args[0], "errorloc303")) {
8176 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8177 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8178 } else {
8179 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8180 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8181 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008182
8183 if (errnum == 400) {
8184 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008185 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008186 free(curproxy->errmsg.msg400);
8187 }
8188 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008189 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008190 }
8191 else if (errnum == 403) {
8192 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008193 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008194 free(curproxy->errmsg.msg403);
8195 }
8196 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008197 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008198 }
8199 else if (errnum == 408) {
8200 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008201 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008202 free(curproxy->errmsg.msg408);
8203 }
8204 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008205 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008206 }
8207 else if (errnum == 500) {
8208 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008209 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008210 free(curproxy->errmsg.msg500);
8211 }
8212 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008213 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008214 }
8215 else if (errnum == 502) {
8216 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008217 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008218 free(curproxy->errmsg.msg502);
8219 }
8220 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008221 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008222 }
8223 else if (errnum == 503) {
8224 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008225 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008226 free(curproxy->errmsg.msg503);
8227 }
8228 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008229 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008230 }
8231 else if (errnum == 504) {
8232 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008233 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008234 free(curproxy->errmsg.msg504);
8235 }
8236 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008237 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008238 }
8239 else {
8240 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8241 free(err);
8242 }
8243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008244 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008245 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008246 return -1;
8247 }
8248 return 0;
8249}
willy tarreaue39cd132005-12-17 13:00:18 +01008250
willy tarreau5cbea6f2005-12-17 12:48:26 +01008251
willy tarreau9fe663a2005-12-17 13:02:59 +01008252/*
8253 * This function reads and parses the configuration file given in the argument.
8254 * returns 0 if OK, -1 if error.
8255 */
8256int readcfgfile(char *file) {
8257 char thisline[256];
8258 char *line;
8259 FILE *f;
8260 int linenum = 0;
8261 char *end;
8262 char *args[MAX_LINE_ARGS];
8263 int arg;
8264 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008265 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008266 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008267
willy tarreau9fe663a2005-12-17 13:02:59 +01008268 struct proxy *curproxy = NULL;
8269 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008270
willy tarreau9fe663a2005-12-17 13:02:59 +01008271 if ((f=fopen(file,"r")) == NULL)
8272 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008273
willy tarreaueedaa9f2005-12-17 14:08:03 +01008274 init_default_instance();
8275
willy tarreau9fe663a2005-12-17 13:02:59 +01008276 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8277 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008278
willy tarreau9fe663a2005-12-17 13:02:59 +01008279 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008280
willy tarreau9fe663a2005-12-17 13:02:59 +01008281 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008282 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008283 line++;
8284
8285 arg = 0;
8286 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008287
willy tarreau9fe663a2005-12-17 13:02:59 +01008288 while (*line && arg < MAX_LINE_ARGS) {
8289 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8290 * C equivalent value. Other combinations left unchanged (eg: \1).
8291 */
8292 if (*line == '\\') {
8293 int skip = 0;
8294 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8295 *line = line[1];
8296 skip = 1;
8297 }
8298 else if (line[1] == 'r') {
8299 *line = '\r';
8300 skip = 1;
8301 }
8302 else if (line[1] == 'n') {
8303 *line = '\n';
8304 skip = 1;
8305 }
8306 else if (line[1] == 't') {
8307 *line = '\t';
8308 skip = 1;
8309 }
willy tarreauc1f47532005-12-18 01:08:26 +01008310 else if (line[1] == 'x') {
8311 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8312 unsigned char hex1, hex2;
8313 hex1 = toupper(line[2]) - '0';
8314 hex2 = toupper(line[3]) - '0';
8315 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8316 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8317 *line = (hex1<<4) + hex2;
8318 skip = 3;
8319 }
8320 else {
8321 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8322 return -1;
8323 }
8324 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008325 if (skip) {
8326 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8327 end -= skip;
8328 }
8329 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008330 }
willy tarreaua1598082005-12-17 13:08:06 +01008331 else if (*line == '#' || *line == '\n' || *line == '\r') {
8332 /* end of string, end of loop */
8333 *line = 0;
8334 break;
8335 }
willy tarreauc29948c2005-12-17 13:10:27 +01008336 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008337 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008338 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008339 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008340 line++;
8341 args[++arg] = line;
8342 }
8343 else {
8344 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008345 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008346 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008347
willy tarreau9fe663a2005-12-17 13:02:59 +01008348 /* empty line */
8349 if (!**args)
8350 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008351
willy tarreau9fe663a2005-12-17 13:02:59 +01008352 /* zero out remaining args */
8353 while (++arg < MAX_LINE_ARGS) {
8354 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008355 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008356
willy tarreaua41a8b42005-12-17 14:02:24 +01008357 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008358 confsect = CFG_LISTEN;
8359 else if (!strcmp(args[0], "global")) /* global config */
8360 confsect = CFG_GLOBAL;
8361 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008362
willy tarreau9fe663a2005-12-17 13:02:59 +01008363 switch (confsect) {
8364 case CFG_LISTEN:
8365 if (cfg_parse_listen(file, linenum, args) < 0)
8366 return -1;
8367 break;
8368 case CFG_GLOBAL:
8369 if (cfg_parse_global(file, linenum, args) < 0)
8370 return -1;
8371 break;
8372 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008373 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008374 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008375 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008376
8377
willy tarreau0f7af912005-12-17 12:21:26 +01008378 }
8379 fclose(f);
8380
8381 /*
8382 * Now, check for the integrity of all that we have collected.
8383 */
8384
Willy TARREAU3759f982006-03-01 22:44:17 +01008385 /* will be needed further to delay some tasks */
8386 tv_now(&now);
8387
willy tarreau0f7af912005-12-17 12:21:26 +01008388 if ((curproxy = proxy) == NULL) {
8389 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8390 file);
8391 return -1;
8392 }
8393
8394 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008395 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008396 curproxy = curproxy->next;
8397 continue;
8398 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008399
8400 if (curproxy->listen == NULL) {
8401 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);
8402 cfgerr++;
8403 }
8404 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008405 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008406 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008407 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8408 file, curproxy->id);
8409 cfgerr++;
8410 }
8411 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8412 if (curproxy->options & PR_O_TRANSP) {
8413 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8414 file, curproxy->id);
8415 cfgerr++;
8416 }
8417 else if (curproxy->srv == NULL) {
8418 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8419 file, curproxy->id);
8420 cfgerr++;
8421 }
willy tarreaua1598082005-12-17 13:08:06 +01008422 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008423 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8424 file, curproxy->id);
8425 }
8426 }
8427 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008428 if (curproxy->cookie_name != NULL) {
8429 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8430 file, curproxy->id);
8431 }
8432 if ((newsrv = curproxy->srv) != NULL) {
8433 Warning("parsing %s : servers will be ignored for listener %s.\n",
8434 file, curproxy->id);
8435 }
willy tarreaue39cd132005-12-17 13:00:18 +01008436 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008437 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8438 file, curproxy->id);
8439 }
willy tarreaue39cd132005-12-17 13:00:18 +01008440 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008441 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8442 file, curproxy->id);
8443 }
8444 }
8445 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8446 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8447 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8448 file, curproxy->id);
8449 cfgerr++;
8450 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008451 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008452
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008453 /* first, we will invert the servers list order */
8454 newsrv = NULL;
8455 while (curproxy->srv) {
8456 struct server *next;
8457
8458 next = curproxy->srv->next;
8459 curproxy->srv->next = newsrv;
8460 newsrv = curproxy->srv;
8461 if (!next)
8462 break;
8463 curproxy->srv = next;
8464 }
8465
8466 /* now, newsrv == curproxy->srv */
8467 if (newsrv) {
8468 struct server *srv;
8469 int pgcd;
8470 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008471
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008472 /* We will factor the weights to reduce the table,
8473 * using Euclide's largest common divisor algorithm
8474 */
8475 pgcd = newsrv->uweight + 1;
8476 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8477 int t, w;
8478
8479 w = srv->uweight + 1;
8480 while (w) {
8481 t = pgcd % w;
8482 pgcd = w;
8483 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008484 }
willy tarreau0f7af912005-12-17 12:21:26 +01008485 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008486
8487 act = bck = 0;
8488 for (srv = newsrv; srv; srv = srv->next) {
8489 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8490 if (srv->state & SRV_BACKUP)
8491 bck += srv->eweight + 1;
8492 else
8493 act += srv->eweight + 1;
8494 }
8495
8496 /* this is the largest map we will ever need for this servers list */
8497 if (act < bck)
8498 act = bck;
8499
8500 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8501 /* recounts servers and their weights */
8502 recount_servers(curproxy);
8503 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008504 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008505
8506 if (curproxy->options & PR_O_LOGASAP)
8507 curproxy->to_log &= ~LW_BYTES;
8508
willy tarreau8337c6b2005-12-17 13:41:01 +01008509 if (curproxy->errmsg.msg400 == NULL) {
8510 curproxy->errmsg.msg400 = (char *)HTTP_400;
8511 curproxy->errmsg.len400 = strlen(HTTP_400);
8512 }
8513 if (curproxy->errmsg.msg403 == NULL) {
8514 curproxy->errmsg.msg403 = (char *)HTTP_403;
8515 curproxy->errmsg.len403 = strlen(HTTP_403);
8516 }
8517 if (curproxy->errmsg.msg408 == NULL) {
8518 curproxy->errmsg.msg408 = (char *)HTTP_408;
8519 curproxy->errmsg.len408 = strlen(HTTP_408);
8520 }
8521 if (curproxy->errmsg.msg500 == NULL) {
8522 curproxy->errmsg.msg500 = (char *)HTTP_500;
8523 curproxy->errmsg.len500 = strlen(HTTP_500);
8524 }
8525 if (curproxy->errmsg.msg502 == NULL) {
8526 curproxy->errmsg.msg502 = (char *)HTTP_502;
8527 curproxy->errmsg.len502 = strlen(HTTP_502);
8528 }
8529 if (curproxy->errmsg.msg503 == NULL) {
8530 curproxy->errmsg.msg503 = (char *)HTTP_503;
8531 curproxy->errmsg.len503 = strlen(HTTP_503);
8532 }
8533 if (curproxy->errmsg.msg504 == NULL) {
8534 curproxy->errmsg.msg504 = (char *)HTTP_504;
8535 curproxy->errmsg.len504 = strlen(HTTP_504);
8536 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008537
8538 /* now we'll start this proxy's health checks if any */
8539 /* 1- count the checkers to run simultaneously */
8540 nbchk = 0;
8541 mininter = 0;
8542 newsrv = curproxy->srv;
8543 while (newsrv != NULL) {
8544 if (newsrv->state & SRV_CHECKED) {
8545 if (!mininter || mininter > newsrv->inter)
8546 mininter = newsrv->inter;
8547 nbchk++;
8548 }
8549 newsrv = newsrv->next;
8550 }
8551
8552 /* 2- start them as far as possible from each others while respecting
8553 * their own intervals. For this, we will start them after their own
8554 * interval added to the min interval divided by the number of servers,
8555 * weighted by the server's position in the list.
8556 */
8557 if (nbchk > 0) {
8558 struct task *t;
8559 int srvpos;
8560
8561 newsrv = curproxy->srv;
8562 srvpos = 0;
8563 while (newsrv != NULL) {
8564 /* should this server be checked ? */
8565 if (newsrv->state & SRV_CHECKED) {
8566 if ((t = pool_alloc(task)) == NULL) {
8567 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8568 return -1;
8569 }
8570
8571 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008572 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008573 t->state = TASK_IDLE;
8574 t->process = process_chk;
8575 t->context = newsrv;
8576
8577 /* check this every ms */
8578 tv_delayfrom(&t->expire, &now,
8579 newsrv->inter + mininter * srvpos / nbchk);
8580 task_queue(t);
8581 //task_wakeup(&rq, t);
8582 srvpos++;
8583 }
8584 newsrv = newsrv->next;
8585 }
8586 }
8587
willy tarreau0f7af912005-12-17 12:21:26 +01008588 curproxy = curproxy->next;
8589 }
8590 if (cfgerr > 0) {
8591 Alert("Errors found in configuration file, aborting.\n");
8592 return -1;
8593 }
8594 else
8595 return 0;
8596}
8597
8598
8599/*
8600 * This function initializes all the necessary variables. It only returns
8601 * if everything is OK. If something fails, it exits.
8602 */
8603void init(int argc, char **argv) {
8604 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008605 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008606 char *old_argv = *argv;
8607 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008608 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008609
8610 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008611 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008612 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008613 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008614 exit(1);
8615 }
8616
willy tarreau746e26b2006-03-25 11:14:35 +01008617#ifdef HAPROXY_MEMMAX
8618 global.rlimit_memmax = HAPROXY_MEMMAX;
8619#endif
8620
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008621 /* initialize the libc's localtime structures once for all so that we
8622 * won't be missing memory if we want to send alerts under OOM conditions.
8623 */
8624 tv_now(&now);
8625 localtime(&now.tv_sec);
8626
willy tarreau4302f492005-12-18 01:00:37 +01008627 /* initialize the log header encoding map : '{|}"#' should be encoded with
8628 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8629 * URL encoding only requires '"', '#' to be encoded as well as non-
8630 * printable characters above.
8631 */
8632 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8633 memset(url_encode_map, 0, sizeof(url_encode_map));
8634 for (i = 0; i < 32; i++) {
8635 FD_SET(i, hdr_encode_map);
8636 FD_SET(i, url_encode_map);
8637 }
8638 for (i = 127; i < 256; i++) {
8639 FD_SET(i, hdr_encode_map);
8640 FD_SET(i, url_encode_map);
8641 }
8642
8643 tmp = "\"#{|}";
8644 while (*tmp) {
8645 FD_SET(*tmp, hdr_encode_map);
8646 tmp++;
8647 }
8648
8649 tmp = "\"#";
8650 while (*tmp) {
8651 FD_SET(*tmp, url_encode_map);
8652 tmp++;
8653 }
8654
willy tarreau64a3cc32005-12-18 01:13:11 +01008655 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8656#if defined(ENABLE_POLL)
8657 cfg_polling_mechanism |= POLL_USE_POLL;
8658#endif
8659#if defined(ENABLE_EPOLL)
8660 cfg_polling_mechanism |= POLL_USE_EPOLL;
8661#endif
8662
willy tarreau0f7af912005-12-17 12:21:26 +01008663 pid = getpid();
8664 progname = *argv;
8665 while ((tmp = strchr(progname, '/')) != NULL)
8666 progname = tmp + 1;
8667
8668 argc--; argv++;
8669 while (argc > 0) {
8670 char *flag;
8671
8672 if (**argv == '-') {
8673 flag = *argv+1;
8674
8675 /* 1 arg */
8676 if (*flag == 'v') {
8677 display_version();
8678 exit(0);
8679 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008680#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008681 else if (*flag == 'd' && flag[1] == 'e')
8682 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008683#endif
8684#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008685 else if (*flag == 'd' && flag[1] == 'p')
8686 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008687#endif
willy tarreau982249e2005-12-18 00:57:06 +01008688 else if (*flag == 'V')
8689 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008690 else if (*flag == 'd' && flag[1] == 'b')
8691 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008692 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008693 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008694 else if (*flag == 'c')
8695 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008696 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008697 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008698 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008699 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008700 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8701 /* list of pids to finish ('f') or terminate ('t') */
8702
8703 if (flag[1] == 'f')
8704 oldpids_sig = SIGUSR1; /* finish then exit */
8705 else
8706 oldpids_sig = SIGTERM; /* terminate immediately */
8707 argv++; argc--;
8708
8709 if (argc > 0) {
8710 oldpids = calloc(argc, sizeof(int));
8711 while (argc > 0) {
8712 oldpids[nb_oldpids] = atol(*argv);
8713 if (oldpids[nb_oldpids] <= 0)
8714 usage(old_argv);
8715 argc--; argv++;
8716 nb_oldpids++;
8717 }
8718 }
8719 }
willy tarreau2c513732006-04-15 19:25:16 +02008720#if STATTIME > 0
8721 else if (*flag == 's')
8722 arg_mode |= MODE_STATS;
8723 else if (*flag == 'l')
8724 arg_mode |= MODE_LOG;
8725#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008726 else { /* >=2 args */
8727 argv++; argc--;
8728 if (argc == 0)
8729 usage(old_argv);
8730
8731 switch (*flag) {
8732 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008733 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008734 case 'N' : cfg_maxpconn = atol(*argv); break;
8735 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008736 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008737 default: usage(old_argv);
8738 }
8739 }
8740 }
8741 else
8742 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008743 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008744 }
8745
willy tarreaud0fb4652005-12-18 01:32:04 +01008746 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008747 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8748 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008749
willy tarreau0f7af912005-12-17 12:21:26 +01008750 if (!cfg_cfgfile)
8751 usage(old_argv);
8752
8753 gethostname(hostname, MAX_HOSTNAME_LEN);
8754
willy tarreau12350152005-12-18 01:03:27 +01008755 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008756 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008757 if (readcfgfile(cfg_cfgfile) < 0) {
8758 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8759 exit(1);
8760 }
willy tarreau12350152005-12-18 01:03:27 +01008761 if (have_appsession)
8762 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008763
willy tarreau982249e2005-12-18 00:57:06 +01008764 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008765 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8766 exit(0);
8767 }
8768
willy tarreau9fe663a2005-12-17 13:02:59 +01008769 if (cfg_maxconn > 0)
8770 global.maxconn = cfg_maxconn;
8771
willy tarreaufe2c5c12005-12-17 14:14:34 +01008772 if (cfg_pidfile) {
8773 if (global.pidfile)
8774 free(global.pidfile);
8775 global.pidfile = strdup(cfg_pidfile);
8776 }
8777
willy tarreau9fe663a2005-12-17 13:02:59 +01008778 if (global.maxconn == 0)
8779 global.maxconn = DEFAULT_MAXCONN;
8780
Willy TARREAU203b0b62006-03-12 18:00:28 +01008781 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008782
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008783 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008784 /* command line debug mode inhibits configuration mode */
8785 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8786 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008787 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8788 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008789
8790 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8791 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8792 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8793 }
8794
8795 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008796 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8797 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008798 global.nbproc = 1;
8799 }
8800
8801 if (global.nbproc < 1)
8802 global.nbproc = 1;
8803
willy tarreau0f7af912005-12-17 12:21:26 +01008804 StaticReadEvent = (fd_set *)calloc(1,
8805 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008806 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008807 StaticWriteEvent = (fd_set *)calloc(1,
8808 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008809 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008810
8811 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008812 sizeof(struct fdtab) * (global.maxsock));
8813 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008814 fdtab[i].state = FD_STCLOSE;
8815 }
8816}
8817
8818/*
willy tarreau41310e72006-03-25 18:17:56 +01008819 * this function starts all the proxies. Its return value is composed from
8820 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8821 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008822 */
willy tarreau41310e72006-03-25 18:17:56 +01008823int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008824 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008825 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008826 int err = ERR_NONE;
8827 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008828
8829 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008830 if (curproxy->state != PR_STNEW)
8831 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008832
willy tarreau41310e72006-03-25 18:17:56 +01008833 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008834 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008835 if (listener->fd != -1)
8836 continue; /* already initialized */
8837
8838 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8839 if (verbose)
8840 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8841 curproxy->id);
8842 err |= ERR_RETRYABLE;
8843 pxerr |= 1;
8844 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008845 }
willy tarreau0f7af912005-12-17 12:21:26 +01008846
willy tarreaua41a8b42005-12-17 14:02:24 +01008847 if (fd >= global.maxsock) {
8848 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8849 curproxy->id);
8850 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008851 err |= ERR_FATAL;
8852 pxerr |= 1;
8853 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008854 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008855
willy tarreaua41a8b42005-12-17 14:02:24 +01008856 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8857 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8858 (char *) &one, sizeof(one)) == -1)) {
8859 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8860 curproxy->id);
8861 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008862 err |= ERR_FATAL;
8863 pxerr |= 1;
8864 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008865 }
willy tarreau0f7af912005-12-17 12:21:26 +01008866
willy tarreaua41a8b42005-12-17 14:02:24 +01008867 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8868 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8869 curproxy->id);
8870 }
willy tarreau0f7af912005-12-17 12:21:26 +01008871
willy tarreaua41a8b42005-12-17 14:02:24 +01008872 if (bind(fd,
8873 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008874 listener->addr.ss_family == AF_INET6 ?
8875 sizeof(struct sockaddr_in6) :
8876 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008877 if (verbose)
8878 Alert("cannot bind socket for proxy %s. Aborting.\n",
8879 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008880 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008881 err |= ERR_RETRYABLE;
8882 pxerr |= 1;
8883 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008884 }
willy tarreau0f7af912005-12-17 12:21:26 +01008885
willy tarreaua41a8b42005-12-17 14:02:24 +01008886 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008887 if (verbose)
8888 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8889 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008890 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008891 err |= ERR_RETRYABLE;
8892 pxerr |= 1;
8893 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008894 }
willy tarreau0f7af912005-12-17 12:21:26 +01008895
willy tarreau41310e72006-03-25 18:17:56 +01008896 /* the socket is ready */
8897 listener->fd = fd;
8898
willy tarreaua41a8b42005-12-17 14:02:24 +01008899 /* the function for the accept() event */
8900 fdtab[fd].read = &event_accept;
8901 fdtab[fd].write = NULL; /* never called */
8902 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008903 fdtab[fd].state = FD_STLISTEN;
8904 FD_SET(fd, StaticReadEvent);
8905 fd_insert(fd);
8906 listeners++;
8907 }
willy tarreau41310e72006-03-25 18:17:56 +01008908
8909 if (!pxerr) {
8910 curproxy->state = PR_STRUN;
8911 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8912 }
willy tarreau0f7af912005-12-17 12:21:26 +01008913 }
willy tarreau41310e72006-03-25 18:17:56 +01008914
8915 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008916}
8917
willy tarreaub952e1d2005-12-18 01:31:20 +01008918int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008919
8920 appsess *temp1,*temp2;
8921 temp1 = (appsess *)key1;
8922 temp2 = (appsess *)key2;
8923
8924 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8925 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8926
8927 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8928}/* end match_str */
8929
willy tarreaub952e1d2005-12-18 01:31:20 +01008930void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008931 appsess *temp1;
8932
8933 //printf("destroy called\n");
8934 temp1 = (appsess *)data;
8935
8936 if (temp1->sessid)
8937 pool_free_to(apools.sessid, temp1->sessid);
8938
8939 if (temp1->serverid)
8940 pool_free_to(apools.serverid, temp1->serverid);
8941
8942 pool_free(appsess, temp1);
8943} /* end destroy */
8944
8945void appsession_cleanup( void )
8946{
8947 struct proxy *p = proxy;
8948
8949 while(p) {
8950 chtbl_destroy(&(p->htbl_proxy));
8951 p = p->next;
8952 }
8953}/* end appsession_cleanup() */
8954
8955void pool_destroy(void **pool)
8956{
8957 void *temp, *next;
8958 next = pool;
8959 while (next) {
8960 temp = next;
8961 next = *(void **)temp;
8962 free(temp);
8963 }
8964}/* end pool_destroy() */
8965
willy tarreaub952e1d2005-12-18 01:31:20 +01008966void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008967 struct proxy *p = proxy;
8968 struct cap_hdr *h,*h_next;
8969 struct server *s,*s_next;
8970 struct listener *l,*l_next;
8971
8972 while (p) {
8973 if (p->id)
8974 free(p->id);
8975
8976 if (p->check_req)
8977 free(p->check_req);
8978
8979 if (p->cookie_name)
8980 free(p->cookie_name);
8981
8982 if (p->capture_name)
8983 free(p->capture_name);
8984
8985 /* only strup if the user have set in config.
8986 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008987 if (p->errmsg.msg400) free(p->errmsg.msg400);
8988 if (p->errmsg.msg403) free(p->errmsg.msg403);
8989 if (p->errmsg.msg408) free(p->errmsg.msg408);
8990 if (p->errmsg.msg500) free(p->errmsg.msg500);
8991 if (p->errmsg.msg502) free(p->errmsg.msg502);
8992 if (p->errmsg.msg503) free(p->errmsg.msg503);
8993 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008994 */
8995 if (p->appsession_name)
8996 free(p->appsession_name);
8997
8998 h = p->req_cap;
8999 while (h) {
9000 h_next = h->next;
9001 if (h->name)
9002 free(h->name);
9003 pool_destroy(h->pool);
9004 free(h);
9005 h = h_next;
9006 }/* end while(h) */
9007
9008 h = p->rsp_cap;
9009 while (h) {
9010 h_next = h->next;
9011 if (h->name)
9012 free(h->name);
9013
9014 pool_destroy(h->pool);
9015 free(h);
9016 h = h_next;
9017 }/* end while(h) */
9018
9019 s = p->srv;
9020 while (s) {
9021 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009022 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009023 free(s->id);
9024
willy tarreaub952e1d2005-12-18 01:31:20 +01009025 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009026 free(s->cookie);
9027
9028 free(s);
9029 s = s_next;
9030 }/* end while(s) */
9031
9032 l = p->listen;
9033 while (l) {
9034 l_next = l->next;
9035 free(l);
9036 l = l_next;
9037 }/* end while(l) */
9038
9039 pool_destroy((void **) p->req_cap_pool);
9040 pool_destroy((void **) p->rsp_cap_pool);
9041 p = p->next;
9042 }/* end while(p) */
9043
9044 if (global.chroot) free(global.chroot);
9045 if (global.pidfile) free(global.pidfile);
9046
willy tarreau12350152005-12-18 01:03:27 +01009047 if (StaticReadEvent) free(StaticReadEvent);
9048 if (StaticWriteEvent) free(StaticWriteEvent);
9049 if (fdtab) free(fdtab);
9050
9051 pool_destroy(pool_session);
9052 pool_destroy(pool_buffer);
9053 pool_destroy(pool_fdtab);
9054 pool_destroy(pool_requri);
9055 pool_destroy(pool_task);
9056 pool_destroy(pool_capture);
9057 pool_destroy(pool_appsess);
9058
9059 if (have_appsession) {
9060 pool_destroy(apools.serverid);
9061 pool_destroy(apools.sessid);
9062 }
9063} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009064
willy tarreau41310e72006-03-25 18:17:56 +01009065/* sends the signal <sig> to all pids found in <oldpids> */
9066static void tell_old_pids(int sig) {
9067 int p;
9068 for (p = 0; p < nb_oldpids; p++)
9069 kill(oldpids[p], sig);
9070}
9071
willy tarreau0f7af912005-12-17 12:21:26 +01009072int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009073 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009074 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009075 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009076 init(argc, argv);
9077
willy tarreau0f7af912005-12-17 12:21:26 +01009078 signal(SIGQUIT, dump);
9079 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009080 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009081#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009082 signal(SIGINT, sig_int);
9083 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009084#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009085
9086 /* on very high loads, a sigpipe sometimes happen just between the
9087 * getsockopt() which tells "it's OK to write", and the following write :-(
9088 */
willy tarreau3242e862005-12-17 12:27:53 +01009089#ifndef MSG_NOSIGNAL
9090 signal(SIGPIPE, SIG_IGN);
9091#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009092
willy tarreau41310e72006-03-25 18:17:56 +01009093 /* We will loop at most 100 times with 10 ms delay each time.
9094 * That's at most 1 second. We only send a signal to old pids
9095 * if we cannot grab at least one port.
9096 */
9097 retry = MAX_START_RETRIES;
9098 err = ERR_NONE;
9099 while (retry >= 0) {
9100 struct timeval w;
9101 err = start_proxies(retry == 0 || nb_oldpids == 0);
9102 if (err != ERR_RETRYABLE)
9103 break;
9104 if (nb_oldpids == 0)
9105 break;
9106
9107 tell_old_pids(SIGTTOU);
9108 /* give some time to old processes to stop listening */
9109 w.tv_sec = 0;
9110 w.tv_usec = 10*1000;
9111 select(0, NULL, NULL, NULL, &w);
9112 retry--;
9113 }
9114
9115 /* Note: start_proxies() sends an alert when it fails. */
9116 if (err != ERR_NONE) {
9117 if (retry != MAX_START_RETRIES && nb_oldpids)
9118 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009119 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009120 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009121
9122 if (listeners == 0) {
9123 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009124 /* Note: we don't have to send anything to the old pids because we
9125 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009126 exit(1);
9127 }
9128
willy tarreaudbd3bef2006-01-20 19:35:18 +01009129 /* prepare pause/play signals */
9130 signal(SIGTTOU, sig_pause);
9131 signal(SIGTTIN, sig_listen);
9132
Willy TARREAUe3283d12006-03-01 22:15:29 +01009133 if (global.mode & MODE_DAEMON) {
9134 global.mode &= ~MODE_VERBOSE;
9135 global.mode |= MODE_QUIET;
9136 }
9137
willy tarreaud0fb4652005-12-18 01:32:04 +01009138 /* MODE_QUIET can inhibit alerts and warnings below this line */
9139
9140 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009141 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009142 /* detach from the tty */
9143 fclose(stdin); fclose(stdout); fclose(stderr);
9144 close(0); close(1); close(2);
9145 }
willy tarreau0f7af912005-12-17 12:21:26 +01009146
willy tarreaufe2c5c12005-12-17 14:14:34 +01009147 /* open log & pid files before the chroot */
9148 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9149 int pidfd;
9150 unlink(global.pidfile);
9151 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9152 if (pidfd < 0) {
9153 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009154 if (nb_oldpids)
9155 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009156 exit(1);
9157 }
9158 pidfile = fdopen(pidfd, "w");
9159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009160
9161 /* chroot if needed */
9162 if (global.chroot != NULL) {
9163 if (chroot(global.chroot) == -1) {
9164 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009165 if (nb_oldpids)
9166 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009167 }
9168 chdir("/");
9169 }
9170
willy tarreaub1285d52005-12-18 01:20:14 +01009171 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009172 if (!global.rlimit_nofile)
9173 global.rlimit_nofile = global.maxsock;
9174
willy tarreaub1285d52005-12-18 01:20:14 +01009175 if (global.rlimit_nofile) {
9176 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9177 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9178 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9179 }
willy tarreau746e26b2006-03-25 11:14:35 +01009180 }
9181
9182 if (global.rlimit_memmax) {
9183 limit.rlim_cur = limit.rlim_max =
9184 global.rlimit_memmax * 1048576 / global.nbproc;
9185#ifdef RLIMIT_AS
9186 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9187 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9188 argv[0], global.rlimit_memmax);
9189 }
9190#else
9191 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9192 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9193 argv[0], global.rlimit_memmax);
9194 }
9195#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009196 }
9197
willy tarreau41310e72006-03-25 18:17:56 +01009198 if (nb_oldpids)
9199 tell_old_pids(oldpids_sig);
9200
9201 /* Note that any error at this stage will be fatal because we will not
9202 * be able to restart the old pids.
9203 */
9204
willy tarreau9fe663a2005-12-17 13:02:59 +01009205 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009206 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009207 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9208 exit(1);
9209 }
9210
willy tarreau036e1ce2005-12-17 13:46:33 +01009211 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009212 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9213 exit(1);
9214 }
9215
willy tarreaub1285d52005-12-18 01:20:14 +01009216 /* check ulimits */
9217 limit.rlim_cur = limit.rlim_max = 0;
9218 getrlimit(RLIMIT_NOFILE, &limit);
9219 if (limit.rlim_cur < global.maxsock) {
9220 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",
9221 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9222 }
9223
willy tarreau9fe663a2005-12-17 13:02:59 +01009224 if (global.mode & MODE_DAEMON) {
9225 int ret = 0;
9226 int proc;
9227
9228 /* the father launches the required number of processes */
9229 for (proc = 0; proc < global.nbproc; proc++) {
9230 ret = fork();
9231 if (ret < 0) {
9232 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009233 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009234 exit(1); /* there has been an error */
9235 }
9236 else if (ret == 0) /* child breaks here */
9237 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009238 if (pidfile != NULL) {
9239 fprintf(pidfile, "%d\n", ret);
9240 fflush(pidfile);
9241 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009242 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009243 /* close the pidfile both in children and father */
9244 if (pidfile != NULL)
9245 fclose(pidfile);
9246 free(global.pidfile);
9247
willy tarreau9fe663a2005-12-17 13:02:59 +01009248 if (proc == global.nbproc)
9249 exit(0); /* parent must leave */
9250
willy tarreau750a4722005-12-17 13:21:24 +01009251 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9252 * that we can detach from the TTY. We MUST NOT do it in other cases since
9253 * it would have already be done, and 0-2 would have been affected to listening
9254 * sockets
9255 */
9256 if (!(global.mode & MODE_QUIET)) {
9257 /* detach from the tty */
9258 fclose(stdin); fclose(stdout); fclose(stderr);
9259 close(0); close(1); close(2); /* close all fd's */
9260 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9261 }
willy tarreaua1598082005-12-17 13:08:06 +01009262 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009263 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009264 }
9265
willy tarreau1c2ad212005-12-18 01:11:29 +01009266#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009267 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009268 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9269 epoll_loop(POLL_LOOP_ACTION_RUN);
9270 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009271 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009272 }
9273 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009274 Warning("epoll() is not available. Using poll()/select() instead.\n");
9275 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009276 }
9277 }
9278#endif
9279
9280#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009281 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009282 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9283 poll_loop(POLL_LOOP_ACTION_RUN);
9284 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009285 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009286 }
9287 else {
9288 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009289 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009290 }
9291 }
9292#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009293 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009294 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9295 select_loop(POLL_LOOP_ACTION_RUN);
9296 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009297 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009298 }
9299 }
9300
willy tarreau0f7af912005-12-17 12:21:26 +01009301
willy tarreau12350152005-12-18 01:03:27 +01009302 /* Free all Hash Keys and all Hash elements */
9303 appsession_cleanup();
9304 /* Do some cleanup */
9305 deinit();
9306
willy tarreau0f7af912005-12-17 12:21:26 +01009307 exit(0);
9308}
willy tarreau12350152005-12-18 01:03:27 +01009309
9310#if defined(DEBUG_HASH)
9311static void print_table(const CHTbl *htbl) {
9312
9313 ListElmt *element;
9314 int i;
9315 appsess *asession;
9316
9317 /*****************************************************************************
9318 * *
9319 * Display the chained hash table. *
9320 * *
9321 *****************************************************************************/
9322
9323 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9324
9325 for (i = 0; i < TBLSIZ; i++) {
9326 fprintf(stdout, "Bucket[%03d]\n", i);
9327
9328 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9329 //fprintf(stdout, "%c", *(char *)list_data(element));
9330 asession = (appsess *)list_data(element);
9331 fprintf(stdout, "ELEM :%s:", asession->sessid);
9332 fprintf(stdout, " Server :%s: \n", asession->serverid);
9333 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9334 }
9335
9336 fprintf(stdout, "\n");
9337 }
9338 return;
9339} /* end print_table */
9340#endif
9341
9342static int appsession_init(void)
9343{
9344 static int initialized = 0;
9345 int idlen;
9346 struct server *s;
9347 struct proxy *p = proxy;
9348
9349 if (!initialized) {
9350 if (!appsession_task_init()) {
9351 apools.sessid = NULL;
9352 apools.serverid = NULL;
9353 apools.ser_waste = 0;
9354 apools.ser_use = 0;
9355 apools.ser_msize = sizeof(void *);
9356 apools.ses_waste = 0;
9357 apools.ses_use = 0;
9358 apools.ses_msize = sizeof(void *);
9359 while (p) {
9360 s = p->srv;
9361 if (apools.ses_msize < p->appsession_len)
9362 apools.ses_msize = p->appsession_len;
9363 while (s) {
9364 idlen = strlen(s->id);
9365 if (apools.ser_msize < idlen)
9366 apools.ser_msize = idlen;
9367 s = s->next;
9368 }
9369 p = p->next;
9370 }
9371 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9372 apools.ses_msize ++;
9373 }
9374 else {
9375 fprintf(stderr, "appsession_task_init failed\n");
9376 return -1;
9377 }
9378 initialized ++;
9379 }
9380 return 0;
9381}
9382
9383static int appsession_task_init(void)
9384{
9385 static int initialized = 0;
9386 struct task *t;
9387 if (!initialized) {
9388 if ((t = pool_alloc(task)) == NULL)
9389 return -1;
9390 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009391 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009392 t->state = TASK_IDLE;
9393 t->context = NULL;
9394 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9395 task_queue(t);
9396 t->process = appsession_refresh;
9397 initialized ++;
9398 }
9399 return 0;
9400}
9401
9402static int appsession_refresh(struct task *t) {
9403 struct proxy *p = proxy;
9404 CHTbl *htbl;
9405 ListElmt *element, *last;
9406 int i;
9407 appsess *asession;
9408 void *data;
9409
9410 while (p) {
9411 if (p->appsession_name != NULL) {
9412 htbl = &p->htbl_proxy;
9413 /* if we ever give up the use of TBLSIZ, we need to change this */
9414 for (i = 0; i < TBLSIZ; i++) {
9415 last = NULL;
9416 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9417 asession = (appsess *)list_data(element);
9418 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9419 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9420 int len;
9421 /*
9422 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9423 */
9424 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9425 asession->sessid, asession->serverid?asession->serverid:"(null)");
9426 write(1, trash, len);
9427 }
9428 /* delete the expired element from within the hash table */
9429 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9430 && (htbl->table[i].destroy != NULL)) {
9431 htbl->table[i].destroy(data);
9432 }
9433 if (last == NULL) {/* patient lost his head, get a new one */
9434 element = list_head(&htbl->table[i]);
9435 if (element == NULL) break; /* no heads left, go to next patient */
9436 }
9437 else
9438 element = last;
9439 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9440 else
9441 last = element;
9442 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9443 }
9444 }
9445 p = p->next;
9446 }
9447 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9448 return TBLCHKINT;
9449} /* end appsession_refresh */
9450
willy tarreau18a957c2006-04-12 19:26:23 +02009451
9452/*
9453 * Local variables:
9454 * c-indent-level: 4
9455 * c-basic-offset: 4
9456 * End:
9457 */