blob: 722ff04412d4e20cd18657b627713d1c13813d6f [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 tarreau9fea1942006-05-12 19:46:40 +0200421#define SV_STCONN 1
422#define SV_STHEADERS 2
423#define SV_STDATA 3
424#define SV_STSHUTR 4
425#define SV_STSHUTW 5
426#define SV_STCLOSE 6
willy tarreau0f7af912005-12-17 12:21:26 +0100427
428/* result of an I/O event */
429#define RES_SILENT 0 /* didn't happen */
430#define RES_DATA 1 /* data were sent or received */
431#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
432#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
433
willy tarreau9fe663a2005-12-17 13:02:59 +0100434/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100435#define MODE_DEBUG 1
436#define MODE_STATS 2
437#define MODE_LOG 4
438#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100439#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100440#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100441#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100442#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100443#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100444
445/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100446#define SRV_RUNNING 1 /* the server is UP */
447#define SRV_BACKUP 2 /* this server is a backup server */
448#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100449#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100450#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100451
willy tarreaudfece232006-05-02 00:19:57 +0200452/* function which act on servers need to return various errors */
453#define SRV_STATUS_OK 0 /* everything is OK. */
454#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
455#define SRV_STATUS_NOSRV 2 /* no server is available */
456#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
457#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
458
willy tarreaue39cd132005-12-17 13:00:18 +0100459/* what to do when a header matches a regex */
460#define ACT_ALLOW 0 /* allow the request */
461#define ACT_REPLACE 1 /* replace the matching header */
462#define ACT_REMOVE 2 /* remove the matching header */
463#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100464#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100465
willy tarreau9fe663a2005-12-17 13:02:59 +0100466/* configuration sections */
467#define CFG_NONE 0
468#define CFG_GLOBAL 1
469#define CFG_LISTEN 2
470
willy tarreaua1598082005-12-17 13:08:06 +0100471/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100472#define LW_DATE 1 /* date */
473#define LW_CLIP 2 /* CLient IP */
474#define LW_SVIP 4 /* SerVer IP */
475#define LW_SVID 8 /* server ID */
476#define LW_REQ 16 /* http REQuest */
477#define LW_RESP 32 /* http RESPonse */
478#define LW_PXIP 64 /* proxy IP */
479#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100480#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100481#define LW_COOKIE 512 /* captured cookie */
482#define LW_REQHDR 1024 /* request header(s) */
483#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100484
willy tarreau41310e72006-03-25 18:17:56 +0100485#define ERR_NONE 0 /* no error */
486#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
487#define ERR_FATAL 2 /* fatal error, may be cumulated */
488
willy tarreau0f7af912005-12-17 12:21:26 +0100489/*********************************************************************/
490
491#define LIST_HEAD(a) ((void *)(&(a)))
492
493/*********************************************************************/
494
willy tarreau4302f492005-12-18 01:00:37 +0100495struct cap_hdr {
496 struct cap_hdr *next;
497 char *name; /* header name, case insensitive */
498 int namelen; /* length of the header name, to speed-up lookups */
499 int len; /* capture length, not including terminal zero */
500 int index; /* index in the output array */
501 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
502};
503
willy tarreau0f7af912005-12-17 12:21:26 +0100504struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100505 struct hdr_exp *next;
506 regex_t *preg; /* expression to look for */
507 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
508 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100509};
510
511struct buffer {
512 unsigned int l; /* data length */
513 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100514 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100515 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100516 char data[BUFSIZE];
517};
518
willy tarreau18a957c2006-04-12 19:26:23 +0200519struct pendconn {
520 struct list list; /* chaining ... */
521 struct session *sess; /* the session waiting for a connection */
522 struct server *srv; /* the server we are waiting for */
523};
524
willy tarreau0f7af912005-12-17 12:21:26 +0100525struct server {
526 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100527 int state; /* server state (SRV_*) */
528 int cklen; /* the len of the cookie, to speed up checks */
529 char *cookie; /* the id set in the cookie */
530 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200531 struct list pendconns; /* pending connections */
532 int nbpend; /* number of pending connections */
willy tarreau59a6cc22006-05-12 01:29:08 +0200533 struct task *queue_mgt; /* the task associated to the queue processing */
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 tarreau5e69b162006-05-12 19:49:37 +0200594 unsigned long srv_queue_size; /* number of sessions waiting for a connect slot on this server at accept() time (in direct assignment) */
595 unsigned long prx_queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100596 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100597 char *cli_cookie; /* cookie presented by the client, in capture mode */
598 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100599 int status; /* HTTP status from the server, negative if from proxy */
600 long long bytes; /* number of bytes transferred from the server */
601 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100602 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100603};
604
willy tarreaua41a8b42005-12-17 14:02:24 +0100605struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100606 int fd; /* the listen socket */
607 struct sockaddr_storage addr; /* the address we listen to */
608 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100609};
willy tarreauf32f5242006-05-02 22:54:52 +0200610
willy tarreau0f7af912005-12-17 12:21:26 +0100611struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100612 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100613 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 +0100614 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100615 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200616 struct server *srv; /* known servers */
617 int srv_act, srv_bck; /* # of running servers */
618 int tot_wact, tot_wbck; /* total weights of active and backup servers */
619 struct server **srv_map; /* the server map used to apply weights */
620 int srv_map_sz; /* the size of the effective server map */
621 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100622 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100623 int cookie_len; /* strlen(cookie_name), computed only once */
624 char *appsession_name; /* name of the cookie to look for */
625 int appsession_name_len; /* strlen(appsession_name), computed only once */
626 int appsession_len; /* length of the appsession cookie value to be used */
627 int appsession_timeout;
628 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100629 char *capture_name; /* beginning of the name of the cookie to capture */
630 int capture_namelen; /* length of the cookie name to match */
631 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100632 int clitimeout; /* client I/O timeout (in milliseconds) */
633 int srvtimeout; /* server I/O timeout (in milliseconds) */
634 int contimeout; /* connect timeout (in milliseconds) */
635 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200636 struct list pendconns; /* pending connections with no server assigned yet */
637 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200638 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100639 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200640 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100641 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100642 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100643 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100644 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100645 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100646 struct proxy *next;
647 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100648 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100649 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100650 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100651 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100652 int nb_reqadd, nb_rspadd;
653 struct hdr_exp *req_exp; /* regular expressions for request headers */
654 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100655 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
656 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
657 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
658 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100659 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100660 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100661 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
662 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100663 struct {
664 char *msg400; /* message for error 400 */
665 int len400; /* message length for error 400 */
666 char *msg403; /* message for error 403 */
667 int len403; /* message length for error 403 */
668 char *msg408; /* message for error 408 */
669 int len408; /* message length for error 408 */
670 char *msg500; /* message for error 500 */
671 int len500; /* message length for error 500 */
672 char *msg502; /* message for error 502 */
673 int len502; /* message length for error 502 */
674 char *msg503; /* message for error 503 */
675 int len503; /* message length for error 503 */
676 char *msg504; /* message for error 504 */
677 int len504; /* message length for error 504 */
678 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100679};
680
681/* info about one given fd */
682struct fdtab {
683 int (*read)(int fd); /* read function */
684 int (*write)(int fd); /* write function */
685 struct task *owner; /* the session (or proxy) associated with this fd */
686 int state; /* the state of this fd */
687};
688
689/*********************************************************************/
690
willy tarreaub952e1d2005-12-18 01:31:20 +0100691int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100692int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100693char *cfg_cfgfile = NULL; /* configuration file */
694char *progname = NULL; /* program name */
695int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100696
697/* global options */
698static struct {
699 int uid;
700 int gid;
701 int nbproc;
702 int maxconn;
703 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100704 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100705 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100706 int mode;
707 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100708 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100709 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100710 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100711 struct sockaddr_in logsrv1, logsrv2;
712} global = {
713 logfac1 : -1,
714 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100715 loglev1 : 7, /* max syslog level : debug */
716 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100717 /* others NULL OK */
718};
719
willy tarreau0f7af912005-12-17 12:21:26 +0100720/*********************************************************************/
721
willy tarreau1c2ad212005-12-18 01:11:29 +0100722fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100723 *StaticWriteEvent;
724
willy tarreau64a3cc32005-12-18 01:13:11 +0100725int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100726
willy tarreau0f7af912005-12-17 12:21:26 +0100727void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200728 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100729 **pool_buffer = NULL,
730 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100731 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100732 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100733 **pool_capture = NULL,
734 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100735
736struct proxy *proxy = NULL; /* list of all existing proxies */
737struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100738struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200739struct task wait_queue[2] = { /* global wait queue */
740 {
741 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
742 next:LIST_HEAD(wait_queue[0]),
743 },
744 {
745 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
746 next:LIST_HEAD(wait_queue[1]),
747 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100748};
willy tarreau0f7af912005-12-17 12:21:26 +0100749
willy tarreau0f7af912005-12-17 12:21:26 +0100750static int totalconn = 0; /* total # of terminated sessions */
751static int actconn = 0; /* # of active sessions */
752static int maxfd = 0; /* # of the highest fd + 1 */
753static int listeners = 0; /* # of listeners */
754static int stopping = 0; /* non zero means stopping in progress */
755static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100756static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100757
willy tarreau53e99702006-03-25 18:53:50 +0100758/* Here we store informations about the pids of the processes we may pause
759 * or kill. We will send them a signal every 10 ms until we can bind to all
760 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100761 */
willy tarreau53e99702006-03-25 18:53:50 +0100762#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100763static int nb_oldpids = 0;
764static int *oldpids = NULL;
765static int oldpids_sig; /* use USR1 or TERM */
766
willy tarreau08dedbe2005-12-18 01:13:48 +0100767#if defined(ENABLE_EPOLL)
768/* FIXME: this is dirty, but at the moment, there's no other solution to remove
769 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
770 * structure with pointers to functions such as init_fd() and close_fd(), plus
771 * a private structure with several pointers to places such as below.
772 */
773
774static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
775#endif
776
willy tarreau0f7af912005-12-17 12:21:26 +0100777static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100778/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100779static char trash[BUFSIZE];
780
willy tarreaudd07e972005-12-18 00:48:48 +0100781const int zero = 0;
782const int one = 1;
783
willy tarreau0f7af912005-12-17 12:21:26 +0100784/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100785 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100786 */
787
788#define MAX_SYSLOG_LEN 1024
789#define NB_LOG_FACILITIES 24
790const char *log_facilities[NB_LOG_FACILITIES] = {
791 "kern", "user", "mail", "daemon",
792 "auth", "syslog", "lpr", "news",
793 "uucp", "cron", "auth2", "ftp",
794 "ntp", "audit", "alert", "cron2",
795 "local0", "local1", "local2", "local3",
796 "local4", "local5", "local6", "local7"
797};
798
799
800#define NB_LOG_LEVELS 8
801const char *log_levels[NB_LOG_LEVELS] = {
802 "emerg", "alert", "crit", "err",
803 "warning", "notice", "info", "debug"
804};
805
806#define SYSLOG_PORT 514
807
808const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
809 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100810
willy tarreaub1285d52005-12-18 01:20:14 +0100811const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100812const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
813const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
814const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
815 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
816 unknown, Set-cookie Rewritten */
817
willy tarreau0f7af912005-12-17 12:21:26 +0100818#define MAX_HOSTNAME_LEN 32
819static char hostname[MAX_HOSTNAME_LEN] = "";
820
willy tarreau8337c6b2005-12-17 13:41:01 +0100821const char *HTTP_302 =
822 "HTTP/1.0 302 Found\r\n"
823 "Cache-Control: no-cache\r\n"
824 "Connection: close\r\n"
825 "Location: "; /* not terminated since it will be concatenated with the URL */
826
willy tarreauc1f47532005-12-18 01:08:26 +0100827/* same as 302 except that the browser MUST retry with the GET method */
828const char *HTTP_303 =
829 "HTTP/1.0 303 See Other\r\n"
830 "Cache-Control: no-cache\r\n"
831 "Connection: close\r\n"
832 "Location: "; /* not terminated since it will be concatenated with the URL */
833
willy tarreaua1598082005-12-17 13:08:06 +0100834const char *HTTP_400 =
835 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100836 "Cache-Control: no-cache\r\n"
837 "Connection: close\r\n"
838 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100839 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100840
willy tarreaua1598082005-12-17 13:08:06 +0100841const char *HTTP_403 =
842 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100843 "Cache-Control: no-cache\r\n"
844 "Connection: close\r\n"
845 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100846 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
847
willy tarreau8337c6b2005-12-17 13:41:01 +0100848const char *HTTP_408 =
849 "HTTP/1.0 408 Request Time-out\r\n"
850 "Cache-Control: no-cache\r\n"
851 "Connection: close\r\n"
852 "\r\n"
853 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
854
willy tarreau750a4722005-12-17 13:21:24 +0100855const char *HTTP_500 =
856 "HTTP/1.0 500 Server Error\r\n"
857 "Cache-Control: no-cache\r\n"
858 "Connection: close\r\n"
859 "\r\n"
860 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100861
862const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100863 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100864 "Cache-Control: no-cache\r\n"
865 "Connection: close\r\n"
866 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100867 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
868
869const char *HTTP_503 =
870 "HTTP/1.0 503 Service Unavailable\r\n"
871 "Cache-Control: no-cache\r\n"
872 "Connection: close\r\n"
873 "\r\n"
874 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
875
876const char *HTTP_504 =
877 "HTTP/1.0 504 Gateway Time-out\r\n"
878 "Cache-Control: no-cache\r\n"
879 "Connection: close\r\n"
880 "\r\n"
881 "<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 +0100882
willy tarreau0f7af912005-12-17 12:21:26 +0100883/*********************************************************************/
884/* statistics ******************************************************/
885/*********************************************************************/
886
willy tarreau750a4722005-12-17 13:21:24 +0100887#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100888static int stats_tsk_lsrch, stats_tsk_rsrch,
889 stats_tsk_good, stats_tsk_right, stats_tsk_left,
890 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100891#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100892
893
894/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100895/* debugging *******************************************************/
896/*********************************************************************/
897#ifdef DEBUG_FULL
898static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200899static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100900#endif
901
902/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100903/* function prototypes *********************************************/
904/*********************************************************************/
905
906int event_accept(int fd);
907int event_cli_read(int fd);
908int event_cli_write(int fd);
909int event_srv_read(int fd);
910int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100911int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100912
willy tarreau12350152005-12-18 01:03:27 +0100913static int appsession_task_init(void);
914static int appsession_init(void);
915static int appsession_refresh(struct task *t);
916
willy tarreau0f7af912005-12-17 12:21:26 +0100917/*********************************************************************/
918/* general purpose functions ***************************************/
919/*********************************************************************/
920
921void display_version() {
922 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100923 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100924}
925
926/*
927 * This function prints the command line usage and exits
928 */
929void usage(char *name) {
930 display_version();
931 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100932 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100933#if STATTIME > 0
934 "sl"
935#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100936 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
937 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100938 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100939 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100940 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100941#if STATTIME > 0
942 " -s enables statistics output\n"
943 " -l enables long statistics format\n"
944#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100945 " -D goes daemon ; implies -q\n"
946 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100947 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100948 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100949 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100950 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100951 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100952#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100953 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100954#endif
955#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100956 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100957#endif
willy tarreau53e99702006-03-25 18:53:50 +0100958 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100959 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100960 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100961 exit(1);
962}
963
964
965/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100966 * Displays the message on stderr with the date and pid. Overrides the quiet
967 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100968 */
969void Alert(char *fmt, ...) {
970 va_list argp;
971 struct timeval tv;
972 struct tm *tm;
973
willy tarreaud0fb4652005-12-18 01:32:04 +0100974 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100975 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100976
willy tarreau5cbea6f2005-12-17 12:48:26 +0100977 gettimeofday(&tv, NULL);
978 tm=localtime(&tv.tv_sec);
979 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100980 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100981 vfprintf(stderr, fmt, argp);
982 fflush(stderr);
983 va_end(argp);
984 }
willy tarreau0f7af912005-12-17 12:21:26 +0100985}
986
987
988/*
989 * Displays the message on stderr with the date and pid.
990 */
991void Warning(char *fmt, ...) {
992 va_list argp;
993 struct timeval tv;
994 struct tm *tm;
995
willy tarreau982249e2005-12-18 00:57:06 +0100996 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100997 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100998
willy tarreau5cbea6f2005-12-17 12:48:26 +0100999 gettimeofday(&tv, NULL);
1000 tm=localtime(&tv.tv_sec);
1001 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001002 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001003 vfprintf(stderr, fmt, argp);
1004 fflush(stderr);
1005 va_end(argp);
1006 }
1007}
1008
1009/*
1010 * Displays the message on <out> only if quiet mode is not set.
1011 */
1012void qfprintf(FILE *out, char *fmt, ...) {
1013 va_list argp;
1014
willy tarreau982249e2005-12-18 00:57:06 +01001015 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001016 va_start(argp, fmt);
1017 vfprintf(out, fmt, argp);
1018 fflush(out);
1019 va_end(argp);
1020 }
willy tarreau0f7af912005-12-17 12:21:26 +01001021}
1022
1023
1024/*
1025 * converts <str> to a struct sockaddr_in* which is locally allocated.
1026 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1027 * INADDR_ANY.
1028 */
1029struct sockaddr_in *str2sa(char *str) {
1030 static struct sockaddr_in sa;
1031 char *c;
1032 int port;
1033
willy tarreaua1598082005-12-17 13:08:06 +01001034 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001035 str=strdup(str);
1036
1037 if ((c=strrchr(str,':')) != NULL) {
1038 *c++=0;
1039 port=atol(c);
1040 }
1041 else
1042 port=0;
1043
1044 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1045 sa.sin_addr.s_addr = INADDR_ANY;
1046 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001047 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001048 struct hostent *he;
1049
1050 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001051 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001052 }
1053 else
1054 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1055 }
1056 sa.sin_port=htons(port);
1057 sa.sin_family=AF_INET;
1058
1059 free(str);
1060 return &sa;
1061}
1062
willy tarreaub1285d52005-12-18 01:20:14 +01001063/*
1064 * converts <str> to a two struct in_addr* which are locally allocated.
1065 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1066 * is optionnal and either in the dotted or CIDR notation.
1067 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1068 */
1069int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1070 char *c;
1071 unsigned long len;
1072
1073 memset(mask, 0, sizeof(*mask));
1074 memset(addr, 0, sizeof(*addr));
1075 str=strdup(str);
1076
1077 if ((c = strrchr(str, '/')) != NULL) {
1078 *c++ = 0;
1079 /* c points to the mask */
1080 if (strchr(c, '.') != NULL) { /* dotted notation */
1081 if (!inet_pton(AF_INET, c, mask))
1082 return 0;
1083 }
1084 else { /* mask length */
1085 char *err;
1086 len = strtol(c, &err, 10);
1087 if (!*c || (err && *err) || (unsigned)len > 32)
1088 return 0;
1089 if (len)
1090 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1091 else
1092 mask->s_addr = 0;
1093 }
1094 }
1095 else {
1096 mask->s_addr = 0xFFFFFFFF;
1097 }
1098 if (!inet_pton(AF_INET, str, addr)) {
1099 struct hostent *he;
1100
1101 if ((he = gethostbyname(str)) == NULL) {
1102 return 0;
1103 }
1104 else
1105 *addr = *(struct in_addr *) *(he->h_addr_list);
1106 }
1107 free(str);
1108 return 1;
1109}
1110
willy tarreau9fe663a2005-12-17 13:02:59 +01001111
1112/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001113 * converts <str> to a list of listeners which are dynamically allocated.
1114 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1115 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1116 * - <port> is a numerical port from 1 to 65535 ;
1117 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1118 * This can be repeated as many times as necessary, separated by a coma.
1119 * The <tail> argument is a pointer to a current list which should be appended
1120 * to the tail of the new list. The pointer to the new list is returned.
1121 */
1122struct listener *str2listener(char *str, struct listener *tail) {
1123 struct listener *l;
1124 char *c, *next, *range, *dupstr;
1125 int port, end;
1126
1127 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001128
willy tarreaua41a8b42005-12-17 14:02:24 +01001129 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001130 struct sockaddr_storage ss;
1131
willy tarreaua41a8b42005-12-17 14:02:24 +01001132 str = next;
1133 /* 1) look for the end of the first address */
1134 if ((next = strrchr(str, ',')) != NULL) {
1135 *next++ = 0;
1136 }
1137
willy tarreau8a86dbf2005-12-18 00:45:59 +01001138 /* 2) look for the addr/port delimiter, it's the last colon. */
1139 if ((range = strrchr(str, ':')) == NULL) {
1140 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001141 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001142 }
1143
1144 *range++ = 0;
1145
1146 if (strrchr(str, ':') != NULL) {
1147 /* IPv6 address contains ':' */
1148 memset(&ss, 0, sizeof(ss));
1149 ss.ss_family = AF_INET6;
1150
1151 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1152 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001153 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001154 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001155 }
1156 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001157 memset(&ss, 0, sizeof(ss));
1158 ss.ss_family = AF_INET;
1159
1160 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1161 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1162 }
1163 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1164 struct hostent *he;
1165
1166 if ((he = gethostbyname(str)) == NULL) {
1167 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001168 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001169 }
1170 else
1171 ((struct sockaddr_in *)&ss)->sin_addr =
1172 *(struct in_addr *) *(he->h_addr_list);
1173 }
1174 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001175
1176 /* 3) look for the port-end delimiter */
1177 if ((c = strchr(range, '-')) != NULL) {
1178 *c++ = 0;
1179 end = atol(c);
1180 }
1181 else {
1182 end = atol(range);
1183 }
1184
willy tarreaud0fb4652005-12-18 01:32:04 +01001185 port = atol(range);
1186
1187 if (port < 1 || port > 65535) {
1188 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1189 goto fail;
1190 }
1191
1192 if (end < 1 || end > 65535) {
1193 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1194 goto fail;
1195 }
1196
1197 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001198 l = (struct listener *)calloc(1, sizeof(struct listener));
1199 l->next = tail;
1200 tail = l;
1201
willy tarreau41310e72006-03-25 18:17:56 +01001202 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001203 l->addr = ss;
1204 if (ss.ss_family == AF_INET6)
1205 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1206 else
1207 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1208
willy tarreaua41a8b42005-12-17 14:02:24 +01001209 } /* end for(port) */
1210 } /* end while(next) */
1211 free(dupstr);
1212 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001213 fail:
1214 free(dupstr);
1215 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001216}
1217
willy tarreau4302f492005-12-18 01:00:37 +01001218
1219#define FD_SETS_ARE_BITFIELDS
1220#ifdef FD_SETS_ARE_BITFIELDS
1221/*
1222 * This map is used with all the FD_* macros to check whether a particular bit
1223 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1224 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1225 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1226 * exclusively to the macros.
1227 */
1228fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1229fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1230
1231#else
1232#error "Check if your OS uses bitfields for fd_sets"
1233#endif
1234
1235/* will try to encode the string <string> replacing all characters tagged in
1236 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1237 * prefixed by <escape>, and will store the result between <start> (included
1238 *) and <stop> (excluded), and will always terminate the string with a '\0'
1239 * before <stop>. The position of the '\0' is returned if the conversion
1240 * completes. If bytes are missing between <start> and <stop>, then the
1241 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1242 * cannot even be stored so we return <start> without writing the 0.
1243 * The input string must also be zero-terminated.
1244 */
1245char hextab[16] = "0123456789ABCDEF";
1246char *encode_string(char *start, char *stop,
1247 const char escape, const fd_set *map,
1248 const char *string)
1249{
1250 if (start < stop) {
1251 stop--; /* reserve one byte for the final '\0' */
1252 while (start < stop && *string != 0) {
1253 if (!FD_ISSET((unsigned char)(*string), map))
1254 *start++ = *string;
1255 else {
1256 if (start + 3 >= stop)
1257 break;
1258 *start++ = escape;
1259 *start++ = hextab[(*string >> 4) & 15];
1260 *start++ = hextab[*string & 15];
1261 }
1262 string++;
1263 }
1264 *start = '\0';
1265 }
1266 return start;
1267}
willy tarreaua41a8b42005-12-17 14:02:24 +01001268
1269/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001270 * This function sends a syslog message to both log servers of a proxy,
1271 * or to global log servers if the proxy is NULL.
1272 * It also tries not to waste too much time computing the message header.
1273 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001274 */
1275void send_log(struct proxy *p, int level, char *message, ...) {
1276 static int logfd = -1; /* syslog UDP socket */
1277 static long tvsec = -1; /* to force the string to be initialized */
1278 struct timeval tv;
1279 va_list argp;
1280 static char logmsg[MAX_SYSLOG_LEN];
1281 static char *dataptr = NULL;
1282 int fac_level;
1283 int hdr_len, data_len;
1284 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001285 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001286 int nbloggers = 0;
1287 char *log_ptr;
1288
1289 if (logfd < 0) {
1290 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1291 return;
1292 }
1293
1294 if (level < 0 || progname == NULL || message == NULL)
1295 return;
1296
1297 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001298 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001299 /* this string is rebuild only once a second */
1300 struct tm *tm = localtime(&tv.tv_sec);
1301 tvsec = tv.tv_sec;
1302
willy tarreauc29948c2005-12-17 13:10:27 +01001303 hdr_len = snprintf(logmsg, sizeof(logmsg),
1304 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1305 monthname[tm->tm_mon],
1306 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1307 progname, pid);
1308 /* WARNING: depending upon implementations, snprintf may return
1309 * either -1 or the number of bytes that would be needed to store
1310 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001311 */
willy tarreauc29948c2005-12-17 13:10:27 +01001312 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1313 hdr_len = sizeof(logmsg);
1314
1315 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001316 }
1317
1318 va_start(argp, message);
1319 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001320 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1321 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001322 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001323 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001324
1325 if (p == NULL) {
1326 if (global.logfac1 >= 0) {
1327 sa[nbloggers] = &global.logsrv1;
1328 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001329 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001330 nbloggers++;
1331 }
1332 if (global.logfac2 >= 0) {
1333 sa[nbloggers] = &global.logsrv2;
1334 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001335 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001336 nbloggers++;
1337 }
1338 } else {
1339 if (p->logfac1 >= 0) {
1340 sa[nbloggers] = &p->logsrv1;
1341 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001342 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001343 nbloggers++;
1344 }
1345 if (p->logfac2 >= 0) {
1346 sa[nbloggers] = &p->logsrv2;
1347 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001348 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001349 nbloggers++;
1350 }
1351 }
1352
1353 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001354 /* we can filter the level of the messages that are sent to each logger */
1355 if (level > loglevel[nbloggers])
1356 continue;
1357
willy tarreauc29948c2005-12-17 13:10:27 +01001358 /* For each target, we may have a different facility.
1359 * We can also have a different log level for each message.
1360 * This induces variations in the message header length.
1361 * Since we don't want to recompute it each time, nor copy it every
1362 * time, we only change the facility in the pre-computed header,
1363 * and we change the pointer to the header accordingly.
1364 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001365 fac_level = (facilities[nbloggers] << 3) + level;
1366 log_ptr = logmsg + 3; /* last digit of the log level */
1367 do {
1368 *log_ptr = '0' + fac_level % 10;
1369 fac_level /= 10;
1370 log_ptr--;
1371 } while (fac_level && log_ptr > logmsg);
1372 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001373
willy tarreauc29948c2005-12-17 13:10:27 +01001374 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001375
1376#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001377 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001378 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1379#else
willy tarreauc29948c2005-12-17 13:10:27 +01001380 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001381 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1382#endif
1383 }
willy tarreau0f7af912005-12-17 12:21:26 +01001384}
1385
1386
1387/* sets <tv> to the current time */
1388static inline struct timeval *tv_now(struct timeval *tv) {
1389 if (tv)
1390 gettimeofday(tv, NULL);
1391 return tv;
1392}
1393
1394/*
1395 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1396 */
willy tarreaudab722b2006-05-04 19:23:38 +02001397static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001398 if (!tv || !from)
1399 return NULL;
1400 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1401 tv->tv_sec = from->tv_sec + (ms/1000);
1402 while (tv->tv_usec >= 1000000) {
1403 tv->tv_usec -= 1000000;
1404 tv->tv_sec++;
1405 }
1406 return tv;
1407}
1408
1409/*
1410 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001411 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001412 */
1413static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001414 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001415 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001416 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001417 return 1;
1418 else if (tv1->tv_usec < tv2->tv_usec)
1419 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001420 else if (tv1->tv_usec > tv2->tv_usec)
1421 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001422 else
1423 return 0;
1424}
1425
1426/*
1427 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001428 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001429 */
1430unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1431 int cmp;
1432 unsigned long ret;
1433
1434
willy tarreauef900ab2005-12-17 12:52:52 +01001435 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001436 if (!cmp)
1437 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001438 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001439 struct timeval *tmp = tv1;
1440 tv1 = tv2;
1441 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001442 }
willy tarreauef900ab2005-12-17 12:52:52 +01001443 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001444 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001445 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001446 else
willy tarreauef900ab2005-12-17 12:52:52 +01001447 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001448 return (unsigned long) ret;
1449}
1450
1451/*
willy tarreau750a4722005-12-17 13:21:24 +01001452 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001453 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001454 */
1455static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1456 unsigned long ret;
1457
willy tarreau6e682ce2005-12-17 13:26:49 +01001458 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1459 if (tv2->tv_usec > tv1->tv_usec)
1460 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001461 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001462 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001463 return (unsigned long) ret;
1464}
1465
1466/*
willy tarreau0f7af912005-12-17 12:21:26 +01001467 * 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 +01001468 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001469 */
willy tarreaudab722b2006-05-04 19:23:38 +02001470static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001471 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001472 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001473 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001474 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001475 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001476 else
1477 return 0;
1478 }
willy tarreau0f7af912005-12-17 12:21:26 +01001479 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001480 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001481 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001482 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001483 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001484 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001485 else
1486 return 0;
1487}
1488
1489/*
1490 * returns the remaining time between tv1=now and event=tv2
1491 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001492 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001493 */
1494static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1495 unsigned long ret;
1496
willy tarreau0f7af912005-12-17 12:21:26 +01001497 if (tv_cmp_ms(tv1, tv2) >= 0)
1498 return 0; /* event elapsed */
1499
willy tarreauef900ab2005-12-17 12:52:52 +01001500 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001501 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001502 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001503 else
willy tarreauef900ab2005-12-17 12:52:52 +01001504 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001505 return (unsigned long) ret;
1506}
1507
1508
1509/*
1510 * zeroes a struct timeval
1511 */
1512
1513static inline struct timeval *tv_eternity(struct timeval *tv) {
1514 tv->tv_sec = tv->tv_usec = 0;
1515 return tv;
1516}
1517
1518/*
1519 * returns 1 if tv is null, else 0
1520 */
1521static inline int tv_iseternity(struct timeval *tv) {
1522 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1523 return 1;
1524 else
1525 return 0;
1526}
1527
1528/*
1529 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1530 * considering that 0 is the eternity.
1531 */
willy tarreaudab722b2006-05-04 19:23:38 +02001532static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001533 if (tv_iseternity(tv1))
1534 if (tv_iseternity(tv2))
1535 return 0; /* same */
1536 else
1537 return 1; /* tv1 later than tv2 */
1538 else if (tv_iseternity(tv2))
1539 return -1; /* tv2 later than tv1 */
1540
1541 if (tv1->tv_sec > tv2->tv_sec)
1542 return 1;
1543 else if (tv1->tv_sec < tv2->tv_sec)
1544 return -1;
1545 else if (tv1->tv_usec > tv2->tv_usec)
1546 return 1;
1547 else if (tv1->tv_usec < tv2->tv_usec)
1548 return -1;
1549 else
1550 return 0;
1551}
1552
1553/*
1554 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1555 * considering that 0 is the eternity.
1556 */
willy tarreaudab722b2006-05-04 19:23:38 +02001557static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001558 if (tv_iseternity(tv1))
1559 if (tv_iseternity(tv2))
1560 return 0; /* same */
1561 else
1562 return 1; /* tv1 later than tv2 */
1563 else if (tv_iseternity(tv2))
1564 return -1; /* tv2 later than tv1 */
1565
willy tarreauefae1842005-12-17 12:51:03 +01001566 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001567 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001568 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001569 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001570 return -1;
1571 else
1572 return 0;
1573 }
1574 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001575 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001576 return 1;
1577 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001578 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001579 return -1;
1580 else
1581 return 0;
1582}
1583
1584/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001585 * returns the remaining time between tv1=now and event=tv2
1586 * if tv2 is passed, 0 is returned.
1587 * Returns TIME_ETERNITY if tv2 is eternity.
1588 */
willy tarreaudab722b2006-05-04 19:23:38 +02001589static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001590 unsigned long ret;
1591
1592 if (tv_iseternity(tv2))
1593 return TIME_ETERNITY;
1594
1595 if (tv_cmp_ms(tv1, tv2) >= 0)
1596 return 0; /* event elapsed */
1597
1598 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1599 if (tv2->tv_usec > tv1->tv_usec)
1600 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1601 else
1602 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1603 return (unsigned long) ret;
1604}
1605
1606/*
willy tarreau0f7af912005-12-17 12:21:26 +01001607 * returns the first event between tv1 and tv2 into tvmin.
1608 * a zero tv is ignored. tvmin is returned.
1609 */
1610static inline struct timeval *tv_min(struct timeval *tvmin,
1611 struct timeval *tv1, struct timeval *tv2) {
1612
1613 if (tv_cmp2(tv1, tv2) <= 0)
1614 *tvmin = *tv1;
1615 else
1616 *tvmin = *tv2;
1617
1618 return tvmin;
1619}
1620
1621
1622
1623/***********************************************************/
1624/* fd management ***************************************/
1625/***********************************************************/
1626
1627
1628
willy tarreau5cbea6f2005-12-17 12:48:26 +01001629/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1630 * The file descriptor is also closed.
1631 */
willy tarreaudab722b2006-05-04 19:23:38 +02001632static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001633 FD_CLR(fd, StaticReadEvent);
1634 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001635#if defined(ENABLE_EPOLL)
1636 if (PrevReadEvent) {
1637 FD_CLR(fd, PrevReadEvent);
1638 FD_CLR(fd, PrevWriteEvent);
1639 }
1640#endif
1641
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642 close(fd);
1643 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001644
1645 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1646 maxfd--;
1647}
1648
1649/* recomputes the maxfd limit from the fd */
1650static inline void fd_insert(int fd) {
1651 if (fd+1 > maxfd)
1652 maxfd = fd+1;
1653}
1654
1655/*************************************************************/
1656/* task management ***************************************/
1657/*************************************************************/
1658
willy tarreau5cbea6f2005-12-17 12:48:26 +01001659/* puts the task <t> in run queue <q>, and returns <t> */
1660static inline struct task *task_wakeup(struct task **q, struct task *t) {
1661 if (t->state == TASK_RUNNING)
1662 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001663 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001664 t->rqnext = *q;
1665 t->state = TASK_RUNNING;
1666 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001667 }
1668}
1669
willy tarreau5cbea6f2005-12-17 12:48:26 +01001670/* removes the task <t> from the queue <q>
1671 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001672 * set the run queue to point to the next one, and return it
1673 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001674static inline struct task *task_sleep(struct task **q, struct task *t) {
1675 if (t->state == TASK_RUNNING) {
1676 *q = t->rqnext;
1677 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001678 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001679 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001680}
1681
1682/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001683 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001684 * from the run queue. A pointer to the task itself is returned.
1685 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001686static inline struct task *task_delete(struct task *t) {
1687 t->prev->next = t->next;
1688 t->next->prev = t->prev;
1689 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001690}
1691
1692/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001693 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001694 */
1695static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001696 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001697}
1698
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001700 * may be only moved or left where it was, depending on its timing requirements.
1701 * <task> is returned.
1702 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001703struct task *task_queue(struct task *task) {
1704 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001705 struct task *start_from;
1706
willy tarreau5e698ef2006-05-02 14:51:00 +02001707 /* This is a very dirty hack to queue non-expirable tasks in another queue
1708 * in order to avoid pulluting the tail of the standard queue. This will go
1709 * away with the new O(log(n)) scheduler anyway.
1710 */
1711 if (tv_iseternity(&task->expire)) {
1712 /* if the task was queued in the standard wait queue, we must dequeue it */
1713 if (task->prev) {
1714 if (task->wq == LIST_HEAD(wait_queue[1]))
1715 return task;
1716 else {
1717 task_delete(task);
1718 task->prev = NULL;
1719 }
1720 }
1721 list = task->wq = LIST_HEAD(wait_queue[1]);
1722 } else {
1723 /* if the task was queued in the eternity queue, we must dequeue it */
1724 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1725 task_delete(task);
1726 task->prev = NULL;
1727 list = task->wq = LIST_HEAD(wait_queue[0]);
1728 }
1729 }
1730
1731 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001732 if (task->prev == NULL) {
1733 // start_from = list;
1734 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001735#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001736 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001737#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001738 /* insert the unlinked <task> into the list, searching back from the last entry */
1739 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1740 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001741#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001742 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001743#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001744 }
1745
1746 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1747 // start_from = start_from->next;
1748 // stats_tsk_nsrch++;
1749 // }
1750 }
1751 else if (task->prev == list ||
1752 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1753 start_from = task->next;
1754 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001755#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001756 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001757#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001758 return task; /* it's already in the right place */
1759 }
1760
willy tarreau750a4722005-12-17 13:21:24 +01001761#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001762 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001763#endif
1764
1765 /* if the task is not at the right place, there's little chance that
1766 * it has only shifted a bit, and it will nearly always be queued
1767 * at the end of the list because of constant timeouts
1768 * (observed in real case).
1769 */
1770#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1771 start_from = list->prev; /* assume we'll queue to the end of the list */
1772 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1773 start_from = start_from->prev;
1774#if STATTIME > 0
1775 stats_tsk_lsrch++;
1776#endif
1777 }
1778#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001779 /* insert the unlinked <task> into the list, searching after position <start_from> */
1780 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1781 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001782#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001783 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001784#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001785 }
willy tarreau750a4722005-12-17 13:21:24 +01001786#endif /* WE_REALLY_... */
1787
willy tarreau0f7af912005-12-17 12:21:26 +01001788 /* we need to unlink it now */
1789 task_delete(task);
1790 }
1791 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001792#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001793 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001794#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001795#ifdef LEFT_TO_TOP /* not very good */
1796 start_from = list;
1797 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1798 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001799#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001800 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001801#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001802 }
1803#else
1804 start_from = task->prev->prev; /* valid because of the previous test above */
1805 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1806 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001807#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001808 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001809#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001810 }
1811#endif
1812 /* we need to unlink it now */
1813 task_delete(task);
1814 }
1815 task->prev = start_from;
1816 task->next = start_from->next;
1817 task->next->prev = task;
1818 start_from->next = task;
1819 return task;
1820}
1821
1822
1823/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001824/* pending connections queues **************************************/
1825/*********************************************************************/
1826
1827/*
willy tarreaudfece232006-05-02 00:19:57 +02001828 * Detaches pending connection <p>, decreases the pending count, and frees
1829 * the pending connection. The connection might have been queued to a specific
1830 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001831 */
willy tarreaudfece232006-05-02 00:19:57 +02001832static void pendconn_free(struct pendconn *p) {
1833 LIST_DEL(&p->list);
1834 p->sess->pend_pos = NULL;
1835 if (p->srv)
1836 p->srv->nbpend--;
1837 else
1838 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001839 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001840 pool_free(pendconn, p);
1841}
1842
1843/* Returns the first pending connection for server <s>, which may be NULL if
1844 * nothing is pending.
1845 */
1846static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001847 if (!s->nbpend)
1848 return NULL;
1849
1850 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1851}
1852
willy tarreaudfece232006-05-02 00:19:57 +02001853/* Returns the first pending connection for proxy <px>, which may be NULL if
1854 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001855 */
willy tarreaudfece232006-05-02 00:19:57 +02001856static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1857 if (!px->nbpend)
1858 return NULL;
1859
1860 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001861}
1862
willy tarreaubc2eda62006-05-04 15:16:23 +02001863/* Detaches the next pending connection from either a server or a proxy, and
1864 * returns its associated session. If no pending connection is found, NULL is
1865 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001866 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001867static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001868 struct pendconn *p;
1869 struct session *sess;
1870
willy tarreaubc2eda62006-05-04 15:16:23 +02001871 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001872 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001873 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001874 if (!p)
1875 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001876 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001877 }
willy tarreau18a957c2006-04-12 19:26:23 +02001878 sess = p->sess;
1879 pendconn_free(p);
1880 return sess;
1881}
1882
willy tarreaudfece232006-05-02 00:19:57 +02001883/* Adds the session <sess> to the pending connection list of server <sess>->srv
1884 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1885 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1886 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001887 */
willy tarreaudfece232006-05-02 00:19:57 +02001888static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001889 struct pendconn *p;
1890
1891 p = pool_alloc(pendconn);
1892 if (!p)
1893 return NULL;
1894
willy tarreau18a957c2006-04-12 19:26:23 +02001895 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001896 p->sess = sess;
1897 p->srv = sess->srv;
1898 if (sess->srv) {
1899 LIST_ADDQ(&sess->srv->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001900 sess->logs.srv_queue_size += sess->srv->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001901 sess->srv->nbpend++;
1902 } else {
1903 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
willy tarreau5e69b162006-05-12 19:49:37 +02001904 sess->logs.prx_queue_size += sess->proxy->nbpend;
willy tarreaudfece232006-05-02 00:19:57 +02001905 sess->proxy->nbpend++;
1906 }
willy tarreauf32f5242006-05-02 22:54:52 +02001907 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001908 return p;
1909}
1910
willy tarreau59a6cc22006-05-12 01:29:08 +02001911/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1912 * and non-zero otherwise. Suited for and if/else usage.
1913 */
1914static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1915 return (s && (s->nbpend || p->nbpend) &&
1916 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1917}
1918
1919
1920
willy tarreau18a957c2006-04-12 19:26:23 +02001921/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001922/* more specific functions ***************************************/
1923/*********************************************************************/
1924
1925/* some prototypes */
1926static int maintain_proxies(void);
1927
willy tarreaub952e1d2005-12-18 01:31:20 +01001928/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001929 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1930 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001931static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001932#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001933 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1934#else
willy tarreaua1598082005-12-17 13:08:06 +01001935#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001936 return getsockname(fd, (struct sockaddr *)sa, salen);
1937#else
1938 return -1;
1939#endif
1940#endif
1941}
1942
1943/*
1944 * frees the context associated to a session. It must have been removed first.
1945 */
willy tarreaudfece232006-05-02 00:19:57 +02001946static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001947 if (s->pend_pos)
1948 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001949 if (s->req)
1950 pool_free(buffer, s->req);
1951 if (s->rep)
1952 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001953
1954 if (s->rsp_cap != NULL) {
1955 struct cap_hdr *h;
1956 for (h = s->proxy->rsp_cap; h; h = h->next) {
1957 if (s->rsp_cap[h->index] != NULL)
1958 pool_free_to(h->pool, s->rsp_cap[h->index]);
1959 }
1960 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1961 }
1962 if (s->req_cap != NULL) {
1963 struct cap_hdr *h;
1964 for (h = s->proxy->req_cap; h; h = h->next) {
1965 if (s->req_cap[h->index] != NULL)
1966 pool_free_to(h->pool, s->req_cap[h->index]);
1967 }
1968 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1969 }
1970
willy tarreaua1598082005-12-17 13:08:06 +01001971 if (s->logs.uri)
1972 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001973 if (s->logs.cli_cookie)
1974 pool_free(capture, s->logs.cli_cookie);
1975 if (s->logs.srv_cookie)
1976 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001977
willy tarreau5cbea6f2005-12-17 12:48:26 +01001978 pool_free(session, s);
1979}
1980
willy tarreau0f7af912005-12-17 12:21:26 +01001981
1982/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001983 * This function recounts the number of usable active and backup servers for
1984 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001985 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001986 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001987static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001988 struct server *srv;
1989
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001990 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001991 for (srv = px->srv; srv != NULL; srv = srv->next) {
1992 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001993 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001994 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001995 px->tot_wbck += srv->eweight + 1;
1996 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001997 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001998 px->tot_wact += srv->eweight + 1;
1999 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01002000 }
2001 }
2002}
2003
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002004/* This function recomputes the server map for proxy px. It
2005 * relies on px->tot_wact and px->tot_wbck, so it must be
2006 * called after recount_servers(). It also expects px->srv_map
2007 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002008 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002009static void recalc_server_map(struct proxy *px) {
2010 int o, tot, flag;
2011 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002012
willy tarreau4c8c2b52006-03-24 19:36:41 +01002013 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002014 flag = SRV_RUNNING;
2015 tot = px->tot_wact;
2016 } else if (px->srv_bck) {
2017 flag = SRV_RUNNING | SRV_BACKUP;
2018 if (px->options & PR_O_USE_ALL_BK)
2019 tot = px->tot_wbck;
2020 else
2021 tot = 1; /* the first server is enough */
2022 } else {
2023 px->srv_map_sz = 0;
2024 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002025 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002026
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002027 /* this algorithm gives priority to the first server, which means that
2028 * it will respect the declaration order for equivalent weights, and
2029 * that whatever the weights, the first server called will always be
2030 * the first declard. This is an important asumption for the backup
2031 * case, where we want the first server only.
2032 */
2033 for (cur = px->srv; cur; cur = cur->next)
2034 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002035
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002036 for (o = 0; o < tot; o++) {
2037 int max = 0;
2038 best = NULL;
2039 for (cur = px->srv; cur; cur = cur->next) {
2040 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2041 int v;
2042
2043 /* If we are forced to return only one server, we don't want to
2044 * go further, because we would return the wrong one due to
2045 * divide overflow.
2046 */
2047 if (tot == 1) {
2048 best = cur;
2049 break;
2050 }
2051
2052 cur->wscore += cur->eweight + 1;
2053 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2054 if (best == NULL || v > max) {
2055 max = v;
2056 best = cur;
2057 }
2058 }
2059 }
2060 px->srv_map[o] = best;
2061 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002062 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002063 px->srv_map_sz = tot;
2064}
Willy TARREAU3481c462006-03-01 22:37:57 +01002065
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002066/*
willy tarreau898db9d2006-04-12 20:29:08 +02002067 * This function tries to find a running server with free connection slots for
2068 * the proxy <px> following the round-robin method.
2069 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2070 * to point to the next server. If no valid server is found, NULL is returned.
2071 */
2072static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2073 int newidx;
2074 struct server *srv;
2075
2076 if (px->srv_map_sz == 0)
2077 return NULL;
2078
2079 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2080 px->srv_rr_idx = 0;
2081 newidx = px->srv_rr_idx;
2082
2083 do {
2084 srv = px->srv_map[newidx++];
2085 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2086 px->srv_rr_idx = newidx;
2087 return srv;
2088 }
2089 if (newidx == px->srv_map_sz)
2090 newidx = 0;
2091 } while (newidx != px->srv_rr_idx);
2092
2093 return NULL;
2094}
2095
2096
2097/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002098 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002099 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002100 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2101 * to point to the next server. If no valid server is found, NULL is returned.
2102 */
2103static inline struct server *get_server_rr(struct proxy *px) {
2104 if (px->srv_map_sz == 0)
2105 return NULL;
2106
2107 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2108 px->srv_rr_idx = 0;
2109 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002110}
2111
willy tarreau62084d42006-03-24 18:57:41 +01002112
2113/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002114 * This function tries to find a running server for the proxy <px> following
2115 * the source hash method. Depending on the number of active/backup servers,
2116 * it will either look for active servers, or for backup servers.
2117 * If any server is found, it will be returned. If no valid server is found,
2118 * NULL is returned.
2119 */
2120static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002122
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002123 if (px->srv_map_sz == 0)
2124 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002125
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002126 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002127 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002128 while ((l + sizeof (int)) <= len) {
2129 h ^= ntohl(*(unsigned int *)(&addr[l]));
2130 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002131 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002132 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002133 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002134 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002135}
2136
2137
2138/*
willy tarreaudfece232006-05-02 00:19:57 +02002139 * This function marks the session as 'assigned' in direct or dispatch modes,
2140 * or tries to assign one in balance mode, according to the algorithm. It does
2141 * nothing if the session had already been assigned a server.
2142 *
2143 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002144 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2145 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2146 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002147 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2148 *
2149 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2150 * not need to be called anymore. This usually means that s->srv can be trusted
2151 * in balance and direct modes. This flag is not cleared, so it's to the caller
2152 * to clear it if required (eg: redispatch).
2153 *
willy tarreau0f7af912005-12-17 12:21:26 +01002154 */
willy tarreau0f7af912005-12-17 12:21:26 +01002155
willy tarreaudfece232006-05-02 00:19:57 +02002156int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002157#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002158 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002159#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002160
willy tarreaudfece232006-05-02 00:19:57 +02002161 if (s->pend_pos)
2162 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002163
willy tarreaudfece232006-05-02 00:19:57 +02002164 if (!(s->flags & SN_ASSIGNED)) {
2165 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2166 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2167 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002168
willy tarreaudfece232006-05-02 00:19:57 +02002169 if (s->proxy->options & PR_O_BALANCE_RR) {
2170 s->srv = get_server_rr_with_conns(s->proxy);
2171 if (!s->srv)
2172 return SRV_STATUS_FULL;
2173 }
2174 else if (s->proxy->options & PR_O_BALANCE_SH) {
2175 int len;
2176
2177 if (s->cli_addr.ss_family == AF_INET)
2178 len = 4;
2179 else if (s->cli_addr.ss_family == AF_INET6)
2180 len = 16;
2181 else /* unknown IP family */
2182 return SRV_STATUS_INTERNAL;
2183
2184 s->srv = get_server_sh(s->proxy,
2185 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2186 len);
2187 }
2188 else /* unknown balancing algorithm */
2189 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002190 }
willy tarreaudfece232006-05-02 00:19:57 +02002191 s->flags |= SN_ASSIGNED;
2192 }
2193 return SRV_STATUS_OK;
2194}
willy tarreau1a3442d2006-03-24 21:03:20 +01002195
willy tarreaudfece232006-05-02 00:19:57 +02002196/*
2197 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2198 * The address is taken from the currently assigned server, or from the
2199 * dispatch or transparent address.
2200 *
2201 * It may return :
2202 * SRV_STATUS_OK if everything is OK.
2203 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2204 *
2205 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2206 * not cleared, so it's to the caller to clear it if required.
2207 *
2208 */
2209int assign_server_address(struct session *s) {
2210#ifdef DEBUG_FULL
2211 fprintf(stderr,"assign_server_address : s=%p\n",s);
2212#endif
2213
2214 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2215 /* A server is necessarily known for this session */
2216 if (!(s->flags & SN_ASSIGNED))
2217 return SRV_STATUS_INTERNAL;
2218
2219 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002220
willy tarreaudfece232006-05-02 00:19:57 +02002221 /* if this server remaps proxied ports, we'll use
2222 * the port the client connected to with an offset. */
2223 if (s->srv->state & SRV_MAPPORTS) {
2224 struct sockaddr_in sockname;
2225 socklen_t namelen = sizeof(sockname);
2226
2227 if (!(s->proxy->options & PR_O_TRANSP) ||
2228 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2229 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2230 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002231 }
willy tarreau0f7af912005-12-17 12:21:26 +01002232 }
willy tarreaua1598082005-12-17 13:08:06 +01002233 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002234 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002235 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002236 }
2237 else if (s->proxy->options & PR_O_TRANSP) {
2238 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002239 socklen_t salen = sizeof(s->srv_addr);
2240
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2242 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002243 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002244 }
2245 }
willy tarreau0f7af912005-12-17 12:21:26 +01002246
willy tarreaudfece232006-05-02 00:19:57 +02002247 s->flags |= SN_ADDR_SET;
2248 return SRV_STATUS_OK;
2249}
willy tarreaua41a8b42005-12-17 14:02:24 +01002250
willy tarreaudfece232006-05-02 00:19:57 +02002251/* This function assigns a server to session <s> if required, and can add the
2252 * connection to either the assigned server's queue or to the proxy's queue.
2253 *
2254 * Returns :
2255 *
2256 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002257 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002258 * SRV_STATUS_QUEUED if the connection has been queued.
2259 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2260 * connection could not be queued.
2261 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2262 *
2263 */
2264int assign_server_and_queue(struct session *s) {
2265 struct pendconn *p;
2266 int err;
2267
2268 if (s->pend_pos)
2269 return SRV_STATUS_INTERNAL;
2270
2271 if (s->flags & SN_ASSIGNED) {
2272 /* a server does not need to be assigned, perhaps because we're in
2273 * direct mode, or in dispatch or transparent modes where the server
2274 * is not needed.
2275 */
2276 if (s->srv &&
2277 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2278 p = pendconn_add(s);
2279 if (p)
2280 return SRV_STATUS_QUEUED;
2281 else
2282 return SRV_STATUS_FULL;
2283 }
2284 return SRV_STATUS_OK;
2285 }
2286
2287 /* a server needs to be assigned */
2288 err = assign_server(s);
2289 switch (err) {
2290 case SRV_STATUS_OK:
2291 /* in balance mode, we might have servers with connection limits */
2292 if (s->srv != NULL &&
2293 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2294 p = pendconn_add(s);
2295 if (p)
2296 return SRV_STATUS_QUEUED;
2297 else
2298 return SRV_STATUS_FULL;
2299 }
2300 return SRV_STATUS_OK;
2301
2302 case SRV_STATUS_FULL:
2303 /* queue this session into the proxy's queue */
2304 p = pendconn_add(s);
2305 if (p)
2306 return SRV_STATUS_QUEUED;
2307 else
2308 return SRV_STATUS_FULL;
2309
2310 case SRV_STATUS_NOSRV:
2311 case SRV_STATUS_INTERNAL:
2312 return err;
2313 default:
2314 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002315 }
willy tarreaudfece232006-05-02 00:19:57 +02002316}
2317
2318
2319/*
2320 * This function initiates a connection to the server assigned to this session
2321 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2322 * It can return one of :
2323 * - SN_ERR_NONE if everything's OK
2324 * - SN_ERR_SRVTO if there are no more servers
2325 * - SN_ERR_SRVCL if the connection was refused by the server
2326 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2327 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2328 * - SN_ERR_INTERNAL for any other purely internal errors
2329 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2330 */
2331int connect_server(struct session *s) {
2332 int fd, err;
2333
2334 if (!(s->flags & SN_ADDR_SET)) {
2335 err = assign_server_address(s);
2336 if (err != SRV_STATUS_OK)
2337 return SN_ERR_INTERNAL;
2338 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002339
willy tarreau0f7af912005-12-17 12:21:26 +01002340 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002341 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002342
2343 if (errno == ENFILE)
2344 send_log(s->proxy, LOG_EMERG,
2345 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2346 s->proxy->id, maxfd);
2347 else if (errno == EMFILE)
2348 send_log(s->proxy, LOG_EMERG,
2349 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2350 s->proxy->id, maxfd);
2351 else if (errno == ENOBUFS || errno == ENOMEM)
2352 send_log(s->proxy, LOG_EMERG,
2353 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2354 s->proxy->id, maxfd);
2355 /* this is a resource error */
2356 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002357 }
2358
willy tarreau9fe663a2005-12-17 13:02:59 +01002359 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002360 /* do not log anything there, it's a normal condition when this option
2361 * is used to serialize connections to a server !
2362 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002363 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2364 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002365 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002366 }
2367
willy tarreau0f7af912005-12-17 12:21:26 +01002368 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2369 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002370 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002371 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002372 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002373 }
2374
willy tarreaub952e1d2005-12-18 01:31:20 +01002375 if (s->proxy->options & PR_O_TCP_SRV_KA)
2376 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2377
willy tarreau0174f312005-12-18 01:02:42 +01002378 /* allow specific binding :
2379 * - server-specific at first
2380 * - proxy-specific next
2381 */
2382 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2383 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2384 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2385 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2386 s->proxy->id, s->srv->id);
2387 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002388 send_log(s->proxy, LOG_EMERG,
2389 "Cannot bind to source address before connect() for server %s/%s.\n",
2390 s->proxy->id, s->srv->id);
2391 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002392 }
2393 }
2394 else if (s->proxy->options & PR_O_BIND_SRC) {
2395 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2396 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2397 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2398 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002399 send_log(s->proxy, LOG_EMERG,
2400 "Cannot bind to source address before connect() for server %s/%s.\n",
2401 s->proxy->id, s->srv->id);
2402 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002403 }
willy tarreaua1598082005-12-17 13:08:06 +01002404 }
2405
willy tarreaub1285d52005-12-18 01:20:14 +01002406 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2407 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2408
2409 if (errno == EAGAIN || errno == EADDRINUSE) {
2410 char *msg;
2411 if (errno == EAGAIN) /* no free ports left, try again later */
2412 msg = "no free ports";
2413 else
2414 msg = "local address already in use";
2415
2416 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002417 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002418 send_log(s->proxy, LOG_EMERG,
2419 "Connect() failed for server %s/%s: %s.\n",
2420 s->proxy->id, s->srv->id, msg);
2421 return SN_ERR_RESOURCE;
2422 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002423 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002424 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002425 return SN_ERR_SRVTO;
2426 } else {
2427 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002428 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002429 close(fd);
2430 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002431 }
2432 }
2433
willy tarreau5cbea6f2005-12-17 12:48:26 +01002434 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002435 fdtab[fd].read = &event_srv_read;
2436 fdtab[fd].write = &event_srv_write;
2437 fdtab[fd].state = FD_STCONN; /* connection in progress */
2438
2439 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002440#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2441 if (PrevReadEvent) {
2442 assert(!(FD_ISSET(fd, PrevReadEvent)));
2443 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2444 }
2445#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002446
2447 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002448 if (s->srv)
2449 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002450
2451 if (s->proxy->contimeout)
2452 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2453 else
2454 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002455 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002456}
2457
2458/*
2459 * this function is called on a read event from a client socket.
2460 * It returns 0.
2461 */
2462int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002463 struct task *t = fdtab[fd].owner;
2464 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002465 struct buffer *b = s->req;
2466 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002467
willy tarreau12350152005-12-18 01:03:27 +01002468#ifdef DEBUG_FULL
2469 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2470#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002471
willy tarreau0f7af912005-12-17 12:21:26 +01002472 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002473#ifdef FILL_BUFFERS
2474 while (1)
2475#else
2476 do
2477#endif
2478 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002479 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2480 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002481 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002482 }
2483 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002484 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 }
2486 else {
2487 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002488 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2489 * since it means that the rewrite protection has been removed. This
2490 * implies that the if statement can be removed.
2491 */
2492 if (max > b->rlim - b->data)
2493 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002494 }
2495
2496 if (max == 0) { /* not anymore room to store data */
2497 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002498 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002499 }
2500
willy tarreau3242e862005-12-17 12:27:53 +01002501#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002502 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002503 int skerr;
2504 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002505
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2507 if (skerr)
2508 ret = -1;
2509 else
2510 ret = recv(fd, b->r, max, 0);
2511 }
willy tarreau3242e862005-12-17 12:27:53 +01002512#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002514#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515 if (ret > 0) {
2516 b->r += ret;
2517 b->l += ret;
2518 s->res_cr = RES_DATA;
2519
2520 if (b->r == b->data + BUFSIZE) {
2521 b->r = b->data; /* wrap around the buffer */
2522 }
willy tarreaua1598082005-12-17 13:08:06 +01002523
2524 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002525 /* we hope to read more data or to get a close on next round */
2526 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002527 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002528 else if (ret == 0) {
2529 s->res_cr = RES_NULL;
2530 break;
2531 }
2532 else if (errno == EAGAIN) {/* ignore EAGAIN */
2533 break;
2534 }
2535 else {
2536 s->res_cr = RES_ERROR;
2537 fdtab[fd].state = FD_STERROR;
2538 break;
2539 }
2540 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002541#ifndef FILL_BUFFERS
2542 while (0);
2543#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002544 }
2545 else {
2546 s->res_cr = RES_ERROR;
2547 fdtab[fd].state = FD_STERROR;
2548 }
2549
willy tarreau5cbea6f2005-12-17 12:48:26 +01002550 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002551 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002552 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2553 else
2554 tv_eternity(&s->crexpire);
2555
2556 task_wakeup(&rq, t);
2557 }
willy tarreau0f7af912005-12-17 12:21:26 +01002558
willy tarreau0f7af912005-12-17 12:21:26 +01002559 return 0;
2560}
2561
2562
2563/*
2564 * this function is called on a read event from a server socket.
2565 * It returns 0.
2566 */
2567int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002568 struct task *t = fdtab[fd].owner;
2569 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002570 struct buffer *b = s->rep;
2571 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002572
willy tarreau12350152005-12-18 01:03:27 +01002573#ifdef DEBUG_FULL
2574 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2575#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002576
willy tarreau0f7af912005-12-17 12:21:26 +01002577 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002578#ifdef FILL_BUFFERS
2579 while (1)
2580#else
2581 do
2582#endif
2583 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002584 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2585 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002586 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 }
2588 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002589 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 }
2591 else {
2592 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002593 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2594 * since it means that the rewrite protection has been removed. This
2595 * implies that the if statement can be removed.
2596 */
2597 if (max > b->rlim - b->data)
2598 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002599 }
2600
2601 if (max == 0) { /* not anymore room to store data */
2602 FD_CLR(fd, StaticReadEvent);
2603 break;
2604 }
2605
willy tarreau3242e862005-12-17 12:27:53 +01002606#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002607 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002608 int skerr;
2609 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002610
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2612 if (skerr)
2613 ret = -1;
2614 else
2615 ret = recv(fd, b->r, max, 0);
2616 }
willy tarreau3242e862005-12-17 12:27:53 +01002617#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002618 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002619#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620 if (ret > 0) {
2621 b->r += ret;
2622 b->l += ret;
2623 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002624
willy tarreau5cbea6f2005-12-17 12:48:26 +01002625 if (b->r == b->data + BUFSIZE) {
2626 b->r = b->data; /* wrap around the buffer */
2627 }
willy tarreaua1598082005-12-17 13:08:06 +01002628
2629 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 /* we hope to read more data or to get a close on next round */
2631 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002632 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002633 else if (ret == 0) {
2634 s->res_sr = RES_NULL;
2635 break;
2636 }
2637 else if (errno == EAGAIN) {/* ignore EAGAIN */
2638 break;
2639 }
2640 else {
2641 s->res_sr = RES_ERROR;
2642 fdtab[fd].state = FD_STERROR;
2643 break;
2644 }
2645 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002646#ifndef FILL_BUFFERS
2647 while (0);
2648#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002649 }
2650 else {
2651 s->res_sr = RES_ERROR;
2652 fdtab[fd].state = FD_STERROR;
2653 }
2654
willy tarreau5cbea6f2005-12-17 12:48:26 +01002655 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002656 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002657 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2658 else
2659 tv_eternity(&s->srexpire);
2660
2661 task_wakeup(&rq, t);
2662 }
willy tarreau0f7af912005-12-17 12:21:26 +01002663
willy tarreau0f7af912005-12-17 12:21:26 +01002664 return 0;
2665}
2666
2667/*
2668 * this function is called on a write event from a client socket.
2669 * It returns 0.
2670 */
2671int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 struct task *t = fdtab[fd].owner;
2673 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002674 struct buffer *b = s->rep;
2675 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002676
willy tarreau12350152005-12-18 01:03:27 +01002677#ifdef DEBUG_FULL
2678 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2679#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002680
2681 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002682 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002683 // max = BUFSIZE; BUG !!!!
2684 max = 0;
2685 }
2686 else if (b->r > b->w) {
2687 max = b->r - b->w;
2688 }
2689 else
2690 max = b->data + BUFSIZE - b->w;
2691
willy tarreau0f7af912005-12-17 12:21:26 +01002692 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002693 if (max == 0) {
2694 s->res_cw = RES_NULL;
2695 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002696 tv_eternity(&s->cwexpire);
2697 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002698 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002699 }
2700
willy tarreau3242e862005-12-17 12:27:53 +01002701#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002702 {
2703 int skerr;
2704 socklen_t lskerr = sizeof(skerr);
2705
2706 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2707 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002708 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002709 else
willy tarreau3242e862005-12-17 12:27:53 +01002710 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002711 }
willy tarreau3242e862005-12-17 12:27:53 +01002712#else
willy tarreau0f7af912005-12-17 12:21:26 +01002713 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002714#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002715
2716 if (ret > 0) {
2717 b->l -= ret;
2718 b->w += ret;
2719
2720 s->res_cw = RES_DATA;
2721
2722 if (b->w == b->data + BUFSIZE) {
2723 b->w = b->data; /* wrap around the buffer */
2724 }
2725 }
2726 else if (ret == 0) {
2727 /* nothing written, just make as if we were never called */
2728// s->res_cw = RES_NULL;
2729 return 0;
2730 }
2731 else if (errno == EAGAIN) /* ignore EAGAIN */
2732 return 0;
2733 else {
2734 s->res_cw = RES_ERROR;
2735 fdtab[fd].state = FD_STERROR;
2736 }
2737 }
2738 else {
2739 s->res_cw = RES_ERROR;
2740 fdtab[fd].state = FD_STERROR;
2741 }
2742
willy tarreaub1ff9db2005-12-17 13:51:03 +01002743 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002744 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002745 /* FIXME: to prevent the client from expiring read timeouts during writes,
2746 * we refresh it. A solution would be to merge read+write timeouts into a
2747 * unique one, although that needs some study particularly on full-duplex
2748 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002749 s->crexpire = s->cwexpire;
2750 }
willy tarreau0f7af912005-12-17 12:21:26 +01002751 else
2752 tv_eternity(&s->cwexpire);
2753
willy tarreau5cbea6f2005-12-17 12:48:26 +01002754 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002755 return 0;
2756}
2757
2758
2759/*
2760 * this function is called on a write event from a server socket.
2761 * It returns 0.
2762 */
2763int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002764 struct task *t = fdtab[fd].owner;
2765 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002766 struct buffer *b = s->req;
2767 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002768
willy tarreau12350152005-12-18 01:03:27 +01002769#ifdef DEBUG_FULL
2770 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2771#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002772
2773 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002774 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002775 // max = BUFSIZE; BUG !!!!
2776 max = 0;
2777 }
2778 else if (b->r > b->w) {
2779 max = b->r - b->w;
2780 }
2781 else
2782 max = b->data + BUFSIZE - b->w;
2783
willy tarreau0f7af912005-12-17 12:21:26 +01002784 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002785 if (max == 0) {
2786 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002787 if (s->srv_state == SV_STCONN) {
2788 int skerr;
2789 socklen_t lskerr = sizeof(skerr);
2790 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2791 if (skerr) {
2792 s->res_sw = RES_ERROR;
2793 fdtab[fd].state = FD_STERROR;
2794 task_wakeup(&rq, t);
2795 tv_eternity(&s->swexpire);
2796 FD_CLR(fd, StaticWriteEvent);
2797 return 0;
2798 }
2799 }
2800
willy tarreau0f7af912005-12-17 12:21:26 +01002801 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002802 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002803 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002804 tv_eternity(&s->swexpire);
2805 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002806 return 0;
2807 }
2808
willy tarreau3242e862005-12-17 12:27:53 +01002809#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002810 {
2811 int skerr;
2812 socklen_t lskerr = sizeof(skerr);
2813 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2814 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002815 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002816 else
willy tarreau3242e862005-12-17 12:27:53 +01002817 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002818 }
willy tarreau3242e862005-12-17 12:27:53 +01002819#else
willy tarreau0f7af912005-12-17 12:21:26 +01002820 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002821#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002822 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002823 if (ret > 0) {
2824 b->l -= ret;
2825 b->w += ret;
2826
2827 s->res_sw = RES_DATA;
2828
2829 if (b->w == b->data + BUFSIZE) {
2830 b->w = b->data; /* wrap around the buffer */
2831 }
2832 }
2833 else if (ret == 0) {
2834 /* nothing written, just make as if we were never called */
2835 // s->res_sw = RES_NULL;
2836 return 0;
2837 }
2838 else if (errno == EAGAIN) /* ignore EAGAIN */
2839 return 0;
2840 else {
2841 s->res_sw = RES_ERROR;
2842 fdtab[fd].state = FD_STERROR;
2843 }
2844 }
2845 else {
2846 s->res_sw = RES_ERROR;
2847 fdtab[fd].state = FD_STERROR;
2848 }
2849
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002850 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2851 * otherwise it could loop indefinitely !
2852 */
2853 if (s->srv_state != SV_STCONN) {
2854 if (s->proxy->srvtimeout) {
2855 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002856 /* FIXME: to prevent the server from expiring read timeouts during writes,
2857 * we refresh it. A solution would be to merge read+write+connect timeouts
2858 * into a unique one since we don't mind expiring on read or write, and none
2859 * of them is enabled while waiting for connect(), although that needs some
2860 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002861 s->srexpire = s->swexpire;
2862 }
2863 else
2864 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002865 }
willy tarreau0f7af912005-12-17 12:21:26 +01002866
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002868 return 0;
2869}
2870
2871
2872/*
willy tarreaue39cd132005-12-17 13:00:18 +01002873 * returns a message to the client ; the connection is shut down for read,
2874 * and the request is cleared so that no server connection can be initiated.
2875 * The client must be in a valid state for this (HEADER, DATA ...).
2876 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002877 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002878 */
2879void client_retnclose(struct session *s, int len, const char *msg) {
2880 FD_CLR(s->cli_fd, StaticReadEvent);
2881 FD_SET(s->cli_fd, StaticWriteEvent);
2882 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002883 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002884 shutdown(s->cli_fd, SHUT_RD);
2885 s->cli_state = CL_STSHUTR;
2886 strcpy(s->rep->data, msg);
2887 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002888 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002889 s->rep->r += len;
2890 s->req->l = 0;
2891}
2892
2893
2894/*
2895 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002896 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002897 */
2898void client_return(struct session *s, int len, const char *msg) {
2899 strcpy(s->rep->data, msg);
2900 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002901 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002902 s->rep->r += len;
2903 s->req->l = 0;
2904}
2905
willy tarreau9fe663a2005-12-17 13:02:59 +01002906/*
2907 * send a log for the session when we have enough info about it
2908 */
2909void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002910 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002911 struct proxy *p = s->proxy;
2912 int log;
2913 char *uri;
2914 char *pxid;
2915 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002916 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002917
2918 /* This is a first attempt at a better logging system.
2919 * For now, we rely on send_log() to provide the date, although it obviously
2920 * is the date of the log and not of the request, and most fields are not
2921 * computed.
2922 */
2923
willy tarreaua1598082005-12-17 13:08:06 +01002924 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002925
willy tarreau8a86dbf2005-12-18 00:45:59 +01002926 if (s->cli_addr.ss_family == AF_INET)
2927 inet_ntop(AF_INET,
2928 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2929 pn, sizeof(pn));
2930 else
2931 inet_ntop(AF_INET6,
2932 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2933 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002934
willy tarreauc1cae632005-12-17 14:12:23 +01002935 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002936 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002937 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002938
willy tarreauc1cae632005-12-17 14:12:23 +01002939 tm = localtime(&s->logs.tv_accept.tv_sec);
2940 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002941 char tmpline[MAX_SYSLOG_LEN], *h;
2942 int hdr;
2943
2944 h = tmpline;
2945 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2946 *(h++) = ' ';
2947 *(h++) = '{';
2948 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2949 if (hdr)
2950 *(h++) = '|';
2951 if (s->req_cap[hdr] != NULL)
2952 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2953 }
2954 *(h++) = '}';
2955 }
2956
2957 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2958 *(h++) = ' ';
2959 *(h++) = '{';
2960 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2961 if (hdr)
2962 *(h++) = '|';
2963 if (s->rsp_cap[hdr] != NULL)
2964 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2965 }
2966 *(h++) = '}';
2967 }
2968
2969 if (h < tmpline + sizeof(tmpline) - 4) {
2970 *(h++) = ' ';
2971 *(h++) = '"';
2972 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2973 *(h++) = '"';
2974 }
2975 *h = '\0';
2976
willy tarreau5e69b162006-05-12 19:49:37 +02002977 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/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002978 pn,
2979 (s->cli_addr.ss_family == AF_INET) ?
2980 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2981 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002982 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2983 tm->tm_hour, tm->tm_min, tm->tm_sec,
2984 pxid, srv,
2985 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002986 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2987 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002988 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002989 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2990 s->logs.status,
2991 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002992 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2993 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002994 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2995 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2996 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2997 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau5e69b162006-05-12 19:49:37 +02002998 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
2999 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01003000 }
3001 else {
willy tarreau5e69b162006-05-12 19:49:37 +02003002 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/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003003 pn,
3004 (s->cli_addr.ss_family == AF_INET) ?
3005 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3006 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003007 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3008 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003009 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003010 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003011 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3012 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003013 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003014 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreau5e69b162006-05-12 19:49:37 +02003015 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn,
3016 s->logs.srv_queue_size, s->logs.prx_queue_size);
willy tarreaua1598082005-12-17 13:08:06 +01003017 }
3018
3019 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003020}
3021
willy tarreaue39cd132005-12-17 13:00:18 +01003022
3023/*
willy tarreau0f7af912005-12-17 12:21:26 +01003024 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003025 * to an accept. It tries to accept as many connections as possible.
3026 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003027 */
3028int event_accept(int fd) {
3029 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003030 struct session *s;
3031 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003032 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003033 int max_accept;
3034
3035 if (global.nbproc > 1)
3036 max_accept = 8; /* let other processes catch some connections too */
3037 else
3038 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003039
willy tarreauc2becdc2006-03-19 19:36:48 +01003040 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003041 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003042 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003043
willy tarreaub1285d52005-12-18 01:20:14 +01003044 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3045 switch (errno) {
3046 case EAGAIN:
3047 case EINTR:
3048 case ECONNABORTED:
3049 return 0; /* nothing more to accept */
3050 case ENFILE:
3051 send_log(p, LOG_EMERG,
3052 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3053 p->id, maxfd);
3054 return 0;
3055 case EMFILE:
3056 send_log(p, LOG_EMERG,
3057 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3058 p->id, maxfd);
3059 return 0;
3060 case ENOBUFS:
3061 case ENOMEM:
3062 send_log(p, LOG_EMERG,
3063 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3064 p->id, maxfd);
3065 return 0;
3066 default:
3067 return 0;
3068 }
3069 }
willy tarreau0f7af912005-12-17 12:21:26 +01003070
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3072 Alert("out of memory in event_accept().\n");
3073 FD_CLR(fd, StaticReadEvent);
3074 p->state = PR_STIDLE;
3075 close(cfd);
3076 return 0;
3077 }
willy tarreau0f7af912005-12-17 12:21:26 +01003078
willy tarreaub1285d52005-12-18 01:20:14 +01003079 /* if this session comes from a known monitoring system, we want to ignore
3080 * it as soon as possible, which means closing it immediately for TCP.
3081 */
3082 s->flags = 0;
3083 if (addr.ss_family == AF_INET &&
3084 p->mon_mask.s_addr &&
3085 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3086 if (p->mode == PR_MODE_TCP) {
3087 close(cfd);
3088 pool_free(session, s);
3089 continue;
3090 }
3091 s->flags |= SN_MONITOR;
3092 }
3093
willy tarreau5cbea6f2005-12-17 12:48:26 +01003094 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3095 Alert("out of memory in event_accept().\n");
3096 FD_CLR(fd, StaticReadEvent);
3097 p->state = PR_STIDLE;
3098 close(cfd);
3099 pool_free(session, s);
3100 return 0;
3101 }
willy tarreau0f7af912005-12-17 12:21:26 +01003102
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003104 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3106 close(cfd);
3107 pool_free(task, t);
3108 pool_free(session, s);
3109 return 0;
3110 }
willy tarreau0f7af912005-12-17 12:21:26 +01003111
willy tarreau5cbea6f2005-12-17 12:48:26 +01003112 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3113 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3114 (char *) &one, sizeof(one)) == -1)) {
3115 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3116 close(cfd);
3117 pool_free(task, t);
3118 pool_free(session, s);
3119 return 0;
3120 }
willy tarreau0f7af912005-12-17 12:21:26 +01003121
willy tarreaub952e1d2005-12-18 01:31:20 +01003122 if (p->options & PR_O_TCP_CLI_KA)
3123 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3124
willy tarreau9fe663a2005-12-17 13:02:59 +01003125 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003126 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003127 t->state = TASK_IDLE;
3128 t->process = process_session;
3129 t->context = s;
3130
3131 s->task = t;
3132 s->proxy = p;
3133 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3134 s->srv_state = SV_STIDLE;
3135 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003136
willy tarreau9fe663a2005-12-17 13:02:59 +01003137 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3138 s->cli_fd = cfd;
3139 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003140 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003141 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003142
willy tarreaub1285d52005-12-18 01:20:14 +01003143 if (s->flags & SN_MONITOR)
3144 s->logs.logwait = 0;
3145 else
3146 s->logs.logwait = p->to_log;
3147
willy tarreaua1598082005-12-17 13:08:06 +01003148 s->logs.tv_accept = now;
3149 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003150 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003151 s->logs.t_connect = -1;
3152 s->logs.t_data = -1;
3153 s->logs.t_close = 0;
3154 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003155 s->logs.cli_cookie = NULL;
3156 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003157 s->logs.status = -1;
3158 s->logs.bytes = 0;
willy tarreau5e69b162006-05-12 19:49:37 +02003159 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3160 s->logs.srv_queue_size = 0; /* we will get this number soon */
willy tarreau9fe663a2005-12-17 13:02:59 +01003161
willy tarreau2f6ba652005-12-17 13:57:42 +01003162 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003163 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003164
willy tarreau4302f492005-12-18 01:00:37 +01003165 if (p->nb_req_cap > 0) {
3166 if ((s->req_cap =
3167 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3168 == NULL) { /* no memory */
3169 close(cfd); /* nothing can be done for this fd without memory */
3170 pool_free(task, t);
3171 pool_free(session, s);
3172 return 0;
3173 }
3174 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3175 }
3176 else
3177 s->req_cap = NULL;
3178
3179 if (p->nb_rsp_cap > 0) {
3180 if ((s->rsp_cap =
3181 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3182 == NULL) { /* no memory */
3183 if (s->req_cap != NULL)
3184 pool_free_to(p->req_cap_pool, s->req_cap);
3185 close(cfd); /* nothing can be done for this fd without memory */
3186 pool_free(task, t);
3187 pool_free(session, s);
3188 return 0;
3189 }
3190 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3191 }
3192 else
3193 s->rsp_cap = NULL;
3194
willy tarreau5cbea6f2005-12-17 12:48:26 +01003195 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3196 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003197 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003198 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003199
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003201 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003202 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003203 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003204
willy tarreau9fe663a2005-12-17 13:02:59 +01003205 if (p->to_log) {
3206 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003207 if (s->logs.logwait & LW_CLIP)
3208 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003209 sess_log(s);
3210 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003211 else if (s->cli_addr.ss_family == AF_INET) {
3212 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3213 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3214 sn, sizeof(sn)) &&
3215 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3216 pn, sizeof(pn))) {
3217 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3218 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3219 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3220 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3221 }
3222 }
3223 else {
3224 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3225 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3226 sn, sizeof(sn)) &&
3227 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3228 pn, sizeof(pn))) {
3229 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3230 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3231 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3232 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3233 }
3234 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003235 }
willy tarreau0f7af912005-12-17 12:21:26 +01003236
willy tarreau982249e2005-12-18 00:57:06 +01003237 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003238 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003239 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003240 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003241 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003242 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003243 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003244 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003245
willy tarreau8a86dbf2005-12-18 00:45:59 +01003246 if (s->cli_addr.ss_family == AF_INET) {
3247 char pn[INET_ADDRSTRLEN];
3248 inet_ntop(AF_INET,
3249 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3250 pn, sizeof(pn));
3251
3252 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3253 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3254 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3255 }
3256 else {
3257 char pn[INET6_ADDRSTRLEN];
3258 inet_ntop(AF_INET6,
3259 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3260 pn, sizeof(pn));
3261
3262 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3263 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3264 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3265 }
3266
willy tarreauef900ab2005-12-17 12:52:52 +01003267 write(1, trash, len);
3268 }
willy tarreau0f7af912005-12-17 12:21:26 +01003269
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003271 if (s->rsp_cap != NULL)
3272 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3273 if (s->req_cap != NULL)
3274 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003275 close(cfd); /* nothing can be done for this fd without memory */
3276 pool_free(task, t);
3277 pool_free(session, s);
3278 return 0;
3279 }
willy tarreau4302f492005-12-18 01:00:37 +01003280
willy tarreau5cbea6f2005-12-17 12:48:26 +01003281 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003282 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003283 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3284 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003285 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003286 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003287
willy tarreau5cbea6f2005-12-17 12:48:26 +01003288 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3289 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003290 if (s->rsp_cap != NULL)
3291 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3292 if (s->req_cap != NULL)
3293 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003294 close(cfd); /* nothing can be done for this fd without memory */
3295 pool_free(task, t);
3296 pool_free(session, s);
3297 return 0;
3298 }
3299 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003300 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003301 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->rlim = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01003302
willy tarreau5cbea6f2005-12-17 12:48:26 +01003303 fdtab[cfd].read = &event_cli_read;
3304 fdtab[cfd].write = &event_cli_write;
3305 fdtab[cfd].owner = t;
3306 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003307
willy tarreaub1285d52005-12-18 01:20:14 +01003308 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3309 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3310 /* Either we got a request from a monitoring system on an HTTP instance,
3311 * or we're in health check mode with the 'httpchk' option enabled. In
3312 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3313 */
3314 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3315 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3316 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 }
3318 else {
3319 FD_SET(cfd, StaticReadEvent);
3320 }
3321
willy tarreaub952e1d2005-12-18 01:31:20 +01003322#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3323 if (PrevReadEvent) {
3324 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3325 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3326 }
3327#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003328 fd_insert(cfd);
3329
3330 tv_eternity(&s->cnexpire);
3331 tv_eternity(&s->srexpire);
3332 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003333 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 tv_eternity(&s->cwexpire);
3335
willy tarreaub1285d52005-12-18 01:20:14 +01003336 if (s->proxy->clitimeout) {
3337 if (FD_ISSET(cfd, StaticReadEvent))
3338 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3339 if (FD_ISSET(cfd, StaticWriteEvent))
3340 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3341 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342
willy tarreaub1285d52005-12-18 01:20:14 +01003343 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344
3345 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003346
3347 if (p->mode != PR_MODE_HEALTH)
3348 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349
3350 p->nbconn++;
3351 actconn++;
3352 totalconn++;
3353
willy tarreaub952e1d2005-12-18 01:31:20 +01003354 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355 } /* end of while (p->nbconn < p->maxconn) */
3356 return 0;
3357}
willy tarreau0f7af912005-12-17 12:21:26 +01003358
willy tarreau0f7af912005-12-17 12:21:26 +01003359
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360/*
3361 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003362 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3363 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 * or -1 if an error occured.
3365 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003366int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 struct task *t = fdtab[fd].owner;
3368 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003369 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003370 socklen_t lskerr = sizeof(skerr);
3371
willy tarreau05be12b2006-03-19 19:35:00 +01003372 skerr = 1;
3373 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3374 || (skerr != 0)) {
3375 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003377 fdtab[fd].state = FD_STERROR;
3378 FD_CLR(fd, StaticWriteEvent);
3379 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003380 else if (s->result != -1) {
3381 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003382 if (s->proxy->options & PR_O_HTTP_CHK) {
3383 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003384 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003385 * so we'll send the request, and won't wake the checker up now.
3386 */
3387#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003388 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003389#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003390 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003391#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003392 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003393 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3394 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3395 return 0;
3396 }
willy tarreau05be12b2006-03-19 19:35:00 +01003397 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003398 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003399 FD_CLR(fd, StaticWriteEvent);
3400 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003401 }
3402 else {
3403 /* good TCP connection is enough */
3404 s->result = 1;
3405 }
3406 }
3407
3408 task_wakeup(&rq, t);
3409 return 0;
3410}
3411
willy tarreau0f7af912005-12-17 12:21:26 +01003412
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003413/*
3414 * This function is used only for server health-checks. It handles
3415 * the server's reply to an HTTP request. It returns 1 if the server replies
3416 * 2xx or 3xx (valid responses), or -1 in other cases.
3417 */
3418int event_srv_chk_r(int fd) {
3419 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003420 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003421 struct task *t = fdtab[fd].owner;
3422 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003423 int skerr;
3424 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003425
willy tarreaua4a583a2005-12-18 01:39:19 +01003426 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003427
willy tarreau05be12b2006-03-19 19:35:00 +01003428 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3429 if (!skerr) {
3430#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003431 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003432#else
willy tarreau05be12b2006-03-19 19:35:00 +01003433 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3434 * but the connection was closed on the remote end. Fortunately, recv still
3435 * works correctly and we don't need to do the getsockopt() on linux.
3436 */
3437 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003438#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003439
3440 if ((len >= sizeof("HTTP/1.0 000")) &&
3441 !memcmp(reply, "HTTP/1.", 7) &&
3442 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3443 result = 1;
3444 }
3445
3446 if (result == -1)
3447 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003448
3449 if (s->result != -1)
3450 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003451
3452 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003454 return 0;
3455}
3456
3457
3458/*
3459 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3460 * and moves <end> just after the end of <str>.
3461 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3462 * the shift value (positive or negative) is returned.
3463 * If there's no space left, the move is not done.
3464 *
3465 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003466int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003467 int delta;
3468 int len;
3469
3470 len = strlen(str);
3471 delta = len - (end - pos);
3472
3473 if (delta + b->r >= b->data + BUFSIZE)
3474 return 0; /* no space left */
3475
3476 /* first, protect the end of the buffer */
3477 memmove(end + delta, end, b->data + b->l - end);
3478
3479 /* now, copy str over pos */
3480 memcpy(pos, str,len);
3481
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 /* we only move data after the displaced zone */
3483 if (b->r > pos) b->r += delta;
3484 if (b->w > pos) b->w += delta;
3485 if (b->h > pos) b->h += delta;
3486 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003487 b->l += delta;
3488
3489 return delta;
3490}
3491
willy tarreau8337c6b2005-12-17 13:41:01 +01003492/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003493 * len is 0.
3494 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003496 int delta;
3497
3498 delta = len - (end - pos);
3499
3500 if (delta + b->r >= b->data + BUFSIZE)
3501 return 0; /* no space left */
3502
Willy TARREAUe78ae262006-01-08 01:24:12 +01003503 if (b->data + b->l < end)
3504 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3505 return 0;
3506
willy tarreau0f7af912005-12-17 12:21:26 +01003507 /* first, protect the end of the buffer */
3508 memmove(end + delta, end, b->data + b->l - end);
3509
3510 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003511 if (len)
3512 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003513
willy tarreau5cbea6f2005-12-17 12:48:26 +01003514 /* we only move data after the displaced zone */
3515 if (b->r > pos) b->r += delta;
3516 if (b->w > pos) b->w += delta;
3517 if (b->h > pos) b->h += delta;
3518 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003519 b->l += delta;
3520
3521 return delta;
3522}
3523
3524
3525int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3526 char *old_dst = dst;
3527
3528 while (*str) {
3529 if (*str == '\\') {
3530 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003531 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003532 int len, num;
3533
3534 num = *str - '0';
3535 str++;
3536
willy tarreau8a86dbf2005-12-18 00:45:59 +01003537 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003538 len = matches[num].rm_eo - matches[num].rm_so;
3539 memcpy(dst, src + matches[num].rm_so, len);
3540 dst += len;
3541 }
3542
3543 }
3544 else if (*str == 'x') {
3545 unsigned char hex1, hex2;
3546 str++;
3547
willy tarreauc1f47532005-12-18 01:08:26 +01003548 hex1 = toupper(*str++) - '0';
3549 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003550
3551 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3552 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3553 *dst++ = (hex1<<4) + hex2;
3554 }
3555 else
3556 *dst++ = *str++;
3557 }
3558 else
3559 *dst++ = *str++;
3560 }
3561 *dst = 0;
3562 return dst - old_dst;
3563}
3564
willy tarreauc1f47532005-12-18 01:08:26 +01003565static int ishex(char s)
3566{
3567 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3568}
3569
3570/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3571char *check_replace_string(char *str)
3572{
3573 char *err = NULL;
3574 while (*str) {
3575 if (*str == '\\') {
3576 err = str; /* in case of a backslash, we return the pointer to it */
3577 str++;
3578 if (!*str)
3579 return err;
3580 else if (isdigit((int)*str))
3581 err = NULL;
3582 else if (*str == 'x') {
3583 str++;
3584 if (!ishex(*str))
3585 return err;
3586 str++;
3587 if (!ishex(*str))
3588 return err;
3589 err = NULL;
3590 }
3591 else {
3592 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3593 err = NULL;
3594 }
3595 }
3596 str++;
3597 }
3598 return err;
3599}
3600
3601
willy tarreau9fe663a2005-12-17 13:02:59 +01003602
willy tarreau0f7af912005-12-17 12:21:26 +01003603/*
3604 * manages the client FSM and its socket. BTW, it also tries to handle the
3605 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3606 * 0 else.
3607 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003609 int s = t->srv_state;
3610 int c = t->cli_state;
3611 struct buffer *req = t->req;
3612 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003613 int method_checked = 0;
3614 appsess *asession_temp = NULL;
3615 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003616
willy tarreau750a4722005-12-17 13:21:24 +01003617#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003618 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3619 cli_stnames[c], srv_stnames[s],
3620 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3621 t->crexpire.tv_sec, t->crexpire.tv_usec,
3622 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003623#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003624 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3625 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3626 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3627 //);
3628 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003629 /* now parse the partial (or complete) headers */
3630 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3631 char *ptr;
3632 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003633 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003634
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003636
willy tarreau0f7af912005-12-17 12:21:26 +01003637 /* look for the end of the current header */
3638 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3639 ptr++;
3640
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003643
3644 /*
3645 * first, let's check that it's not a leading empty line, in
3646 * which case we'll ignore and remove it (according to RFC2616).
3647 */
3648 if (req->h == req->data) {
3649 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3650 if (ptr > req->r - 2) {
3651 /* this is a partial header, let's wait for more to come */
3652 req->lr = ptr;
3653 break;
3654 }
3655
3656 /* now we know that *ptr is either \r or \n,
3657 * and that there are at least 1 char after it.
3658 */
3659 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3660 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3661 else
3662 req->lr = ptr + 2; /* \r\n or \n\r */
3663 /* ignore empty leading lines */
3664 buffer_replace2(req, req->h, req->lr, NULL, 0);
3665 req->h = req->lr;
3666 continue;
3667 }
3668
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 /* we can only get here after an end of headers */
3670 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003671
willy tarreaue39cd132005-12-17 13:00:18 +01003672 if (t->flags & SN_CLDENY) {
3673 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003674 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003675 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003676 if (!(t->flags & SN_ERR_MASK))
3677 t->flags |= SN_ERR_PRXCOND;
3678 if (!(t->flags & SN_FINST_MASK))
3679 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003680 return 1;
3681 }
3682
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003684 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3685 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003686 }
willy tarreau0f7af912005-12-17 12:21:26 +01003687
willy tarreau9fe663a2005-12-17 13:02:59 +01003688 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003689 if (t->cli_addr.ss_family == AF_INET) {
3690 unsigned char *pn;
3691 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3692 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3693 pn[0], pn[1], pn[2], pn[3]);
3694 buffer_replace2(req, req->h, req->h, trash, len);
3695 }
3696 else if (t->cli_addr.ss_family == AF_INET6) {
3697 char pn[INET6_ADDRSTRLEN];
3698 inet_ntop(AF_INET6,
3699 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3700 pn, sizeof(pn));
3701 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3702 buffer_replace2(req, req->h, req->h, trash, len);
3703 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003704 }
3705
willy tarreau25c4ea52005-12-18 00:49:49 +01003706 /* add a "connection: close" line if needed */
3707 if (t->proxy->options & PR_O_HTTP_CLOSE)
3708 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3709
willy tarreau982249e2005-12-18 00:57:06 +01003710 if (!memcmp(req->data, "POST ", 5)) {
3711 /* this is a POST request, which is not cacheable by default */
3712 t->flags |= SN_POST;
3713 }
willy tarreaucd878942005-12-17 13:27:43 +01003714
willy tarreau5cbea6f2005-12-17 12:48:26 +01003715 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003716 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003717
willy tarreau750a4722005-12-17 13:21:24 +01003718 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003719 /* FIXME: we'll set the client in a wait state while we try to
3720 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003721 * better to release the maximum of system buffers instead ?
3722 * The solution is to enable the FD but set its time-out to
3723 * eternity as long as the server-side does not enable data xfer.
3724 * CL_STDATA also has to take care of this, which is done below.
3725 */
willy tarreauef900ab2005-12-17 12:52:52 +01003726 //FD_CLR(t->cli_fd, StaticReadEvent);
3727 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003728
3729 /* FIXME: if we break here (as up to 1.1.23), having the client
3730 * shutdown its connection can lead to an abort further.
3731 * it's better to either return 1 or even jump directly to the
3732 * data state which will save one schedule.
3733 */
3734 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003735
3736 if (!t->proxy->clitimeout ||
3737 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3738 /* If the client has no timeout, or if the server is not ready yet,
3739 * and we know for sure that it can expire, then it's cleaner to
3740 * disable the timeout on the client side so that too low values
3741 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003742 *
3743 * FIXME-20050705: the server needs a way to re-enable this time-out
3744 * when it switches its state, otherwise a client can stay connected
3745 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003746 */
3747 tv_eternity(&t->crexpire);
3748
willy tarreau197e8ec2005-12-17 14:10:59 +01003749 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 }
willy tarreau0f7af912005-12-17 12:21:26 +01003751
Willy TARREAU13032e72006-03-12 17:31:45 +01003752 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3753 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 /* this is a partial header, let's wait for more to come */
3755 req->lr = ptr;
3756 break;
3757 }
willy tarreau0f7af912005-12-17 12:21:26 +01003758
willy tarreau5cbea6f2005-12-17 12:48:26 +01003759 /* now we know that *ptr is either \r or \n,
3760 * and that there are at least 1 char after it.
3761 */
3762 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3763 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3764 else
3765 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003766
willy tarreau5cbea6f2005-12-17 12:48:26 +01003767 /*
3768 * now we know that we have a full header ; we can do whatever
3769 * we want with these pointers :
3770 * req->h = beginning of header
3771 * ptr = end of header (first \r or \n)
3772 * req->lr = beginning of next line (next rep->h)
3773 * req->r = end of data (not used at this stage)
3774 */
willy tarreau0f7af912005-12-17 12:21:26 +01003775
willy tarreau12350152005-12-18 01:03:27 +01003776 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3777 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3778 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3779
3780 /* skip ; */
3781 request_line++;
3782
3783 /* look if we have a jsessionid */
3784
3785 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3786
3787 /* skip jsessionid= */
3788 request_line += t->proxy->appsession_name_len + 1;
3789
3790 /* First try if we allready have an appsession */
3791 asession_temp = &local_asession;
3792
3793 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3794 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3795 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3796 return 0;
3797 }
3798
3799 /* Copy the sessionid */
3800 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3801 asession_temp->sessid[t->proxy->appsession_len] = 0;
3802 asession_temp->serverid = NULL;
3803
3804 /* only do insert, if lookup fails */
3805 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3806 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3807 Alert("Not enough memory process_cli():asession:calloc().\n");
3808 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3809 return 0;
3810 }
3811 asession_temp->sessid = local_asession.sessid;
3812 asession_temp->serverid = local_asession.serverid;
3813 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003814 } /* end if (chtbl_lookup()) */
3815 else {
willy tarreau12350152005-12-18 01:03:27 +01003816 /*free wasted memory;*/
3817 pool_free_to(apools.sessid, local_asession.sessid);
3818 }
3819
3820 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3821 asession_temp->request_count++;
3822
3823#if defined(DEBUG_HASH)
3824 print_table(&(t->proxy->htbl_proxy));
3825#endif
3826
3827 if (asession_temp->serverid == NULL) {
3828 Alert("Found Application Session without matching server.\n");
3829 } else {
3830 struct server *srv = t->proxy->srv;
3831 while (srv) {
3832 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3833 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3834 /* we found the server and it's usable */
3835 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003836 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003837 t->srv = srv;
3838 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003839 } else {
willy tarreau12350152005-12-18 01:03:27 +01003840 t->flags &= ~SN_CK_MASK;
3841 t->flags |= SN_CK_DOWN;
3842 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003843 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003844 srv = srv->next;
3845 }/* end while(srv) */
3846 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003847 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003848 else {
3849 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3850 }
willy tarreau598da412005-12-18 01:07:29 +01003851 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003852 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003853 else{
3854 //printf("No Methode-Header with Session-String\n");
3855 }
3856
willy tarreau8337c6b2005-12-17 13:41:01 +01003857 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003858 /* we have a complete HTTP request that we must log */
3859 int urilen;
3860
willy tarreaua1598082005-12-17 13:08:06 +01003861 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003862 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003863 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003864 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003865 if (!(t->flags & SN_ERR_MASK))
3866 t->flags |= SN_ERR_PRXCOND;
3867 if (!(t->flags & SN_FINST_MASK))
3868 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003869 return 1;
3870 }
3871
3872 urilen = ptr - req->h;
3873 if (urilen >= REQURI_LEN)
3874 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003875 memcpy(t->logs.uri, req->h, urilen);
3876 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003877
willy tarreaua1598082005-12-17 13:08:06 +01003878 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003879 sess_log(t);
3880 }
willy tarreau4302f492005-12-18 01:00:37 +01003881 else if (t->logs.logwait & LW_REQHDR) {
3882 struct cap_hdr *h;
3883 int len;
3884 for (h = t->proxy->req_cap; h; h = h->next) {
3885 if ((h->namelen + 2 <= ptr - req->h) &&
3886 (req->h[h->namelen] == ':') &&
3887 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3888
3889 if (t->req_cap[h->index] == NULL)
3890 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3891
3892 len = ptr - (req->h + h->namelen + 2);
3893 if (len > h->len)
3894 len = h->len;
3895
3896 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3897 t->req_cap[h->index][len]=0;
3898 }
3899 }
3900
3901 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003902
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003904
willy tarreau982249e2005-12-18 00:57:06 +01003905 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003906 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003907 len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 max = ptr - req->h;
3909 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003910 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 trash[len++] = '\n';
3912 write(1, trash, len);
3913 }
willy tarreau0f7af912005-12-17 12:21:26 +01003914
willy tarreau25c4ea52005-12-18 00:49:49 +01003915
3916 /* remove "connection: " if needed */
3917 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3918 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3919 delete_header = 1;
3920 }
3921
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003923 if (!delete_header && t->proxy->req_exp != NULL
3924 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003925 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003926 char term;
3927
3928 term = *ptr;
3929 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003930 exp = t->proxy->req_exp;
3931 do {
3932 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3933 switch (exp->action) {
3934 case ACT_ALLOW:
3935 if (!(t->flags & SN_CLDENY))
3936 t->flags |= SN_CLALLOW;
3937 break;
3938 case ACT_REPLACE:
3939 if (!(t->flags & SN_CLDENY)) {
3940 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3941 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3942 }
3943 break;
3944 case ACT_REMOVE:
3945 if (!(t->flags & SN_CLDENY))
3946 delete_header = 1;
3947 break;
3948 case ACT_DENY:
3949 if (!(t->flags & SN_CLALLOW))
3950 t->flags |= SN_CLDENY;
3951 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003952 case ACT_PASS: /* we simply don't deny this one */
3953 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003954 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003955 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003956 }
willy tarreaue39cd132005-12-17 13:00:18 +01003957 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003958 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003959 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960
willy tarreau240afa62005-12-17 13:14:35 +01003961 /* Now look for cookies. Conforming to RFC2109, we have to support
3962 * attributes whose name begin with a '$', and associate them with
3963 * the right cookie, if we want to delete this cookie.
3964 * So there are 3 cases for each cookie read :
3965 * 1) it's a special attribute, beginning with a '$' : ignore it.
3966 * 2) it's a server id cookie that we *MAY* want to delete : save
3967 * some pointers on it (last semi-colon, beginning of cookie...)
3968 * 3) it's an application cookie : we *MAY* have to delete a previous
3969 * "special" cookie.
3970 * At the end of loop, if a "special" cookie remains, we may have to
3971 * remove it. If no application cookie persists in the header, we
3972 * *MUST* delete it
3973 */
willy tarreau12350152005-12-18 01:03:27 +01003974 if (!delete_header &&
3975 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003976 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003977 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003978 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003979 char *del_colon, *del_cookie, *colon;
3980 int app_cookies;
3981
willy tarreau5cbea6f2005-12-17 12:48:26 +01003982 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003983 colon = p1;
3984 /* del_cookie == NULL => nothing to be deleted */
3985 del_colon = del_cookie = NULL;
3986 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003987
3988 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003989 /* skip spaces and colons, but keep an eye on these ones */
3990 while (p1 < ptr) {
3991 if (*p1 == ';' || *p1 == ',')
3992 colon = p1;
3993 else if (!isspace((int)*p1))
3994 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003995 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003996 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003997
3998 if (p1 == ptr)
3999 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000
4001 /* p1 is at the beginning of the cookie name */
4002 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01004003 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 p2++;
4005
4006 if (p2 == ptr)
4007 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004008
4009 p3 = p2 + 1; /* skips the '=' sign */
4010 if (p3 == ptr)
4011 break;
4012
willy tarreau240afa62005-12-17 13:14:35 +01004013 p4 = p3;
4014 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015 p4++;
4016
4017 /* here, we have the cookie name between p1 and p2,
4018 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004019 * we can process it :
4020 *
4021 * Cookie: NAME=VALUE;
4022 * | || || |
4023 * | || || +--> p4
4024 * | || |+-------> p3
4025 * | || +--------> p2
4026 * | |+------------> p1
4027 * | +-------------> colon
4028 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004029 */
4030
willy tarreau240afa62005-12-17 13:14:35 +01004031 if (*p1 == '$') {
4032 /* skip this one */
4033 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004034 else {
4035 /* first, let's see if we want to capture it */
4036 if (t->proxy->capture_name != NULL &&
4037 t->logs.cli_cookie == NULL &&
4038 (p4 - p1 >= t->proxy->capture_namelen) &&
4039 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4040 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004041
willy tarreau8337c6b2005-12-17 13:41:01 +01004042 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4043 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004044 } else {
4045 if (log_len > t->proxy->capture_len)
4046 log_len = t->proxy->capture_len;
4047 memcpy(t->logs.cli_cookie, p1, log_len);
4048 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004051
4052 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4053 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4054 /* Cool... it's the right one */
4055 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004056 char *delim;
4057
4058 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4059 * have the server ID betweek p3 and delim, and the original cookie between
4060 * delim+1 and p4. Otherwise, delim==p4 :
4061 *
4062 * Cookie: NAME=SRV~VALUE;
4063 * | || || | |
4064 * | || || | +--> p4
4065 * | || || +--------> delim
4066 * | || |+-----------> p3
4067 * | || +------------> p2
4068 * | |+----------------> p1
4069 * | +-----------------> colon
4070 * +------------------------> req->h
4071 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004072
willy tarreau0174f312005-12-18 01:02:42 +01004073 if (t->proxy->options & PR_O_COOK_PFX) {
4074 for (delim = p3; delim < p4; delim++)
4075 if (*delim == COOKIE_DELIM)
4076 break;
4077 }
4078 else
4079 delim = p4;
4080
4081
4082 /* Here, we'll look for the first running server which supports the cookie.
4083 * This allows to share a same cookie between several servers, for example
4084 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004085 * However, to prevent clients from sticking to cookie-less backup server
4086 * when they have incidentely learned an empty cookie, we simply ignore
4087 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004088 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004089 if (delim == p3)
4090 srv = NULL;
4091
willy tarreau0174f312005-12-18 01:02:42 +01004092 while (srv) {
4093 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4094 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4095 /* we found the server and it's usable */
4096 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004097 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004098 t->srv = srv;
4099 break;
willy tarreau12350152005-12-18 01:03:27 +01004100 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004101 /* we found a server, but it's down */
4102 t->flags &= ~SN_CK_MASK;
4103 t->flags |= SN_CK_DOWN;
4104 }
4105 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004106 srv = srv->next;
4107 }
4108
willy tarreau0174f312005-12-18 01:02:42 +01004109 if (!srv && !(t->flags & SN_CK_DOWN)) {
4110 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004111 t->flags &= ~SN_CK_MASK;
4112 t->flags |= SN_CK_INVALID;
4113 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004114
willy tarreau0174f312005-12-18 01:02:42 +01004115 /* depending on the cookie mode, we may have to either :
4116 * - delete the complete cookie if we're in insert+indirect mode, so that
4117 * the server never sees it ;
4118 * - remove the server id from the cookie value, and tag the cookie as an
4119 * application cookie so that it does not get accidentely removed later,
4120 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004121 */
willy tarreau0174f312005-12-18 01:02:42 +01004122 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4123 buffer_replace2(req, p3, delim + 1, NULL, 0);
4124 p4 -= (delim + 1 - p3);
4125 ptr -= (delim + 1 - p3);
4126 del_cookie = del_colon = NULL;
4127 app_cookies++; /* protect the header from deletion */
4128 }
4129 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004130 (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 +01004131 del_cookie = p1;
4132 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004133 }
willy tarreau12350152005-12-18 01:03:27 +01004134 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004135 /* now we know that we must keep this cookie since it's
4136 * not ours. But if we wanted to delete our cookie
4137 * earlier, we cannot remove the complete header, but we
4138 * can remove the previous block itself.
4139 */
4140 app_cookies++;
4141
4142 if (del_cookie != NULL) {
4143 buffer_replace2(req, del_cookie, p1, NULL, 0);
4144 p4 -= (p1 - del_cookie);
4145 ptr -= (p1 - del_cookie);
4146 del_cookie = del_colon = NULL;
4147 }
willy tarreau240afa62005-12-17 13:14:35 +01004148 }
willy tarreau12350152005-12-18 01:03:27 +01004149
4150 if ((t->proxy->appsession_name != NULL) &&
4151 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4152 /* first, let's see if the cookie is our appcookie*/
4153
4154 /* Cool... it's the right one */
4155
4156 asession_temp = &local_asession;
4157
4158 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4159 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4160 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4161 return 0;
4162 }
4163
4164 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4165 asession_temp->sessid[t->proxy->appsession_len] = 0;
4166 asession_temp->serverid = NULL;
4167
4168 /* only do insert, if lookup fails */
4169 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4170 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4171 Alert("Not enough memory process_cli():asession:calloc().\n");
4172 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4173 return 0;
4174 }
4175
4176 asession_temp->sessid = local_asession.sessid;
4177 asession_temp->serverid = local_asession.serverid;
4178 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4179 }
4180 else{
4181 /* free wasted memory */
4182 pool_free_to(apools.sessid, local_asession.sessid);
4183 }
4184
4185 if (asession_temp->serverid == NULL) {
4186 Alert("Found Application Session without matching server.\n");
4187 } else {
4188 struct server *srv = t->proxy->srv;
4189 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004190 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004191 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4192 /* we found the server and it's usable */
4193 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004194 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004195 t->srv = srv;
4196 break;
4197 } else {
4198 t->flags &= ~SN_CK_MASK;
4199 t->flags |= SN_CK_DOWN;
4200 }
4201 }
4202 srv = srv->next;
4203 }/* end while(srv) */
4204 }/* end else if server == NULL */
4205
4206 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004207 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004208 }
willy tarreau240afa62005-12-17 13:14:35 +01004209
willy tarreau5cbea6f2005-12-17 12:48:26 +01004210 /* we'll have to look for another cookie ... */
4211 p1 = p4;
4212 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004213
4214 /* There's no more cookie on this line.
4215 * We may have marked the last one(s) for deletion.
4216 * We must do this now in two ways :
4217 * - if there is no app cookie, we simply delete the header ;
4218 * - if there are app cookies, we must delete the end of the
4219 * string properly, including the colon/semi-colon before
4220 * the cookie name.
4221 */
4222 if (del_cookie != NULL) {
4223 if (app_cookies) {
4224 buffer_replace2(req, del_colon, ptr, NULL, 0);
4225 /* WARNING! <ptr> becomes invalid for now. If some code
4226 * below needs to rely on it before the end of the global
4227 * header loop, we need to correct it with this code :
4228 * ptr = del_colon;
4229 */
4230 }
4231 else
4232 delete_header = 1;
4233 }
4234 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004235
4236 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004237 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004238 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004239 }
willy tarreau240afa62005-12-17 13:14:35 +01004240 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4241
willy tarreau5cbea6f2005-12-17 12:48:26 +01004242 req->h = req->lr;
4243 } /* while (req->lr < req->r) */
4244
4245 /* end of header processing (even if incomplete) */
4246
willy tarreauef900ab2005-12-17 12:52:52 +01004247 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4248 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4249 * full. We cannot loop here since event_cli_read will disable it only if
4250 * req->l == rlim-data
4251 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004252 FD_SET(t->cli_fd, StaticReadEvent);
4253 if (t->proxy->clitimeout)
4254 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4255 else
4256 tv_eternity(&t->crexpire);
4257 }
4258
willy tarreaue39cd132005-12-17 13:00:18 +01004259 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004260 * won't be able to free more later, so the session will never terminate.
4261 */
willy tarreaue39cd132005-12-17 13:00:18 +01004262 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004263 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004264 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004265 if (!(t->flags & SN_ERR_MASK))
4266 t->flags |= SN_ERR_PRXCOND;
4267 if (!(t->flags & SN_FINST_MASK))
4268 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004269 return 1;
4270 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004271 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004272 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004273 tv_eternity(&t->crexpire);
4274 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004275 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004276 if (!(t->flags & SN_ERR_MASK))
4277 t->flags |= SN_ERR_CLICL;
4278 if (!(t->flags & SN_FINST_MASK))
4279 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004280 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004281 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004282 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4283
4284 /* read timeout : give up with an error message.
4285 */
4286 t->logs.status = 408;
4287 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004288 if (!(t->flags & SN_ERR_MASK))
4289 t->flags |= SN_ERR_CLITO;
4290 if (!(t->flags & SN_FINST_MASK))
4291 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004292 return 1;
4293 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004294
4295 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004296 }
4297 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004298 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004299 /* FIXME: this error handling is partly buggy because we always report
4300 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4301 * or HEADER phase. BTW, it's not logical to expire the client while
4302 * we're waiting for the server to connect.
4303 */
willy tarreau0f7af912005-12-17 12:21:26 +01004304 /* read or write error */
4305 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004306 tv_eternity(&t->crexpire);
4307 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004308 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004309 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004310 if (!(t->flags & SN_ERR_MASK))
4311 t->flags |= SN_ERR_CLICL;
4312 if (!(t->flags & SN_FINST_MASK))
4313 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004314 return 1;
4315 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004316 /* last read, or end of server write */
4317 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004318 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004319 tv_eternity(&t->crexpire);
4320 shutdown(t->cli_fd, SHUT_RD);
4321 t->cli_state = CL_STSHUTR;
4322 return 1;
4323 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004324 /* last server read and buffer empty */
4325 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004326 FD_CLR(t->cli_fd, StaticWriteEvent);
4327 tv_eternity(&t->cwexpire);
4328 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004329 /* We must ensure that the read part is still alive when switching
4330 * to shutw */
4331 FD_SET(t->cli_fd, StaticReadEvent);
4332 if (t->proxy->clitimeout)
4333 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004334 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004335 //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 +01004336 return 1;
4337 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004338 /* read timeout */
4339 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4340 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004341 tv_eternity(&t->crexpire);
4342 shutdown(t->cli_fd, SHUT_RD);
4343 t->cli_state = CL_STSHUTR;
4344 if (!(t->flags & SN_ERR_MASK))
4345 t->flags |= SN_ERR_CLITO;
4346 if (!(t->flags & SN_FINST_MASK))
4347 t->flags |= SN_FINST_D;
4348 return 1;
4349 }
4350 /* write timeout */
4351 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4352 FD_CLR(t->cli_fd, StaticWriteEvent);
4353 tv_eternity(&t->cwexpire);
4354 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004355 /* We must ensure that the read part is still alive when switching
4356 * to shutw */
4357 FD_SET(t->cli_fd, StaticReadEvent);
4358 if (t->proxy->clitimeout)
4359 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4360
willy tarreau036e1ce2005-12-17 13:46:33 +01004361 t->cli_state = CL_STSHUTW;
4362 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004363 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004364 if (!(t->flags & SN_FINST_MASK))
4365 t->flags |= SN_FINST_D;
4366 return 1;
4367 }
willy tarreau0f7af912005-12-17 12:21:26 +01004368
willy tarreauc58fc692005-12-17 14:13:08 +01004369 if (req->l >= req->rlim - req->data) {
4370 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004371 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004372 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004373 FD_CLR(t->cli_fd, StaticReadEvent);
4374 tv_eternity(&t->crexpire);
4375 }
4376 }
4377 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004378 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004379 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4380 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004381 if (!t->proxy->clitimeout ||
4382 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4383 /* If the client has no timeout, or if the server not ready yet, and we
4384 * know for sure that it can expire, then it's cleaner to disable the
4385 * timeout on the client side so that too low values cannot make the
4386 * sessions abort too early.
4387 */
willy tarreau0f7af912005-12-17 12:21:26 +01004388 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004389 else
4390 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004391 }
4392 }
4393
4394 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004395 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004396 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4397 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4398 tv_eternity(&t->cwexpire);
4399 }
4400 }
4401 else { /* buffer not empty */
4402 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4403 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004404 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004405 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004406 /* FIXME: to prevent the client from expiring read timeouts during writes,
4407 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004408 t->crexpire = t->cwexpire;
4409 }
willy tarreau0f7af912005-12-17 12:21:26 +01004410 else
4411 tv_eternity(&t->cwexpire);
4412 }
4413 }
4414 return 0; /* other cases change nothing */
4415 }
4416 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004417 if (t->res_cw == RES_ERROR) {
4418 tv_eternity(&t->cwexpire);
4419 fd_delete(t->cli_fd);
4420 t->cli_state = CL_STCLOSE;
4421 if (!(t->flags & SN_ERR_MASK))
4422 t->flags |= SN_ERR_CLICL;
4423 if (!(t->flags & SN_FINST_MASK))
4424 t->flags |= SN_FINST_D;
4425 return 1;
4426 }
4427 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004428 tv_eternity(&t->cwexpire);
4429 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004430 t->cli_state = CL_STCLOSE;
4431 return 1;
4432 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004433 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4434 tv_eternity(&t->cwexpire);
4435 fd_delete(t->cli_fd);
4436 t->cli_state = CL_STCLOSE;
4437 if (!(t->flags & SN_ERR_MASK))
4438 t->flags |= SN_ERR_CLITO;
4439 if (!(t->flags & SN_FINST_MASK))
4440 t->flags |= SN_FINST_D;
4441 return 1;
4442 }
willy tarreau0f7af912005-12-17 12:21:26 +01004443 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004444 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004445 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4446 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4447 tv_eternity(&t->cwexpire);
4448 }
4449 }
4450 else { /* buffer not empty */
4451 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4452 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004453 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004454 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004455 /* FIXME: to prevent the client from expiring read timeouts during writes,
4456 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004457 t->crexpire = t->cwexpire;
4458 }
willy tarreau0f7af912005-12-17 12:21:26 +01004459 else
4460 tv_eternity(&t->cwexpire);
4461 }
4462 }
4463 return 0;
4464 }
4465 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004466 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004467 tv_eternity(&t->crexpire);
4468 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004469 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004470 if (!(t->flags & SN_ERR_MASK))
4471 t->flags |= SN_ERR_CLICL;
4472 if (!(t->flags & SN_FINST_MASK))
4473 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004474 return 1;
4475 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004476 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4477 tv_eternity(&t->crexpire);
4478 fd_delete(t->cli_fd);
4479 t->cli_state = CL_STCLOSE;
4480 return 1;
4481 }
4482 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4483 tv_eternity(&t->crexpire);
4484 fd_delete(t->cli_fd);
4485 t->cli_state = CL_STCLOSE;
4486 if (!(t->flags & SN_ERR_MASK))
4487 t->flags |= SN_ERR_CLITO;
4488 if (!(t->flags & SN_FINST_MASK))
4489 t->flags |= SN_FINST_D;
4490 return 1;
4491 }
willy tarreauef900ab2005-12-17 12:52:52 +01004492 else if (req->l >= req->rlim - req->data) {
4493 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004494
4495 /* FIXME-20050705: is it possible for a client to maintain a session
4496 * after the timeout by sending more data after it receives a close ?
4497 */
4498
willy tarreau0f7af912005-12-17 12:21:26 +01004499 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004500 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004501 FD_CLR(t->cli_fd, StaticReadEvent);
4502 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004503 //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 +01004504 }
4505 }
4506 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004507 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004508 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4509 FD_SET(t->cli_fd, StaticReadEvent);
4510 if (t->proxy->clitimeout)
4511 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4512 else
4513 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004514 //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 +01004515 }
4516 }
4517 return 0;
4518 }
4519 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004520 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004521 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004522 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 +01004523 write(1, trash, len);
4524 }
4525 return 0;
4526 }
4527 return 0;
4528}
4529
willy tarreaudfece232006-05-02 00:19:57 +02004530/* This function turns the server state into the SV_STCLOSE, and sets
4531 * indicators accordingly. Note that if <status> is 0, no message is
4532 * returned.
4533 */
4534void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4535 t->srv_state = SV_STCLOSE;
4536 if (status > 0) {
4537 t->logs.status = status;
4538 if (t->proxy->mode == PR_MODE_HTTP)
4539 client_return(t, msglen, msg);
4540 }
4541 if (!(t->flags & SN_ERR_MASK))
4542 t->flags |= err;
4543 if (!(t->flags & SN_FINST_MASK))
4544 t->flags |= finst;
4545}
4546
4547/*
4548 * This function checks the retry count during the connect() job.
4549 * It updates the session's srv_state and retries, so that the caller knows
4550 * what it has to do. It uses the last connection error to set the log when
4551 * it expires. It returns 1 when it has expired, and 0 otherwise.
4552 */
4553int srv_count_retry_down(struct session *t, int conn_err) {
4554 /* we are in front of a retryable error */
4555 t->conn_retries--;
4556 if (t->conn_retries < 0) {
4557 /* if not retryable anymore, let's abort */
4558 tv_eternity(&t->cnexpire);
4559 srv_close_with_err(t, conn_err, SN_FINST_C,
4560 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4561
4562 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004563 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004564 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004565 if (may_dequeue_tasks(t->srv, t->proxy))
4566 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004567 return 1;
4568 }
4569 return 0;
4570}
willy tarreau0f7af912005-12-17 12:21:26 +01004571
4572/*
willy tarreaudfece232006-05-02 00:19:57 +02004573 * This function performs the retryable part of the connect() job.
4574 * It updates the session's srv_state and retries, so that the caller knows
4575 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4576 * it needs to redispatch.
4577 */
4578int srv_retryable_connect(struct session *t) {
4579 int conn_err;
4580
4581 /* This loop ensures that we stop before the last retry in case of a
4582 * redispatchable server.
4583 */
4584 do {
4585 /* initiate a connection to the server */
4586 conn_err = connect_server(t);
4587 switch (conn_err) {
4588
4589 case SN_ERR_NONE:
4590 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4591 t->srv_state = SV_STCONN;
4592 return 1;
4593
4594 case SN_ERR_INTERNAL:
4595 tv_eternity(&t->cnexpire);
4596 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4597 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4598 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004599 if (may_dequeue_tasks(t->srv, t->proxy))
4600 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004601 return 1;
4602 }
4603 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004604 if (srv_count_retry_down(t, conn_err)) {
4605 /* let's try to offer this slot to anybody */
4606 if (may_dequeue_tasks(t->srv, t->proxy))
4607 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004608 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004609 }
willy tarreaudfece232006-05-02 00:19:57 +02004610 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4611
4612 /* We're on our last chance, and the REDISP option was specified.
4613 * We will ignore cookie and force to balance or use the dispatcher.
4614 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004615 /* let's try to offer this slot to anybody */
4616 if (may_dequeue_tasks(t->srv, t->proxy))
4617 task_wakeup(&rq, t->srv->queue_mgt);
4618
willy tarreaudfece232006-05-02 00:19:57 +02004619 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4620 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4621 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4622 t->flags &= ~SN_CK_MASK;
4623 t->flags |= SN_CK_DOWN;
4624 }
4625 return 0;
4626}
4627
4628/* This function performs the "redispatch" part of a connection attempt. It
4629 * will assign a server if required, queue the connection if required, and
4630 * handle errors that might arise at this level. It can change the server
4631 * state. It will return 1 if it encounters an error, switches the server
4632 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4633 * that the connection is ready to use.
4634 */
4635
4636int srv_redispatch_connect(struct session *t) {
4637 int conn_err;
4638
4639 /* We know that we don't have any connection pending, so we will
4640 * try to get a new one, and wait in this state if it's queued
4641 */
4642 conn_err = assign_server_and_queue(t);
4643 switch (conn_err) {
4644 case SRV_STATUS_OK:
4645 break;
4646
4647 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004648 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004649 tv_eternity(&t->cnexpire);
4650 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4651 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004652 return 1;
4653
4654 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004655 /* FIXME-20060503 : we should use the queue timeout instead */
4656 if (t->proxy->contimeout)
4657 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4658 else
4659 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004660 t->srv_state = SV_STIDLE;
4661 /* do nothing else and do not wake any other session up */
4662 return 1;
4663
4664 case SRV_STATUS_FULL:
4665 case SRV_STATUS_INTERNAL:
4666 default:
4667 tv_eternity(&t->cnexpire);
4668 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4669 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4670 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004671 if (may_dequeue_tasks(t->srv, t->proxy))
4672 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004673 return 1;
4674 }
4675 /* if we get here, it's because we got SRV_STATUS_OK, which also
4676 * means that the connection has not been queued.
4677 */
4678 return 0;
4679}
4680
4681
4682/*
willy tarreau0f7af912005-12-17 12:21:26 +01004683 * manages the server FSM and its socket. It returns 1 if a state has changed
4684 * (and a resync may be needed), 0 else.
4685 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004686int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004687 int s = t->srv_state;
4688 int c = t->cli_state;
4689 struct buffer *req = t->req;
4690 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004691 appsess *asession_temp = NULL;
4692 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004693 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004694
willy tarreau750a4722005-12-17 13:21:24 +01004695#ifdef DEBUG_FULL
4696 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4697#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004698 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4699 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4700 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4701 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004702 if (s == SV_STIDLE) {
4703 if (c == CL_STHEADERS)
4704 return 0; /* stay in idle, waiting for data to reach the client side */
4705 else if (c == CL_STCLOSE ||
4706 c == CL_STSHUTW ||
4707 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4708 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004709 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
4710
willy tarreau0f7af912005-12-17 12:21:26 +01004711 return 1;
4712 }
willy tarreaudfece232006-05-02 00:19:57 +02004713 else {
4714 /* Right now, we will need to create a connection to the server.
4715 * We might already have tried, and got a connection pending, in
4716 * which case we will not do anything till it's pending. It's up
4717 * to any other session to release it and wake us up again.
4718 */
willy tarreau45526ed2006-05-03 20:11:50 +02004719 if (t->pend_pos) {
4720 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4721 return 0;
4722 else {
4723 /* we've been waiting too long here */
4724 tv_eternity(&t->cnexpire);
4725 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4726 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4727 return 1;
4728 }
4729 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004730
willy tarreaudfece232006-05-02 00:19:57 +02004731 do {
4732 /* first, get a connection */
4733 if (srv_redispatch_connect(t))
4734 return t->srv_state != SV_STIDLE;
4735
4736 /* try to (re-)connect to the server, and fail if we expire the
4737 * number of retries.
4738 */
willy tarreauf32f5242006-05-02 22:54:52 +02004739 if (srv_retryable_connect(t)) {
4740 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004741 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004742 }
willy tarreaudfece232006-05-02 00:19:57 +02004743
4744 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004745 }
4746 }
4747 else if (s == SV_STCONN) { /* connection in progress */
4748 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004749 //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 +01004750 return 0; /* nothing changed */
4751 }
4752 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004753 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004754 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004755
willy tarreau0f7af912005-12-17 12:21:26 +01004756 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004757 if (t->srv)
4758 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004759
4760 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004761 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4762 else
willy tarreaudfece232006-05-02 00:19:57 +02004763 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004764
willy tarreaudfece232006-05-02 00:19:57 +02004765 /* ensure that we have enough retries left */
4766 if (srv_count_retry_down(t, conn_err))
4767 return 1;
4768
4769 do {
4770 /* Now we will try to either reconnect to the same server or
4771 * connect to another server. If the connection gets queued
4772 * because all servers are saturated, then we will go back to
4773 * the SV_STIDLE state.
4774 */
willy tarreauf32f5242006-05-02 22:54:52 +02004775 if (srv_retryable_connect(t)) {
4776 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004777 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004778 }
willy tarreaudfece232006-05-02 00:19:57 +02004779
4780 /* we need to redispatch the connection to another server */
4781 if (srv_redispatch_connect(t))
4782 return t->srv_state != SV_STCONN;
4783 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004784 }
4785 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004786 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004787
willy tarreau0f7af912005-12-17 12:21:26 +01004788 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004789 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004790 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004791 tv_eternity(&t->swexpire);
4792 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004793 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004794 if (t->proxy->srvtimeout) {
4795 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004796 /* FIXME: to prevent the server from expiring read timeouts during writes,
4797 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004798 t->srexpire = t->swexpire;
4799 }
4800 else
4801 tv_eternity(&t->swexpire);
4802 }
willy tarreau0f7af912005-12-17 12:21:26 +01004803
4804 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4805 FD_SET(t->srv_fd, StaticReadEvent);
4806 if (t->proxy->srvtimeout)
4807 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4808 else
4809 tv_eternity(&t->srexpire);
4810
4811 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004812 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004813 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004814
4815 /* if the user wants to log as soon as possible, without counting
4816 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004817 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004818 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4819 sess_log(t);
4820 }
willy tarreau0f7af912005-12-17 12:21:26 +01004821 }
willy tarreauef900ab2005-12-17 12:52:52 +01004822 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004823 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004824 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004825 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4826 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004827 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004828 return 1;
4829 }
4830 }
4831 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004832 /* now parse the partial (or complete) headers */
4833 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4834 char *ptr;
4835 int delete_header;
4836
4837 ptr = rep->lr;
4838
4839 /* look for the end of the current header */
4840 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4841 ptr++;
4842
4843 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004844 int line, len;
4845
4846 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004847
4848 /* first, we'll block if security checks have caught nasty things */
4849 if (t->flags & SN_CACHEABLE) {
4850 if ((t->flags & SN_CACHE_COOK) &&
4851 (t->flags & SN_SCK_ANY) &&
4852 (t->proxy->options & PR_O_CHK_CACHE)) {
4853
4854 /* we're in presence of a cacheable response containing
4855 * a set-cookie header. We'll block it as requested by
4856 * the 'checkcache' option, and send an alert.
4857 */
4858 tv_eternity(&t->srexpire);
4859 tv_eternity(&t->swexpire);
4860 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004861 if (t->srv)
4862 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004863 t->srv_state = SV_STCLOSE;
4864 t->logs.status = 502;
4865 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4866 if (!(t->flags & SN_ERR_MASK))
4867 t->flags |= SN_ERR_PRXCOND;
4868 if (!(t->flags & SN_FINST_MASK))
4869 t->flags |= SN_FINST_H;
4870
4871 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4872 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4873
willy tarreaudfece232006-05-02 00:19:57 +02004874 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004875 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004876 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004877 if (may_dequeue_tasks(t->srv, t->proxy))
4878 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004879
willy tarreau97f58572005-12-18 00:53:44 +01004880 return 1;
4881 }
4882 }
4883
willy tarreau982249e2005-12-18 00:57:06 +01004884 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4885 if (t->flags & SN_SVDENY) {
4886 tv_eternity(&t->srexpire);
4887 tv_eternity(&t->swexpire);
4888 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004889 if (t->srv)
4890 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004891 t->srv_state = SV_STCLOSE;
4892 t->logs.status = 502;
4893 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4894 if (!(t->flags & SN_ERR_MASK))
4895 t->flags |= SN_ERR_PRXCOND;
4896 if (!(t->flags & SN_FINST_MASK))
4897 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004898 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004899 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004900 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004901 if (may_dequeue_tasks(t->srv, t->proxy))
4902 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004903
willy tarreau982249e2005-12-18 00:57:06 +01004904 return 1;
4905 }
4906
willy tarreau5cbea6f2005-12-17 12:48:26 +01004907 /* we'll have something else to do here : add new headers ... */
4908
willy tarreaucd878942005-12-17 13:27:43 +01004909 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4910 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004912 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02004913 * requests and this one isn't. Note that servers which don't have cookies
4914 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004915 */
willy tarreau750a4722005-12-17 13:21:24 +01004916 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004917 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02004918 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01004919
willy tarreau036e1ce2005-12-17 13:46:33 +01004920 t->flags |= SN_SCK_INSERTED;
4921
willy tarreau750a4722005-12-17 13:21:24 +01004922 /* Here, we will tell an eventual cache on the client side that we don't
4923 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4924 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4925 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4926 */
willy tarreau240afa62005-12-17 13:14:35 +01004927 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004928 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4929 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004930
4931 if (rep->data + rep->l < rep->h)
4932 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4933 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004934 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004935 }
4936
4937 /* headers to be added */
4938 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004939 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4940 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 }
4942
willy tarreau25c4ea52005-12-18 00:49:49 +01004943 /* add a "connection: close" line if needed */
4944 if (t->proxy->options & PR_O_HTTP_CLOSE)
4945 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4946
willy tarreau5cbea6f2005-12-17 12:48:26 +01004947 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004948 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004949 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004950
Willy TARREAU767ba712006-03-01 22:40:50 +01004951 /* client connection already closed or option 'httpclose' required :
4952 * we close the server's outgoing connection right now.
4953 */
4954 if ((req->l == 0) &&
4955 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4956 FD_CLR(t->srv_fd, StaticWriteEvent);
4957 tv_eternity(&t->swexpire);
4958
4959 /* We must ensure that the read part is still alive when switching
4960 * to shutw */
4961 FD_SET(t->srv_fd, StaticReadEvent);
4962 if (t->proxy->srvtimeout)
4963 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4964
4965 shutdown(t->srv_fd, SHUT_WR);
4966 t->srv_state = SV_STSHUTW;
4967 }
4968
willy tarreau25c4ea52005-12-18 00:49:49 +01004969 /* if the user wants to log as soon as possible, without counting
4970 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004971 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004972 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4973 t->logs.bytes = rep->h - rep->data;
4974 sess_log(t);
4975 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004976 break;
4977 }
4978
4979 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4980 if (ptr > rep->r - 2) {
4981 /* this is a partial header, let's wait for more to come */
4982 rep->lr = ptr;
4983 break;
4984 }
4985
4986 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4987 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4988
4989 /* now we know that *ptr is either \r or \n,
4990 * and that there are at least 1 char after it.
4991 */
4992 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4993 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4994 else
4995 rep->lr = ptr + 2; /* \r\n or \n\r */
4996
4997 /*
4998 * now we know that we have a full header ; we can do whatever
4999 * we want with these pointers :
5000 * rep->h = beginning of header
5001 * ptr = end of header (first \r or \n)
5002 * rep->lr = beginning of next line (next rep->h)
5003 * rep->r = end of data (not used at this stage)
5004 */
5005
willy tarreaua1598082005-12-17 13:08:06 +01005006
willy tarreau982249e2005-12-18 00:57:06 +01005007 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005008 t->logs.logwait &= ~LW_RESP;
5009 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005010 switch (t->logs.status) {
5011 case 200:
5012 case 203:
5013 case 206:
5014 case 300:
5015 case 301:
5016 case 410:
5017 /* RFC2616 @13.4:
5018 * "A response received with a status code of
5019 * 200, 203, 206, 300, 301 or 410 MAY be stored
5020 * by a cache (...) unless a cache-control
5021 * directive prohibits caching."
5022 *
5023 * RFC2616 @9.5: POST method :
5024 * "Responses to this method are not cacheable,
5025 * unless the response includes appropriate
5026 * Cache-Control or Expires header fields."
5027 */
5028 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5029 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5030 break;
5031 default:
5032 break;
5033 }
willy tarreau4302f492005-12-18 01:00:37 +01005034 }
5035 else if (t->logs.logwait & LW_RSPHDR) {
5036 struct cap_hdr *h;
5037 int len;
5038 for (h = t->proxy->rsp_cap; h; h = h->next) {
5039 if ((h->namelen + 2 <= ptr - rep->h) &&
5040 (rep->h[h->namelen] == ':') &&
5041 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5042
5043 if (t->rsp_cap[h->index] == NULL)
5044 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5045
5046 len = ptr - (rep->h + h->namelen + 2);
5047 if (len > h->len)
5048 len = h->len;
5049
5050 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5051 t->rsp_cap[h->index][len]=0;
5052 }
5053 }
5054
willy tarreaua1598082005-12-17 13:08:06 +01005055 }
5056
willy tarreau5cbea6f2005-12-17 12:48:26 +01005057 delete_header = 0;
5058
willy tarreau982249e2005-12-18 00:57:06 +01005059 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005061 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 +01005062 max = ptr - rep->h;
5063 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005064 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005065 trash[len++] = '\n';
5066 write(1, trash, len);
5067 }
5068
willy tarreau25c4ea52005-12-18 00:49:49 +01005069 /* remove "connection: " if needed */
5070 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5071 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5072 delete_header = 1;
5073 }
5074
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005076 if (!delete_header && t->proxy->rsp_exp != NULL
5077 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005078 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 char term;
5080
5081 term = *ptr;
5082 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005083 exp = t->proxy->rsp_exp;
5084 do {
5085 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5086 switch (exp->action) {
5087 case ACT_ALLOW:
5088 if (!(t->flags & SN_SVDENY))
5089 t->flags |= SN_SVALLOW;
5090 break;
5091 case ACT_REPLACE:
5092 if (!(t->flags & SN_SVDENY)) {
5093 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5094 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5095 }
5096 break;
5097 case ACT_REMOVE:
5098 if (!(t->flags & SN_SVDENY))
5099 delete_header = 1;
5100 break;
5101 case ACT_DENY:
5102 if (!(t->flags & SN_SVALLOW))
5103 t->flags |= SN_SVDENY;
5104 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005105 case ACT_PASS: /* we simply don't deny this one */
5106 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005107 }
5108 break;
5109 }
willy tarreaue39cd132005-12-17 13:00:18 +01005110 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005111 *ptr = term; /* restore the string terminator */
5112 }
5113
willy tarreau97f58572005-12-18 00:53:44 +01005114 /* check for cache-control: or pragma: headers */
5115 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5116 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5117 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5118 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5119 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005120 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005121 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5122 else {
5123 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005124 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005125 t->flags &= ~SN_CACHE_COOK;
5126 }
5127 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005128 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005129 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005130 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005131 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5132 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005133 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005134 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005135 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5136 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5137 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5138 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5139 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5140 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005141 }
5142 }
5143 }
5144
willy tarreau5cbea6f2005-12-17 12:48:26 +01005145 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005146 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005147 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005148 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149 char *p1, *p2, *p3, *p4;
5150
willy tarreau97f58572005-12-18 00:53:44 +01005151 t->flags |= SN_SCK_ANY;
5152
willy tarreau5cbea6f2005-12-17 12:48:26 +01005153 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5154
5155 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005156 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005157 p1++;
5158
5159 if (p1 == ptr || *p1 == ';') /* end of cookie */
5160 break;
5161
5162 /* p1 is at the beginning of the cookie name */
5163 p2 = p1;
5164
5165 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5166 p2++;
5167
5168 if (p2 == ptr || *p2 == ';') /* next cookie */
5169 break;
5170
5171 p3 = p2 + 1; /* skips the '=' sign */
5172 if (p3 == ptr)
5173 break;
5174
5175 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005176 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005177 p4++;
5178
5179 /* here, we have the cookie name between p1 and p2,
5180 * and its value between p3 and p4.
5181 * we can process it.
5182 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005183
5184 /* first, let's see if we want to capture it */
5185 if (t->proxy->capture_name != NULL &&
5186 t->logs.srv_cookie == NULL &&
5187 (p4 - p1 >= t->proxy->capture_namelen) &&
5188 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5189 int log_len = p4 - p1;
5190
5191 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5192 Alert("HTTP logging : out of memory.\n");
5193 }
5194
5195 if (log_len > t->proxy->capture_len)
5196 log_len = t->proxy->capture_len;
5197 memcpy(t->logs.srv_cookie, p1, log_len);
5198 t->logs.srv_cookie[log_len] = 0;
5199 }
5200
5201 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5202 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005203 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005204 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005205
5206 /* If the cookie is in insert mode on a known server, we'll delete
5207 * this occurrence because we'll insert another one later.
5208 * We'll delete it too if the "indirect" option is set and we're in
5209 * a direct access. */
5210 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005211 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005212 /* this header must be deleted */
5213 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005214 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005215 }
5216 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5217 /* replace bytes p3->p4 with the cookie name associated
5218 * with this server since we know it.
5219 */
5220 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005221 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005222 }
willy tarreau0174f312005-12-18 01:02:42 +01005223 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5224 /* insert the cookie name associated with this server
5225 * before existing cookie, and insert a delimitor between them..
5226 */
5227 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5228 p3[t->srv->cklen] = COOKIE_DELIM;
5229 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5230 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005231 break;
5232 }
willy tarreau12350152005-12-18 01:03:27 +01005233
5234 /* first, let's see if the cookie is our appcookie*/
5235 if ((t->proxy->appsession_name != NULL) &&
5236 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5237
5238 /* Cool... it's the right one */
5239
willy tarreaub952e1d2005-12-18 01:31:20 +01005240 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005241 asession_temp = &local_asession;
5242
willy tarreaub952e1d2005-12-18 01:31:20 +01005243 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005244 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5245 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5246 }
5247 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5248 asession_temp->sessid[t->proxy->appsession_len] = 0;
5249 asession_temp->serverid = NULL;
5250
5251 /* only do insert, if lookup fails */
5252 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5253 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5254 Alert("Not enought Memory process_srv():asession:calloc().\n");
5255 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5256 return 0;
5257 }
5258 asession_temp->sessid = local_asession.sessid;
5259 asession_temp->serverid = local_asession.serverid;
5260 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005261 }/* end if (chtbl_lookup()) */
5262 else {
willy tarreau12350152005-12-18 01:03:27 +01005263 /* free wasted memory */
5264 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005265 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005266
willy tarreaub952e1d2005-12-18 01:31:20 +01005267 if (asession_temp->serverid == NULL) {
5268 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005269 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5270 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5271 }
5272 asession_temp->serverid[0] = '\0';
5273 }
5274
willy tarreaub952e1d2005-12-18 01:31:20 +01005275 if (asession_temp->serverid[0] == '\0')
5276 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005277
5278 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5279
5280#if defined(DEBUG_HASH)
5281 print_table(&(t->proxy->htbl_proxy));
5282#endif
5283 break;
5284 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 else {
5286 // fprintf(stderr,"Ignoring unknown cookie : ");
5287 // write(2, p1, p2-p1);
5288 // fprintf(stderr," = ");
5289 // write(2, p3, p4-p3);
5290 // fprintf(stderr,"\n");
5291 }
5292 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5293 } /* we're now at the end of the cookie value */
5294 } /* end of cookie processing */
5295
willy tarreau97f58572005-12-18 00:53:44 +01005296 /* check for any set-cookie in case we check for cacheability */
5297 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5298 (t->proxy->options & PR_O_CHK_CACHE) &&
5299 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5300 t->flags |= SN_SCK_ANY;
5301 }
5302
willy tarreau5cbea6f2005-12-17 12:48:26 +01005303 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005304 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005305 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005306
willy tarreau5cbea6f2005-12-17 12:48:26 +01005307 rep->h = rep->lr;
5308 } /* while (rep->lr < rep->r) */
5309
5310 /* end of header processing (even if incomplete) */
5311
willy tarreauef900ab2005-12-17 12:52:52 +01005312 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5313 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5314 * full. We cannot loop here since event_srv_read will disable it only if
5315 * rep->l == rlim-data
5316 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005317 FD_SET(t->srv_fd, StaticReadEvent);
5318 if (t->proxy->srvtimeout)
5319 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5320 else
5321 tv_eternity(&t->srexpire);
5322 }
willy tarreau0f7af912005-12-17 12:21:26 +01005323
willy tarreau8337c6b2005-12-17 13:41:01 +01005324 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005325 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005326 tv_eternity(&t->srexpire);
5327 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005328 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005329 if (t->srv)
5330 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005331 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005332 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005333 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005334 if (!(t->flags & SN_ERR_MASK))
5335 t->flags |= SN_ERR_SRVCL;
5336 if (!(t->flags & SN_FINST_MASK))
5337 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005338 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005339 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005340 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005341 if (may_dequeue_tasks(t->srv, t->proxy))
5342 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005343
willy tarreau0f7af912005-12-17 12:21:26 +01005344 return 1;
5345 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005346 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005347 * since we are in header mode, if there's no space left for headers, we
5348 * won't be able to free more later, so the session will never terminate.
5349 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005350 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 +01005351 FD_CLR(t->srv_fd, StaticReadEvent);
5352 tv_eternity(&t->srexpire);
5353 shutdown(t->srv_fd, SHUT_RD);
5354 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005355 //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 +01005356 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005357 }
5358 /* read timeout : return a 504 to the client.
5359 */
5360 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5361 tv_eternity(&t->srexpire);
5362 tv_eternity(&t->swexpire);
5363 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005364 if (t->srv)
5365 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005366 t->srv_state = SV_STCLOSE;
5367 t->logs.status = 504;
5368 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005369 if (!(t->flags & SN_ERR_MASK))
5370 t->flags |= SN_ERR_SRVTO;
5371 if (!(t->flags & SN_FINST_MASK))
5372 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005373 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005374 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005375 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005376 if (may_dequeue_tasks(t->srv, t->proxy))
5377 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005378
willy tarreau8337c6b2005-12-17 13:41:01 +01005379 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005380 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005381 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005382 /* FIXME!!! here, we don't want to switch to SHUTW if the
5383 * client shuts read too early, because we may still have
5384 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005385 * The side-effect is that if the client completely closes its
5386 * connection during SV_STHEADER, the connection to the server
5387 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005388 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005389 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005390 FD_CLR(t->srv_fd, StaticWriteEvent);
5391 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005392
5393 /* 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
willy tarreau0f7af912005-12-17 12:21:26 +01005399 shutdown(t->srv_fd, SHUT_WR);
5400 t->srv_state = SV_STSHUTW;
5401 return 1;
5402 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005403 /* write timeout */
5404 /* FIXME!!! here, we don't want to switch to SHUTW if the
5405 * client shuts read too early, because we may still have
5406 * some work to do on the headers.
5407 */
5408 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5409 FD_CLR(t->srv_fd, StaticWriteEvent);
5410 tv_eternity(&t->swexpire);
5411 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005412 /* We must ensure that the read part is still alive when switching
5413 * to shutw */
5414 FD_SET(t->srv_fd, StaticReadEvent);
5415 if (t->proxy->srvtimeout)
5416 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5417
5418 /* We must ensure that the read part is still alive when switching
5419 * to shutw */
5420 FD_SET(t->srv_fd, StaticReadEvent);
5421 if (t->proxy->srvtimeout)
5422 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5423
willy tarreau036e1ce2005-12-17 13:46:33 +01005424 t->srv_state = SV_STSHUTW;
5425 if (!(t->flags & SN_ERR_MASK))
5426 t->flags |= SN_ERR_SRVTO;
5427 if (!(t->flags & SN_FINST_MASK))
5428 t->flags |= SN_FINST_H;
5429 return 1;
5430 }
willy tarreau0f7af912005-12-17 12:21:26 +01005431
5432 if (req->l == 0) {
5433 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5434 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5435 tv_eternity(&t->swexpire);
5436 }
5437 }
5438 else { /* client buffer not empty */
5439 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5440 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005441 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005442 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005443 /* FIXME: to prevent the server from expiring read timeouts during writes,
5444 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005445 t->srexpire = t->swexpire;
5446 }
willy tarreau0f7af912005-12-17 12:21:26 +01005447 else
5448 tv_eternity(&t->swexpire);
5449 }
5450 }
5451
willy tarreau5cbea6f2005-12-17 12:48:26 +01005452 /* be nice with the client side which would like to send a complete header
5453 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5454 * would read all remaining data at once ! The client should not write past rep->lr
5455 * when the server is in header state.
5456 */
5457 //return header_processed;
5458 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005459 }
5460 else if (s == SV_STDATA) {
5461 /* read or write error */
5462 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005463 tv_eternity(&t->srexpire);
5464 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005465 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005466 if (t->srv)
5467 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005468 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005469 if (!(t->flags & SN_ERR_MASK))
5470 t->flags |= SN_ERR_SRVCL;
5471 if (!(t->flags & SN_FINST_MASK))
5472 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005473 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005474 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005475 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005476 if (may_dequeue_tasks(t->srv, t->proxy))
5477 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005478
willy tarreau0f7af912005-12-17 12:21:26 +01005479 return 1;
5480 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005481 /* last read, or end of client write */
5482 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005483 FD_CLR(t->srv_fd, StaticReadEvent);
5484 tv_eternity(&t->srexpire);
5485 shutdown(t->srv_fd, SHUT_RD);
5486 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005487 //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 +01005488 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005489 }
5490 /* end of client read and no more data to send */
5491 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5492 FD_CLR(t->srv_fd, StaticWriteEvent);
5493 tv_eternity(&t->swexpire);
5494 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005495 /* We must ensure that the read part is still alive when switching
5496 * to shutw */
5497 FD_SET(t->srv_fd, StaticReadEvent);
5498 if (t->proxy->srvtimeout)
5499 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5500
willy tarreaua41a8b42005-12-17 14:02:24 +01005501 t->srv_state = SV_STSHUTW;
5502 return 1;
5503 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005504 /* read timeout */
5505 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5506 FD_CLR(t->srv_fd, StaticReadEvent);
5507 tv_eternity(&t->srexpire);
5508 shutdown(t->srv_fd, SHUT_RD);
5509 t->srv_state = SV_STSHUTR;
5510 if (!(t->flags & SN_ERR_MASK))
5511 t->flags |= SN_ERR_SRVTO;
5512 if (!(t->flags & SN_FINST_MASK))
5513 t->flags |= SN_FINST_D;
5514 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005515 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005516 /* write timeout */
5517 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005518 FD_CLR(t->srv_fd, StaticWriteEvent);
5519 tv_eternity(&t->swexpire);
5520 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005521 /* We must ensure that the read part is still alive when switching
5522 * to shutw */
5523 FD_SET(t->srv_fd, StaticReadEvent);
5524 if (t->proxy->srvtimeout)
5525 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005526 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005527 if (!(t->flags & SN_ERR_MASK))
5528 t->flags |= SN_ERR_SRVTO;
5529 if (!(t->flags & SN_FINST_MASK))
5530 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005531 return 1;
5532 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005533
5534 /* recompute request time-outs */
5535 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005536 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5537 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5538 tv_eternity(&t->swexpire);
5539 }
5540 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005541 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005542 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5543 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005544 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005545 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005546 /* FIXME: to prevent the server from expiring read timeouts during writes,
5547 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005548 t->srexpire = t->swexpire;
5549 }
willy tarreau0f7af912005-12-17 12:21:26 +01005550 else
5551 tv_eternity(&t->swexpire);
5552 }
5553 }
5554
willy tarreaub1ff9db2005-12-17 13:51:03 +01005555 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005556 if (rep->l == BUFSIZE) { /* no room to read more data */
5557 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5558 FD_CLR(t->srv_fd, StaticReadEvent);
5559 tv_eternity(&t->srexpire);
5560 }
5561 }
5562 else {
5563 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5564 FD_SET(t->srv_fd, StaticReadEvent);
5565 if (t->proxy->srvtimeout)
5566 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5567 else
5568 tv_eternity(&t->srexpire);
5569 }
5570 }
5571
5572 return 0; /* other cases change nothing */
5573 }
5574 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005575 if (t->res_sw == RES_ERROR) {
5576 //FD_CLR(t->srv_fd, StaticWriteEvent);
5577 tv_eternity(&t->swexpire);
5578 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005579 if (t->srv)
5580 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005581 //close(t->srv_fd);
5582 t->srv_state = SV_STCLOSE;
5583 if (!(t->flags & SN_ERR_MASK))
5584 t->flags |= SN_ERR_SRVCL;
5585 if (!(t->flags & SN_FINST_MASK))
5586 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005587 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005588 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005589 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005590 if (may_dequeue_tasks(t->srv, t->proxy))
5591 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005592
willy tarreau036e1ce2005-12-17 13:46:33 +01005593 return 1;
5594 }
5595 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005596 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005597 tv_eternity(&t->swexpire);
5598 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005599 if (t->srv)
5600 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005601 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005602 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005603 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005604 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005605 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005606 if (may_dequeue_tasks(t->srv, t->proxy))
5607 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005608
willy tarreau0f7af912005-12-17 12:21:26 +01005609 return 1;
5610 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005611 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5612 //FD_CLR(t->srv_fd, StaticWriteEvent);
5613 tv_eternity(&t->swexpire);
5614 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005615 if (t->srv)
5616 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005617 //close(t->srv_fd);
5618 t->srv_state = SV_STCLOSE;
5619 if (!(t->flags & SN_ERR_MASK))
5620 t->flags |= SN_ERR_SRVTO;
5621 if (!(t->flags & SN_FINST_MASK))
5622 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005623 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005624 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005625 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005626 if (may_dequeue_tasks(t->srv, t->proxy))
5627 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005628
willy tarreau036e1ce2005-12-17 13:46:33 +01005629 return 1;
5630 }
willy tarreau0f7af912005-12-17 12:21:26 +01005631 else if (req->l == 0) {
5632 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5633 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5634 tv_eternity(&t->swexpire);
5635 }
5636 }
5637 else { /* buffer not empty */
5638 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5639 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005640 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005641 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005642 /* FIXME: to prevent the server from expiring read timeouts during writes,
5643 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005644 t->srexpire = t->swexpire;
5645 }
willy tarreau0f7af912005-12-17 12:21:26 +01005646 else
5647 tv_eternity(&t->swexpire);
5648 }
5649 }
5650 return 0;
5651 }
5652 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005653 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005654 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005655 tv_eternity(&t->srexpire);
5656 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005657 if (t->srv)
5658 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005659 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005660 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005661 if (!(t->flags & SN_ERR_MASK))
5662 t->flags |= SN_ERR_SRVCL;
5663 if (!(t->flags & SN_FINST_MASK))
5664 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005665 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005666 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005667 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005668 if (may_dequeue_tasks(t->srv, t->proxy))
5669 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005670
willy tarreau0f7af912005-12-17 12:21:26 +01005671 return 1;
5672 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005673 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5674 //FD_CLR(t->srv_fd, StaticReadEvent);
5675 tv_eternity(&t->srexpire);
5676 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005677 if (t->srv)
5678 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005679 //close(t->srv_fd);
5680 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005681 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005682 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005683 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005684 if (may_dequeue_tasks(t->srv, t->proxy))
5685 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005686
willy tarreau036e1ce2005-12-17 13:46:33 +01005687 return 1;
5688 }
5689 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5690 //FD_CLR(t->srv_fd, StaticReadEvent);
5691 tv_eternity(&t->srexpire);
5692 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005693 if (t->srv)
5694 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005695 //close(t->srv_fd);
5696 t->srv_state = SV_STCLOSE;
5697 if (!(t->flags & SN_ERR_MASK))
5698 t->flags |= SN_ERR_SRVTO;
5699 if (!(t->flags & SN_FINST_MASK))
5700 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005701 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005702 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005703 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005704 if (may_dequeue_tasks(t->srv, t->proxy))
5705 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005706
willy tarreau036e1ce2005-12-17 13:46:33 +01005707 return 1;
5708 }
willy tarreau0f7af912005-12-17 12:21:26 +01005709 else if (rep->l == BUFSIZE) { /* no room to read more data */
5710 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5711 FD_CLR(t->srv_fd, StaticReadEvent);
5712 tv_eternity(&t->srexpire);
5713 }
5714 }
5715 else {
5716 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5717 FD_SET(t->srv_fd, StaticReadEvent);
5718 if (t->proxy->srvtimeout)
5719 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5720 else
5721 tv_eternity(&t->srexpire);
5722 }
5723 }
5724 return 0;
5725 }
5726 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005727 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005728 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005729 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 +01005730 write(1, trash, len);
5731 }
5732 return 0;
5733 }
5734 return 0;
5735}
5736
5737
willy tarreau5cbea6f2005-12-17 12:48:26 +01005738/* Processes the client and server jobs of a session task, then
5739 * puts it back to the wait queue in a clean state, or
5740 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005741 * the time the task accepts to wait, or TIME_ETERNITY for
5742 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005743 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005744int process_session(struct task *t) {
5745 struct session *s = t->context;
5746 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005747
willy tarreau5cbea6f2005-12-17 12:48:26 +01005748 do {
5749 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005750 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005751 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005752 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005753 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005754 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005755 } while (fsm_resync);
5756
5757 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005758 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005759 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005760
willy tarreau5cbea6f2005-12-17 12:48:26 +01005761 tv_min(&min1, &s->crexpire, &s->cwexpire);
5762 tv_min(&min2, &s->srexpire, &s->swexpire);
5763 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005764 tv_min(&t->expire, &min1, &min2);
5765
5766 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005767 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005768
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005769#ifdef DEBUG_FULL
5770 /* DEBUG code : this should never ever happen, otherwise it indicates
5771 * that a task still has something to do and will provoke a quick loop.
5772 */
5773 if (tv_remain2(&now, &t->expire) <= 0)
5774 exit(100);
5775#endif
5776
willy tarreaub952e1d2005-12-18 01:31:20 +01005777 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005778 }
5779
willy tarreau5cbea6f2005-12-17 12:48:26 +01005780 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005781 actconn--;
5782
willy tarreau982249e2005-12-18 00:57:06 +01005783 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005784 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005785 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 +01005786 write(1, trash, len);
5787 }
5788
willy tarreau750a4722005-12-17 13:21:24 +01005789 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005790 if (s->rep != NULL)
5791 s->logs.bytes = s->rep->total;
5792
willy tarreau9fe663a2005-12-17 13:02:59 +01005793 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005794 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005795 sess_log(s);
5796
willy tarreau0f7af912005-12-17 12:21:26 +01005797 /* the task MUST not be in the run queue anymore */
5798 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005799 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005800 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005801 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005802}
5803
5804
willy tarreau2812edc2006-05-04 12:09:37 +02005805/* Sets server <s> down, notifies by all available means, recounts the
5806 * remaining servers on the proxy and transfers queued sessions whenever
5807 * possible to other servers.
5808 */
5809void set_server_down(struct server *s) {
5810 struct pendconn *pc, *pc_bck, *pc_end;
5811 struct session *sess;
5812 int xferred;
5813
5814 s->state &= ~SRV_RUNNING;
5815
5816 if (s->health == s->rise) {
5817 recount_servers(s->proxy);
5818 recalc_server_map(s->proxy);
5819
5820 /* we might have sessions queued on this server and waiting for
5821 * a connection. Those which are redispatchable will be queued
5822 * to another server or to the proxy itself.
5823 */
5824 xferred = 0;
5825 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5826 sess = pc->sess;
5827 if ((sess->proxy->options & PR_O_REDISP)) {
5828 /* The REDISP option was specified. We will ignore
5829 * cookie and force to balance or use the dispatcher.
5830 */
5831 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5832 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5833 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5834 sess->flags &= ~SN_CK_MASK;
5835 sess->flags |= SN_CK_DOWN;
5836 }
5837 pendconn_free(pc);
5838 task_wakeup(&rq, sess->task);
5839 xferred++;
5840 }
5841 }
5842
5843 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5844 " %d sessions active, %d requeued, %d remaining in queue.\n",
5845 s->state & SRV_BACKUP ? "Backup " : "",
5846 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5847 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5848 s->cur_sess, xferred, s->nbpend);
5849
willy tarreaubc2eda62006-05-04 15:16:23 +02005850 Warning("%s", trash);
5851 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005852
5853 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5854 Alert("Proxy %s has no server available !\n", s->proxy->id);
5855 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5856 }
5857 }
5858 s->health = 0; /* failure */
5859}
5860
5861
willy tarreau5cbea6f2005-12-17 12:48:26 +01005862
5863/*
5864 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005865 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005866 */
5867int process_chk(struct task *t) {
5868 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005869 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005870 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005871
willy tarreauef900ab2005-12-17 12:52:52 +01005872 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005873
willy tarreau25424f82006-03-19 19:37:48 +01005874 new_chk:
5875 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005876 if (fd < 0) { /* no check currently running */
5877 //fprintf(stderr, "process_chk: 2\n");
5878 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5879 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005880 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005881 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005882
5883 /* we don't send any health-checks when the proxy is stopped or when
5884 * the server should not be checked.
5885 */
5886 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005887 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5888 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005889 task_queue(t); /* restore t to its place in the task list */
5890 return tv_remain2(&now, &t->expire);
5891 }
5892
willy tarreau5cbea6f2005-12-17 12:48:26 +01005893 /* we'll initiate a new check */
5894 s->result = 0; /* no result yet */
5895 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005896 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005897 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5898 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5899 //fprintf(stderr, "process_chk: 3\n");
5900
willy tarreaua41a8b42005-12-17 14:02:24 +01005901 /* we'll connect to the check port on the server */
5902 sa = s->addr;
5903 sa.sin_port = htons(s->check_port);
5904
willy tarreau0174f312005-12-18 01:02:42 +01005905 /* allow specific binding :
5906 * - server-specific at first
5907 * - proxy-specific next
5908 */
5909 if (s->state & SRV_BIND_SRC) {
5910 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5911 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5912 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5913 s->proxy->id, s->id);
5914 s->result = -1;
5915 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005916 }
willy tarreau0174f312005-12-18 01:02:42 +01005917 else if (s->proxy->options & PR_O_BIND_SRC) {
5918 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5919 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5920 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5921 s->proxy->id);
5922 s->result = -1;
5923 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005924 }
willy tarreau0174f312005-12-18 01:02:42 +01005925
5926 if (!s->result) {
5927 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5928 /* OK, connection in progress or established */
5929
5930 //fprintf(stderr, "process_chk: 4\n");
5931
5932 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5933 fdtab[fd].owner = t;
5934 fdtab[fd].read = &event_srv_chk_r;
5935 fdtab[fd].write = &event_srv_chk_w;
5936 fdtab[fd].state = FD_STCONN; /* connection in progress */
5937 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005938#ifdef DEBUG_FULL
5939 assert (!FD_ISSET(fd, StaticReadEvent));
5940#endif
willy tarreau0174f312005-12-18 01:02:42 +01005941 fd_insert(fd);
5942 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5943 tv_delayfrom(&t->expire, &now, s->inter);
5944 task_queue(t); /* restore t to its place in the task list */
5945 return tv_remain(&now, &t->expire);
5946 }
5947 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5948 s->result = -1; /* a real error */
5949 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005950 }
5951 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005952 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005953 }
5954
5955 if (!s->result) { /* nothing done */
5956 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005957 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5958 tv_delayfrom(&t->expire, &t->expire, s->inter);
5959 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005960 }
5961
5962 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005963 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005964 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02005965 else
5966 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005967
5968 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005969 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005970 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5971 tv_delayfrom(&t->expire, &t->expire, s->inter);
5972 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005973 }
5974 else {
5975 //fprintf(stderr, "process_chk: 8\n");
5976 /* there was a test running */
5977 if (s->result > 0) { /* good server detected */
5978 //fprintf(stderr, "process_chk: 9\n");
5979 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005980 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005981 s->state |= SRV_RUNNING;
5982
willy tarreau535ae7a2005-12-17 12:58:00 +01005983 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02005984 int xferred;
5985
willy tarreau62084d42006-03-24 18:57:41 +01005986 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005987 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02005988
5989 /* check if we can handle some connections queued at the proxy. We
5990 * will take as many as we can handle.
5991 */
5992 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
5993 struct session *sess;
5994 struct pendconn *p;
5995
5996 p = pendconn_from_px(s->proxy);
5997 if (!p)
5998 break;
5999 p->sess->srv = s;
6000 sess = p->sess;
6001 pendconn_free(p);
6002 task_wakeup(&rq, sess->task);
6003 }
6004
6005 sprintf(trash,
6006 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6007 " %d sessions requeued, %d total in queue.\n",
6008 s->state & SRV_BACKUP ? "Backup " : "",
6009 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6010 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6011 xferred, s->nbpend);
6012
6013 Warning("%s", trash);
6014 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006015 }
willy tarreauef900ab2005-12-17 12:52:52 +01006016
willy tarreaue47c8d72005-12-17 12:55:52 +01006017 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006018 }
willy tarreauef900ab2005-12-17 12:52:52 +01006019 s->curfd = -1; /* no check running anymore */
6020 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006021 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006022 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6023 tv_delayfrom(&t->expire, &t->expire, s->inter);
6024 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006025 }
6026 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6027 //fprintf(stderr, "process_chk: 10\n");
6028 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006029 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006030 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006031 else
6032 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006033 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006034 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006035 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006036 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6037 tv_delayfrom(&t->expire, &t->expire, s->inter);
6038 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006039 }
6040 /* if result is 0 and there's no timeout, we have to wait again */
6041 }
6042 //fprintf(stderr, "process_chk: 11\n");
6043 s->result = 0;
6044 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006045 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006046}
6047
6048
willy tarreau5cbea6f2005-12-17 12:48:26 +01006049
willy tarreau59a6cc22006-05-12 01:29:08 +02006050/*
6051 * Manages a server's connection queue. If woken up, will try to dequeue as
6052 * many pending sessions as possible, and wake them up. The task has nothing
6053 * else to do, so it always returns TIME_ETERNITY.
6054 */
6055int process_srv_queue(struct task *t) {
6056 struct server *s = (struct server*)t->context;
6057 struct proxy *p = s->proxy;
6058 int xferred;
6059
6060 /* First, check if we can handle some connections queued at the proxy. We
6061 * will take as many as we can handle.
6062 */
6063 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6064 struct session *sess;
6065
6066 sess = pendconn_get_next_sess(s, p);
6067 if (sess == NULL)
6068 break;
6069 task_wakeup(&rq, sess->task);
6070 }
6071
6072 return TIME_ETERNITY;
6073}
6074
willy tarreau0f7af912005-12-17 12:21:26 +01006075#if STATTIME > 0
6076int stats(void);
6077#endif
6078
6079/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006080 * This does 4 things :
6081 * - wake up all expired tasks
6082 * - call all runnable tasks
6083 * - call maintain_proxies() to enable/disable the listeners
6084 * - return the delay till next event in ms, -1 = wait indefinitely
6085 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6086 *
willy tarreau0f7af912005-12-17 12:21:26 +01006087 */
6088
willy tarreau1c2ad212005-12-18 01:11:29 +01006089int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006090 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006091 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006092 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006093
willy tarreaub952e1d2005-12-18 01:31:20 +01006094 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006095
willy tarreau1c2ad212005-12-18 01:11:29 +01006096 /* look for expired tasks and add them to the run queue.
6097 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006098 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6099 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006100 tnext = t->next;
6101 if (t->state & TASK_RUNNING)
6102 continue;
6103
willy tarreaub952e1d2005-12-18 01:31:20 +01006104 if (tv_iseternity(&t->expire))
6105 continue;
6106
willy tarreau1c2ad212005-12-18 01:11:29 +01006107 /* wakeup expired entries. It doesn't matter if they are
6108 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006109 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006110 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006111 task_wakeup(&rq, t);
6112 }
6113 else {
6114 /* first non-runnable task. Use its expiration date as an upper bound */
6115 int temp_time = tv_remain(&now, &t->expire);
6116 if (temp_time)
6117 next_time = temp_time;
6118 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006119 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006120 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006121
willy tarreau1c2ad212005-12-18 01:11:29 +01006122 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006123 * since we only use the run queue's head. Note that any task can be
6124 * woken up by any other task and it will be processed immediately
6125 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006126 */
willy tarreau7feab592006-04-22 15:13:16 +02006127 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006128 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006129
willy tarreau1c2ad212005-12-18 01:11:29 +01006130 task_sleep(&rq, t);
6131 temp_time = t->process(t);
6132 next_time = MINTIME(temp_time, next_time);
6133 }
6134
6135 /* maintain all proxies in a consistent state. This should quickly become a task */
6136 time2 = maintain_proxies();
6137 return MINTIME(time2, next_time);
6138}
6139
6140
6141#if defined(ENABLE_EPOLL)
6142
6143/*
6144 * Main epoll() loop.
6145 */
6146
6147/* does 3 actions :
6148 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6149 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6150 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6151 *
6152 * returns 0 if initialization failed, !0 otherwise.
6153 */
6154
6155int epoll_loop(int action) {
6156 int next_time;
6157 int status;
6158 int fd;
6159
6160 int fds, count;
6161 int pr, pw, sr, sw;
6162 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6163 struct epoll_event ev;
6164
6165 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006166 static struct epoll_event *epoll_events = NULL;
6167 static int epoll_fd;
6168
6169 if (action == POLL_LOOP_ACTION_INIT) {
6170 epoll_fd = epoll_create(global.maxsock + 1);
6171 if (epoll_fd < 0)
6172 return 0;
6173 else {
6174 epoll_events = (struct epoll_event*)
6175 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6176 PrevReadEvent = (fd_set *)
6177 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6178 PrevWriteEvent = (fd_set *)
6179 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006180 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006181 return 1;
6182 }
6183 else if (action == POLL_LOOP_ACTION_CLEAN) {
6184 if (PrevWriteEvent) free(PrevWriteEvent);
6185 if (PrevReadEvent) free(PrevReadEvent);
6186 if (epoll_events) free(epoll_events);
6187 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006188 epoll_fd = 0;
6189 return 1;
6190 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006191
willy tarreau1c2ad212005-12-18 01:11:29 +01006192 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006193
willy tarreau1c2ad212005-12-18 01:11:29 +01006194 tv_now(&now);
6195
6196 while (1) {
6197 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006198
6199 /* stop when there's no connection left and we don't allow them anymore */
6200 if (!actconn && listeners == 0)
6201 break;
6202
willy tarreau0f7af912005-12-17 12:21:26 +01006203#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006204 {
6205 int time2;
6206 time2 = stats();
6207 next_time = MINTIME(time2, next_time);
6208 }
willy tarreau0f7af912005-12-17 12:21:26 +01006209#endif
6210
willy tarreau1c2ad212005-12-18 01:11:29 +01006211 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6212
6213 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6214 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6215
6216 if ((ro^rn) | (wo^wn)) {
6217 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6218#define FDSETS_ARE_INT_ALIGNED
6219#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006220
willy tarreauad90a0c2005-12-18 01:09:15 +01006221#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6222#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006223 pr = (ro >> count) & 1;
6224 pw = (wo >> count) & 1;
6225 sr = (rn >> count) & 1;
6226 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006227#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006228 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6229 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6230 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6231 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006232#endif
6233#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006234 pr = FD_ISSET(fd, PrevReadEvent);
6235 pw = FD_ISSET(fd, PrevWriteEvent);
6236 sr = FD_ISSET(fd, StaticReadEvent);
6237 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006238#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006239 if (!((sr^pr) | (sw^pw)))
6240 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006241
willy tarreau1c2ad212005-12-18 01:11:29 +01006242 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6243 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006244
willy tarreaub952e1d2005-12-18 01:31:20 +01006245#ifdef EPOLL_CTL_MOD_WORKAROUND
6246 /* I encountered a rarely reproducible problem with
6247 * EPOLL_CTL_MOD where a modified FD (systematically
6248 * the one in epoll_events[0], fd#7) would sometimes
6249 * be set EPOLL_OUT while asked for a read ! This is
6250 * with the 2.4 epoll patch. The workaround is to
6251 * delete then recreate in case of modification.
6252 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6253 * nor RHEL kernels.
6254 */
6255
6256 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6257 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6258
6259 if ((sr | sw))
6260 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6261#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006262 if ((pr | pw)) {
6263 /* the file-descriptor already exists... */
6264 if ((sr | sw)) {
6265 /* ...and it will still exist */
6266 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6267 // perror("epoll_ctl(MOD)");
6268 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006269 }
6270 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006271 /* ...and it will be removed */
6272 if (fdtab[fd].state != FD_STCLOSE &&
6273 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6274 // perror("epoll_ctl(DEL)");
6275 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006276 }
6277 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006278 } else {
6279 /* the file-descriptor did not exist, let's add it */
6280 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6281 // perror("epoll_ctl(ADD)");
6282 // exit(1);
6283 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006284 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006285#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006286 }
6287 ((int*)PrevReadEvent)[fds] = rn;
6288 ((int*)PrevWriteEvent)[fds] = wn;
6289 }
6290 }
6291
6292 /* now let's wait for events */
6293 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6294 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006295
willy tarreau1c2ad212005-12-18 01:11:29 +01006296 for (count = 0; count < status; count++) {
6297 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006298
6299 if (FD_ISSET(fd, StaticReadEvent)) {
6300 if (fdtab[fd].state == FD_STCLOSE)
6301 continue;
6302 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6303 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006304 }
willy tarreau05be12b2006-03-19 19:35:00 +01006305
6306 if (FD_ISSET(fd, StaticWriteEvent)) {
6307 if (fdtab[fd].state == FD_STCLOSE)
6308 continue;
6309 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6310 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006311 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006312 }
6313 }
6314 return 1;
6315}
6316#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006317
willy tarreauad90a0c2005-12-18 01:09:15 +01006318
willy tarreau5cbea6f2005-12-17 12:48:26 +01006319
willy tarreau1c2ad212005-12-18 01:11:29 +01006320#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006321
willy tarreau1c2ad212005-12-18 01:11:29 +01006322/*
6323 * Main poll() loop.
6324 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006325
willy tarreau1c2ad212005-12-18 01:11:29 +01006326/* does 3 actions :
6327 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6328 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6329 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6330 *
6331 * returns 0 if initialization failed, !0 otherwise.
6332 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006333
willy tarreau1c2ad212005-12-18 01:11:29 +01006334int poll_loop(int action) {
6335 int next_time;
6336 int status;
6337 int fd, nbfd;
6338
6339 int fds, count;
6340 int sr, sw;
6341 unsigned rn, wn; /* read new, write new */
6342
6343 /* private data */
6344 static struct pollfd *poll_events = NULL;
6345
6346 if (action == POLL_LOOP_ACTION_INIT) {
6347 poll_events = (struct pollfd*)
6348 calloc(1, sizeof(struct pollfd) * global.maxsock);
6349 return 1;
6350 }
6351 else if (action == POLL_LOOP_ACTION_CLEAN) {
6352 if (poll_events)
6353 free(poll_events);
6354 return 1;
6355 }
6356
6357 /* OK, it's POLL_LOOP_ACTION_RUN */
6358
6359 tv_now(&now);
6360
6361 while (1) {
6362 next_time = process_runnable_tasks();
6363
6364 /* stop when there's no connection left and we don't allow them anymore */
6365 if (!actconn && listeners == 0)
6366 break;
6367
6368#if STATTIME > 0
6369 {
6370 int time2;
6371 time2 = stats();
6372 next_time = MINTIME(time2, next_time);
6373 }
6374#endif
6375
6376
6377 nbfd = 0;
6378 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6379
6380 rn = ((int*)StaticReadEvent)[fds];
6381 wn = ((int*)StaticWriteEvent)[fds];
6382
6383 if ((rn|wn)) {
6384 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6385#define FDSETS_ARE_INT_ALIGNED
6386#ifdef FDSETS_ARE_INT_ALIGNED
6387
6388#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6389#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6390 sr = (rn >> count) & 1;
6391 sw = (wn >> count) & 1;
6392#else
6393 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6394 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6395#endif
6396#else
6397 sr = FD_ISSET(fd, StaticReadEvent);
6398 sw = FD_ISSET(fd, StaticWriteEvent);
6399#endif
6400 if ((sr|sw)) {
6401 poll_events[nbfd].fd = fd;
6402 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6403 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006404 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006405 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006406 }
6407 }
6408
6409 /* now let's wait for events */
6410 status = poll(poll_events, nbfd, next_time);
6411 tv_now(&now);
6412
6413 for (count = 0; status > 0 && count < nbfd; count++) {
6414 fd = poll_events[count].fd;
6415
6416 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6417 continue;
6418
6419 /* ok, we found one active fd */
6420 status--;
6421
willy tarreau05be12b2006-03-19 19:35:00 +01006422 if (FD_ISSET(fd, StaticReadEvent)) {
6423 if (fdtab[fd].state == FD_STCLOSE)
6424 continue;
6425 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6426 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006427 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006428
willy tarreau05be12b2006-03-19 19:35:00 +01006429 if (FD_ISSET(fd, StaticWriteEvent)) {
6430 if (fdtab[fd].state == FD_STCLOSE)
6431 continue;
6432 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6433 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006434 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006435 }
6436 }
6437 return 1;
6438}
willy tarreauad90a0c2005-12-18 01:09:15 +01006439#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006440
willy tarreauad90a0c2005-12-18 01:09:15 +01006441
willy tarreauad90a0c2005-12-18 01:09:15 +01006442
willy tarreau1c2ad212005-12-18 01:11:29 +01006443/*
6444 * Main select() loop.
6445 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006446
willy tarreau1c2ad212005-12-18 01:11:29 +01006447/* does 3 actions :
6448 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6449 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6450 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6451 *
6452 * returns 0 if initialization failed, !0 otherwise.
6453 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006454
willy tarreauad90a0c2005-12-18 01:09:15 +01006455
willy tarreau1c2ad212005-12-18 01:11:29 +01006456int select_loop(int action) {
6457 int next_time;
6458 int status;
6459 int fd,i;
6460 struct timeval delta;
6461 int readnotnull, writenotnull;
6462 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006463
willy tarreau1c2ad212005-12-18 01:11:29 +01006464 if (action == POLL_LOOP_ACTION_INIT) {
6465 ReadEvent = (fd_set *)
6466 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6467 WriteEvent = (fd_set *)
6468 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6469 return 1;
6470 }
6471 else if (action == POLL_LOOP_ACTION_CLEAN) {
6472 if (WriteEvent) free(WriteEvent);
6473 if (ReadEvent) free(ReadEvent);
6474 return 1;
6475 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006476
willy tarreau1c2ad212005-12-18 01:11:29 +01006477 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006478
willy tarreau1c2ad212005-12-18 01:11:29 +01006479 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006480
willy tarreau1c2ad212005-12-18 01:11:29 +01006481 while (1) {
6482 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006483
willy tarreau1c2ad212005-12-18 01:11:29 +01006484 /* stop when there's no connection left and we don't allow them anymore */
6485 if (!actconn && listeners == 0)
6486 break;
6487
6488#if STATTIME > 0
6489 {
6490 int time2;
6491 time2 = stats();
6492 next_time = MINTIME(time2, next_time);
6493 }
6494#endif
6495
willy tarreau1c2ad212005-12-18 01:11:29 +01006496 if (next_time > 0) { /* FIXME */
6497 /* Convert to timeval */
6498 /* to avoid eventual select loops due to timer precision */
6499 next_time += SCHEDULER_RESOLUTION;
6500 delta.tv_sec = next_time / 1000;
6501 delta.tv_usec = (next_time % 1000) * 1000;
6502 }
6503 else if (next_time == 0) { /* allow select to return immediately when needed */
6504 delta.tv_sec = delta.tv_usec = 0;
6505 }
6506
6507
6508 /* let's restore fdset state */
6509
6510 readnotnull = 0; writenotnull = 0;
6511 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6512 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6513 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6514 }
6515
6516 // /* just a verification code, needs to be removed for performance */
6517 // for (i=0; i<maxfd; i++) {
6518 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6519 // abort();
6520 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6521 // abort();
6522 //
6523 // }
6524
6525 status = select(maxfd,
6526 readnotnull ? ReadEvent : NULL,
6527 writenotnull ? WriteEvent : NULL,
6528 NULL,
6529 (next_time >= 0) ? &delta : NULL);
6530
6531 /* this is an experiment on the separation of the select work */
6532 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6533 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6534
6535 tv_now(&now);
6536
6537 if (status > 0) { /* must proceed with events */
6538
6539 int fds;
6540 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006541
willy tarreau1c2ad212005-12-18 01:11:29 +01006542 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6543 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6544 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6545
6546 /* if we specify read first, the accepts and zero reads will be
6547 * seen first. Moreover, system buffers will be flushed faster.
6548 */
willy tarreau05be12b2006-03-19 19:35:00 +01006549 if (FD_ISSET(fd, ReadEvent)) {
6550 if (fdtab[fd].state == FD_STCLOSE)
6551 continue;
6552 fdtab[fd].read(fd);
6553 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006554
willy tarreau05be12b2006-03-19 19:35:00 +01006555 if (FD_ISSET(fd, WriteEvent)) {
6556 if (fdtab[fd].state == FD_STCLOSE)
6557 continue;
6558 fdtab[fd].write(fd);
6559 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006560 }
6561 }
6562 else {
6563 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006564 }
willy tarreau0f7af912005-12-17 12:21:26 +01006565 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006566 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006567}
6568
6569
6570#if STATTIME > 0
6571/*
6572 * Display proxy statistics regularly. It is designed to be called from the
6573 * select_loop().
6574 */
6575int stats(void) {
6576 static int lines;
6577 static struct timeval nextevt;
6578 static struct timeval lastevt;
6579 static struct timeval starttime = {0,0};
6580 unsigned long totaltime, deltatime;
6581 int ret;
6582
willy tarreau750a4722005-12-17 13:21:24 +01006583 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006584 deltatime = (tv_diff(&lastevt, &now)?:1);
6585 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006586
willy tarreau9fe663a2005-12-17 13:02:59 +01006587 if (global.mode & MODE_STATS) {
6588 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006589 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006590 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6591 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006592 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006593 actconn, totalconn,
6594 stats_tsk_new, stats_tsk_good,
6595 stats_tsk_left, stats_tsk_right,
6596 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6597 }
6598 }
6599
6600 tv_delayfrom(&nextevt, &now, STATTIME);
6601
6602 lastevt=now;
6603 }
6604 ret = tv_remain(&now, &nextevt);
6605 return ret;
6606}
6607#endif
6608
6609
6610/*
6611 * this function enables proxies when there are enough free sessions,
6612 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006613 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006614 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006615 */
6616static int maintain_proxies(void) {
6617 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006618 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006619 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006620
6621 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006622 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006623
6624 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006625 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006626 while (p) {
6627 if (p->nbconn < p->maxconn) {
6628 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006629 for (l = p->listen; l != NULL; l = l->next) {
6630 FD_SET(l->fd, StaticReadEvent);
6631 }
willy tarreau0f7af912005-12-17 12:21:26 +01006632 p->state = PR_STRUN;
6633 }
6634 }
6635 else {
6636 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006637 for (l = p->listen; l != NULL; l = l->next) {
6638 FD_CLR(l->fd, StaticReadEvent);
6639 }
willy tarreau0f7af912005-12-17 12:21:26 +01006640 p->state = PR_STIDLE;
6641 }
6642 }
6643 p = p->next;
6644 }
6645 }
6646 else { /* block all proxies */
6647 while (p) {
6648 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006649 for (l = p->listen; l != NULL; l = l->next) {
6650 FD_CLR(l->fd, StaticReadEvent);
6651 }
willy tarreau0f7af912005-12-17 12:21:26 +01006652 p->state = PR_STIDLE;
6653 }
6654 p = p->next;
6655 }
6656 }
6657
willy tarreau5cbea6f2005-12-17 12:48:26 +01006658 if (stopping) {
6659 p = proxy;
6660 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006661 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006662 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006663 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006664 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006665 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006666 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006667
willy tarreaua41a8b42005-12-17 14:02:24 +01006668 for (l = p->listen; l != NULL; l = l->next) {
6669 fd_delete(l->fd);
6670 listeners--;
6671 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006672 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006673 }
6674 else {
6675 tleft = MINTIME(t, tleft);
6676 }
6677 }
6678 p = p->next;
6679 }
6680 }
6681 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006682}
6683
6684/*
6685 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006686 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6687 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006688 */
6689static void soft_stop(void) {
6690 struct proxy *p;
6691
6692 stopping = 1;
6693 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006694 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006695 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006696 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006697 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006698 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006699 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006700 }
willy tarreau0f7af912005-12-17 12:21:26 +01006701 p = p->next;
6702 }
6703}
6704
willy tarreaudbd3bef2006-01-20 19:35:18 +01006705static void pause_proxy(struct proxy *p) {
6706 struct listener *l;
6707 for (l = p->listen; l != NULL; l = l->next) {
6708 shutdown(l->fd, SHUT_RD);
6709 FD_CLR(l->fd, StaticReadEvent);
6710 p->state = PR_STPAUSED;
6711 }
6712}
6713
6714/*
6715 * This function temporarily disables listening so that another new instance
6716 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006717 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006718 * the proxy, or a SIGTTIN can be sent to listen again.
6719 */
6720static void pause_proxies(void) {
6721 struct proxy *p;
6722
6723 p = proxy;
6724 tv_now(&now); /* else, the old time before select will be used */
6725 while (p) {
6726 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6727 Warning("Pausing proxy %s.\n", p->id);
6728 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6729 pause_proxy(p);
6730 }
6731 p = p->next;
6732 }
6733}
6734
6735
6736/*
6737 * This function reactivates listening. This can be used after a call to
6738 * sig_pause(), for example when a new instance has failed starting up.
6739 * It is designed to be called upon reception of a SIGTTIN.
6740 */
6741static void listen_proxies(void) {
6742 struct proxy *p;
6743 struct listener *l;
6744
6745 p = proxy;
6746 tv_now(&now); /* else, the old time before select will be used */
6747 while (p) {
6748 if (p->state == PR_STPAUSED) {
6749 Warning("Enabling proxy %s.\n", p->id);
6750 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6751
6752 for (l = p->listen; l != NULL; l = l->next) {
6753 if (listen(l->fd, p->maxconn) == 0) {
6754 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6755 FD_SET(l->fd, StaticReadEvent);
6756 p->state = PR_STRUN;
6757 }
6758 else
6759 p->state = PR_STIDLE;
6760 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006761 int port;
6762
6763 if (l->addr.ss_family == AF_INET6)
6764 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6765 else
6766 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6767
willy tarreaudbd3bef2006-01-20 19:35:18 +01006768 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006769 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006770 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006771 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006772 /* Another port might have been enabled. Let's stop everything. */
6773 pause_proxy(p);
6774 break;
6775 }
6776 }
6777 }
6778 p = p->next;
6779 }
6780}
6781
6782
willy tarreau0f7af912005-12-17 12:21:26 +01006783/*
6784 * upon SIGUSR1, let's have a soft stop.
6785 */
6786void sig_soft_stop(int sig) {
6787 soft_stop();
6788 signal(sig, SIG_IGN);
6789}
6790
willy tarreaudbd3bef2006-01-20 19:35:18 +01006791/*
6792 * upon SIGTTOU, we pause everything
6793 */
6794void sig_pause(int sig) {
6795 pause_proxies();
6796 signal(sig, sig_pause);
6797}
willy tarreau0f7af912005-12-17 12:21:26 +01006798
willy tarreau8337c6b2005-12-17 13:41:01 +01006799/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006800 * upon SIGTTIN, let's have a soft stop.
6801 */
6802void sig_listen(int sig) {
6803 listen_proxies();
6804 signal(sig, sig_listen);
6805}
6806
6807/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006808 * this function dumps every server's state when the process receives SIGHUP.
6809 */
6810void sig_dump_state(int sig) {
6811 struct proxy *p = proxy;
6812
6813 Warning("SIGHUP received, dumping servers states.\n");
6814 while (p) {
6815 struct server *s = p->srv;
6816
willy tarreau4632c212006-05-02 23:32:51 +02006817 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006818 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006819 snprintf(trash, sizeof(trash),
6820 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6821 p->id, s->id,
6822 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6823 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006824 Warning("%s\n", trash);
6825 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006826 s = s->next;
6827 }
willy tarreaudd07e972005-12-18 00:48:48 +01006828
willy tarreau62084d42006-03-24 18:57:41 +01006829 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006830 snprintf(trash, sizeof(trash),
6831 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6832 p->id,
6833 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6834 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006835 } else {
6836 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006837 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6838 " Conn: %d act, %d pend (%d unass), %d tot.",
6839 p->id, p->srv_act, p->srv_bck,
6840 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006841 }
6842 Warning("%s\n", trash);
6843 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006844
willy tarreau8337c6b2005-12-17 13:41:01 +01006845 p = p->next;
6846 }
6847 signal(sig, sig_dump_state);
6848}
6849
willy tarreau0f7af912005-12-17 12:21:26 +01006850void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006851 struct task *t, *tnext;
6852 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006853
willy tarreau5e698ef2006-05-02 14:51:00 +02006854 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6855 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006856 tnext = t->next;
6857 s = t->context;
6858 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6859 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6860 "req=%d, rep=%d, clifd=%d\n",
6861 s, tv_remain(&now, &t->expire),
6862 s->cli_state,
6863 s->srv_state,
6864 FD_ISSET(s->cli_fd, StaticReadEvent),
6865 FD_ISSET(s->cli_fd, StaticWriteEvent),
6866 FD_ISSET(s->srv_fd, StaticReadEvent),
6867 FD_ISSET(s->srv_fd, StaticWriteEvent),
6868 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6869 );
willy tarreau0f7af912005-12-17 12:21:26 +01006870 }
willy tarreau12350152005-12-18 01:03:27 +01006871}
6872
willy tarreau64a3cc32005-12-18 01:13:11 +01006873#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006874static void fast_stop(void)
6875{
6876 struct proxy *p;
6877 p = proxy;
6878 while (p) {
6879 p->grace = 0;
6880 p = p->next;
6881 }
6882 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006883}
6884
willy tarreau12350152005-12-18 01:03:27 +01006885void sig_int(int sig) {
6886 /* This would normally be a hard stop,
6887 but we want to be sure about deallocation,
6888 and so on, so we do a soft stop with
6889 0 GRACE time
6890 */
6891 fast_stop();
6892 /* If we are killed twice, we decide to die*/
6893 signal(sig, SIG_DFL);
6894}
6895
6896void sig_term(int sig) {
6897 /* This would normally be a hard stop,
6898 but we want to be sure about deallocation,
6899 and so on, so we do a soft stop with
6900 0 GRACE time
6901 */
6902 fast_stop();
6903 /* If we are killed twice, we decide to die*/
6904 signal(sig, SIG_DFL);
6905}
willy tarreau64a3cc32005-12-18 01:13:11 +01006906#endif
willy tarreau12350152005-12-18 01:03:27 +01006907
willy tarreauc1f47532005-12-18 01:08:26 +01006908/* returns the pointer to an error in the replacement string, or NULL if OK */
6909char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006910 struct hdr_exp *exp;
6911
willy tarreauc1f47532005-12-18 01:08:26 +01006912 if (replace != NULL) {
6913 char *err;
6914 err = check_replace_string(replace);
6915 if (err)
6916 return err;
6917 }
6918
willy tarreaue39cd132005-12-17 13:00:18 +01006919 while (*head != NULL)
6920 head = &(*head)->next;
6921
6922 exp = calloc(1, sizeof(struct hdr_exp));
6923
6924 exp->preg = preg;
6925 exp->replace = replace;
6926 exp->action = action;
6927 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006928
6929 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006930}
6931
willy tarreau9fe663a2005-12-17 13:02:59 +01006932
willy tarreau0f7af912005-12-17 12:21:26 +01006933/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006934 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006935 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006936int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006937
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 if (!strcmp(args[0], "global")) { /* new section */
6939 /* no option, nothing special to do */
6940 return 0;
6941 }
6942 else if (!strcmp(args[0], "daemon")) {
6943 global.mode |= MODE_DAEMON;
6944 }
6945 else if (!strcmp(args[0], "debug")) {
6946 global.mode |= MODE_DEBUG;
6947 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006948 else if (!strcmp(args[0], "noepoll")) {
6949 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6950 }
6951 else if (!strcmp(args[0], "nopoll")) {
6952 cfg_polling_mechanism &= ~POLL_USE_POLL;
6953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 else if (!strcmp(args[0], "quiet")) {
6955 global.mode |= MODE_QUIET;
6956 }
6957 else if (!strcmp(args[0], "stats")) {
6958 global.mode |= MODE_STATS;
6959 }
6960 else if (!strcmp(args[0], "uid")) {
6961 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006962 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006964 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006965 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006967 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006968 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006969 global.uid = atol(args[1]);
6970 }
6971 else if (!strcmp(args[0], "gid")) {
6972 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006973 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006974 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006976 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006977 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006978 return -1;
6979 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006980 global.gid = atol(args[1]);
6981 }
6982 else if (!strcmp(args[0], "nbproc")) {
6983 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006984 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006986 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006987 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006988 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006989 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006990 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006991 global.nbproc = atol(args[1]);
6992 }
6993 else if (!strcmp(args[0], "maxconn")) {
6994 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006995 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006999 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007000 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007001 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007002 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01007003#ifdef SYSTEM_MAXCONN
7004 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7005 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);
7006 global.maxconn = DEFAULT_MAXCONN;
7007 }
7008#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007009 }
willy tarreaub1285d52005-12-18 01:20:14 +01007010 else if (!strcmp(args[0], "ulimit-n")) {
7011 if (global.rlimit_nofile != 0) {
7012 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7013 return 0;
7014 }
7015 if (*(args[1]) == 0) {
7016 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7017 return -1;
7018 }
7019 global.rlimit_nofile = atol(args[1]);
7020 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007021 else if (!strcmp(args[0], "chroot")) {
7022 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007023 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 return 0;
7025 }
7026 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007027 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007028 return -1;
7029 }
7030 global.chroot = strdup(args[1]);
7031 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007032 else if (!strcmp(args[0], "pidfile")) {
7033 if (global.pidfile != NULL) {
7034 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7035 return 0;
7036 }
7037 if (*(args[1]) == 0) {
7038 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7039 return -1;
7040 }
7041 global.pidfile = strdup(args[1]);
7042 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 else if (!strcmp(args[0], "log")) { /* syslog server address */
7044 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007045 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007046
7047 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007048 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007049 return -1;
7050 }
7051
7052 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7053 if (!strcmp(log_facilities[facility], args[2]))
7054 break;
7055
7056 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007057 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007058 exit(1);
7059 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007060
7061 level = 7; /* max syslog level = debug */
7062 if (*(args[3])) {
7063 while (level >= 0 && strcmp(log_levels[level], args[3]))
7064 level--;
7065 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007066 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007067 exit(1);
7068 }
7069 }
7070
willy tarreau9fe663a2005-12-17 13:02:59 +01007071 sa = str2sa(args[1]);
7072 if (!sa->sin_port)
7073 sa->sin_port = htons(SYSLOG_PORT);
7074
7075 if (global.logfac1 == -1) {
7076 global.logsrv1 = *sa;
7077 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007078 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007079 }
7080 else if (global.logfac2 == -1) {
7081 global.logsrv2 = *sa;
7082 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007083 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007084 }
7085 else {
7086 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7087 return -1;
7088 }
7089
7090 }
7091 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007092 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007093 return -1;
7094 }
7095 return 0;
7096}
7097
7098
willy tarreaua41a8b42005-12-17 14:02:24 +01007099void init_default_instance() {
7100 memset(&defproxy, 0, sizeof(defproxy));
7101 defproxy.mode = PR_MODE_TCP;
7102 defproxy.state = PR_STNEW;
7103 defproxy.maxconn = cfg_maxpconn;
7104 defproxy.conn_retries = CONN_RETRIES;
7105 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7106}
7107
willy tarreau9fe663a2005-12-17 13:02:59 +01007108/*
7109 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7110 */
7111int cfg_parse_listen(char *file, int linenum, char **args) {
7112 static struct proxy *curproxy = NULL;
7113 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007114 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007115 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007116
7117 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007118 if (!*args[1]) {
7119 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7120 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007121 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007122 return -1;
7123 }
7124
7125 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007126 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007127 return -1;
7128 }
willy tarreaudfece232006-05-02 00:19:57 +02007129
willy tarreau9fe663a2005-12-17 13:02:59 +01007130 curproxy->next = proxy;
7131 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007132 LIST_INIT(&curproxy->pendconns);
7133
willy tarreau9fe663a2005-12-17 13:02:59 +01007134 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007135
7136 /* parse the listener address if any */
7137 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007138 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007139 if (!curproxy->listen)
7140 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007141 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007142 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007143
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007145 curproxy->state = defproxy.state;
7146 curproxy->maxconn = defproxy.maxconn;
7147 curproxy->conn_retries = defproxy.conn_retries;
7148 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007149
7150 if (defproxy.check_req)
7151 curproxy->check_req = strdup(defproxy.check_req);
7152 curproxy->check_len = defproxy.check_len;
7153
7154 if (defproxy.cookie_name)
7155 curproxy->cookie_name = strdup(defproxy.cookie_name);
7156 curproxy->cookie_len = defproxy.cookie_len;
7157
7158 if (defproxy.capture_name)
7159 curproxy->capture_name = strdup(defproxy.capture_name);
7160 curproxy->capture_namelen = defproxy.capture_namelen;
7161 curproxy->capture_len = defproxy.capture_len;
7162
7163 if (defproxy.errmsg.msg400)
7164 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7165 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7166
7167 if (defproxy.errmsg.msg403)
7168 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7169 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7170
7171 if (defproxy.errmsg.msg408)
7172 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7173 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7174
7175 if (defproxy.errmsg.msg500)
7176 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7177 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7178
7179 if (defproxy.errmsg.msg502)
7180 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7181 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7182
7183 if (defproxy.errmsg.msg503)
7184 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7185 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7186
7187 if (defproxy.errmsg.msg504)
7188 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7189 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7190
willy tarreaua41a8b42005-12-17 14:02:24 +01007191 curproxy->clitimeout = defproxy.clitimeout;
7192 curproxy->contimeout = defproxy.contimeout;
7193 curproxy->srvtimeout = defproxy.srvtimeout;
7194 curproxy->mode = defproxy.mode;
7195 curproxy->logfac1 = defproxy.logfac1;
7196 curproxy->logsrv1 = defproxy.logsrv1;
7197 curproxy->loglev1 = defproxy.loglev1;
7198 curproxy->logfac2 = defproxy.logfac2;
7199 curproxy->logsrv2 = defproxy.logsrv2;
7200 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007201 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007202 curproxy->grace = defproxy.grace;
7203 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007204 curproxy->mon_net = defproxy.mon_net;
7205 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007206 return 0;
7207 }
7208 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007209 /* some variables may have already been initialized earlier */
7210 if (defproxy.check_req) free(defproxy.check_req);
7211 if (defproxy.cookie_name) free(defproxy.cookie_name);
7212 if (defproxy.capture_name) free(defproxy.capture_name);
7213 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7214 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7215 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7216 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7217 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7218 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7219 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7220
7221 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007222 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007223 return 0;
7224 }
7225 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007226 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007227 return -1;
7228 }
7229
willy tarreaua41a8b42005-12-17 14:02:24 +01007230 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7231 if (curproxy == &defproxy) {
7232 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7233 return -1;
7234 }
7235
7236 if (strchr(args[1], ':') == NULL) {
7237 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7238 file, linenum, args[0]);
7239 return -1;
7240 }
7241 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007242 if (!curproxy->listen)
7243 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007244 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007245 return 0;
7246 }
willy tarreaub1285d52005-12-18 01:20:14 +01007247 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7248 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7249 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7250 file, linenum, args[0]);
7251 return -1;
7252 }
7253 /* flush useless bits */
7254 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7255 return 0;
7256 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007257 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007258 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7259 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7260 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7261 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007262 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007263 return -1;
7264 }
7265 }
7266 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007267 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007269 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7270 curproxy->state = PR_STNEW;
7271 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007272 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7273 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007274// if (curproxy == &defproxy) {
7275// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7276// return -1;
7277// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007278
willy tarreau9fe663a2005-12-17 13:02:59 +01007279 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007280// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7281// file, linenum);
7282// return 0;
7283 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007284 }
7285
7286 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007287 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7288 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 return -1;
7290 }
7291 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007292 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007293
7294 cur_arg = 2;
7295 while (*(args[cur_arg])) {
7296 if (!strcmp(args[cur_arg], "rewrite")) {
7297 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007298 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007299 else if (!strcmp(args[cur_arg], "indirect")) {
7300 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007301 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007302 else if (!strcmp(args[cur_arg], "insert")) {
7303 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007304 }
willy tarreau240afa62005-12-17 13:14:35 +01007305 else if (!strcmp(args[cur_arg], "nocache")) {
7306 curproxy->options |= PR_O_COOK_NOC;
7307 }
willy tarreaucd878942005-12-17 13:27:43 +01007308 else if (!strcmp(args[cur_arg], "postonly")) {
7309 curproxy->options |= PR_O_COOK_POST;
7310 }
willy tarreau0174f312005-12-18 01:02:42 +01007311 else if (!strcmp(args[cur_arg], "prefix")) {
7312 curproxy->options |= PR_O_COOK_PFX;
7313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007314 else {
willy tarreau0174f312005-12-18 01:02:42 +01007315 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007316 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007317 return -1;
7318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007319 cur_arg++;
7320 }
willy tarreau0174f312005-12-18 01:02:42 +01007321 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7322 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7323 file, linenum);
7324 return -1;
7325 }
7326
7327 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7328 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007329 file, linenum);
7330 return -1;
7331 }
willy tarreau12350152005-12-18 01:03:27 +01007332 }/* end else if (!strcmp(args[0], "cookie")) */
7333 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7334// if (curproxy == &defproxy) {
7335// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7336// return -1;
7337// }
7338
7339 if (curproxy->appsession_name != NULL) {
7340// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7341// file, linenum);
7342// return 0;
7343 free(curproxy->appsession_name);
7344 }
7345
7346 if (*(args[5]) == 0) {
7347 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7348 file, linenum, args[0]);
7349 return -1;
7350 }
7351 have_appsession = 1;
7352 curproxy->appsession_name = strdup(args[1]);
7353 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7354 curproxy->appsession_len = atoi(args[3]);
7355 curproxy->appsession_timeout = atoi(args[5]);
7356 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7357 if (rc) {
7358 Alert("Error Init Appsession Hashtable.\n");
7359 return -1;
7360 }
7361 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007362 else if (!strcmp(args[0], "capture")) {
7363 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7364 // if (curproxy == &defproxy) {
7365 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7366 // return -1;
7367 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007368
willy tarreau4302f492005-12-18 01:00:37 +01007369 if (curproxy->capture_name != NULL) {
7370 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7371 // file, linenum, args[0]);
7372 // return 0;
7373 free(curproxy->capture_name);
7374 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007375
willy tarreau4302f492005-12-18 01:00:37 +01007376 if (*(args[4]) == 0) {
7377 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7378 file, linenum, args[0]);
7379 return -1;
7380 }
7381 curproxy->capture_name = strdup(args[2]);
7382 curproxy->capture_namelen = strlen(curproxy->capture_name);
7383 curproxy->capture_len = atol(args[4]);
7384 if (curproxy->capture_len >= CAPTURE_LEN) {
7385 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7386 file, linenum, CAPTURE_LEN - 1);
7387 curproxy->capture_len = CAPTURE_LEN - 1;
7388 }
7389 curproxy->to_log |= LW_COOKIE;
7390 }
7391 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7392 struct cap_hdr *hdr;
7393
7394 if (curproxy == &defproxy) {
7395 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7396 return -1;
7397 }
7398
7399 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7400 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7401 file, linenum, args[0], args[1]);
7402 return -1;
7403 }
7404
7405 hdr = calloc(sizeof(struct cap_hdr), 1);
7406 hdr->next = curproxy->req_cap;
7407 hdr->name = strdup(args[3]);
7408 hdr->namelen = strlen(args[3]);
7409 hdr->len = atol(args[5]);
7410 hdr->index = curproxy->nb_req_cap++;
7411 curproxy->req_cap = hdr;
7412 curproxy->to_log |= LW_REQHDR;
7413 }
7414 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7415 struct cap_hdr *hdr;
7416
7417 if (curproxy == &defproxy) {
7418 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7419 return -1;
7420 }
7421
7422 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7423 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7424 file, linenum, args[0], args[1]);
7425 return -1;
7426 }
7427 hdr = calloc(sizeof(struct cap_hdr), 1);
7428 hdr->next = curproxy->rsp_cap;
7429 hdr->name = strdup(args[3]);
7430 hdr->namelen = strlen(args[3]);
7431 hdr->len = atol(args[5]);
7432 hdr->index = curproxy->nb_rsp_cap++;
7433 curproxy->rsp_cap = hdr;
7434 curproxy->to_log |= LW_RSPHDR;
7435 }
7436 else {
7437 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007438 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007439 return -1;
7440 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007441 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007442 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007443 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007444 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007445 return 0;
7446 }
7447 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007448 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7449 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007450 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007452 curproxy->contimeout = atol(args[1]);
7453 }
7454 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007455 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007456 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7457 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007458 return 0;
7459 }
7460 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007461 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7462 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007463 return -1;
7464 }
7465 curproxy->clitimeout = atol(args[1]);
7466 }
7467 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007468 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007469 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007470 return 0;
7471 }
7472 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007473 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7474 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007475 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007476 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007477 curproxy->srvtimeout = atol(args[1]);
7478 }
7479 else if (!strcmp(args[0], "retries")) { /* connection retries */
7480 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007481 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7482 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007483 return -1;
7484 }
7485 curproxy->conn_retries = atol(args[1]);
7486 }
7487 else if (!strcmp(args[0], "option")) {
7488 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007489 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007490 return -1;
7491 }
7492 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007493 /* enable reconnections to dispatch */
7494 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007495#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007496 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007497 /* enable transparent proxy connections */
7498 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007499#endif
7500 else if (!strcmp(args[1], "keepalive"))
7501 /* enable keep-alive */
7502 curproxy->options |= PR_O_KEEPALIVE;
7503 else if (!strcmp(args[1], "forwardfor"))
7504 /* insert x-forwarded-for field */
7505 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007506 else if (!strcmp(args[1], "logasap"))
7507 /* log as soon as possible, without waiting for the session to complete */
7508 curproxy->options |= PR_O_LOGASAP;
7509 else if (!strcmp(args[1], "httpclose"))
7510 /* force connection: close in both directions in HTTP mode */
7511 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007512 else if (!strcmp(args[1], "forceclose"))
7513 /* force connection: close in both directions in HTTP mode and enforce end of session */
7514 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007515 else if (!strcmp(args[1], "checkcache"))
7516 /* require examination of cacheability of the 'set-cookie' field */
7517 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007518 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007519 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007520 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007521 else if (!strcmp(args[1], "tcplog"))
7522 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007523 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007524 else if (!strcmp(args[1], "dontlognull")) {
7525 /* don't log empty requests */
7526 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007527 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007528 else if (!strcmp(args[1], "tcpka")) {
7529 /* enable TCP keep-alives on client and server sessions */
7530 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7531 }
7532 else if (!strcmp(args[1], "clitcpka")) {
7533 /* enable TCP keep-alives on client sessions */
7534 curproxy->options |= PR_O_TCP_CLI_KA;
7535 }
7536 else if (!strcmp(args[1], "srvtcpka")) {
7537 /* enable TCP keep-alives on server sessions */
7538 curproxy->options |= PR_O_TCP_SRV_KA;
7539 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007540 else if (!strcmp(args[1], "allbackups")) {
7541 /* Use all backup servers simultaneously */
7542 curproxy->options |= PR_O_USE_ALL_BK;
7543 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007544 else if (!strcmp(args[1], "httpchk")) {
7545 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007546 if (curproxy->check_req != NULL) {
7547 free(curproxy->check_req);
7548 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007549 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007550 if (!*args[2]) { /* no argument */
7551 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7552 curproxy->check_len = strlen(DEF_CHECK_REQ);
7553 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007554 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7555 curproxy->check_req = (char *)malloc(reqlen);
7556 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7557 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007558 } else { /* more arguments : METHOD URI [HTTP_VER] */
7559 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7560 if (*args[4])
7561 reqlen += strlen(args[4]);
7562 else
7563 reqlen += strlen("HTTP/1.0");
7564
7565 curproxy->check_req = (char *)malloc(reqlen);
7566 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7567 "%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 +01007568 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007569 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007570 else if (!strcmp(args[1], "persist")) {
7571 /* persist on using the server specified by the cookie, even when it's down */
7572 curproxy->options |= PR_O_PERSIST;
7573 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007574 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007575 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007576 return -1;
7577 }
7578 return 0;
7579 }
7580 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7581 /* enable reconnections to dispatch */
7582 curproxy->options |= PR_O_REDISP;
7583 }
willy tarreaua1598082005-12-17 13:08:06 +01007584#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007585 else if (!strcmp(args[0], "transparent")) {
7586 /* enable transparent proxy connections */
7587 curproxy->options |= PR_O_TRANSP;
7588 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007589#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007590 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7591 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007592 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007593 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007594 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007595 curproxy->maxconn = atol(args[1]);
7596 }
7597 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7598 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007599 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007600 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007601 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007602 curproxy->grace = atol(args[1]);
7603 }
7604 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007605 if (curproxy == &defproxy) {
7606 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7607 return -1;
7608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007609 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007610 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007611 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007612 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007613 curproxy->dispatch_addr = *str2sa(args[1]);
7614 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007615 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007616 if (*(args[1])) {
7617 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007618 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007619 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007620 else if (!strcmp(args[1], "source")) {
7621 curproxy->options |= PR_O_BALANCE_SH;
7622 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007623 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007624 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007625 return -1;
7626 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007627 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007628 else /* if no option is set, use round-robin by default */
7629 curproxy->options |= PR_O_BALANCE_RR;
7630 }
7631 else if (!strcmp(args[0], "server")) { /* server address */
7632 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007633 char *rport;
7634 char *raddr;
7635 short realport;
7636 int do_check;
7637
7638 if (curproxy == &defproxy) {
7639 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7640 return -1;
7641 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007642
willy tarreaua41a8b42005-12-17 14:02:24 +01007643 if (!*args[2]) {
7644 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007645 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007646 return -1;
7647 }
7648 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7649 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7650 return -1;
7651 }
willy tarreau0174f312005-12-18 01:02:42 +01007652
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007653 /* the servers are linked backwards first */
7654 newsrv->next = curproxy->srv;
7655 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007657
willy tarreau18a957c2006-04-12 19:26:23 +02007658 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007659 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007660 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007661 newsrv->id = strdup(args[1]);
7662
7663 /* several ways to check the port component :
7664 * - IP => port=+0, relative
7665 * - IP: => port=+0, relative
7666 * - IP:N => port=N, absolute
7667 * - IP:+N => port=+N, relative
7668 * - IP:-N => port=-N, relative
7669 */
7670 raddr = strdup(args[2]);
7671 rport = strchr(raddr, ':');
7672 if (rport) {
7673 *rport++ = 0;
7674 realport = atol(rport);
7675 if (!isdigit((int)*rport))
7676 newsrv->state |= SRV_MAPPORTS;
7677 } else {
7678 realport = 0;
7679 newsrv->state |= SRV_MAPPORTS;
7680 }
7681
7682 newsrv->addr = *str2sa(raddr);
7683 newsrv->addr.sin_port = htons(realport);
7684 free(raddr);
7685
willy tarreau9fe663a2005-12-17 13:02:59 +01007686 newsrv->curfd = -1; /* no health-check in progress */
7687 newsrv->inter = DEF_CHKINTR;
7688 newsrv->rise = DEF_RISETIME;
7689 newsrv->fall = DEF_FALLTIME;
7690 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7691 cur_arg = 3;
7692 while (*args[cur_arg]) {
7693 if (!strcmp(args[cur_arg], "cookie")) {
7694 newsrv->cookie = strdup(args[cur_arg + 1]);
7695 newsrv->cklen = strlen(args[cur_arg + 1]);
7696 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007697 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007698 else if (!strcmp(args[cur_arg], "rise")) {
7699 newsrv->rise = atol(args[cur_arg + 1]);
7700 newsrv->health = newsrv->rise;
7701 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007702 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007703 else if (!strcmp(args[cur_arg], "fall")) {
7704 newsrv->fall = atol(args[cur_arg + 1]);
7705 cur_arg += 2;
7706 }
7707 else if (!strcmp(args[cur_arg], "inter")) {
7708 newsrv->inter = atol(args[cur_arg + 1]);
7709 cur_arg += 2;
7710 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007711 else if (!strcmp(args[cur_arg], "port")) {
7712 newsrv->check_port = atol(args[cur_arg + 1]);
7713 cur_arg += 2;
7714 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007715 else if (!strcmp(args[cur_arg], "backup")) {
7716 newsrv->state |= SRV_BACKUP;
7717 cur_arg ++;
7718 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007719 else if (!strcmp(args[cur_arg], "weight")) {
7720 int w;
7721 w = atol(args[cur_arg + 1]);
7722 if (w < 1 || w > 256) {
7723 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7724 file, linenum, newsrv->id, w);
7725 return -1;
7726 }
7727 newsrv->uweight = w - 1;
7728 cur_arg += 2;
7729 }
willy tarreau18a957c2006-04-12 19:26:23 +02007730 else if (!strcmp(args[cur_arg], "maxconn")) {
7731 newsrv->maxconn = atol(args[cur_arg + 1]);
7732 cur_arg += 2;
7733 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007734 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007735 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007736 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007737 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007738 }
willy tarreau0174f312005-12-18 01:02:42 +01007739 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7740 if (!*args[cur_arg + 1]) {
7741 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7742 file, linenum, "source");
7743 return -1;
7744 }
7745 newsrv->state |= SRV_BIND_SRC;
7746 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7747 cur_arg += 2;
7748 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007749 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007750 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 +01007751 file, linenum, newsrv->id);
7752 return -1;
7753 }
7754 }
7755
7756 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007757 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7758 newsrv->check_port = realport; /* by default */
7759 if (!newsrv->check_port) {
7760 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 +01007761 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007762 return -1;
7763 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007764 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007765 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007766
willy tarreau62084d42006-03-24 18:57:41 +01007767 if (newsrv->state & SRV_BACKUP)
7768 curproxy->srv_bck++;
7769 else
7770 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007771 }
7772 else if (!strcmp(args[0], "log")) { /* syslog server address */
7773 struct sockaddr_in *sa;
7774 int facility;
7775
7776 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7777 curproxy->logfac1 = global.logfac1;
7778 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007779 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007780 curproxy->logfac2 = global.logfac2;
7781 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007782 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007783 }
7784 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007785 int level;
7786
willy tarreau0f7af912005-12-17 12:21:26 +01007787 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7788 if (!strcmp(log_facilities[facility], args[2]))
7789 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007790
willy tarreau0f7af912005-12-17 12:21:26 +01007791 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007792 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007793 exit(1);
7794 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007795
willy tarreau8337c6b2005-12-17 13:41:01 +01007796 level = 7; /* max syslog level = debug */
7797 if (*(args[3])) {
7798 while (level >= 0 && strcmp(log_levels[level], args[3]))
7799 level--;
7800 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007801 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007802 exit(1);
7803 }
7804 }
7805
willy tarreau0f7af912005-12-17 12:21:26 +01007806 sa = str2sa(args[1]);
7807 if (!sa->sin_port)
7808 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007809
willy tarreau0f7af912005-12-17 12:21:26 +01007810 if (curproxy->logfac1 == -1) {
7811 curproxy->logsrv1 = *sa;
7812 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007813 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007814 }
7815 else if (curproxy->logfac2 == -1) {
7816 curproxy->logsrv2 = *sa;
7817 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007818 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007819 }
7820 else {
7821 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007822 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007823 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007824 }
7825 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007826 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007827 file, linenum);
7828 return -1;
7829 }
7830 }
willy tarreaua1598082005-12-17 13:08:06 +01007831 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007832 if (!*args[1]) {
7833 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007834 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007835 return -1;
7836 }
7837
7838 curproxy->source_addr = *str2sa(args[1]);
7839 curproxy->options |= PR_O_BIND_SRC;
7840 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007841 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7842 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007843 if (curproxy == &defproxy) {
7844 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7845 return -1;
7846 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007847
7848 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007849 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7850 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007851 return -1;
7852 }
7853
7854 preg = calloc(1, sizeof(regex_t));
7855 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007856 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007857 return -1;
7858 }
7859
willy tarreauc1f47532005-12-18 01:08:26 +01007860 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7861 if (err) {
7862 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7863 file, linenum, *err);
7864 return -1;
7865 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007866 }
7867 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7868 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007869 if (curproxy == &defproxy) {
7870 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7871 return -1;
7872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007873
7874 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007875 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007876 return -1;
7877 }
7878
7879 preg = calloc(1, sizeof(regex_t));
7880 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007881 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007882 return -1;
7883 }
7884
7885 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7886 }
7887 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7888 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007889 if (curproxy == &defproxy) {
7890 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7891 return -1;
7892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007893
7894 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007895 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007896 return -1;
7897 }
7898
7899 preg = calloc(1, sizeof(regex_t));
7900 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007901 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007902 return -1;
7903 }
7904
7905 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7906 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007907 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7908 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007909 if (curproxy == &defproxy) {
7910 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7911 return -1;
7912 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007913
7914 if (*(args[1]) == 0) {
7915 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7916 return -1;
7917 }
7918
7919 preg = calloc(1, sizeof(regex_t));
7920 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7921 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7922 return -1;
7923 }
7924
7925 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7926 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007927 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7928 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007929 if (curproxy == &defproxy) {
7930 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7931 return -1;
7932 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007933
7934 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007935 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007936 return -1;
7937 }
7938
7939 preg = calloc(1, sizeof(regex_t));
7940 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007941 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007942 return -1;
7943 }
7944
7945 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7946 }
7947 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7948 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007949 if (curproxy == &defproxy) {
7950 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7951 return -1;
7952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007953
7954 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007955 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7956 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007957 return -1;
7958 }
7959
7960 preg = calloc(1, sizeof(regex_t));
7961 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007962 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007963 return -1;
7964 }
7965
willy tarreauc1f47532005-12-18 01:08:26 +01007966 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7967 if (err) {
7968 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7969 file, linenum, *err);
7970 return -1;
7971 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007972 }
7973 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7974 regex_t *preg;
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 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007979
7980 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007981 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007982 return -1;
7983 }
7984
7985 preg = calloc(1, sizeof(regex_t));
7986 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007987 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007988 return -1;
7989 }
7990
7991 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7992 }
7993 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7994 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007995 if (curproxy == &defproxy) {
7996 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7997 return -1;
7998 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007999
8000 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008001 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008002 return -1;
8003 }
8004
8005 preg = calloc(1, sizeof(regex_t));
8006 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008007 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008008 return -1;
8009 }
8010
8011 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8012 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008013 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8014 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008015 if (curproxy == &defproxy) {
8016 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8017 return -1;
8018 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008019
8020 if (*(args[1]) == 0) {
8021 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8022 return -1;
8023 }
8024
8025 preg = calloc(1, sizeof(regex_t));
8026 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8027 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8028 return -1;
8029 }
8030
8031 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8032 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008033 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8034 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008035 if (curproxy == &defproxy) {
8036 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8037 return -1;
8038 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008039
8040 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008041 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008042 return -1;
8043 }
8044
8045 preg = calloc(1, sizeof(regex_t));
8046 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008047 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008048 return -1;
8049 }
8050
8051 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8052 }
8053 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008054 if (curproxy == &defproxy) {
8055 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8056 return -1;
8057 }
8058
willy tarreau9fe663a2005-12-17 13:02:59 +01008059 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008060 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008061 return 0;
8062 }
8063
8064 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008065 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008066 return -1;
8067 }
8068
willy tarreau4302f492005-12-18 01:00:37 +01008069 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8070 }
8071 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8072 regex_t *preg;
8073
8074 if (*(args[1]) == 0 || *(args[2]) == 0) {
8075 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8076 file, linenum, args[0]);
8077 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008078 }
willy tarreau4302f492005-12-18 01:00:37 +01008079
8080 preg = calloc(1, sizeof(regex_t));
8081 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8083 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008084 }
willy tarreau4302f492005-12-18 01:00:37 +01008085
willy tarreauc1f47532005-12-18 01:08:26 +01008086 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8087 if (err) {
8088 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8089 file, linenum, *err);
8090 return -1;
8091 }
willy tarreau4302f492005-12-18 01:00:37 +01008092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008093 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8094 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008095 if (curproxy == &defproxy) {
8096 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8097 return -1;
8098 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008099
8100 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008101 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008102 return -1;
8103 }
willy tarreaue39cd132005-12-17 13:00:18 +01008104
willy tarreau9fe663a2005-12-17 13:02:59 +01008105 preg = calloc(1, sizeof(regex_t));
8106 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008107 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008108 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008109 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008110
willy tarreauc1f47532005-12-18 01:08:26 +01008111 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8112 if (err) {
8113 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8114 file, linenum, *err);
8115 return -1;
8116 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008117 }
willy tarreau982249e2005-12-18 00:57:06 +01008118 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8119 regex_t *preg;
8120 if (curproxy == &defproxy) {
8121 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8122 return -1;
8123 }
8124
8125 if (*(args[1]) == 0) {
8126 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8127 return -1;
8128 }
8129
8130 preg = calloc(1, sizeof(regex_t));
8131 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8132 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8133 return -1;
8134 }
8135
willy tarreauc1f47532005-12-18 01:08:26 +01008136 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8137 if (err) {
8138 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8139 file, linenum, *err);
8140 return -1;
8141 }
willy tarreau982249e2005-12-18 00:57:06 +01008142 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008143 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008144 regex_t *preg;
8145 if (curproxy == &defproxy) {
8146 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8147 return -1;
8148 }
willy tarreaue39cd132005-12-17 13:00:18 +01008149
willy tarreaua41a8b42005-12-17 14:02:24 +01008150 if (*(args[1]) == 0 || *(args[2]) == 0) {
8151 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8152 file, linenum, args[0]);
8153 return -1;
8154 }
willy tarreaue39cd132005-12-17 13:00:18 +01008155
willy tarreaua41a8b42005-12-17 14:02:24 +01008156 preg = calloc(1, sizeof(regex_t));
8157 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8158 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8159 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008160 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008161
willy tarreauc1f47532005-12-18 01:08:26 +01008162 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8163 if (err) {
8164 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8165 file, linenum, *err);
8166 return -1;
8167 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008168 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008169 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8170 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008171 if (curproxy == &defproxy) {
8172 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8173 return -1;
8174 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008175
8176 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008177 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008178 return -1;
8179 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008180
willy tarreau9fe663a2005-12-17 13:02:59 +01008181 preg = calloc(1, sizeof(regex_t));
8182 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008183 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008184 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008185 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008186
willy tarreauc1f47532005-12-18 01:08:26 +01008187 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8188 if (err) {
8189 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8190 file, linenum, *err);
8191 return -1;
8192 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008193 }
willy tarreau982249e2005-12-18 00:57:06 +01008194 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8195 regex_t *preg;
8196 if (curproxy == &defproxy) {
8197 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8198 return -1;
8199 }
8200
8201 if (*(args[1]) == 0) {
8202 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8203 return -1;
8204 }
8205
8206 preg = calloc(1, sizeof(regex_t));
8207 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8208 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8209 return -1;
8210 }
8211
willy tarreauc1f47532005-12-18 01:08:26 +01008212 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8213 if (err) {
8214 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8215 file, linenum, *err);
8216 return -1;
8217 }
willy tarreau982249e2005-12-18 00:57:06 +01008218 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008219 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008220 if (curproxy == &defproxy) {
8221 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8222 return -1;
8223 }
8224
willy tarreau9fe663a2005-12-17 13:02:59 +01008225 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008226 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008227 return 0;
8228 }
8229
8230 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008231 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008232 return -1;
8233 }
8234
8235 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8236 }
willy tarreauc1f47532005-12-18 01:08:26 +01008237 else if (!strcmp(args[0], "errorloc") ||
8238 !strcmp(args[0], "errorloc302") ||
8239 !strcmp(args[0], "errorloc303")) { /* error location */
8240 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008241 char *err;
8242
willy tarreaueedaa9f2005-12-17 14:08:03 +01008243 // if (curproxy == &defproxy) {
8244 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8245 // return -1;
8246 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008247
willy tarreau8337c6b2005-12-17 13:41:01 +01008248 if (*(args[2]) == 0) {
8249 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8250 return -1;
8251 }
8252
8253 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008254 if (!strcmp(args[0], "errorloc303")) {
8255 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8256 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8257 } else {
8258 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8259 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8260 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008261
8262 if (errnum == 400) {
8263 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008264 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008265 free(curproxy->errmsg.msg400);
8266 }
8267 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008268 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008269 }
8270 else if (errnum == 403) {
8271 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008272 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008273 free(curproxy->errmsg.msg403);
8274 }
8275 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008276 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008277 }
8278 else if (errnum == 408) {
8279 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008280 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008281 free(curproxy->errmsg.msg408);
8282 }
8283 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008284 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008285 }
8286 else if (errnum == 500) {
8287 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008288 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008289 free(curproxy->errmsg.msg500);
8290 }
8291 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008292 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008293 }
8294 else if (errnum == 502) {
8295 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008296 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008297 free(curproxy->errmsg.msg502);
8298 }
8299 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008300 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008301 }
8302 else if (errnum == 503) {
8303 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008304 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008305 free(curproxy->errmsg.msg503);
8306 }
8307 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008308 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008309 }
8310 else if (errnum == 504) {
8311 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008312 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008313 free(curproxy->errmsg.msg504);
8314 }
8315 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008316 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008317 }
8318 else {
8319 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8320 free(err);
8321 }
8322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008323 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008324 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008325 return -1;
8326 }
8327 return 0;
8328}
willy tarreaue39cd132005-12-17 13:00:18 +01008329
willy tarreau5cbea6f2005-12-17 12:48:26 +01008330
willy tarreau9fe663a2005-12-17 13:02:59 +01008331/*
8332 * This function reads and parses the configuration file given in the argument.
8333 * returns 0 if OK, -1 if error.
8334 */
8335int readcfgfile(char *file) {
8336 char thisline[256];
8337 char *line;
8338 FILE *f;
8339 int linenum = 0;
8340 char *end;
8341 char *args[MAX_LINE_ARGS];
8342 int arg;
8343 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008344 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008345 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008346
willy tarreau9fe663a2005-12-17 13:02:59 +01008347 struct proxy *curproxy = NULL;
8348 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008349
willy tarreau9fe663a2005-12-17 13:02:59 +01008350 if ((f=fopen(file,"r")) == NULL)
8351 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008352
willy tarreaueedaa9f2005-12-17 14:08:03 +01008353 init_default_instance();
8354
willy tarreau9fe663a2005-12-17 13:02:59 +01008355 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8356 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008357
willy tarreau9fe663a2005-12-17 13:02:59 +01008358 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008359
willy tarreau9fe663a2005-12-17 13:02:59 +01008360 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008361 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008362 line++;
8363
8364 arg = 0;
8365 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008366
willy tarreau9fe663a2005-12-17 13:02:59 +01008367 while (*line && arg < MAX_LINE_ARGS) {
8368 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8369 * C equivalent value. Other combinations left unchanged (eg: \1).
8370 */
8371 if (*line == '\\') {
8372 int skip = 0;
8373 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8374 *line = line[1];
8375 skip = 1;
8376 }
8377 else if (line[1] == 'r') {
8378 *line = '\r';
8379 skip = 1;
8380 }
8381 else if (line[1] == 'n') {
8382 *line = '\n';
8383 skip = 1;
8384 }
8385 else if (line[1] == 't') {
8386 *line = '\t';
8387 skip = 1;
8388 }
willy tarreauc1f47532005-12-18 01:08:26 +01008389 else if (line[1] == 'x') {
8390 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8391 unsigned char hex1, hex2;
8392 hex1 = toupper(line[2]) - '0';
8393 hex2 = toupper(line[3]) - '0';
8394 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8395 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8396 *line = (hex1<<4) + hex2;
8397 skip = 3;
8398 }
8399 else {
8400 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8401 return -1;
8402 }
8403 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008404 if (skip) {
8405 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8406 end -= skip;
8407 }
8408 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008409 }
willy tarreaua1598082005-12-17 13:08:06 +01008410 else if (*line == '#' || *line == '\n' || *line == '\r') {
8411 /* end of string, end of loop */
8412 *line = 0;
8413 break;
8414 }
willy tarreauc29948c2005-12-17 13:10:27 +01008415 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008416 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008417 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008418 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008419 line++;
8420 args[++arg] = line;
8421 }
8422 else {
8423 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008424 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008425 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008426
willy tarreau9fe663a2005-12-17 13:02:59 +01008427 /* empty line */
8428 if (!**args)
8429 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008430
willy tarreau9fe663a2005-12-17 13:02:59 +01008431 /* zero out remaining args */
8432 while (++arg < MAX_LINE_ARGS) {
8433 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008434 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008435
willy tarreaua41a8b42005-12-17 14:02:24 +01008436 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008437 confsect = CFG_LISTEN;
8438 else if (!strcmp(args[0], "global")) /* global config */
8439 confsect = CFG_GLOBAL;
8440 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008441
willy tarreau9fe663a2005-12-17 13:02:59 +01008442 switch (confsect) {
8443 case CFG_LISTEN:
8444 if (cfg_parse_listen(file, linenum, args) < 0)
8445 return -1;
8446 break;
8447 case CFG_GLOBAL:
8448 if (cfg_parse_global(file, linenum, args) < 0)
8449 return -1;
8450 break;
8451 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008452 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008453 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008454 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008455
8456
willy tarreau0f7af912005-12-17 12:21:26 +01008457 }
8458 fclose(f);
8459
8460 /*
8461 * Now, check for the integrity of all that we have collected.
8462 */
8463
Willy TARREAU3759f982006-03-01 22:44:17 +01008464 /* will be needed further to delay some tasks */
8465 tv_now(&now);
8466
willy tarreau0f7af912005-12-17 12:21:26 +01008467 if ((curproxy = proxy) == NULL) {
8468 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8469 file);
8470 return -1;
8471 }
8472
8473 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008474 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008475 curproxy = curproxy->next;
8476 continue;
8477 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008478
8479 if (curproxy->listen == NULL) {
8480 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);
8481 cfgerr++;
8482 }
8483 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008484 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008485 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008486 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8487 file, curproxy->id);
8488 cfgerr++;
8489 }
8490 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8491 if (curproxy->options & PR_O_TRANSP) {
8492 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8493 file, curproxy->id);
8494 cfgerr++;
8495 }
8496 else if (curproxy->srv == NULL) {
8497 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8498 file, curproxy->id);
8499 cfgerr++;
8500 }
willy tarreaua1598082005-12-17 13:08:06 +01008501 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008502 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8503 file, curproxy->id);
8504 }
8505 }
8506 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008507 if (curproxy->cookie_name != NULL) {
8508 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8509 file, curproxy->id);
8510 }
8511 if ((newsrv = curproxy->srv) != NULL) {
8512 Warning("parsing %s : servers will be ignored for listener %s.\n",
8513 file, curproxy->id);
8514 }
willy tarreaue39cd132005-12-17 13:00:18 +01008515 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008516 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8517 file, curproxy->id);
8518 }
willy tarreaue39cd132005-12-17 13:00:18 +01008519 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008520 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8521 file, curproxy->id);
8522 }
8523 }
8524 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8525 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8526 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8527 file, curproxy->id);
8528 cfgerr++;
8529 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008530 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008531
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008532 /* first, we will invert the servers list order */
8533 newsrv = NULL;
8534 while (curproxy->srv) {
8535 struct server *next;
8536
8537 next = curproxy->srv->next;
8538 curproxy->srv->next = newsrv;
8539 newsrv = curproxy->srv;
8540 if (!next)
8541 break;
8542 curproxy->srv = next;
8543 }
8544
8545 /* now, newsrv == curproxy->srv */
8546 if (newsrv) {
8547 struct server *srv;
8548 int pgcd;
8549 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008550
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008551 /* We will factor the weights to reduce the table,
8552 * using Euclide's largest common divisor algorithm
8553 */
8554 pgcd = newsrv->uweight + 1;
8555 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8556 int t, w;
8557
8558 w = srv->uweight + 1;
8559 while (w) {
8560 t = pgcd % w;
8561 pgcd = w;
8562 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008563 }
willy tarreau0f7af912005-12-17 12:21:26 +01008564 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008565
8566 act = bck = 0;
8567 for (srv = newsrv; srv; srv = srv->next) {
8568 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8569 if (srv->state & SRV_BACKUP)
8570 bck += srv->eweight + 1;
8571 else
8572 act += srv->eweight + 1;
8573 }
8574
8575 /* this is the largest map we will ever need for this servers list */
8576 if (act < bck)
8577 act = bck;
8578
8579 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8580 /* recounts servers and their weights */
8581 recount_servers(curproxy);
8582 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008583 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008584
8585 if (curproxy->options & PR_O_LOGASAP)
8586 curproxy->to_log &= ~LW_BYTES;
8587
willy tarreau8337c6b2005-12-17 13:41:01 +01008588 if (curproxy->errmsg.msg400 == NULL) {
8589 curproxy->errmsg.msg400 = (char *)HTTP_400;
8590 curproxy->errmsg.len400 = strlen(HTTP_400);
8591 }
8592 if (curproxy->errmsg.msg403 == NULL) {
8593 curproxy->errmsg.msg403 = (char *)HTTP_403;
8594 curproxy->errmsg.len403 = strlen(HTTP_403);
8595 }
8596 if (curproxy->errmsg.msg408 == NULL) {
8597 curproxy->errmsg.msg408 = (char *)HTTP_408;
8598 curproxy->errmsg.len408 = strlen(HTTP_408);
8599 }
8600 if (curproxy->errmsg.msg500 == NULL) {
8601 curproxy->errmsg.msg500 = (char *)HTTP_500;
8602 curproxy->errmsg.len500 = strlen(HTTP_500);
8603 }
8604 if (curproxy->errmsg.msg502 == NULL) {
8605 curproxy->errmsg.msg502 = (char *)HTTP_502;
8606 curproxy->errmsg.len502 = strlen(HTTP_502);
8607 }
8608 if (curproxy->errmsg.msg503 == NULL) {
8609 curproxy->errmsg.msg503 = (char *)HTTP_503;
8610 curproxy->errmsg.len503 = strlen(HTTP_503);
8611 }
8612 if (curproxy->errmsg.msg504 == NULL) {
8613 curproxy->errmsg.msg504 = (char *)HTTP_504;
8614 curproxy->errmsg.len504 = strlen(HTTP_504);
8615 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008616
willy tarreau59a6cc22006-05-12 01:29:08 +02008617 /*
8618 * If this server supports a maxconn parameter, it needs a dedicated
8619 * tasks to fill the emptied slots when a connection leaves.
8620 */
8621 newsrv = curproxy->srv;
8622 while (newsrv != NULL) {
8623 if (newsrv->maxconn > 0) {
8624 struct task *t;
8625
8626 if ((t = pool_alloc(task)) == NULL) {
8627 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8628 return -1;
8629 }
8630
8631 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8632 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8633 t->state = TASK_IDLE;
8634 t->process = process_srv_queue;
8635 t->context = newsrv;
8636 newsrv->queue_mgt = t;
8637
8638 /* never run it unless specifically woken up */
8639 tv_eternity(&t->expire);
8640 task_queue(t);
8641 }
8642 newsrv = newsrv->next;
8643 }
8644
Willy TARREAU3759f982006-03-01 22:44:17 +01008645 /* now we'll start this proxy's health checks if any */
8646 /* 1- count the checkers to run simultaneously */
8647 nbchk = 0;
8648 mininter = 0;
8649 newsrv = curproxy->srv;
8650 while (newsrv != NULL) {
8651 if (newsrv->state & SRV_CHECKED) {
8652 if (!mininter || mininter > newsrv->inter)
8653 mininter = newsrv->inter;
8654 nbchk++;
8655 }
8656 newsrv = newsrv->next;
8657 }
8658
8659 /* 2- start them as far as possible from each others while respecting
8660 * their own intervals. For this, we will start them after their own
8661 * interval added to the min interval divided by the number of servers,
8662 * weighted by the server's position in the list.
8663 */
8664 if (nbchk > 0) {
8665 struct task *t;
8666 int srvpos;
8667
8668 newsrv = curproxy->srv;
8669 srvpos = 0;
8670 while (newsrv != NULL) {
8671 /* should this server be checked ? */
8672 if (newsrv->state & SRV_CHECKED) {
8673 if ((t = pool_alloc(task)) == NULL) {
8674 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8675 return -1;
8676 }
8677
8678 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008679 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008680 t->state = TASK_IDLE;
8681 t->process = process_chk;
8682 t->context = newsrv;
8683
8684 /* check this every ms */
8685 tv_delayfrom(&t->expire, &now,
8686 newsrv->inter + mininter * srvpos / nbchk);
8687 task_queue(t);
8688 //task_wakeup(&rq, t);
8689 srvpos++;
8690 }
8691 newsrv = newsrv->next;
8692 }
8693 }
8694
willy tarreau0f7af912005-12-17 12:21:26 +01008695 curproxy = curproxy->next;
8696 }
8697 if (cfgerr > 0) {
8698 Alert("Errors found in configuration file, aborting.\n");
8699 return -1;
8700 }
8701 else
8702 return 0;
8703}
8704
8705
8706/*
8707 * This function initializes all the necessary variables. It only returns
8708 * if everything is OK. If something fails, it exits.
8709 */
8710void init(int argc, char **argv) {
8711 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008712 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008713 char *old_argv = *argv;
8714 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008715 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008716
8717 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008718 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008719 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008720 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008721 exit(1);
8722 }
8723
willy tarreau746e26b2006-03-25 11:14:35 +01008724#ifdef HAPROXY_MEMMAX
8725 global.rlimit_memmax = HAPROXY_MEMMAX;
8726#endif
8727
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008728 /* initialize the libc's localtime structures once for all so that we
8729 * won't be missing memory if we want to send alerts under OOM conditions.
8730 */
8731 tv_now(&now);
8732 localtime(&now.tv_sec);
8733
willy tarreau4302f492005-12-18 01:00:37 +01008734 /* initialize the log header encoding map : '{|}"#' should be encoded with
8735 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8736 * URL encoding only requires '"', '#' to be encoded as well as non-
8737 * printable characters above.
8738 */
8739 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8740 memset(url_encode_map, 0, sizeof(url_encode_map));
8741 for (i = 0; i < 32; i++) {
8742 FD_SET(i, hdr_encode_map);
8743 FD_SET(i, url_encode_map);
8744 }
8745 for (i = 127; i < 256; i++) {
8746 FD_SET(i, hdr_encode_map);
8747 FD_SET(i, url_encode_map);
8748 }
8749
8750 tmp = "\"#{|}";
8751 while (*tmp) {
8752 FD_SET(*tmp, hdr_encode_map);
8753 tmp++;
8754 }
8755
8756 tmp = "\"#";
8757 while (*tmp) {
8758 FD_SET(*tmp, url_encode_map);
8759 tmp++;
8760 }
8761
willy tarreau64a3cc32005-12-18 01:13:11 +01008762 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8763#if defined(ENABLE_POLL)
8764 cfg_polling_mechanism |= POLL_USE_POLL;
8765#endif
8766#if defined(ENABLE_EPOLL)
8767 cfg_polling_mechanism |= POLL_USE_EPOLL;
8768#endif
8769
willy tarreau0f7af912005-12-17 12:21:26 +01008770 pid = getpid();
8771 progname = *argv;
8772 while ((tmp = strchr(progname, '/')) != NULL)
8773 progname = tmp + 1;
8774
8775 argc--; argv++;
8776 while (argc > 0) {
8777 char *flag;
8778
8779 if (**argv == '-') {
8780 flag = *argv+1;
8781
8782 /* 1 arg */
8783 if (*flag == 'v') {
8784 display_version();
8785 exit(0);
8786 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008787#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008788 else if (*flag == 'd' && flag[1] == 'e')
8789 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008790#endif
8791#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008792 else if (*flag == 'd' && flag[1] == 'p')
8793 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008794#endif
willy tarreau982249e2005-12-18 00:57:06 +01008795 else if (*flag == 'V')
8796 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008797 else if (*flag == 'd' && flag[1] == 'b')
8798 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008799 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008800 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008801 else if (*flag == 'c')
8802 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008803 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008804 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008805 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008806 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008807 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8808 /* list of pids to finish ('f') or terminate ('t') */
8809
8810 if (flag[1] == 'f')
8811 oldpids_sig = SIGUSR1; /* finish then exit */
8812 else
8813 oldpids_sig = SIGTERM; /* terminate immediately */
8814 argv++; argc--;
8815
8816 if (argc > 0) {
8817 oldpids = calloc(argc, sizeof(int));
8818 while (argc > 0) {
8819 oldpids[nb_oldpids] = atol(*argv);
8820 if (oldpids[nb_oldpids] <= 0)
8821 usage(old_argv);
8822 argc--; argv++;
8823 nb_oldpids++;
8824 }
8825 }
8826 }
willy tarreau2c513732006-04-15 19:25:16 +02008827#if STATTIME > 0
8828 else if (*flag == 's')
8829 arg_mode |= MODE_STATS;
8830 else if (*flag == 'l')
8831 arg_mode |= MODE_LOG;
8832#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008833 else { /* >=2 args */
8834 argv++; argc--;
8835 if (argc == 0)
8836 usage(old_argv);
8837
8838 switch (*flag) {
8839 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008840 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008841 case 'N' : cfg_maxpconn = atol(*argv); break;
8842 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008843 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008844 default: usage(old_argv);
8845 }
8846 }
8847 }
8848 else
8849 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008850 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008851 }
8852
willy tarreaud0fb4652005-12-18 01:32:04 +01008853 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008854 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8855 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008856
willy tarreau0f7af912005-12-17 12:21:26 +01008857 if (!cfg_cfgfile)
8858 usage(old_argv);
8859
8860 gethostname(hostname, MAX_HOSTNAME_LEN);
8861
willy tarreau12350152005-12-18 01:03:27 +01008862 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008863 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008864 if (readcfgfile(cfg_cfgfile) < 0) {
8865 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8866 exit(1);
8867 }
willy tarreau12350152005-12-18 01:03:27 +01008868 if (have_appsession)
8869 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008870
willy tarreau982249e2005-12-18 00:57:06 +01008871 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008872 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8873 exit(0);
8874 }
8875
willy tarreau9fe663a2005-12-17 13:02:59 +01008876 if (cfg_maxconn > 0)
8877 global.maxconn = cfg_maxconn;
8878
willy tarreaufe2c5c12005-12-17 14:14:34 +01008879 if (cfg_pidfile) {
8880 if (global.pidfile)
8881 free(global.pidfile);
8882 global.pidfile = strdup(cfg_pidfile);
8883 }
8884
willy tarreau9fe663a2005-12-17 13:02:59 +01008885 if (global.maxconn == 0)
8886 global.maxconn = DEFAULT_MAXCONN;
8887
Willy TARREAU203b0b62006-03-12 18:00:28 +01008888 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008889
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008890 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008891 /* command line debug mode inhibits configuration mode */
8892 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8893 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008894 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8895 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008896
8897 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8898 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8899 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8900 }
8901
8902 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008903 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8904 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008905 global.nbproc = 1;
8906 }
8907
8908 if (global.nbproc < 1)
8909 global.nbproc = 1;
8910
willy tarreau0f7af912005-12-17 12:21:26 +01008911 StaticReadEvent = (fd_set *)calloc(1,
8912 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008913 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008914 StaticWriteEvent = (fd_set *)calloc(1,
8915 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008916 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008917
8918 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008919 sizeof(struct fdtab) * (global.maxsock));
8920 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008921 fdtab[i].state = FD_STCLOSE;
8922 }
8923}
8924
8925/*
willy tarreau41310e72006-03-25 18:17:56 +01008926 * this function starts all the proxies. Its return value is composed from
8927 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8928 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008929 */
willy tarreau41310e72006-03-25 18:17:56 +01008930int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008931 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008932 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008933 int err = ERR_NONE;
8934 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008935
8936 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008937 if (curproxy->state != PR_STNEW)
8938 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008939
willy tarreau41310e72006-03-25 18:17:56 +01008940 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008941 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008942 if (listener->fd != -1)
8943 continue; /* already initialized */
8944
8945 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8946 if (verbose)
8947 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8948 curproxy->id);
8949 err |= ERR_RETRYABLE;
8950 pxerr |= 1;
8951 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008952 }
willy tarreau0f7af912005-12-17 12:21:26 +01008953
willy tarreaua41a8b42005-12-17 14:02:24 +01008954 if (fd >= global.maxsock) {
8955 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8956 curproxy->id);
8957 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008958 err |= ERR_FATAL;
8959 pxerr |= 1;
8960 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008961 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008962
willy tarreaua41a8b42005-12-17 14:02:24 +01008963 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8964 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8965 (char *) &one, sizeof(one)) == -1)) {
8966 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8967 curproxy->id);
8968 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008969 err |= ERR_FATAL;
8970 pxerr |= 1;
8971 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008972 }
willy tarreau0f7af912005-12-17 12:21:26 +01008973
willy tarreaua41a8b42005-12-17 14:02:24 +01008974 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8975 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8976 curproxy->id);
8977 }
willy tarreau0f7af912005-12-17 12:21:26 +01008978
willy tarreaua41a8b42005-12-17 14:02:24 +01008979 if (bind(fd,
8980 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008981 listener->addr.ss_family == AF_INET6 ?
8982 sizeof(struct sockaddr_in6) :
8983 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008984 if (verbose)
8985 Alert("cannot bind socket for proxy %s. Aborting.\n",
8986 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008987 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008988 err |= ERR_RETRYABLE;
8989 pxerr |= 1;
8990 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008991 }
willy tarreau0f7af912005-12-17 12:21:26 +01008992
willy tarreaua41a8b42005-12-17 14:02:24 +01008993 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008994 if (verbose)
8995 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8996 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008997 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008998 err |= ERR_RETRYABLE;
8999 pxerr |= 1;
9000 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01009001 }
willy tarreau0f7af912005-12-17 12:21:26 +01009002
willy tarreau41310e72006-03-25 18:17:56 +01009003 /* the socket is ready */
9004 listener->fd = fd;
9005
willy tarreaua41a8b42005-12-17 14:02:24 +01009006 /* the function for the accept() event */
9007 fdtab[fd].read = &event_accept;
9008 fdtab[fd].write = NULL; /* never called */
9009 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009010 fdtab[fd].state = FD_STLISTEN;
9011 FD_SET(fd, StaticReadEvent);
9012 fd_insert(fd);
9013 listeners++;
9014 }
willy tarreau41310e72006-03-25 18:17:56 +01009015
9016 if (!pxerr) {
9017 curproxy->state = PR_STRUN;
9018 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9019 }
willy tarreau0f7af912005-12-17 12:21:26 +01009020 }
willy tarreau41310e72006-03-25 18:17:56 +01009021
9022 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009023}
9024
willy tarreaub952e1d2005-12-18 01:31:20 +01009025int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009026
9027 appsess *temp1,*temp2;
9028 temp1 = (appsess *)key1;
9029 temp2 = (appsess *)key2;
9030
9031 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9032 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9033
9034 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9035}/* end match_str */
9036
willy tarreaub952e1d2005-12-18 01:31:20 +01009037void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009038 appsess *temp1;
9039
9040 //printf("destroy called\n");
9041 temp1 = (appsess *)data;
9042
9043 if (temp1->sessid)
9044 pool_free_to(apools.sessid, temp1->sessid);
9045
9046 if (temp1->serverid)
9047 pool_free_to(apools.serverid, temp1->serverid);
9048
9049 pool_free(appsess, temp1);
9050} /* end destroy */
9051
9052void appsession_cleanup( void )
9053{
9054 struct proxy *p = proxy;
9055
9056 while(p) {
9057 chtbl_destroy(&(p->htbl_proxy));
9058 p = p->next;
9059 }
9060}/* end appsession_cleanup() */
9061
9062void pool_destroy(void **pool)
9063{
9064 void *temp, *next;
9065 next = pool;
9066 while (next) {
9067 temp = next;
9068 next = *(void **)temp;
9069 free(temp);
9070 }
9071}/* end pool_destroy() */
9072
willy tarreaub952e1d2005-12-18 01:31:20 +01009073void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009074 struct proxy *p = proxy;
9075 struct cap_hdr *h,*h_next;
9076 struct server *s,*s_next;
9077 struct listener *l,*l_next;
9078
9079 while (p) {
9080 if (p->id)
9081 free(p->id);
9082
9083 if (p->check_req)
9084 free(p->check_req);
9085
9086 if (p->cookie_name)
9087 free(p->cookie_name);
9088
9089 if (p->capture_name)
9090 free(p->capture_name);
9091
9092 /* only strup if the user have set in config.
9093 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009094 if (p->errmsg.msg400) free(p->errmsg.msg400);
9095 if (p->errmsg.msg403) free(p->errmsg.msg403);
9096 if (p->errmsg.msg408) free(p->errmsg.msg408);
9097 if (p->errmsg.msg500) free(p->errmsg.msg500);
9098 if (p->errmsg.msg502) free(p->errmsg.msg502);
9099 if (p->errmsg.msg503) free(p->errmsg.msg503);
9100 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009101 */
9102 if (p->appsession_name)
9103 free(p->appsession_name);
9104
9105 h = p->req_cap;
9106 while (h) {
9107 h_next = h->next;
9108 if (h->name)
9109 free(h->name);
9110 pool_destroy(h->pool);
9111 free(h);
9112 h = h_next;
9113 }/* end while(h) */
9114
9115 h = p->rsp_cap;
9116 while (h) {
9117 h_next = h->next;
9118 if (h->name)
9119 free(h->name);
9120
9121 pool_destroy(h->pool);
9122 free(h);
9123 h = h_next;
9124 }/* end while(h) */
9125
9126 s = p->srv;
9127 while (s) {
9128 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009129 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009130 free(s->id);
9131
willy tarreaub952e1d2005-12-18 01:31:20 +01009132 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009133 free(s->cookie);
9134
9135 free(s);
9136 s = s_next;
9137 }/* end while(s) */
9138
9139 l = p->listen;
9140 while (l) {
9141 l_next = l->next;
9142 free(l);
9143 l = l_next;
9144 }/* end while(l) */
9145
9146 pool_destroy((void **) p->req_cap_pool);
9147 pool_destroy((void **) p->rsp_cap_pool);
9148 p = p->next;
9149 }/* end while(p) */
9150
9151 if (global.chroot) free(global.chroot);
9152 if (global.pidfile) free(global.pidfile);
9153
willy tarreau12350152005-12-18 01:03:27 +01009154 if (StaticReadEvent) free(StaticReadEvent);
9155 if (StaticWriteEvent) free(StaticWriteEvent);
9156 if (fdtab) free(fdtab);
9157
9158 pool_destroy(pool_session);
9159 pool_destroy(pool_buffer);
9160 pool_destroy(pool_fdtab);
9161 pool_destroy(pool_requri);
9162 pool_destroy(pool_task);
9163 pool_destroy(pool_capture);
9164 pool_destroy(pool_appsess);
9165
9166 if (have_appsession) {
9167 pool_destroy(apools.serverid);
9168 pool_destroy(apools.sessid);
9169 }
9170} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009171
willy tarreau41310e72006-03-25 18:17:56 +01009172/* sends the signal <sig> to all pids found in <oldpids> */
9173static void tell_old_pids(int sig) {
9174 int p;
9175 for (p = 0; p < nb_oldpids; p++)
9176 kill(oldpids[p], sig);
9177}
9178
willy tarreau0f7af912005-12-17 12:21:26 +01009179int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009180 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009181 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009182 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009183 init(argc, argv);
9184
willy tarreau0f7af912005-12-17 12:21:26 +01009185 signal(SIGQUIT, dump);
9186 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009187 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009188#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009189 signal(SIGINT, sig_int);
9190 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009191#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009192
9193 /* on very high loads, a sigpipe sometimes happen just between the
9194 * getsockopt() which tells "it's OK to write", and the following write :-(
9195 */
willy tarreau3242e862005-12-17 12:27:53 +01009196#ifndef MSG_NOSIGNAL
9197 signal(SIGPIPE, SIG_IGN);
9198#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009199
willy tarreau41310e72006-03-25 18:17:56 +01009200 /* We will loop at most 100 times with 10 ms delay each time.
9201 * That's at most 1 second. We only send a signal to old pids
9202 * if we cannot grab at least one port.
9203 */
9204 retry = MAX_START_RETRIES;
9205 err = ERR_NONE;
9206 while (retry >= 0) {
9207 struct timeval w;
9208 err = start_proxies(retry == 0 || nb_oldpids == 0);
9209 if (err != ERR_RETRYABLE)
9210 break;
9211 if (nb_oldpids == 0)
9212 break;
9213
9214 tell_old_pids(SIGTTOU);
9215 /* give some time to old processes to stop listening */
9216 w.tv_sec = 0;
9217 w.tv_usec = 10*1000;
9218 select(0, NULL, NULL, NULL, &w);
9219 retry--;
9220 }
9221
9222 /* Note: start_proxies() sends an alert when it fails. */
9223 if (err != ERR_NONE) {
9224 if (retry != MAX_START_RETRIES && nb_oldpids)
9225 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009226 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009227 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009228
9229 if (listeners == 0) {
9230 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009231 /* Note: we don't have to send anything to the old pids because we
9232 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009233 exit(1);
9234 }
9235
willy tarreaudbd3bef2006-01-20 19:35:18 +01009236 /* prepare pause/play signals */
9237 signal(SIGTTOU, sig_pause);
9238 signal(SIGTTIN, sig_listen);
9239
Willy TARREAUe3283d12006-03-01 22:15:29 +01009240 if (global.mode & MODE_DAEMON) {
9241 global.mode &= ~MODE_VERBOSE;
9242 global.mode |= MODE_QUIET;
9243 }
9244
willy tarreaud0fb4652005-12-18 01:32:04 +01009245 /* MODE_QUIET can inhibit alerts and warnings below this line */
9246
9247 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009248 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009249 /* detach from the tty */
9250 fclose(stdin); fclose(stdout); fclose(stderr);
9251 close(0); close(1); close(2);
9252 }
willy tarreau0f7af912005-12-17 12:21:26 +01009253
willy tarreaufe2c5c12005-12-17 14:14:34 +01009254 /* open log & pid files before the chroot */
9255 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9256 int pidfd;
9257 unlink(global.pidfile);
9258 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9259 if (pidfd < 0) {
9260 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009261 if (nb_oldpids)
9262 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009263 exit(1);
9264 }
9265 pidfile = fdopen(pidfd, "w");
9266 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009267
9268 /* chroot if needed */
9269 if (global.chroot != NULL) {
9270 if (chroot(global.chroot) == -1) {
9271 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009272 if (nb_oldpids)
9273 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009274 }
9275 chdir("/");
9276 }
9277
willy tarreaub1285d52005-12-18 01:20:14 +01009278 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009279 if (!global.rlimit_nofile)
9280 global.rlimit_nofile = global.maxsock;
9281
willy tarreaub1285d52005-12-18 01:20:14 +01009282 if (global.rlimit_nofile) {
9283 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9284 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9285 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9286 }
willy tarreau746e26b2006-03-25 11:14:35 +01009287 }
9288
9289 if (global.rlimit_memmax) {
9290 limit.rlim_cur = limit.rlim_max =
9291 global.rlimit_memmax * 1048576 / global.nbproc;
9292#ifdef RLIMIT_AS
9293 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9294 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9295 argv[0], global.rlimit_memmax);
9296 }
9297#else
9298 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9299 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9300 argv[0], global.rlimit_memmax);
9301 }
9302#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009303 }
9304
willy tarreau41310e72006-03-25 18:17:56 +01009305 if (nb_oldpids)
9306 tell_old_pids(oldpids_sig);
9307
9308 /* Note that any error at this stage will be fatal because we will not
9309 * be able to restart the old pids.
9310 */
9311
willy tarreau9fe663a2005-12-17 13:02:59 +01009312 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009313 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009314 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9315 exit(1);
9316 }
9317
willy tarreau036e1ce2005-12-17 13:46:33 +01009318 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009319 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9320 exit(1);
9321 }
9322
willy tarreaub1285d52005-12-18 01:20:14 +01009323 /* check ulimits */
9324 limit.rlim_cur = limit.rlim_max = 0;
9325 getrlimit(RLIMIT_NOFILE, &limit);
9326 if (limit.rlim_cur < global.maxsock) {
9327 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",
9328 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9329 }
9330
willy tarreau9fe663a2005-12-17 13:02:59 +01009331 if (global.mode & MODE_DAEMON) {
9332 int ret = 0;
9333 int proc;
9334
9335 /* the father launches the required number of processes */
9336 for (proc = 0; proc < global.nbproc; proc++) {
9337 ret = fork();
9338 if (ret < 0) {
9339 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009340 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009341 exit(1); /* there has been an error */
9342 }
9343 else if (ret == 0) /* child breaks here */
9344 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009345 if (pidfile != NULL) {
9346 fprintf(pidfile, "%d\n", ret);
9347 fflush(pidfile);
9348 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009349 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009350 /* close the pidfile both in children and father */
9351 if (pidfile != NULL)
9352 fclose(pidfile);
9353 free(global.pidfile);
9354
willy tarreau9fe663a2005-12-17 13:02:59 +01009355 if (proc == global.nbproc)
9356 exit(0); /* parent must leave */
9357
willy tarreau750a4722005-12-17 13:21:24 +01009358 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9359 * that we can detach from the TTY. We MUST NOT do it in other cases since
9360 * it would have already be done, and 0-2 would have been affected to listening
9361 * sockets
9362 */
9363 if (!(global.mode & MODE_QUIET)) {
9364 /* detach from the tty */
9365 fclose(stdin); fclose(stdout); fclose(stderr);
9366 close(0); close(1); close(2); /* close all fd's */
9367 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9368 }
willy tarreaua1598082005-12-17 13:08:06 +01009369 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009370 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009371 }
9372
willy tarreau1c2ad212005-12-18 01:11:29 +01009373#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009374 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009375 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9376 epoll_loop(POLL_LOOP_ACTION_RUN);
9377 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009378 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009379 }
9380 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009381 Warning("epoll() is not available. Using poll()/select() instead.\n");
9382 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009383 }
9384 }
9385#endif
9386
9387#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009388 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009389 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9390 poll_loop(POLL_LOOP_ACTION_RUN);
9391 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009392 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009393 }
9394 else {
9395 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009396 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009397 }
9398 }
9399#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009400 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009401 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9402 select_loop(POLL_LOOP_ACTION_RUN);
9403 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009404 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009405 }
9406 }
9407
willy tarreau0f7af912005-12-17 12:21:26 +01009408
willy tarreau12350152005-12-18 01:03:27 +01009409 /* Free all Hash Keys and all Hash elements */
9410 appsession_cleanup();
9411 /* Do some cleanup */
9412 deinit();
9413
willy tarreau0f7af912005-12-17 12:21:26 +01009414 exit(0);
9415}
willy tarreau12350152005-12-18 01:03:27 +01009416
9417#if defined(DEBUG_HASH)
9418static void print_table(const CHTbl *htbl) {
9419
9420 ListElmt *element;
9421 int i;
9422 appsess *asession;
9423
9424 /*****************************************************************************
9425 * *
9426 * Display the chained hash table. *
9427 * *
9428 *****************************************************************************/
9429
9430 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9431
9432 for (i = 0; i < TBLSIZ; i++) {
9433 fprintf(stdout, "Bucket[%03d]\n", i);
9434
9435 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9436 //fprintf(stdout, "%c", *(char *)list_data(element));
9437 asession = (appsess *)list_data(element);
9438 fprintf(stdout, "ELEM :%s:", asession->sessid);
9439 fprintf(stdout, " Server :%s: \n", asession->serverid);
9440 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9441 }
9442
9443 fprintf(stdout, "\n");
9444 }
9445 return;
9446} /* end print_table */
9447#endif
9448
9449static int appsession_init(void)
9450{
9451 static int initialized = 0;
9452 int idlen;
9453 struct server *s;
9454 struct proxy *p = proxy;
9455
9456 if (!initialized) {
9457 if (!appsession_task_init()) {
9458 apools.sessid = NULL;
9459 apools.serverid = NULL;
9460 apools.ser_waste = 0;
9461 apools.ser_use = 0;
9462 apools.ser_msize = sizeof(void *);
9463 apools.ses_waste = 0;
9464 apools.ses_use = 0;
9465 apools.ses_msize = sizeof(void *);
9466 while (p) {
9467 s = p->srv;
9468 if (apools.ses_msize < p->appsession_len)
9469 apools.ses_msize = p->appsession_len;
9470 while (s) {
9471 idlen = strlen(s->id);
9472 if (apools.ser_msize < idlen)
9473 apools.ser_msize = idlen;
9474 s = s->next;
9475 }
9476 p = p->next;
9477 }
9478 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9479 apools.ses_msize ++;
9480 }
9481 else {
9482 fprintf(stderr, "appsession_task_init failed\n");
9483 return -1;
9484 }
9485 initialized ++;
9486 }
9487 return 0;
9488}
9489
9490static int appsession_task_init(void)
9491{
9492 static int initialized = 0;
9493 struct task *t;
9494 if (!initialized) {
9495 if ((t = pool_alloc(task)) == NULL)
9496 return -1;
9497 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009498 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009499 t->state = TASK_IDLE;
9500 t->context = NULL;
9501 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9502 task_queue(t);
9503 t->process = appsession_refresh;
9504 initialized ++;
9505 }
9506 return 0;
9507}
9508
9509static int appsession_refresh(struct task *t) {
9510 struct proxy *p = proxy;
9511 CHTbl *htbl;
9512 ListElmt *element, *last;
9513 int i;
9514 appsess *asession;
9515 void *data;
9516
9517 while (p) {
9518 if (p->appsession_name != NULL) {
9519 htbl = &p->htbl_proxy;
9520 /* if we ever give up the use of TBLSIZ, we need to change this */
9521 for (i = 0; i < TBLSIZ; i++) {
9522 last = NULL;
9523 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9524 asession = (appsess *)list_data(element);
9525 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9526 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9527 int len;
9528 /*
9529 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9530 */
9531 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9532 asession->sessid, asession->serverid?asession->serverid:"(null)");
9533 write(1, trash, len);
9534 }
9535 /* delete the expired element from within the hash table */
9536 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9537 && (htbl->table[i].destroy != NULL)) {
9538 htbl->table[i].destroy(data);
9539 }
9540 if (last == NULL) {/* patient lost his head, get a new one */
9541 element = list_head(&htbl->table[i]);
9542 if (element == NULL) break; /* no heads left, go to next patient */
9543 }
9544 else
9545 element = last;
9546 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9547 else
9548 last = element;
9549 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9550 }
9551 }
9552 p = p->next;
9553 }
9554 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9555 return TBLCHKINT;
9556} /* end appsession_refresh */
9557
willy tarreau18a957c2006-04-12 19:26:23 +02009558
9559/*
9560 * Local variables:
9561 * c-indent-level: 4
9562 * c-basic-offset: 4
9563 * End:
9564 */