blob: 2f5cb04091097bd8398e3079d6f4ac2886b6e62f [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 tarreauf32f5242006-05-02 22:54:52 +0200594 unsigned long queue_size; /* overall number of sessions waiting for a connect slot on this instance at accept() time */
willy tarreaua1598082005-12-17 13:08:06 +0100595 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100596 char *cli_cookie; /* cookie presented by the client, in capture mode */
597 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100598 int status; /* HTTP status from the server, negative if from proxy */
599 long long bytes; /* number of bytes transferred from the server */
600 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100601 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100602};
603
willy tarreaua41a8b42005-12-17 14:02:24 +0100604struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100605 int fd; /* the listen socket */
606 struct sockaddr_storage addr; /* the address we listen to */
607 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100608};
willy tarreauf32f5242006-05-02 22:54:52 +0200609
willy tarreau0f7af912005-12-17 12:21:26 +0100610struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100611 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100612 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100613 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100614 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200615 struct server *srv; /* known servers */
616 int srv_act, srv_bck; /* # of running servers */
617 int tot_wact, tot_wbck; /* total weights of active and backup servers */
618 struct server **srv_map; /* the server map used to apply weights */
619 int srv_map_sz; /* the size of the effective server map */
620 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100621 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100622 int cookie_len; /* strlen(cookie_name), computed only once */
623 char *appsession_name; /* name of the cookie to look for */
624 int appsession_name_len; /* strlen(appsession_name), computed only once */
625 int appsession_len; /* length of the appsession cookie value to be used */
626 int appsession_timeout;
627 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100628 char *capture_name; /* beginning of the name of the cookie to capture */
629 int capture_namelen; /* length of the cookie name to match */
630 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100631 int clitimeout; /* client I/O timeout (in milliseconds) */
632 int srvtimeout; /* server I/O timeout (in milliseconds) */
633 int contimeout; /* connect timeout (in milliseconds) */
634 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200635 struct list pendconns; /* pending connections with no server assigned yet */
636 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreauf32f5242006-05-02 22:54:52 +0200637 int totpend; /* total number of pending connections on this instance (for stats) */
willy tarreau0f7af912005-12-17 12:21:26 +0100638 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200639 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100640 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100641 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100642 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100643 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100644 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100645 struct proxy *next;
646 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100647 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100648 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100649 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100650 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100651 int nb_reqadd, nb_rspadd;
652 struct hdr_exp *req_exp; /* regular expressions for request headers */
653 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100654 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
655 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
656 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
657 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100658 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100659 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100660 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
661 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100662 struct {
663 char *msg400; /* message for error 400 */
664 int len400; /* message length for error 400 */
665 char *msg403; /* message for error 403 */
666 int len403; /* message length for error 403 */
667 char *msg408; /* message for error 408 */
668 int len408; /* message length for error 408 */
669 char *msg500; /* message for error 500 */
670 int len500; /* message length for error 500 */
671 char *msg502; /* message for error 502 */
672 int len502; /* message length for error 502 */
673 char *msg503; /* message for error 503 */
674 int len503; /* message length for error 503 */
675 char *msg504; /* message for error 504 */
676 int len504; /* message length for error 504 */
677 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100678};
679
680/* info about one given fd */
681struct fdtab {
682 int (*read)(int fd); /* read function */
683 int (*write)(int fd); /* write function */
684 struct task *owner; /* the session (or proxy) associated with this fd */
685 int state; /* the state of this fd */
686};
687
688/*********************************************************************/
689
willy tarreaub952e1d2005-12-18 01:31:20 +0100690int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100691int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100692char *cfg_cfgfile = NULL; /* configuration file */
693char *progname = NULL; /* program name */
694int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100695
696/* global options */
697static struct {
698 int uid;
699 int gid;
700 int nbproc;
701 int maxconn;
702 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100703 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100704 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100705 int mode;
706 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100707 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100708 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100709 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100710 struct sockaddr_in logsrv1, logsrv2;
711} global = {
712 logfac1 : -1,
713 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100714 loglev1 : 7, /* max syslog level : debug */
715 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100716 /* others NULL OK */
717};
718
willy tarreau0f7af912005-12-17 12:21:26 +0100719/*********************************************************************/
720
willy tarreau1c2ad212005-12-18 01:11:29 +0100721fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100722 *StaticWriteEvent;
723
willy tarreau64a3cc32005-12-18 01:13:11 +0100724int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100725
willy tarreau0f7af912005-12-17 12:21:26 +0100726void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200727 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100728 **pool_buffer = NULL,
729 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100730 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100731 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100732 **pool_capture = NULL,
733 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100734
735struct proxy *proxy = NULL; /* list of all existing proxies */
736struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100737struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200738struct task wait_queue[2] = { /* global wait queue */
739 {
740 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
741 next:LIST_HEAD(wait_queue[0]),
742 },
743 {
744 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
745 next:LIST_HEAD(wait_queue[1]),
746 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100747};
willy tarreau0f7af912005-12-17 12:21:26 +0100748
willy tarreau0f7af912005-12-17 12:21:26 +0100749static int totalconn = 0; /* total # of terminated sessions */
750static int actconn = 0; /* # of active sessions */
751static int maxfd = 0; /* # of the highest fd + 1 */
752static int listeners = 0; /* # of listeners */
753static int stopping = 0; /* non zero means stopping in progress */
754static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100755static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100756
willy tarreau53e99702006-03-25 18:53:50 +0100757/* Here we store informations about the pids of the processes we may pause
758 * or kill. We will send them a signal every 10 ms until we can bind to all
759 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100760 */
willy tarreau53e99702006-03-25 18:53:50 +0100761#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100762static int nb_oldpids = 0;
763static int *oldpids = NULL;
764static int oldpids_sig; /* use USR1 or TERM */
765
willy tarreau08dedbe2005-12-18 01:13:48 +0100766#if defined(ENABLE_EPOLL)
767/* FIXME: this is dirty, but at the moment, there's no other solution to remove
768 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
769 * structure with pointers to functions such as init_fd() and close_fd(), plus
770 * a private structure with several pointers to places such as below.
771 */
772
773static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
774#endif
775
willy tarreau0f7af912005-12-17 12:21:26 +0100776static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100777/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100778static char trash[BUFSIZE];
779
willy tarreaudd07e972005-12-18 00:48:48 +0100780const int zero = 0;
781const int one = 1;
782
willy tarreau0f7af912005-12-17 12:21:26 +0100783/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100784 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100785 */
786
787#define MAX_SYSLOG_LEN 1024
788#define NB_LOG_FACILITIES 24
789const char *log_facilities[NB_LOG_FACILITIES] = {
790 "kern", "user", "mail", "daemon",
791 "auth", "syslog", "lpr", "news",
792 "uucp", "cron", "auth2", "ftp",
793 "ntp", "audit", "alert", "cron2",
794 "local0", "local1", "local2", "local3",
795 "local4", "local5", "local6", "local7"
796};
797
798
799#define NB_LOG_LEVELS 8
800const char *log_levels[NB_LOG_LEVELS] = {
801 "emerg", "alert", "crit", "err",
802 "warning", "notice", "info", "debug"
803};
804
805#define SYSLOG_PORT 514
806
807const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
808 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100809
willy tarreaub1285d52005-12-18 01:20:14 +0100810const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100811const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
812const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
813const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
814 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
815 unknown, Set-cookie Rewritten */
816
willy tarreau0f7af912005-12-17 12:21:26 +0100817#define MAX_HOSTNAME_LEN 32
818static char hostname[MAX_HOSTNAME_LEN] = "";
819
willy tarreau8337c6b2005-12-17 13:41:01 +0100820const char *HTTP_302 =
821 "HTTP/1.0 302 Found\r\n"
822 "Cache-Control: no-cache\r\n"
823 "Connection: close\r\n"
824 "Location: "; /* not terminated since it will be concatenated with the URL */
825
willy tarreauc1f47532005-12-18 01:08:26 +0100826/* same as 302 except that the browser MUST retry with the GET method */
827const char *HTTP_303 =
828 "HTTP/1.0 303 See Other\r\n"
829 "Cache-Control: no-cache\r\n"
830 "Connection: close\r\n"
831 "Location: "; /* not terminated since it will be concatenated with the URL */
832
willy tarreaua1598082005-12-17 13:08:06 +0100833const char *HTTP_400 =
834 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100835 "Cache-Control: no-cache\r\n"
836 "Connection: close\r\n"
837 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100838 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100839
willy tarreaua1598082005-12-17 13:08:06 +0100840const char *HTTP_403 =
841 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100842 "Cache-Control: no-cache\r\n"
843 "Connection: close\r\n"
844 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100845 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
846
willy tarreau8337c6b2005-12-17 13:41:01 +0100847const char *HTTP_408 =
848 "HTTP/1.0 408 Request Time-out\r\n"
849 "Cache-Control: no-cache\r\n"
850 "Connection: close\r\n"
851 "\r\n"
852 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
853
willy tarreau750a4722005-12-17 13:21:24 +0100854const char *HTTP_500 =
855 "HTTP/1.0 500 Server Error\r\n"
856 "Cache-Control: no-cache\r\n"
857 "Connection: close\r\n"
858 "\r\n"
859 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100860
861const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100862 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100863 "Cache-Control: no-cache\r\n"
864 "Connection: close\r\n"
865 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100866 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
867
868const char *HTTP_503 =
869 "HTTP/1.0 503 Service Unavailable\r\n"
870 "Cache-Control: no-cache\r\n"
871 "Connection: close\r\n"
872 "\r\n"
873 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
874
875const char *HTTP_504 =
876 "HTTP/1.0 504 Gateway Time-out\r\n"
877 "Cache-Control: no-cache\r\n"
878 "Connection: close\r\n"
879 "\r\n"
880 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100881
willy tarreau0f7af912005-12-17 12:21:26 +0100882/*********************************************************************/
883/* statistics ******************************************************/
884/*********************************************************************/
885
willy tarreau750a4722005-12-17 13:21:24 +0100886#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100887static int stats_tsk_lsrch, stats_tsk_rsrch,
888 stats_tsk_good, stats_tsk_right, stats_tsk_left,
889 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100890#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100891
892
893/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100894/* debugging *******************************************************/
895/*********************************************************************/
896#ifdef DEBUG_FULL
897static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200898static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100899#endif
900
901/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100902/* function prototypes *********************************************/
903/*********************************************************************/
904
905int event_accept(int fd);
906int event_cli_read(int fd);
907int event_cli_write(int fd);
908int event_srv_read(int fd);
909int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100910int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100911
willy tarreau12350152005-12-18 01:03:27 +0100912static int appsession_task_init(void);
913static int appsession_init(void);
914static int appsession_refresh(struct task *t);
915
willy tarreau0f7af912005-12-17 12:21:26 +0100916/*********************************************************************/
917/* general purpose functions ***************************************/
918/*********************************************************************/
919
920void display_version() {
921 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100922 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100923}
924
925/*
926 * This function prints the command line usage and exits
927 */
928void usage(char *name) {
929 display_version();
930 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100931 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100932#if STATTIME > 0
933 "sl"
934#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100935 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
936 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100937 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100938 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100939 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100940#if STATTIME > 0
941 " -s enables statistics output\n"
942 " -l enables long statistics format\n"
943#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100944 " -D goes daemon ; implies -q\n"
945 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100946 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100947 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100948 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100949 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100950 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100951#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100952 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100953#endif
954#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100955 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100956#endif
willy tarreau53e99702006-03-25 18:53:50 +0100957 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100958 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100959 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100960 exit(1);
961}
962
963
964/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100965 * Displays the message on stderr with the date and pid. Overrides the quiet
966 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100967 */
968void Alert(char *fmt, ...) {
969 va_list argp;
970 struct timeval tv;
971 struct tm *tm;
972
willy tarreaud0fb4652005-12-18 01:32:04 +0100973 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100974 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100975
willy tarreau5cbea6f2005-12-17 12:48:26 +0100976 gettimeofday(&tv, NULL);
977 tm=localtime(&tv.tv_sec);
978 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100979 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100980 vfprintf(stderr, fmt, argp);
981 fflush(stderr);
982 va_end(argp);
983 }
willy tarreau0f7af912005-12-17 12:21:26 +0100984}
985
986
987/*
988 * Displays the message on stderr with the date and pid.
989 */
990void Warning(char *fmt, ...) {
991 va_list argp;
992 struct timeval tv;
993 struct tm *tm;
994
willy tarreau982249e2005-12-18 00:57:06 +0100995 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100996 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100997
willy tarreau5cbea6f2005-12-17 12:48:26 +0100998 gettimeofday(&tv, NULL);
999 tm=localtime(&tv.tv_sec);
1000 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +01001001 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001002 vfprintf(stderr, fmt, argp);
1003 fflush(stderr);
1004 va_end(argp);
1005 }
1006}
1007
1008/*
1009 * Displays the message on <out> only if quiet mode is not set.
1010 */
1011void qfprintf(FILE *out, char *fmt, ...) {
1012 va_list argp;
1013
willy tarreau982249e2005-12-18 00:57:06 +01001014 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001015 va_start(argp, fmt);
1016 vfprintf(out, fmt, argp);
1017 fflush(out);
1018 va_end(argp);
1019 }
willy tarreau0f7af912005-12-17 12:21:26 +01001020}
1021
1022
1023/*
1024 * converts <str> to a struct sockaddr_in* which is locally allocated.
1025 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1026 * INADDR_ANY.
1027 */
1028struct sockaddr_in *str2sa(char *str) {
1029 static struct sockaddr_in sa;
1030 char *c;
1031 int port;
1032
willy tarreaua1598082005-12-17 13:08:06 +01001033 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001034 str=strdup(str);
1035
1036 if ((c=strrchr(str,':')) != NULL) {
1037 *c++=0;
1038 port=atol(c);
1039 }
1040 else
1041 port=0;
1042
1043 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1044 sa.sin_addr.s_addr = INADDR_ANY;
1045 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001046 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001047 struct hostent *he;
1048
1049 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001050 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001051 }
1052 else
1053 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1054 }
1055 sa.sin_port=htons(port);
1056 sa.sin_family=AF_INET;
1057
1058 free(str);
1059 return &sa;
1060}
1061
willy tarreaub1285d52005-12-18 01:20:14 +01001062/*
1063 * converts <str> to a two struct in_addr* which are locally allocated.
1064 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1065 * is optionnal and either in the dotted or CIDR notation.
1066 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1067 */
1068int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1069 char *c;
1070 unsigned long len;
1071
1072 memset(mask, 0, sizeof(*mask));
1073 memset(addr, 0, sizeof(*addr));
1074 str=strdup(str);
1075
1076 if ((c = strrchr(str, '/')) != NULL) {
1077 *c++ = 0;
1078 /* c points to the mask */
1079 if (strchr(c, '.') != NULL) { /* dotted notation */
1080 if (!inet_pton(AF_INET, c, mask))
1081 return 0;
1082 }
1083 else { /* mask length */
1084 char *err;
1085 len = strtol(c, &err, 10);
1086 if (!*c || (err && *err) || (unsigned)len > 32)
1087 return 0;
1088 if (len)
1089 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1090 else
1091 mask->s_addr = 0;
1092 }
1093 }
1094 else {
1095 mask->s_addr = 0xFFFFFFFF;
1096 }
1097 if (!inet_pton(AF_INET, str, addr)) {
1098 struct hostent *he;
1099
1100 if ((he = gethostbyname(str)) == NULL) {
1101 return 0;
1102 }
1103 else
1104 *addr = *(struct in_addr *) *(he->h_addr_list);
1105 }
1106 free(str);
1107 return 1;
1108}
1109
willy tarreau9fe663a2005-12-17 13:02:59 +01001110
1111/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001112 * converts <str> to a list of listeners which are dynamically allocated.
1113 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1114 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1115 * - <port> is a numerical port from 1 to 65535 ;
1116 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1117 * This can be repeated as many times as necessary, separated by a coma.
1118 * The <tail> argument is a pointer to a current list which should be appended
1119 * to the tail of the new list. The pointer to the new list is returned.
1120 */
1121struct listener *str2listener(char *str, struct listener *tail) {
1122 struct listener *l;
1123 char *c, *next, *range, *dupstr;
1124 int port, end;
1125
1126 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001127
willy tarreaua41a8b42005-12-17 14:02:24 +01001128 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001129 struct sockaddr_storage ss;
1130
willy tarreaua41a8b42005-12-17 14:02:24 +01001131 str = next;
1132 /* 1) look for the end of the first address */
1133 if ((next = strrchr(str, ',')) != NULL) {
1134 *next++ = 0;
1135 }
1136
willy tarreau8a86dbf2005-12-18 00:45:59 +01001137 /* 2) look for the addr/port delimiter, it's the last colon. */
1138 if ((range = strrchr(str, ':')) == NULL) {
1139 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001140 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001141 }
1142
1143 *range++ = 0;
1144
1145 if (strrchr(str, ':') != NULL) {
1146 /* IPv6 address contains ':' */
1147 memset(&ss, 0, sizeof(ss));
1148 ss.ss_family = AF_INET6;
1149
1150 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1151 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001152 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001153 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001154 }
1155 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001156 memset(&ss, 0, sizeof(ss));
1157 ss.ss_family = AF_INET;
1158
1159 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1160 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1161 }
1162 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1163 struct hostent *he;
1164
1165 if ((he = gethostbyname(str)) == NULL) {
1166 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001167 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001168 }
1169 else
1170 ((struct sockaddr_in *)&ss)->sin_addr =
1171 *(struct in_addr *) *(he->h_addr_list);
1172 }
1173 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001174
1175 /* 3) look for the port-end delimiter */
1176 if ((c = strchr(range, '-')) != NULL) {
1177 *c++ = 0;
1178 end = atol(c);
1179 }
1180 else {
1181 end = atol(range);
1182 }
1183
willy tarreaud0fb4652005-12-18 01:32:04 +01001184 port = atol(range);
1185
1186 if (port < 1 || port > 65535) {
1187 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1188 goto fail;
1189 }
1190
1191 if (end < 1 || end > 65535) {
1192 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1193 goto fail;
1194 }
1195
1196 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001197 l = (struct listener *)calloc(1, sizeof(struct listener));
1198 l->next = tail;
1199 tail = l;
1200
willy tarreau41310e72006-03-25 18:17:56 +01001201 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001202 l->addr = ss;
1203 if (ss.ss_family == AF_INET6)
1204 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1205 else
1206 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1207
willy tarreaua41a8b42005-12-17 14:02:24 +01001208 } /* end for(port) */
1209 } /* end while(next) */
1210 free(dupstr);
1211 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001212 fail:
1213 free(dupstr);
1214 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001215}
1216
willy tarreau4302f492005-12-18 01:00:37 +01001217
1218#define FD_SETS_ARE_BITFIELDS
1219#ifdef FD_SETS_ARE_BITFIELDS
1220/*
1221 * This map is used with all the FD_* macros to check whether a particular bit
1222 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1223 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1224 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1225 * exclusively to the macros.
1226 */
1227fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1228fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1229
1230#else
1231#error "Check if your OS uses bitfields for fd_sets"
1232#endif
1233
1234/* will try to encode the string <string> replacing all characters tagged in
1235 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1236 * prefixed by <escape>, and will store the result between <start> (included
1237 *) and <stop> (excluded), and will always terminate the string with a '\0'
1238 * before <stop>. The position of the '\0' is returned if the conversion
1239 * completes. If bytes are missing between <start> and <stop>, then the
1240 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1241 * cannot even be stored so we return <start> without writing the 0.
1242 * The input string must also be zero-terminated.
1243 */
1244char hextab[16] = "0123456789ABCDEF";
1245char *encode_string(char *start, char *stop,
1246 const char escape, const fd_set *map,
1247 const char *string)
1248{
1249 if (start < stop) {
1250 stop--; /* reserve one byte for the final '\0' */
1251 while (start < stop && *string != 0) {
1252 if (!FD_ISSET((unsigned char)(*string), map))
1253 *start++ = *string;
1254 else {
1255 if (start + 3 >= stop)
1256 break;
1257 *start++ = escape;
1258 *start++ = hextab[(*string >> 4) & 15];
1259 *start++ = hextab[*string & 15];
1260 }
1261 string++;
1262 }
1263 *start = '\0';
1264 }
1265 return start;
1266}
willy tarreaua41a8b42005-12-17 14:02:24 +01001267
1268/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001269 * This function sends a syslog message to both log servers of a proxy,
1270 * or to global log servers if the proxy is NULL.
1271 * It also tries not to waste too much time computing the message header.
1272 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001273 */
1274void send_log(struct proxy *p, int level, char *message, ...) {
1275 static int logfd = -1; /* syslog UDP socket */
1276 static long tvsec = -1; /* to force the string to be initialized */
1277 struct timeval tv;
1278 va_list argp;
1279 static char logmsg[MAX_SYSLOG_LEN];
1280 static char *dataptr = NULL;
1281 int fac_level;
1282 int hdr_len, data_len;
1283 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001284 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 int nbloggers = 0;
1286 char *log_ptr;
1287
1288 if (logfd < 0) {
1289 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1290 return;
1291 }
1292
1293 if (level < 0 || progname == NULL || message == NULL)
1294 return;
1295
1296 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001297 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001298 /* this string is rebuild only once a second */
1299 struct tm *tm = localtime(&tv.tv_sec);
1300 tvsec = tv.tv_sec;
1301
willy tarreauc29948c2005-12-17 13:10:27 +01001302 hdr_len = snprintf(logmsg, sizeof(logmsg),
1303 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1304 monthname[tm->tm_mon],
1305 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1306 progname, pid);
1307 /* WARNING: depending upon implementations, snprintf may return
1308 * either -1 or the number of bytes that would be needed to store
1309 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001310 */
willy tarreauc29948c2005-12-17 13:10:27 +01001311 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1312 hdr_len = sizeof(logmsg);
1313
1314 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001315 }
1316
1317 va_start(argp, message);
1318 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001319 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1320 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001321 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001322 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001323
1324 if (p == NULL) {
1325 if (global.logfac1 >= 0) {
1326 sa[nbloggers] = &global.logsrv1;
1327 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001328 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001329 nbloggers++;
1330 }
1331 if (global.logfac2 >= 0) {
1332 sa[nbloggers] = &global.logsrv2;
1333 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001334 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001335 nbloggers++;
1336 }
1337 } else {
1338 if (p->logfac1 >= 0) {
1339 sa[nbloggers] = &p->logsrv1;
1340 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001341 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001342 nbloggers++;
1343 }
1344 if (p->logfac2 >= 0) {
1345 sa[nbloggers] = &p->logsrv2;
1346 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001347 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001348 nbloggers++;
1349 }
1350 }
1351
1352 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001353 /* we can filter the level of the messages that are sent to each logger */
1354 if (level > loglevel[nbloggers])
1355 continue;
1356
willy tarreauc29948c2005-12-17 13:10:27 +01001357 /* For each target, we may have a different facility.
1358 * We can also have a different log level for each message.
1359 * This induces variations in the message header length.
1360 * Since we don't want to recompute it each time, nor copy it every
1361 * time, we only change the facility in the pre-computed header,
1362 * and we change the pointer to the header accordingly.
1363 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001364 fac_level = (facilities[nbloggers] << 3) + level;
1365 log_ptr = logmsg + 3; /* last digit of the log level */
1366 do {
1367 *log_ptr = '0' + fac_level % 10;
1368 fac_level /= 10;
1369 log_ptr--;
1370 } while (fac_level && log_ptr > logmsg);
1371 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001372
willy tarreauc29948c2005-12-17 13:10:27 +01001373 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001374
1375#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001376 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001377 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1378#else
willy tarreauc29948c2005-12-17 13:10:27 +01001379 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001380 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1381#endif
1382 }
willy tarreau0f7af912005-12-17 12:21:26 +01001383}
1384
1385
1386/* sets <tv> to the current time */
1387static inline struct timeval *tv_now(struct timeval *tv) {
1388 if (tv)
1389 gettimeofday(tv, NULL);
1390 return tv;
1391}
1392
1393/*
1394 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1395 */
willy tarreaudab722b2006-05-04 19:23:38 +02001396static struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
willy tarreau0f7af912005-12-17 12:21:26 +01001397 if (!tv || !from)
1398 return NULL;
1399 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1400 tv->tv_sec = from->tv_sec + (ms/1000);
1401 while (tv->tv_usec >= 1000000) {
1402 tv->tv_usec -= 1000000;
1403 tv->tv_sec++;
1404 }
1405 return tv;
1406}
1407
1408/*
1409 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001410 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001411 */
1412static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001413 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001414 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001415 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001416 return 1;
1417 else if (tv1->tv_usec < tv2->tv_usec)
1418 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001419 else if (tv1->tv_usec > tv2->tv_usec)
1420 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001421 else
1422 return 0;
1423}
1424
1425/*
1426 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001427 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001428 */
1429unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1430 int cmp;
1431 unsigned long ret;
1432
1433
willy tarreauef900ab2005-12-17 12:52:52 +01001434 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001435 if (!cmp)
1436 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001437 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001438 struct timeval *tmp = tv1;
1439 tv1 = tv2;
1440 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001441 }
willy tarreauef900ab2005-12-17 12:52:52 +01001442 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001444 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 else
willy tarreauef900ab2005-12-17 12:52:52 +01001446 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001447 return (unsigned long) ret;
1448}
1449
1450/*
willy tarreau750a4722005-12-17 13:21:24 +01001451 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001452 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001453 */
1454static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1455 unsigned long ret;
1456
willy tarreau6e682ce2005-12-17 13:26:49 +01001457 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1458 if (tv2->tv_usec > tv1->tv_usec)
1459 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001460 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001461 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001462 return (unsigned long) ret;
1463}
1464
1465/*
willy tarreau0f7af912005-12-17 12:21:26 +01001466 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001467 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001468 */
willy tarreaudab722b2006-05-04 19:23:38 +02001469static int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001470 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001471 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001472 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001473 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001474 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001475 else
1476 return 0;
1477 }
willy tarreau0f7af912005-12-17 12:21:26 +01001478 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001479 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001480 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001481 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001482 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001483 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001484 else
1485 return 0;
1486}
1487
1488/*
1489 * returns the remaining time between tv1=now and event=tv2
1490 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001491 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001492 */
1493static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1494 unsigned long ret;
1495
willy tarreau0f7af912005-12-17 12:21:26 +01001496 if (tv_cmp_ms(tv1, tv2) >= 0)
1497 return 0; /* event elapsed */
1498
willy tarreauef900ab2005-12-17 12:52:52 +01001499 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001500 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001501 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 else
willy tarreauef900ab2005-12-17 12:52:52 +01001503 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001504 return (unsigned long) ret;
1505}
1506
1507
1508/*
1509 * zeroes a struct timeval
1510 */
1511
1512static inline struct timeval *tv_eternity(struct timeval *tv) {
1513 tv->tv_sec = tv->tv_usec = 0;
1514 return tv;
1515}
1516
1517/*
1518 * returns 1 if tv is null, else 0
1519 */
1520static inline int tv_iseternity(struct timeval *tv) {
1521 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1522 return 1;
1523 else
1524 return 0;
1525}
1526
1527/*
1528 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1529 * considering that 0 is the eternity.
1530 */
willy tarreaudab722b2006-05-04 19:23:38 +02001531static int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001532 if (tv_iseternity(tv1))
1533 if (tv_iseternity(tv2))
1534 return 0; /* same */
1535 else
1536 return 1; /* tv1 later than tv2 */
1537 else if (tv_iseternity(tv2))
1538 return -1; /* tv2 later than tv1 */
1539
1540 if (tv1->tv_sec > tv2->tv_sec)
1541 return 1;
1542 else if (tv1->tv_sec < tv2->tv_sec)
1543 return -1;
1544 else if (tv1->tv_usec > tv2->tv_usec)
1545 return 1;
1546 else if (tv1->tv_usec < tv2->tv_usec)
1547 return -1;
1548 else
1549 return 0;
1550}
1551
1552/*
1553 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1554 * considering that 0 is the eternity.
1555 */
willy tarreaudab722b2006-05-04 19:23:38 +02001556static int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreau0f7af912005-12-17 12:21:26 +01001557 if (tv_iseternity(tv1))
1558 if (tv_iseternity(tv2))
1559 return 0; /* same */
1560 else
1561 return 1; /* tv1 later than tv2 */
1562 else if (tv_iseternity(tv2))
1563 return -1; /* tv2 later than tv1 */
1564
willy tarreauefae1842005-12-17 12:51:03 +01001565 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001566 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001567 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001568 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001569 return -1;
1570 else
1571 return 0;
1572 }
1573 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001574 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001575 return 1;
1576 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001577 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001578 return -1;
1579 else
1580 return 0;
1581}
1582
1583/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001584 * returns the remaining time between tv1=now and event=tv2
1585 * if tv2 is passed, 0 is returned.
1586 * Returns TIME_ETERNITY if tv2 is eternity.
1587 */
willy tarreaudab722b2006-05-04 19:23:38 +02001588static unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001589 unsigned long ret;
1590
1591 if (tv_iseternity(tv2))
1592 return TIME_ETERNITY;
1593
1594 if (tv_cmp_ms(tv1, tv2) >= 0)
1595 return 0; /* event elapsed */
1596
1597 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1598 if (tv2->tv_usec > tv1->tv_usec)
1599 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1600 else
1601 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1602 return (unsigned long) ret;
1603}
1604
1605/*
willy tarreau0f7af912005-12-17 12:21:26 +01001606 * returns the first event between tv1 and tv2 into tvmin.
1607 * a zero tv is ignored. tvmin is returned.
1608 */
1609static inline struct timeval *tv_min(struct timeval *tvmin,
1610 struct timeval *tv1, struct timeval *tv2) {
1611
1612 if (tv_cmp2(tv1, tv2) <= 0)
1613 *tvmin = *tv1;
1614 else
1615 *tvmin = *tv2;
1616
1617 return tvmin;
1618}
1619
1620
1621
1622/***********************************************************/
1623/* fd management ***************************************/
1624/***********************************************************/
1625
1626
1627
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1629 * The file descriptor is also closed.
1630 */
willy tarreaudab722b2006-05-04 19:23:38 +02001631static void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001632 FD_CLR(fd, StaticReadEvent);
1633 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001634#if defined(ENABLE_EPOLL)
1635 if (PrevReadEvent) {
1636 FD_CLR(fd, PrevReadEvent);
1637 FD_CLR(fd, PrevWriteEvent);
1638 }
1639#endif
1640
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641 close(fd);
1642 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001643
1644 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1645 maxfd--;
1646}
1647
1648/* recomputes the maxfd limit from the fd */
1649static inline void fd_insert(int fd) {
1650 if (fd+1 > maxfd)
1651 maxfd = fd+1;
1652}
1653
1654/*************************************************************/
1655/* task management ***************************************/
1656/*************************************************************/
1657
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658/* puts the task <t> in run queue <q>, and returns <t> */
1659static inline struct task *task_wakeup(struct task **q, struct task *t) {
1660 if (t->state == TASK_RUNNING)
1661 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001662 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001663 t->rqnext = *q;
1664 t->state = TASK_RUNNING;
1665 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001666 }
1667}
1668
willy tarreau5cbea6f2005-12-17 12:48:26 +01001669/* removes the task <t> from the queue <q>
1670 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001671 * set the run queue to point to the next one, and return it
1672 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001673static inline struct task *task_sleep(struct task **q, struct task *t) {
1674 if (t->state == TASK_RUNNING) {
1675 *q = t->rqnext;
1676 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001677 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001678 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001679}
1680
1681/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001682 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001683 * from the run queue. A pointer to the task itself is returned.
1684 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685static inline struct task *task_delete(struct task *t) {
1686 t->prev->next = t->next;
1687 t->next->prev = t->prev;
1688 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001689}
1690
1691/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001692 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001693 */
1694static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001695 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001696}
1697
willy tarreau5cbea6f2005-12-17 12:48:26 +01001698/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001699 * may be only moved or left where it was, depending on its timing requirements.
1700 * <task> is returned.
1701 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001702struct task *task_queue(struct task *task) {
1703 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001704 struct task *start_from;
1705
willy tarreau5e698ef2006-05-02 14:51:00 +02001706 /* This is a very dirty hack to queue non-expirable tasks in another queue
1707 * in order to avoid pulluting the tail of the standard queue. This will go
1708 * away with the new O(log(n)) scheduler anyway.
1709 */
1710 if (tv_iseternity(&task->expire)) {
1711 /* if the task was queued in the standard wait queue, we must dequeue it */
1712 if (task->prev) {
1713 if (task->wq == LIST_HEAD(wait_queue[1]))
1714 return task;
1715 else {
1716 task_delete(task);
1717 task->prev = NULL;
1718 }
1719 }
1720 list = task->wq = LIST_HEAD(wait_queue[1]);
1721 } else {
1722 /* if the task was queued in the eternity queue, we must dequeue it */
1723 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1724 task_delete(task);
1725 task->prev = NULL;
1726 list = task->wq = LIST_HEAD(wait_queue[0]);
1727 }
1728 }
1729
1730 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001731 if (task->prev == NULL) {
1732 // start_from = list;
1733 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001734#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001735 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001736#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001737 /* insert the unlinked <task> into the list, searching back from the last entry */
1738 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1739 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001740#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001741 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001742#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001743 }
1744
1745 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1746 // start_from = start_from->next;
1747 // stats_tsk_nsrch++;
1748 // }
1749 }
1750 else if (task->prev == list ||
1751 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1752 start_from = task->next;
1753 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001754#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001755 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001756#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001757 return task; /* it's already in the right place */
1758 }
1759
willy tarreau750a4722005-12-17 13:21:24 +01001760#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001761 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001762#endif
1763
1764 /* if the task is not at the right place, there's little chance that
1765 * it has only shifted a bit, and it will nearly always be queued
1766 * at the end of the list because of constant timeouts
1767 * (observed in real case).
1768 */
1769#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1770 start_from = list->prev; /* assume we'll queue to the end of the list */
1771 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1772 start_from = start_from->prev;
1773#if STATTIME > 0
1774 stats_tsk_lsrch++;
1775#endif
1776 }
1777#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001778 /* insert the unlinked <task> into the list, searching after position <start_from> */
1779 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1780 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001781#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001782 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001783#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001784 }
willy tarreau750a4722005-12-17 13:21:24 +01001785#endif /* WE_REALLY_... */
1786
willy tarreau0f7af912005-12-17 12:21:26 +01001787 /* we need to unlink it now */
1788 task_delete(task);
1789 }
1790 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001791#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001792 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001793#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001794#ifdef LEFT_TO_TOP /* not very good */
1795 start_from = list;
1796 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1797 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001798#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001799 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001800#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001801 }
1802#else
1803 start_from = task->prev->prev; /* valid because of the previous test above */
1804 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1805 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001806#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001807 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001808#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001809 }
1810#endif
1811 /* we need to unlink it now */
1812 task_delete(task);
1813 }
1814 task->prev = start_from;
1815 task->next = start_from->next;
1816 task->next->prev = task;
1817 start_from->next = task;
1818 return task;
1819}
1820
1821
1822/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001823/* pending connections queues **************************************/
1824/*********************************************************************/
1825
1826/*
willy tarreaudfece232006-05-02 00:19:57 +02001827 * Detaches pending connection <p>, decreases the pending count, and frees
1828 * the pending connection. The connection might have been queued to a specific
1829 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001830 */
willy tarreaudfece232006-05-02 00:19:57 +02001831static void pendconn_free(struct pendconn *p) {
1832 LIST_DEL(&p->list);
1833 p->sess->pend_pos = NULL;
1834 if (p->srv)
1835 p->srv->nbpend--;
1836 else
1837 p->sess->proxy->nbpend--;
willy tarreauf32f5242006-05-02 22:54:52 +02001838 p->sess->proxy->totpend--;
willy tarreaudfece232006-05-02 00:19:57 +02001839 pool_free(pendconn, p);
1840}
1841
1842/* Returns the first pending connection for server <s>, which may be NULL if
1843 * nothing is pending.
1844 */
1845static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001846 if (!s->nbpend)
1847 return NULL;
1848
1849 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1850}
1851
willy tarreaudfece232006-05-02 00:19:57 +02001852/* Returns the first pending connection for proxy <px>, which may be NULL if
1853 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001854 */
willy tarreaudfece232006-05-02 00:19:57 +02001855static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1856 if (!px->nbpend)
1857 return NULL;
1858
1859 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001860}
1861
willy tarreaubc2eda62006-05-04 15:16:23 +02001862/* Detaches the next pending connection from either a server or a proxy, and
1863 * returns its associated session. If no pending connection is found, NULL is
1864 * returned. Note that neither <srv> nor <px> can be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001865 */
willy tarreaubc2eda62006-05-04 15:16:23 +02001866static struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) {
willy tarreau18a957c2006-04-12 19:26:23 +02001867 struct pendconn *p;
1868 struct session *sess;
1869
willy tarreaubc2eda62006-05-04 15:16:23 +02001870 p = pendconn_from_srv(srv);
willy tarreaudfece232006-05-02 00:19:57 +02001871 if (!p) {
willy tarreaubc2eda62006-05-04 15:16:23 +02001872 p = pendconn_from_px(px);
willy tarreaudfece232006-05-02 00:19:57 +02001873 if (!p)
1874 return NULL;
willy tarreaubc2eda62006-05-04 15:16:23 +02001875 p->sess->srv = srv;
willy tarreaudfece232006-05-02 00:19:57 +02001876 }
willy tarreau18a957c2006-04-12 19:26:23 +02001877 sess = p->sess;
1878 pendconn_free(p);
1879 return sess;
1880}
1881
willy tarreaudfece232006-05-02 00:19:57 +02001882/* Adds the session <sess> to the pending connection list of server <sess>->srv
1883 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1884 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1885 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001886 */
willy tarreaudfece232006-05-02 00:19:57 +02001887static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001888 struct pendconn *p;
1889
1890 p = pool_alloc(pendconn);
1891 if (!p)
1892 return NULL;
1893
willy tarreau18a957c2006-04-12 19:26:23 +02001894 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001895 p->sess = sess;
1896 p->srv = sess->srv;
1897 if (sess->srv) {
1898 LIST_ADDQ(&sess->srv->pendconns, &p->list);
1899 sess->srv->nbpend++;
1900 } else {
1901 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
1902 sess->proxy->nbpend++;
1903 }
willy tarreauf32f5242006-05-02 22:54:52 +02001904 sess->proxy->totpend++;
willy tarreau18a957c2006-04-12 19:26:23 +02001905 return p;
1906}
1907
willy tarreau59a6cc22006-05-12 01:29:08 +02001908/* returns 0 if nothing has to be done for server <s> regarding queued connections,
1909 * and non-zero otherwise. Suited for and if/else usage.
1910 */
1911static inline int may_dequeue_tasks(struct server *s, struct proxy *p) {
1912 return (s && (s->nbpend || p->nbpend) &&
1913 s->maxconn && s->cur_sess < s->maxconn && s->queue_mgt);
1914}
1915
1916
1917
willy tarreau18a957c2006-04-12 19:26:23 +02001918/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001919/* more specific functions ***************************************/
1920/*********************************************************************/
1921
1922/* some prototypes */
1923static int maintain_proxies(void);
1924
willy tarreaub952e1d2005-12-18 01:31:20 +01001925/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001926 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1927 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001928static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001929#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1931#else
willy tarreaua1598082005-12-17 13:08:06 +01001932#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001933 return getsockname(fd, (struct sockaddr *)sa, salen);
1934#else
1935 return -1;
1936#endif
1937#endif
1938}
1939
1940/*
1941 * frees the context associated to a session. It must have been removed first.
1942 */
willy tarreaudfece232006-05-02 00:19:57 +02001943static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001944 if (s->pend_pos)
1945 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001946 if (s->req)
1947 pool_free(buffer, s->req);
1948 if (s->rep)
1949 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001950
1951 if (s->rsp_cap != NULL) {
1952 struct cap_hdr *h;
1953 for (h = s->proxy->rsp_cap; h; h = h->next) {
1954 if (s->rsp_cap[h->index] != NULL)
1955 pool_free_to(h->pool, s->rsp_cap[h->index]);
1956 }
1957 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1958 }
1959 if (s->req_cap != NULL) {
1960 struct cap_hdr *h;
1961 for (h = s->proxy->req_cap; h; h = h->next) {
1962 if (s->req_cap[h->index] != NULL)
1963 pool_free_to(h->pool, s->req_cap[h->index]);
1964 }
1965 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1966 }
1967
willy tarreaua1598082005-12-17 13:08:06 +01001968 if (s->logs.uri)
1969 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001970 if (s->logs.cli_cookie)
1971 pool_free(capture, s->logs.cli_cookie);
1972 if (s->logs.srv_cookie)
1973 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001974
willy tarreau5cbea6f2005-12-17 12:48:26 +01001975 pool_free(session, s);
1976}
1977
willy tarreau0f7af912005-12-17 12:21:26 +01001978
1979/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001980 * This function recounts the number of usable active and backup servers for
1981 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001982 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001983 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001984static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001985 struct server *srv;
1986
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001987 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001988 for (srv = px->srv; srv != NULL; srv = srv->next) {
1989 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001990 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001991 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001992 px->tot_wbck += srv->eweight + 1;
1993 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001994 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001995 px->tot_wact += srv->eweight + 1;
1996 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001997 }
1998 }
1999}
2000
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002001/* This function recomputes the server map for proxy px. It
2002 * relies on px->tot_wact and px->tot_wbck, so it must be
2003 * called after recount_servers(). It also expects px->srv_map
2004 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002005 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002006static void recalc_server_map(struct proxy *px) {
2007 int o, tot, flag;
2008 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002009
willy tarreau4c8c2b52006-03-24 19:36:41 +01002010 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002011 flag = SRV_RUNNING;
2012 tot = px->tot_wact;
2013 } else if (px->srv_bck) {
2014 flag = SRV_RUNNING | SRV_BACKUP;
2015 if (px->options & PR_O_USE_ALL_BK)
2016 tot = px->tot_wbck;
2017 else
2018 tot = 1; /* the first server is enough */
2019 } else {
2020 px->srv_map_sz = 0;
2021 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002022 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002023
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002024 /* this algorithm gives priority to the first server, which means that
2025 * it will respect the declaration order for equivalent weights, and
2026 * that whatever the weights, the first server called will always be
2027 * the first declard. This is an important asumption for the backup
2028 * case, where we want the first server only.
2029 */
2030 for (cur = px->srv; cur; cur = cur->next)
2031 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002032
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002033 for (o = 0; o < tot; o++) {
2034 int max = 0;
2035 best = NULL;
2036 for (cur = px->srv; cur; cur = cur->next) {
2037 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2038 int v;
2039
2040 /* If we are forced to return only one server, we don't want to
2041 * go further, because we would return the wrong one due to
2042 * divide overflow.
2043 */
2044 if (tot == 1) {
2045 best = cur;
2046 break;
2047 }
2048
2049 cur->wscore += cur->eweight + 1;
2050 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2051 if (best == NULL || v > max) {
2052 max = v;
2053 best = cur;
2054 }
2055 }
2056 }
2057 px->srv_map[o] = best;
2058 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002059 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002060 px->srv_map_sz = tot;
2061}
Willy TARREAU3481c462006-03-01 22:37:57 +01002062
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002063/*
willy tarreau898db9d2006-04-12 20:29:08 +02002064 * This function tries to find a running server with free connection slots for
2065 * the proxy <px> following the round-robin method.
2066 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2067 * to point to the next server. If no valid server is found, NULL is returned.
2068 */
2069static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2070 int newidx;
2071 struct server *srv;
2072
2073 if (px->srv_map_sz == 0)
2074 return NULL;
2075
2076 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2077 px->srv_rr_idx = 0;
2078 newidx = px->srv_rr_idx;
2079
2080 do {
2081 srv = px->srv_map[newidx++];
2082 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2083 px->srv_rr_idx = newidx;
2084 return srv;
2085 }
2086 if (newidx == px->srv_map_sz)
2087 newidx = 0;
2088 } while (newidx != px->srv_rr_idx);
2089
2090 return NULL;
2091}
2092
2093
2094/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002095 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002096 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002097 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2098 * to point to the next server. If no valid server is found, NULL is returned.
2099 */
2100static inline struct server *get_server_rr(struct proxy *px) {
2101 if (px->srv_map_sz == 0)
2102 return NULL;
2103
2104 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2105 px->srv_rr_idx = 0;
2106 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002107}
2108
willy tarreau62084d42006-03-24 18:57:41 +01002109
2110/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002111 * This function tries to find a running server for the proxy <px> following
2112 * the source hash method. Depending on the number of active/backup servers,
2113 * it will either look for active servers, or for backup servers.
2114 * If any server is found, it will be returned. If no valid server is found,
2115 * NULL is returned.
2116 */
2117static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002118 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002119
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002120 if (px->srv_map_sz == 0)
2121 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002122
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002123 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002124 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002125 while ((l + sizeof (int)) <= len) {
2126 h ^= ntohl(*(unsigned int *)(&addr[l]));
2127 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002128 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002130 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002131 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002132}
2133
2134
2135/*
willy tarreaudfece232006-05-02 00:19:57 +02002136 * This function marks the session as 'assigned' in direct or dispatch modes,
2137 * or tries to assign one in balance mode, according to the algorithm. It does
2138 * nothing if the session had already been assigned a server.
2139 *
2140 * It may return :
willy tarreau000375f2006-05-09 23:15:58 +02002141 * SRV_STATUS_OK if everything is OK. s->srv will be valid.
2142 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
2143 * SRV_STATUS_FULL if all servers are saturated. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002144 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2145 *
2146 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2147 * not need to be called anymore. This usually means that s->srv can be trusted
2148 * in balance and direct modes. This flag is not cleared, so it's to the caller
2149 * to clear it if required (eg: redispatch).
2150 *
willy tarreau0f7af912005-12-17 12:21:26 +01002151 */
willy tarreau0f7af912005-12-17 12:21:26 +01002152
willy tarreaudfece232006-05-02 00:19:57 +02002153int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002154#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002155 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002156#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002157
willy tarreaudfece232006-05-02 00:19:57 +02002158 if (s->pend_pos)
2159 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002160
willy tarreaudfece232006-05-02 00:19:57 +02002161 if (!(s->flags & SN_ASSIGNED)) {
2162 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2163 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2164 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002165
willy tarreaudfece232006-05-02 00:19:57 +02002166 if (s->proxy->options & PR_O_BALANCE_RR) {
2167 s->srv = get_server_rr_with_conns(s->proxy);
2168 if (!s->srv)
2169 return SRV_STATUS_FULL;
2170 }
2171 else if (s->proxy->options & PR_O_BALANCE_SH) {
2172 int len;
2173
2174 if (s->cli_addr.ss_family == AF_INET)
2175 len = 4;
2176 else if (s->cli_addr.ss_family == AF_INET6)
2177 len = 16;
2178 else /* unknown IP family */
2179 return SRV_STATUS_INTERNAL;
2180
2181 s->srv = get_server_sh(s->proxy,
2182 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2183 len);
2184 }
2185 else /* unknown balancing algorithm */
2186 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002187 }
willy tarreaudfece232006-05-02 00:19:57 +02002188 s->flags |= SN_ASSIGNED;
2189 }
2190 return SRV_STATUS_OK;
2191}
willy tarreau1a3442d2006-03-24 21:03:20 +01002192
willy tarreaudfece232006-05-02 00:19:57 +02002193/*
2194 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2195 * The address is taken from the currently assigned server, or from the
2196 * dispatch or transparent address.
2197 *
2198 * It may return :
2199 * SRV_STATUS_OK if everything is OK.
2200 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2201 *
2202 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2203 * not cleared, so it's to the caller to clear it if required.
2204 *
2205 */
2206int assign_server_address(struct session *s) {
2207#ifdef DEBUG_FULL
2208 fprintf(stderr,"assign_server_address : s=%p\n",s);
2209#endif
2210
2211 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2212 /* A server is necessarily known for this session */
2213 if (!(s->flags & SN_ASSIGNED))
2214 return SRV_STATUS_INTERNAL;
2215
2216 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002217
willy tarreaudfece232006-05-02 00:19:57 +02002218 /* if this server remaps proxied ports, we'll use
2219 * the port the client connected to with an offset. */
2220 if (s->srv->state & SRV_MAPPORTS) {
2221 struct sockaddr_in sockname;
2222 socklen_t namelen = sizeof(sockname);
2223
2224 if (!(s->proxy->options & PR_O_TRANSP) ||
2225 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2226 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2227 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002228 }
willy tarreau0f7af912005-12-17 12:21:26 +01002229 }
willy tarreaua1598082005-12-17 13:08:06 +01002230 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002231 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002232 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002233 }
2234 else if (s->proxy->options & PR_O_TRANSP) {
2235 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002236 socklen_t salen = sizeof(s->srv_addr);
2237
willy tarreau5cbea6f2005-12-17 12:48:26 +01002238 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2239 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002240 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 }
2242 }
willy tarreau0f7af912005-12-17 12:21:26 +01002243
willy tarreaudfece232006-05-02 00:19:57 +02002244 s->flags |= SN_ADDR_SET;
2245 return SRV_STATUS_OK;
2246}
willy tarreaua41a8b42005-12-17 14:02:24 +01002247
willy tarreaudfece232006-05-02 00:19:57 +02002248/* This function assigns a server to session <s> if required, and can add the
2249 * connection to either the assigned server's queue or to the proxy's queue.
2250 *
2251 * Returns :
2252 *
2253 * SRV_STATUS_OK if everything is OK.
willy tarreau000375f2006-05-09 23:15:58 +02002254 * SRV_STATUS_NOSRV if no server is available. s->srv = NULL.
willy tarreaudfece232006-05-02 00:19:57 +02002255 * SRV_STATUS_QUEUED if the connection has been queued.
2256 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2257 * connection could not be queued.
2258 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2259 *
2260 */
2261int assign_server_and_queue(struct session *s) {
2262 struct pendconn *p;
2263 int err;
2264
2265 if (s->pend_pos)
2266 return SRV_STATUS_INTERNAL;
2267
2268 if (s->flags & SN_ASSIGNED) {
2269 /* a server does not need to be assigned, perhaps because we're in
2270 * direct mode, or in dispatch or transparent modes where the server
2271 * is not needed.
2272 */
2273 if (s->srv &&
2274 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2275 p = pendconn_add(s);
2276 if (p)
2277 return SRV_STATUS_QUEUED;
2278 else
2279 return SRV_STATUS_FULL;
2280 }
2281 return SRV_STATUS_OK;
2282 }
2283
2284 /* a server needs to be assigned */
2285 err = assign_server(s);
2286 switch (err) {
2287 case SRV_STATUS_OK:
2288 /* in balance mode, we might have servers with connection limits */
2289 if (s->srv != NULL &&
2290 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2291 p = pendconn_add(s);
2292 if (p)
2293 return SRV_STATUS_QUEUED;
2294 else
2295 return SRV_STATUS_FULL;
2296 }
2297 return SRV_STATUS_OK;
2298
2299 case SRV_STATUS_FULL:
2300 /* queue this session into the proxy's queue */
2301 p = pendconn_add(s);
2302 if (p)
2303 return SRV_STATUS_QUEUED;
2304 else
2305 return SRV_STATUS_FULL;
2306
2307 case SRV_STATUS_NOSRV:
2308 case SRV_STATUS_INTERNAL:
2309 return err;
2310 default:
2311 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002312 }
willy tarreaudfece232006-05-02 00:19:57 +02002313}
2314
2315
2316/*
2317 * This function initiates a connection to the server assigned to this session
2318 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2319 * It can return one of :
2320 * - SN_ERR_NONE if everything's OK
2321 * - SN_ERR_SRVTO if there are no more servers
2322 * - SN_ERR_SRVCL if the connection was refused by the server
2323 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2324 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2325 * - SN_ERR_INTERNAL for any other purely internal errors
2326 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2327 */
2328int connect_server(struct session *s) {
2329 int fd, err;
2330
2331 if (!(s->flags & SN_ADDR_SET)) {
2332 err = assign_server_address(s);
2333 if (err != SRV_STATUS_OK)
2334 return SN_ERR_INTERNAL;
2335 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002336
willy tarreau0f7af912005-12-17 12:21:26 +01002337 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002339
2340 if (errno == ENFILE)
2341 send_log(s->proxy, LOG_EMERG,
2342 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2343 s->proxy->id, maxfd);
2344 else if (errno == EMFILE)
2345 send_log(s->proxy, LOG_EMERG,
2346 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2347 s->proxy->id, maxfd);
2348 else if (errno == ENOBUFS || errno == ENOMEM)
2349 send_log(s->proxy, LOG_EMERG,
2350 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2351 s->proxy->id, maxfd);
2352 /* this is a resource error */
2353 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002354 }
2355
willy tarreau9fe663a2005-12-17 13:02:59 +01002356 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002357 /* do not log anything there, it's a normal condition when this option
2358 * is used to serialize connections to a server !
2359 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002360 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2361 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002362 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002363 }
2364
willy tarreau0f7af912005-12-17 12:21:26 +01002365 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2366 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002368 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002369 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002370 }
2371
willy tarreaub952e1d2005-12-18 01:31:20 +01002372 if (s->proxy->options & PR_O_TCP_SRV_KA)
2373 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2374
willy tarreau0174f312005-12-18 01:02:42 +01002375 /* allow specific binding :
2376 * - server-specific at first
2377 * - proxy-specific next
2378 */
2379 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2380 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2381 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2382 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2383 s->proxy->id, s->srv->id);
2384 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002385 send_log(s->proxy, LOG_EMERG,
2386 "Cannot bind to source address before connect() for server %s/%s.\n",
2387 s->proxy->id, s->srv->id);
2388 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002389 }
2390 }
2391 else if (s->proxy->options & PR_O_BIND_SRC) {
2392 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2393 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2394 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2395 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002396 send_log(s->proxy, LOG_EMERG,
2397 "Cannot bind to source address before connect() for server %s/%s.\n",
2398 s->proxy->id, s->srv->id);
2399 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002400 }
willy tarreaua1598082005-12-17 13:08:06 +01002401 }
2402
willy tarreaub1285d52005-12-18 01:20:14 +01002403 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2404 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2405
2406 if (errno == EAGAIN || errno == EADDRINUSE) {
2407 char *msg;
2408 if (errno == EAGAIN) /* no free ports left, try again later */
2409 msg = "no free ports";
2410 else
2411 msg = "local address already in use";
2412
2413 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002414 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002415 send_log(s->proxy, LOG_EMERG,
2416 "Connect() failed for server %s/%s: %s.\n",
2417 s->proxy->id, s->srv->id, msg);
2418 return SN_ERR_RESOURCE;
2419 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002420 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002421 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002422 return SN_ERR_SRVTO;
2423 } else {
2424 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002425 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002426 close(fd);
2427 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002428 }
2429 }
2430
willy tarreau5cbea6f2005-12-17 12:48:26 +01002431 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002432 fdtab[fd].read = &event_srv_read;
2433 fdtab[fd].write = &event_srv_write;
2434 fdtab[fd].state = FD_STCONN; /* connection in progress */
2435
2436 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002437#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2438 if (PrevReadEvent) {
2439 assert(!(FD_ISSET(fd, PrevReadEvent)));
2440 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2441 }
2442#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002443
2444 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002445 if (s->srv)
2446 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002447
2448 if (s->proxy->contimeout)
2449 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2450 else
2451 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002452 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002453}
2454
2455/*
2456 * this function is called on a read event from a client socket.
2457 * It returns 0.
2458 */
2459int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002460 struct task *t = fdtab[fd].owner;
2461 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002462 struct buffer *b = s->req;
2463 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002464
willy tarreau12350152005-12-18 01:03:27 +01002465#ifdef DEBUG_FULL
2466 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2467#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002468
willy tarreau0f7af912005-12-17 12:21:26 +01002469 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002470#ifdef FILL_BUFFERS
2471 while (1)
2472#else
2473 do
2474#endif
2475 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2477 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002478 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002479 }
2480 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002481 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002482 }
2483 else {
2484 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002485 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2486 * since it means that the rewrite protection has been removed. This
2487 * implies that the if statement can be removed.
2488 */
2489 if (max > b->rlim - b->data)
2490 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002491 }
2492
2493 if (max == 0) { /* not anymore room to store data */
2494 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002495 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002496 }
2497
willy tarreau3242e862005-12-17 12:27:53 +01002498#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002499 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002500 int skerr;
2501 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002502
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2504 if (skerr)
2505 ret = -1;
2506 else
2507 ret = recv(fd, b->r, max, 0);
2508 }
willy tarreau3242e862005-12-17 12:27:53 +01002509#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002510 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002511#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002512 if (ret > 0) {
2513 b->r += ret;
2514 b->l += ret;
2515 s->res_cr = RES_DATA;
2516
2517 if (b->r == b->data + BUFSIZE) {
2518 b->r = b->data; /* wrap around the buffer */
2519 }
willy tarreaua1598082005-12-17 13:08:06 +01002520
2521 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002522 /* we hope to read more data or to get a close on next round */
2523 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002524 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002525 else if (ret == 0) {
2526 s->res_cr = RES_NULL;
2527 break;
2528 }
2529 else if (errno == EAGAIN) {/* ignore EAGAIN */
2530 break;
2531 }
2532 else {
2533 s->res_cr = RES_ERROR;
2534 fdtab[fd].state = FD_STERROR;
2535 break;
2536 }
2537 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002538#ifndef FILL_BUFFERS
2539 while (0);
2540#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002541 }
2542 else {
2543 s->res_cr = RES_ERROR;
2544 fdtab[fd].state = FD_STERROR;
2545 }
2546
willy tarreau5cbea6f2005-12-17 12:48:26 +01002547 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002548 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2550 else
2551 tv_eternity(&s->crexpire);
2552
2553 task_wakeup(&rq, t);
2554 }
willy tarreau0f7af912005-12-17 12:21:26 +01002555
willy tarreau0f7af912005-12-17 12:21:26 +01002556 return 0;
2557}
2558
2559
2560/*
2561 * this function is called on a read event from a server socket.
2562 * It returns 0.
2563 */
2564int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002565 struct task *t = fdtab[fd].owner;
2566 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002567 struct buffer *b = s->rep;
2568 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002569
willy tarreau12350152005-12-18 01:03:27 +01002570#ifdef DEBUG_FULL
2571 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2572#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002573
willy tarreau0f7af912005-12-17 12:21:26 +01002574 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002575#ifdef FILL_BUFFERS
2576 while (1)
2577#else
2578 do
2579#endif
2580 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002581 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2582 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002583 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002584 }
2585 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002586 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 }
2588 else {
2589 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002590 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2591 * since it means that the rewrite protection has been removed. This
2592 * implies that the if statement can be removed.
2593 */
2594 if (max > b->rlim - b->data)
2595 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002596 }
2597
2598 if (max == 0) { /* not anymore room to store data */
2599 FD_CLR(fd, StaticReadEvent);
2600 break;
2601 }
2602
willy tarreau3242e862005-12-17 12:27:53 +01002603#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002604 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002605 int skerr;
2606 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002607
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2609 if (skerr)
2610 ret = -1;
2611 else
2612 ret = recv(fd, b->r, max, 0);
2613 }
willy tarreau3242e862005-12-17 12:27:53 +01002614#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002615 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002616#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002617 if (ret > 0) {
2618 b->r += ret;
2619 b->l += ret;
2620 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002621
willy tarreau5cbea6f2005-12-17 12:48:26 +01002622 if (b->r == b->data + BUFSIZE) {
2623 b->r = b->data; /* wrap around the buffer */
2624 }
willy tarreaua1598082005-12-17 13:08:06 +01002625
2626 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002627 /* we hope to read more data or to get a close on next round */
2628 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002629 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 else if (ret == 0) {
2631 s->res_sr = RES_NULL;
2632 break;
2633 }
2634 else if (errno == EAGAIN) {/* ignore EAGAIN */
2635 break;
2636 }
2637 else {
2638 s->res_sr = RES_ERROR;
2639 fdtab[fd].state = FD_STERROR;
2640 break;
2641 }
2642 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002643#ifndef FILL_BUFFERS
2644 while (0);
2645#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002646 }
2647 else {
2648 s->res_sr = RES_ERROR;
2649 fdtab[fd].state = FD_STERROR;
2650 }
2651
willy tarreau5cbea6f2005-12-17 12:48:26 +01002652 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002653 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2655 else
2656 tv_eternity(&s->srexpire);
2657
2658 task_wakeup(&rq, t);
2659 }
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau0f7af912005-12-17 12:21:26 +01002661 return 0;
2662}
2663
2664/*
2665 * this function is called on a write event from a client socket.
2666 * It returns 0.
2667 */
2668int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669 struct task *t = fdtab[fd].owner;
2670 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002671 struct buffer *b = s->rep;
2672 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002673
willy tarreau12350152005-12-18 01:03:27 +01002674#ifdef DEBUG_FULL
2675 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2676#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002677
2678 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002679 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002680 // max = BUFSIZE; BUG !!!!
2681 max = 0;
2682 }
2683 else if (b->r > b->w) {
2684 max = b->r - b->w;
2685 }
2686 else
2687 max = b->data + BUFSIZE - b->w;
2688
willy tarreau0f7af912005-12-17 12:21:26 +01002689 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002690 if (max == 0) {
2691 s->res_cw = RES_NULL;
2692 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002693 tv_eternity(&s->cwexpire);
2694 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002695 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002696 }
2697
willy tarreau3242e862005-12-17 12:27:53 +01002698#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002699 {
2700 int skerr;
2701 socklen_t lskerr = sizeof(skerr);
2702
2703 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2704 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002705 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002706 else
willy tarreau3242e862005-12-17 12:27:53 +01002707 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002708 }
willy tarreau3242e862005-12-17 12:27:53 +01002709#else
willy tarreau0f7af912005-12-17 12:21:26 +01002710 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002711#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002712
2713 if (ret > 0) {
2714 b->l -= ret;
2715 b->w += ret;
2716
2717 s->res_cw = RES_DATA;
2718
2719 if (b->w == b->data + BUFSIZE) {
2720 b->w = b->data; /* wrap around the buffer */
2721 }
2722 }
2723 else if (ret == 0) {
2724 /* nothing written, just make as if we were never called */
2725// s->res_cw = RES_NULL;
2726 return 0;
2727 }
2728 else if (errno == EAGAIN) /* ignore EAGAIN */
2729 return 0;
2730 else {
2731 s->res_cw = RES_ERROR;
2732 fdtab[fd].state = FD_STERROR;
2733 }
2734 }
2735 else {
2736 s->res_cw = RES_ERROR;
2737 fdtab[fd].state = FD_STERROR;
2738 }
2739
willy tarreaub1ff9db2005-12-17 13:51:03 +01002740 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002741 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002742 /* FIXME: to prevent the client from expiring read timeouts during writes,
2743 * we refresh it. A solution would be to merge read+write timeouts into a
2744 * unique one, although that needs some study particularly on full-duplex
2745 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002746 s->crexpire = s->cwexpire;
2747 }
willy tarreau0f7af912005-12-17 12:21:26 +01002748 else
2749 tv_eternity(&s->cwexpire);
2750
willy tarreau5cbea6f2005-12-17 12:48:26 +01002751 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002752 return 0;
2753}
2754
2755
2756/*
2757 * this function is called on a write event from a server socket.
2758 * It returns 0.
2759 */
2760int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002761 struct task *t = fdtab[fd].owner;
2762 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002763 struct buffer *b = s->req;
2764 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002765
willy tarreau12350152005-12-18 01:03:27 +01002766#ifdef DEBUG_FULL
2767 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2768#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002769
2770 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002771 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002772 // max = BUFSIZE; BUG !!!!
2773 max = 0;
2774 }
2775 else if (b->r > b->w) {
2776 max = b->r - b->w;
2777 }
2778 else
2779 max = b->data + BUFSIZE - b->w;
2780
willy tarreau0f7af912005-12-17 12:21:26 +01002781 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002782 if (max == 0) {
2783 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002784 if (s->srv_state == SV_STCONN) {
2785 int skerr;
2786 socklen_t lskerr = sizeof(skerr);
2787 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2788 if (skerr) {
2789 s->res_sw = RES_ERROR;
2790 fdtab[fd].state = FD_STERROR;
2791 task_wakeup(&rq, t);
2792 tv_eternity(&s->swexpire);
2793 FD_CLR(fd, StaticWriteEvent);
2794 return 0;
2795 }
2796 }
2797
willy tarreau0f7af912005-12-17 12:21:26 +01002798 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002799 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002800 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002801 tv_eternity(&s->swexpire);
2802 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002803 return 0;
2804 }
2805
willy tarreau3242e862005-12-17 12:27:53 +01002806#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002807 {
2808 int skerr;
2809 socklen_t lskerr = sizeof(skerr);
2810 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2811 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002812 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002813 else
willy tarreau3242e862005-12-17 12:27:53 +01002814 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002815 }
willy tarreau3242e862005-12-17 12:27:53 +01002816#else
willy tarreau0f7af912005-12-17 12:21:26 +01002817 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002818#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002819 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002820 if (ret > 0) {
2821 b->l -= ret;
2822 b->w += ret;
2823
2824 s->res_sw = RES_DATA;
2825
2826 if (b->w == b->data + BUFSIZE) {
2827 b->w = b->data; /* wrap around the buffer */
2828 }
2829 }
2830 else if (ret == 0) {
2831 /* nothing written, just make as if we were never called */
2832 // s->res_sw = RES_NULL;
2833 return 0;
2834 }
2835 else if (errno == EAGAIN) /* ignore EAGAIN */
2836 return 0;
2837 else {
2838 s->res_sw = RES_ERROR;
2839 fdtab[fd].state = FD_STERROR;
2840 }
2841 }
2842 else {
2843 s->res_sw = RES_ERROR;
2844 fdtab[fd].state = FD_STERROR;
2845 }
2846
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002847 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2848 * otherwise it could loop indefinitely !
2849 */
2850 if (s->srv_state != SV_STCONN) {
2851 if (s->proxy->srvtimeout) {
2852 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002853 /* FIXME: to prevent the server from expiring read timeouts during writes,
2854 * we refresh it. A solution would be to merge read+write+connect timeouts
2855 * into a unique one since we don't mind expiring on read or write, and none
2856 * of them is enabled while waiting for connect(), although that needs some
2857 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002858 s->srexpire = s->swexpire;
2859 }
2860 else
2861 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002862 }
willy tarreau0f7af912005-12-17 12:21:26 +01002863
willy tarreau5cbea6f2005-12-17 12:48:26 +01002864 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002865 return 0;
2866}
2867
2868
2869/*
willy tarreaue39cd132005-12-17 13:00:18 +01002870 * returns a message to the client ; the connection is shut down for read,
2871 * and the request is cleared so that no server connection can be initiated.
2872 * The client must be in a valid state for this (HEADER, DATA ...).
2873 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002874 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002875 */
2876void client_retnclose(struct session *s, int len, const char *msg) {
2877 FD_CLR(s->cli_fd, StaticReadEvent);
2878 FD_SET(s->cli_fd, StaticWriteEvent);
2879 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002880 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002881 shutdown(s->cli_fd, SHUT_RD);
2882 s->cli_state = CL_STSHUTR;
2883 strcpy(s->rep->data, msg);
2884 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002885 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002886 s->rep->r += len;
2887 s->req->l = 0;
2888}
2889
2890
2891/*
2892 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002893 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002894 */
2895void client_return(struct session *s, int len, const char *msg) {
2896 strcpy(s->rep->data, msg);
2897 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002898 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002899 s->rep->r += len;
2900 s->req->l = 0;
2901}
2902
willy tarreau9fe663a2005-12-17 13:02:59 +01002903/*
2904 * send a log for the session when we have enough info about it
2905 */
2906void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002907 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002908 struct proxy *p = s->proxy;
2909 int log;
2910 char *uri;
2911 char *pxid;
2912 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002913 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002914
2915 /* This is a first attempt at a better logging system.
2916 * For now, we rely on send_log() to provide the date, although it obviously
2917 * is the date of the log and not of the request, and most fields are not
2918 * computed.
2919 */
2920
willy tarreaua1598082005-12-17 13:08:06 +01002921 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002922
willy tarreau8a86dbf2005-12-18 00:45:59 +01002923 if (s->cli_addr.ss_family == AF_INET)
2924 inet_ntop(AF_INET,
2925 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2926 pn, sizeof(pn));
2927 else
2928 inet_ntop(AF_INET6,
2929 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2930 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002931
willy tarreauc1cae632005-12-17 14:12:23 +01002932 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002933 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002934 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002935
willy tarreauc1cae632005-12-17 14:12:23 +01002936 tm = localtime(&s->logs.tv_accept.tv_sec);
2937 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002938 char tmpline[MAX_SYSLOG_LEN], *h;
2939 int hdr;
2940
2941 h = tmpline;
2942 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2943 *(h++) = ' ';
2944 *(h++) = '{';
2945 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2946 if (hdr)
2947 *(h++) = '|';
2948 if (s->req_cap[hdr] != NULL)
2949 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2950 }
2951 *(h++) = '}';
2952 }
2953
2954 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2955 *(h++) = ' ';
2956 *(h++) = '{';
2957 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2958 if (hdr)
2959 *(h++) = '|';
2960 if (s->rsp_cap[hdr] != NULL)
2961 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2962 }
2963 *(h++) = '}';
2964 }
2965
2966 if (h < tmpline + sizeof(tmpline) - 4) {
2967 *(h++) = ' ';
2968 *(h++) = '"';
2969 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2970 *(h++) = '"';
2971 }
2972 *h = '\0';
2973
willy tarreauf32f5242006-05-02 22:54:52 +02002974 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002975 pn,
2976 (s->cli_addr.ss_family == AF_INET) ?
2977 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2978 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002979 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2980 tm->tm_hour, tm->tm_min, tm->tm_sec,
2981 pxid, srv,
2982 s->logs.t_request,
willy tarreauf32f5242006-05-02 22:54:52 +02002983 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
2984 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
willy tarreaua1598082005-12-17 13:08:06 +01002985 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002986 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2987 s->logs.status,
2988 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002989 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2990 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002991 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2992 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2993 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2994 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreauf2b8d302006-05-08 11:52:55 +02002995 s->logs.queue_size, s->srv ? s->srv->cur_sess : 0,
willy tarreauf32f5242006-05-02 22:54:52 +02002996 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002997 }
2998 else {
willy tarreauf32f5242006-05-02 22:54:52 +02002999 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d/%d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01003000 pn,
3001 (s->cli_addr.ss_family == AF_INET) ?
3002 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
3003 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003004 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3005 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003006 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003007 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003008 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3009 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003010 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003011 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreauf2b8d302006-05-08 11:52:55 +02003012 s->logs.queue_size, s->srv ? s->srv->cur_sess : 0,
willy tarreauf32f5242006-05-02 22:54:52 +02003013 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01003014 }
3015
3016 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003017}
3018
willy tarreaue39cd132005-12-17 13:00:18 +01003019
3020/*
willy tarreau0f7af912005-12-17 12:21:26 +01003021 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003022 * to an accept. It tries to accept as many connections as possible.
3023 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003024 */
3025int event_accept(int fd) {
3026 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003027 struct session *s;
3028 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003029 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003030 int max_accept;
3031
3032 if (global.nbproc > 1)
3033 max_accept = 8; /* let other processes catch some connections too */
3034 else
3035 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003036
willy tarreauc2becdc2006-03-19 19:36:48 +01003037 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003038 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003039 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003040
willy tarreaub1285d52005-12-18 01:20:14 +01003041 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3042 switch (errno) {
3043 case EAGAIN:
3044 case EINTR:
3045 case ECONNABORTED:
3046 return 0; /* nothing more to accept */
3047 case ENFILE:
3048 send_log(p, LOG_EMERG,
3049 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3050 p->id, maxfd);
3051 return 0;
3052 case EMFILE:
3053 send_log(p, LOG_EMERG,
3054 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3055 p->id, maxfd);
3056 return 0;
3057 case ENOBUFS:
3058 case ENOMEM:
3059 send_log(p, LOG_EMERG,
3060 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3061 p->id, maxfd);
3062 return 0;
3063 default:
3064 return 0;
3065 }
3066 }
willy tarreau0f7af912005-12-17 12:21:26 +01003067
willy tarreau5cbea6f2005-12-17 12:48:26 +01003068 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3069 Alert("out of memory in event_accept().\n");
3070 FD_CLR(fd, StaticReadEvent);
3071 p->state = PR_STIDLE;
3072 close(cfd);
3073 return 0;
3074 }
willy tarreau0f7af912005-12-17 12:21:26 +01003075
willy tarreaub1285d52005-12-18 01:20:14 +01003076 /* if this session comes from a known monitoring system, we want to ignore
3077 * it as soon as possible, which means closing it immediately for TCP.
3078 */
3079 s->flags = 0;
3080 if (addr.ss_family == AF_INET &&
3081 p->mon_mask.s_addr &&
3082 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3083 if (p->mode == PR_MODE_TCP) {
3084 close(cfd);
3085 pool_free(session, s);
3086 continue;
3087 }
3088 s->flags |= SN_MONITOR;
3089 }
3090
willy tarreau5cbea6f2005-12-17 12:48:26 +01003091 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3092 Alert("out of memory in event_accept().\n");
3093 FD_CLR(fd, StaticReadEvent);
3094 p->state = PR_STIDLE;
3095 close(cfd);
3096 pool_free(session, s);
3097 return 0;
3098 }
willy tarreau0f7af912005-12-17 12:21:26 +01003099
willy tarreau5cbea6f2005-12-17 12:48:26 +01003100 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003101 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003102 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3103 close(cfd);
3104 pool_free(task, t);
3105 pool_free(session, s);
3106 return 0;
3107 }
willy tarreau0f7af912005-12-17 12:21:26 +01003108
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3110 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3111 (char *) &one, sizeof(one)) == -1)) {
3112 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3113 close(cfd);
3114 pool_free(task, t);
3115 pool_free(session, s);
3116 return 0;
3117 }
willy tarreau0f7af912005-12-17 12:21:26 +01003118
willy tarreaub952e1d2005-12-18 01:31:20 +01003119 if (p->options & PR_O_TCP_CLI_KA)
3120 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3121
willy tarreau9fe663a2005-12-17 13:02:59 +01003122 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003123 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003124 t->state = TASK_IDLE;
3125 t->process = process_session;
3126 t->context = s;
3127
3128 s->task = t;
3129 s->proxy = p;
3130 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3131 s->srv_state = SV_STIDLE;
3132 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003133
willy tarreau9fe663a2005-12-17 13:02:59 +01003134 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3135 s->cli_fd = cfd;
3136 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003137 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003138 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003139
willy tarreaub1285d52005-12-18 01:20:14 +01003140 if (s->flags & SN_MONITOR)
3141 s->logs.logwait = 0;
3142 else
3143 s->logs.logwait = p->to_log;
3144
willy tarreaua1598082005-12-17 13:08:06 +01003145 s->logs.tv_accept = now;
3146 s->logs.t_request = -1;
willy tarreauf32f5242006-05-02 22:54:52 +02003147 s->logs.t_queue = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003148 s->logs.t_connect = -1;
3149 s->logs.t_data = -1;
3150 s->logs.t_close = 0;
3151 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003152 s->logs.cli_cookie = NULL;
3153 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003154 s->logs.status = -1;
3155 s->logs.bytes = 0;
willy tarreauf32f5242006-05-02 22:54:52 +02003156 s->logs.queue_size = p->totpend; /* we get the number of pending conns before us */
willy tarreau9fe663a2005-12-17 13:02:59 +01003157
willy tarreau2f6ba652005-12-17 13:57:42 +01003158 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003159 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003160
willy tarreau4302f492005-12-18 01:00:37 +01003161 if (p->nb_req_cap > 0) {
3162 if ((s->req_cap =
3163 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3164 == NULL) { /* no memory */
3165 close(cfd); /* nothing can be done for this fd without memory */
3166 pool_free(task, t);
3167 pool_free(session, s);
3168 return 0;
3169 }
3170 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3171 }
3172 else
3173 s->req_cap = NULL;
3174
3175 if (p->nb_rsp_cap > 0) {
3176 if ((s->rsp_cap =
3177 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3178 == NULL) { /* no memory */
3179 if (s->req_cap != NULL)
3180 pool_free_to(p->req_cap_pool, s->req_cap);
3181 close(cfd); /* nothing can be done for this fd without memory */
3182 pool_free(task, t);
3183 pool_free(session, s);
3184 return 0;
3185 }
3186 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3187 }
3188 else
3189 s->rsp_cap = NULL;
3190
willy tarreau5cbea6f2005-12-17 12:48:26 +01003191 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3192 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003193 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003194 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003195
willy tarreau8a86dbf2005-12-18 00:45:59 +01003196 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003197 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003198 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003199 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003200
willy tarreau9fe663a2005-12-17 13:02:59 +01003201 if (p->to_log) {
3202 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003203 if (s->logs.logwait & LW_CLIP)
3204 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003205 sess_log(s);
3206 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003207 else if (s->cli_addr.ss_family == AF_INET) {
3208 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3209 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3210 sn, sizeof(sn)) &&
3211 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3212 pn, sizeof(pn))) {
3213 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3214 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3215 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3216 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3217 }
3218 }
3219 else {
3220 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3221 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3222 sn, sizeof(sn)) &&
3223 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3224 pn, sizeof(pn))) {
3225 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3226 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3227 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3228 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3229 }
3230 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003231 }
willy tarreau0f7af912005-12-17 12:21:26 +01003232
willy tarreau982249e2005-12-18 00:57:06 +01003233 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003234 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003235 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003236 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003237 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003238 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003239 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003240 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003241
willy tarreau8a86dbf2005-12-18 00:45:59 +01003242 if (s->cli_addr.ss_family == AF_INET) {
3243 char pn[INET_ADDRSTRLEN];
3244 inet_ntop(AF_INET,
3245 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3246 pn, sizeof(pn));
3247
3248 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3249 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3250 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3251 }
3252 else {
3253 char pn[INET6_ADDRSTRLEN];
3254 inet_ntop(AF_INET6,
3255 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3256 pn, sizeof(pn));
3257
3258 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3259 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3260 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3261 }
3262
willy tarreauef900ab2005-12-17 12:52:52 +01003263 write(1, trash, len);
3264 }
willy tarreau0f7af912005-12-17 12:21:26 +01003265
willy tarreau5cbea6f2005-12-17 12:48:26 +01003266 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003267 if (s->rsp_cap != NULL)
3268 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3269 if (s->req_cap != NULL)
3270 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003271 close(cfd); /* nothing can be done for this fd without memory */
3272 pool_free(task, t);
3273 pool_free(session, s);
3274 return 0;
3275 }
willy tarreau4302f492005-12-18 01:00:37 +01003276
willy tarreau5cbea6f2005-12-17 12:48:26 +01003277 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003278 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003279 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3280 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003281 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003282 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003283
willy tarreau5cbea6f2005-12-17 12:48:26 +01003284 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3285 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003286 if (s->rsp_cap != NULL)
3287 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3288 if (s->req_cap != NULL)
3289 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003290 close(cfd); /* nothing can be done for this fd without memory */
3291 pool_free(task, t);
3292 pool_free(session, s);
3293 return 0;
3294 }
3295 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003296 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003297 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 +01003298
willy tarreau5cbea6f2005-12-17 12:48:26 +01003299 fdtab[cfd].read = &event_cli_read;
3300 fdtab[cfd].write = &event_cli_write;
3301 fdtab[cfd].owner = t;
3302 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003303
willy tarreaub1285d52005-12-18 01:20:14 +01003304 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3305 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3306 /* Either we got a request from a monitoring system on an HTTP instance,
3307 * or we're in health check mode with the 'httpchk' option enabled. In
3308 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3309 */
3310 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3311 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3312 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003313 }
3314 else {
3315 FD_SET(cfd, StaticReadEvent);
3316 }
3317
willy tarreaub952e1d2005-12-18 01:31:20 +01003318#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3319 if (PrevReadEvent) {
3320 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3321 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3322 }
3323#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003324 fd_insert(cfd);
3325
3326 tv_eternity(&s->cnexpire);
3327 tv_eternity(&s->srexpire);
3328 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003329 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003330 tv_eternity(&s->cwexpire);
3331
willy tarreaub1285d52005-12-18 01:20:14 +01003332 if (s->proxy->clitimeout) {
3333 if (FD_ISSET(cfd, StaticReadEvent))
3334 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3335 if (FD_ISSET(cfd, StaticWriteEvent))
3336 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3337 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003338
willy tarreaub1285d52005-12-18 01:20:14 +01003339 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003340
3341 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003342
3343 if (p->mode != PR_MODE_HEALTH)
3344 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003345
3346 p->nbconn++;
3347 actconn++;
3348 totalconn++;
3349
willy tarreaub952e1d2005-12-18 01:31:20 +01003350 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003351 } /* end of while (p->nbconn < p->maxconn) */
3352 return 0;
3353}
willy tarreau0f7af912005-12-17 12:21:26 +01003354
willy tarreau0f7af912005-12-17 12:21:26 +01003355
willy tarreau5cbea6f2005-12-17 12:48:26 +01003356/*
3357 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003358 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3359 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360 * or -1 if an error occured.
3361 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003362int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 struct task *t = fdtab[fd].owner;
3364 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003365 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003366 socklen_t lskerr = sizeof(skerr);
3367
willy tarreau05be12b2006-03-19 19:35:00 +01003368 skerr = 1;
3369 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3370 || (skerr != 0)) {
3371 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003372 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003373 fdtab[fd].state = FD_STERROR;
3374 FD_CLR(fd, StaticWriteEvent);
3375 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003376 else if (s->result != -1) {
3377 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003378 if (s->proxy->options & PR_O_HTTP_CHK) {
3379 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003380 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003381 * so we'll send the request, and won't wake the checker up now.
3382 */
3383#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003384 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003385#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003386 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003387#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003388 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003389 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3390 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3391 return 0;
3392 }
willy tarreau05be12b2006-03-19 19:35:00 +01003393 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003394 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003395 FD_CLR(fd, StaticWriteEvent);
3396 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003397 }
3398 else {
3399 /* good TCP connection is enough */
3400 s->result = 1;
3401 }
3402 }
3403
3404 task_wakeup(&rq, t);
3405 return 0;
3406}
3407
willy tarreau0f7af912005-12-17 12:21:26 +01003408
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003409/*
3410 * This function is used only for server health-checks. It handles
3411 * the server's reply to an HTTP request. It returns 1 if the server replies
3412 * 2xx or 3xx (valid responses), or -1 in other cases.
3413 */
3414int event_srv_chk_r(int fd) {
3415 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003416 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003417 struct task *t = fdtab[fd].owner;
3418 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003419 int skerr;
3420 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003421
willy tarreaua4a583a2005-12-18 01:39:19 +01003422 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003423
willy tarreau05be12b2006-03-19 19:35:00 +01003424 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3425 if (!skerr) {
3426#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003427 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003428#else
willy tarreau05be12b2006-03-19 19:35:00 +01003429 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3430 * but the connection was closed on the remote end. Fortunately, recv still
3431 * works correctly and we don't need to do the getsockopt() on linux.
3432 */
3433 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003434#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003435
3436 if ((len >= sizeof("HTTP/1.0 000")) &&
3437 !memcmp(reply, "HTTP/1.", 7) &&
3438 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3439 result = 1;
3440 }
3441
3442 if (result == -1)
3443 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003444
3445 if (s->result != -1)
3446 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003447
3448 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003450 return 0;
3451}
3452
3453
3454/*
3455 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3456 * and moves <end> just after the end of <str>.
3457 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3458 * the shift value (positive or negative) is returned.
3459 * If there's no space left, the move is not done.
3460 *
3461 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003463 int delta;
3464 int len;
3465
3466 len = strlen(str);
3467 delta = len - (end - pos);
3468
3469 if (delta + b->r >= b->data + BUFSIZE)
3470 return 0; /* no space left */
3471
3472 /* first, protect the end of the buffer */
3473 memmove(end + delta, end, b->data + b->l - end);
3474
3475 /* now, copy str over pos */
3476 memcpy(pos, str,len);
3477
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478 /* we only move data after the displaced zone */
3479 if (b->r > pos) b->r += delta;
3480 if (b->w > pos) b->w += delta;
3481 if (b->h > pos) b->h += delta;
3482 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003483 b->l += delta;
3484
3485 return delta;
3486}
3487
willy tarreau8337c6b2005-12-17 13:41:01 +01003488/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003489 * len is 0.
3490 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003492 int delta;
3493
3494 delta = len - (end - pos);
3495
3496 if (delta + b->r >= b->data + BUFSIZE)
3497 return 0; /* no space left */
3498
Willy TARREAUe78ae262006-01-08 01:24:12 +01003499 if (b->data + b->l < end)
3500 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3501 return 0;
3502
willy tarreau0f7af912005-12-17 12:21:26 +01003503 /* first, protect the end of the buffer */
3504 memmove(end + delta, end, b->data + b->l - end);
3505
3506 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003507 if (len)
3508 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003509
willy tarreau5cbea6f2005-12-17 12:48:26 +01003510 /* we only move data after the displaced zone */
3511 if (b->r > pos) b->r += delta;
3512 if (b->w > pos) b->w += delta;
3513 if (b->h > pos) b->h += delta;
3514 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003515 b->l += delta;
3516
3517 return delta;
3518}
3519
3520
3521int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3522 char *old_dst = dst;
3523
3524 while (*str) {
3525 if (*str == '\\') {
3526 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003527 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003528 int len, num;
3529
3530 num = *str - '0';
3531 str++;
3532
willy tarreau8a86dbf2005-12-18 00:45:59 +01003533 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003534 len = matches[num].rm_eo - matches[num].rm_so;
3535 memcpy(dst, src + matches[num].rm_so, len);
3536 dst += len;
3537 }
3538
3539 }
3540 else if (*str == 'x') {
3541 unsigned char hex1, hex2;
3542 str++;
3543
willy tarreauc1f47532005-12-18 01:08:26 +01003544 hex1 = toupper(*str++) - '0';
3545 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003546
3547 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3548 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3549 *dst++ = (hex1<<4) + hex2;
3550 }
3551 else
3552 *dst++ = *str++;
3553 }
3554 else
3555 *dst++ = *str++;
3556 }
3557 *dst = 0;
3558 return dst - old_dst;
3559}
3560
willy tarreauc1f47532005-12-18 01:08:26 +01003561static int ishex(char s)
3562{
3563 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3564}
3565
3566/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3567char *check_replace_string(char *str)
3568{
3569 char *err = NULL;
3570 while (*str) {
3571 if (*str == '\\') {
3572 err = str; /* in case of a backslash, we return the pointer to it */
3573 str++;
3574 if (!*str)
3575 return err;
3576 else if (isdigit((int)*str))
3577 err = NULL;
3578 else if (*str == 'x') {
3579 str++;
3580 if (!ishex(*str))
3581 return err;
3582 str++;
3583 if (!ishex(*str))
3584 return err;
3585 err = NULL;
3586 }
3587 else {
3588 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3589 err = NULL;
3590 }
3591 }
3592 str++;
3593 }
3594 return err;
3595}
3596
3597
willy tarreau9fe663a2005-12-17 13:02:59 +01003598
willy tarreau0f7af912005-12-17 12:21:26 +01003599/*
3600 * manages the client FSM and its socket. BTW, it also tries to handle the
3601 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3602 * 0 else.
3603 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003605 int s = t->srv_state;
3606 int c = t->cli_state;
3607 struct buffer *req = t->req;
3608 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003609 int method_checked = 0;
3610 appsess *asession_temp = NULL;
3611 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003612
willy tarreau750a4722005-12-17 13:21:24 +01003613#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003614 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3615 cli_stnames[c], srv_stnames[s],
3616 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3617 t->crexpire.tv_sec, t->crexpire.tv_usec,
3618 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003619#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003620 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3621 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3622 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3623 //);
3624 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003625 /* now parse the partial (or complete) headers */
3626 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3627 char *ptr;
3628 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003629 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003630
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003632
willy tarreau0f7af912005-12-17 12:21:26 +01003633 /* look for the end of the current header */
3634 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3635 ptr++;
3636
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003638 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003639
3640 /*
3641 * first, let's check that it's not a leading empty line, in
3642 * which case we'll ignore and remove it (according to RFC2616).
3643 */
3644 if (req->h == req->data) {
3645 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3646 if (ptr > req->r - 2) {
3647 /* this is a partial header, let's wait for more to come */
3648 req->lr = ptr;
3649 break;
3650 }
3651
3652 /* now we know that *ptr is either \r or \n,
3653 * and that there are at least 1 char after it.
3654 */
3655 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3656 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3657 else
3658 req->lr = ptr + 2; /* \r\n or \n\r */
3659 /* ignore empty leading lines */
3660 buffer_replace2(req, req->h, req->lr, NULL, 0);
3661 req->h = req->lr;
3662 continue;
3663 }
3664
willy tarreau5cbea6f2005-12-17 12:48:26 +01003665 /* we can only get here after an end of headers */
3666 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003667
willy tarreaue39cd132005-12-17 13:00:18 +01003668 if (t->flags & SN_CLDENY) {
3669 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003670 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003671 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003672 if (!(t->flags & SN_ERR_MASK))
3673 t->flags |= SN_ERR_PRXCOND;
3674 if (!(t->flags & SN_FINST_MASK))
3675 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003676 return 1;
3677 }
3678
willy tarreau5cbea6f2005-12-17 12:48:26 +01003679 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003680 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3681 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003682 }
willy tarreau0f7af912005-12-17 12:21:26 +01003683
willy tarreau9fe663a2005-12-17 13:02:59 +01003684 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003685 if (t->cli_addr.ss_family == AF_INET) {
3686 unsigned char *pn;
3687 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3688 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3689 pn[0], pn[1], pn[2], pn[3]);
3690 buffer_replace2(req, req->h, req->h, trash, len);
3691 }
3692 else if (t->cli_addr.ss_family == AF_INET6) {
3693 char pn[INET6_ADDRSTRLEN];
3694 inet_ntop(AF_INET6,
3695 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3696 pn, sizeof(pn));
3697 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3698 buffer_replace2(req, req->h, req->h, trash, len);
3699 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003700 }
3701
willy tarreau25c4ea52005-12-18 00:49:49 +01003702 /* add a "connection: close" line if needed */
3703 if (t->proxy->options & PR_O_HTTP_CLOSE)
3704 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3705
willy tarreau982249e2005-12-18 00:57:06 +01003706 if (!memcmp(req->data, "POST ", 5)) {
3707 /* this is a POST request, which is not cacheable by default */
3708 t->flags |= SN_POST;
3709 }
willy tarreaucd878942005-12-17 13:27:43 +01003710
willy tarreau5cbea6f2005-12-17 12:48:26 +01003711 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003712 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003713
willy tarreau750a4722005-12-17 13:21:24 +01003714 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003715 /* FIXME: we'll set the client in a wait state while we try to
3716 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003717 * better to release the maximum of system buffers instead ?
3718 * The solution is to enable the FD but set its time-out to
3719 * eternity as long as the server-side does not enable data xfer.
3720 * CL_STDATA also has to take care of this, which is done below.
3721 */
willy tarreauef900ab2005-12-17 12:52:52 +01003722 //FD_CLR(t->cli_fd, StaticReadEvent);
3723 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003724
3725 /* FIXME: if we break here (as up to 1.1.23), having the client
3726 * shutdown its connection can lead to an abort further.
3727 * it's better to either return 1 or even jump directly to the
3728 * data state which will save one schedule.
3729 */
3730 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003731
3732 if (!t->proxy->clitimeout ||
3733 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3734 /* If the client has no timeout, or if the server is not ready yet,
3735 * and we know for sure that it can expire, then it's cleaner to
3736 * disable the timeout on the client side so that too low values
3737 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003738 *
3739 * FIXME-20050705: the server needs a way to re-enable this time-out
3740 * when it switches its state, otherwise a client can stay connected
3741 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003742 */
3743 tv_eternity(&t->crexpire);
3744
willy tarreau197e8ec2005-12-17 14:10:59 +01003745 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003746 }
willy tarreau0f7af912005-12-17 12:21:26 +01003747
Willy TARREAU13032e72006-03-12 17:31:45 +01003748 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3749 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 /* this is a partial header, let's wait for more to come */
3751 req->lr = ptr;
3752 break;
3753 }
willy tarreau0f7af912005-12-17 12:21:26 +01003754
willy tarreau5cbea6f2005-12-17 12:48:26 +01003755 /* now we know that *ptr is either \r or \n,
3756 * and that there are at least 1 char after it.
3757 */
3758 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3759 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3760 else
3761 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003762
willy tarreau5cbea6f2005-12-17 12:48:26 +01003763 /*
3764 * now we know that we have a full header ; we can do whatever
3765 * we want with these pointers :
3766 * req->h = beginning of header
3767 * ptr = end of header (first \r or \n)
3768 * req->lr = beginning of next line (next rep->h)
3769 * req->r = end of data (not used at this stage)
3770 */
willy tarreau0f7af912005-12-17 12:21:26 +01003771
willy tarreau12350152005-12-18 01:03:27 +01003772 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3773 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3774 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3775
3776 /* skip ; */
3777 request_line++;
3778
3779 /* look if we have a jsessionid */
3780
3781 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3782
3783 /* skip jsessionid= */
3784 request_line += t->proxy->appsession_name_len + 1;
3785
3786 /* First try if we allready have an appsession */
3787 asession_temp = &local_asession;
3788
3789 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3790 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3791 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3792 return 0;
3793 }
3794
3795 /* Copy the sessionid */
3796 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3797 asession_temp->sessid[t->proxy->appsession_len] = 0;
3798 asession_temp->serverid = NULL;
3799
3800 /* only do insert, if lookup fails */
3801 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3802 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3803 Alert("Not enough memory process_cli():asession:calloc().\n");
3804 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3805 return 0;
3806 }
3807 asession_temp->sessid = local_asession.sessid;
3808 asession_temp->serverid = local_asession.serverid;
3809 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003810 } /* end if (chtbl_lookup()) */
3811 else {
willy tarreau12350152005-12-18 01:03:27 +01003812 /*free wasted memory;*/
3813 pool_free_to(apools.sessid, local_asession.sessid);
3814 }
3815
3816 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3817 asession_temp->request_count++;
3818
3819#if defined(DEBUG_HASH)
3820 print_table(&(t->proxy->htbl_proxy));
3821#endif
3822
3823 if (asession_temp->serverid == NULL) {
3824 Alert("Found Application Session without matching server.\n");
3825 } else {
3826 struct server *srv = t->proxy->srv;
3827 while (srv) {
3828 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3829 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3830 /* we found the server and it's usable */
3831 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003832 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003833 t->srv = srv;
3834 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003835 } else {
willy tarreau12350152005-12-18 01:03:27 +01003836 t->flags &= ~SN_CK_MASK;
3837 t->flags |= SN_CK_DOWN;
3838 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003839 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003840 srv = srv->next;
3841 }/* end while(srv) */
3842 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003843 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003844 else {
3845 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3846 }
willy tarreau598da412005-12-18 01:07:29 +01003847 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003848 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003849 else{
3850 //printf("No Methode-Header with Session-String\n");
3851 }
3852
willy tarreau8337c6b2005-12-17 13:41:01 +01003853 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003854 /* we have a complete HTTP request that we must log */
3855 int urilen;
3856
willy tarreaua1598082005-12-17 13:08:06 +01003857 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003858 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003859 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003860 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003861 if (!(t->flags & SN_ERR_MASK))
3862 t->flags |= SN_ERR_PRXCOND;
3863 if (!(t->flags & SN_FINST_MASK))
3864 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003865 return 1;
3866 }
3867
3868 urilen = ptr - req->h;
3869 if (urilen >= REQURI_LEN)
3870 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003871 memcpy(t->logs.uri, req->h, urilen);
3872 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003873
willy tarreaua1598082005-12-17 13:08:06 +01003874 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003875 sess_log(t);
3876 }
willy tarreau4302f492005-12-18 01:00:37 +01003877 else if (t->logs.logwait & LW_REQHDR) {
3878 struct cap_hdr *h;
3879 int len;
3880 for (h = t->proxy->req_cap; h; h = h->next) {
3881 if ((h->namelen + 2 <= ptr - req->h) &&
3882 (req->h[h->namelen] == ':') &&
3883 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3884
3885 if (t->req_cap[h->index] == NULL)
3886 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3887
3888 len = ptr - (req->h + h->namelen + 2);
3889 if (len > h->len)
3890 len = h->len;
3891
3892 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3893 t->req_cap[h->index][len]=0;
3894 }
3895 }
3896
3897 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003898
willy tarreau5cbea6f2005-12-17 12:48:26 +01003899 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003900
willy tarreau982249e2005-12-18 00:57:06 +01003901 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003902 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003903 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 +01003904 max = ptr - req->h;
3905 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003906 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003907 trash[len++] = '\n';
3908 write(1, trash, len);
3909 }
willy tarreau0f7af912005-12-17 12:21:26 +01003910
willy tarreau25c4ea52005-12-18 00:49:49 +01003911
3912 /* remove "connection: " if needed */
3913 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3914 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3915 delete_header = 1;
3916 }
3917
willy tarreau5cbea6f2005-12-17 12:48:26 +01003918 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003919 if (!delete_header && t->proxy->req_exp != NULL
3920 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003921 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922 char term;
3923
3924 term = *ptr;
3925 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003926 exp = t->proxy->req_exp;
3927 do {
3928 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3929 switch (exp->action) {
3930 case ACT_ALLOW:
3931 if (!(t->flags & SN_CLDENY))
3932 t->flags |= SN_CLALLOW;
3933 break;
3934 case ACT_REPLACE:
3935 if (!(t->flags & SN_CLDENY)) {
3936 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3937 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3938 }
3939 break;
3940 case ACT_REMOVE:
3941 if (!(t->flags & SN_CLDENY))
3942 delete_header = 1;
3943 break;
3944 case ACT_DENY:
3945 if (!(t->flags & SN_CLALLOW))
3946 t->flags |= SN_CLDENY;
3947 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003948 case ACT_PASS: /* we simply don't deny this one */
3949 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003950 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003951 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003952 }
willy tarreaue39cd132005-12-17 13:00:18 +01003953 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003954 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003955 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956
willy tarreau240afa62005-12-17 13:14:35 +01003957 /* Now look for cookies. Conforming to RFC2109, we have to support
3958 * attributes whose name begin with a '$', and associate them with
3959 * the right cookie, if we want to delete this cookie.
3960 * So there are 3 cases for each cookie read :
3961 * 1) it's a special attribute, beginning with a '$' : ignore it.
3962 * 2) it's a server id cookie that we *MAY* want to delete : save
3963 * some pointers on it (last semi-colon, beginning of cookie...)
3964 * 3) it's an application cookie : we *MAY* have to delete a previous
3965 * "special" cookie.
3966 * At the end of loop, if a "special" cookie remains, we may have to
3967 * remove it. If no application cookie persists in the header, we
3968 * *MUST* delete it
3969 */
willy tarreau12350152005-12-18 01:03:27 +01003970 if (!delete_header &&
3971 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003972 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003973 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003974 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003975 char *del_colon, *del_cookie, *colon;
3976 int app_cookies;
3977
willy tarreau5cbea6f2005-12-17 12:48:26 +01003978 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003979 colon = p1;
3980 /* del_cookie == NULL => nothing to be deleted */
3981 del_colon = del_cookie = NULL;
3982 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003983
3984 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003985 /* skip spaces and colons, but keep an eye on these ones */
3986 while (p1 < ptr) {
3987 if (*p1 == ';' || *p1 == ',')
3988 colon = p1;
3989 else if (!isspace((int)*p1))
3990 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003991 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003992 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993
3994 if (p1 == ptr)
3995 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003996
3997 /* p1 is at the beginning of the cookie name */
3998 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003999 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000 p2++;
4001
4002 if (p2 == ptr)
4003 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004
4005 p3 = p2 + 1; /* skips the '=' sign */
4006 if (p3 == ptr)
4007 break;
4008
willy tarreau240afa62005-12-17 13:14:35 +01004009 p4 = p3;
4010 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011 p4++;
4012
4013 /* here, we have the cookie name between p1 and p2,
4014 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004015 * we can process it :
4016 *
4017 * Cookie: NAME=VALUE;
4018 * | || || |
4019 * | || || +--> p4
4020 * | || |+-------> p3
4021 * | || +--------> p2
4022 * | |+------------> p1
4023 * | +-------------> colon
4024 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004025 */
4026
willy tarreau240afa62005-12-17 13:14:35 +01004027 if (*p1 == '$') {
4028 /* skip this one */
4029 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004030 else {
4031 /* first, let's see if we want to capture it */
4032 if (t->proxy->capture_name != NULL &&
4033 t->logs.cli_cookie == NULL &&
4034 (p4 - p1 >= t->proxy->capture_namelen) &&
4035 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4036 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004037
willy tarreau8337c6b2005-12-17 13:41:01 +01004038 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4039 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004040 } else {
4041 if (log_len > t->proxy->capture_len)
4042 log_len = t->proxy->capture_len;
4043 memcpy(t->logs.cli_cookie, p1, log_len);
4044 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004045 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004046 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004047
4048 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4049 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4050 /* Cool... it's the right one */
4051 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004052 char *delim;
4053
4054 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4055 * have the server ID betweek p3 and delim, and the original cookie between
4056 * delim+1 and p4. Otherwise, delim==p4 :
4057 *
4058 * Cookie: NAME=SRV~VALUE;
4059 * | || || | |
4060 * | || || | +--> p4
4061 * | || || +--------> delim
4062 * | || |+-----------> p3
4063 * | || +------------> p2
4064 * | |+----------------> p1
4065 * | +-----------------> colon
4066 * +------------------------> req->h
4067 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004068
willy tarreau0174f312005-12-18 01:02:42 +01004069 if (t->proxy->options & PR_O_COOK_PFX) {
4070 for (delim = p3; delim < p4; delim++)
4071 if (*delim == COOKIE_DELIM)
4072 break;
4073 }
4074 else
4075 delim = p4;
4076
4077
4078 /* Here, we'll look for the first running server which supports the cookie.
4079 * This allows to share a same cookie between several servers, for example
4080 * to dedicate backup servers to specific servers only.
willy tarreau422bb2e2006-05-10 04:27:21 +02004081 * However, to prevent clients from sticking to cookie-less backup server
4082 * when they have incidentely learned an empty cookie, we simply ignore
4083 * empty cookies and mark them as invalid.
willy tarreau0174f312005-12-18 01:02:42 +01004084 */
willy tarreau422bb2e2006-05-10 04:27:21 +02004085 if (delim == p3)
4086 srv = NULL;
4087
willy tarreau0174f312005-12-18 01:02:42 +01004088 while (srv) {
4089 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4090 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4091 /* we found the server and it's usable */
4092 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004093 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004094 t->srv = srv;
4095 break;
willy tarreau12350152005-12-18 01:03:27 +01004096 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004097 /* we found a server, but it's down */
4098 t->flags &= ~SN_CK_MASK;
4099 t->flags |= SN_CK_DOWN;
4100 }
4101 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004102 srv = srv->next;
4103 }
4104
willy tarreau0174f312005-12-18 01:02:42 +01004105 if (!srv && !(t->flags & SN_CK_DOWN)) {
4106 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004107 t->flags &= ~SN_CK_MASK;
4108 t->flags |= SN_CK_INVALID;
4109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004110
willy tarreau0174f312005-12-18 01:02:42 +01004111 /* depending on the cookie mode, we may have to either :
4112 * - delete the complete cookie if we're in insert+indirect mode, so that
4113 * the server never sees it ;
4114 * - remove the server id from the cookie value, and tag the cookie as an
4115 * application cookie so that it does not get accidentely removed later,
4116 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004117 */
willy tarreau0174f312005-12-18 01:02:42 +01004118 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4119 buffer_replace2(req, p3, delim + 1, NULL, 0);
4120 p4 -= (delim + 1 - p3);
4121 ptr -= (delim + 1 - p3);
4122 del_cookie = del_colon = NULL;
4123 app_cookies++; /* protect the header from deletion */
4124 }
4125 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004126 (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 +01004127 del_cookie = p1;
4128 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004129 }
willy tarreau12350152005-12-18 01:03:27 +01004130 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004131 /* now we know that we must keep this cookie since it's
4132 * not ours. But if we wanted to delete our cookie
4133 * earlier, we cannot remove the complete header, but we
4134 * can remove the previous block itself.
4135 */
4136 app_cookies++;
4137
4138 if (del_cookie != NULL) {
4139 buffer_replace2(req, del_cookie, p1, NULL, 0);
4140 p4 -= (p1 - del_cookie);
4141 ptr -= (p1 - del_cookie);
4142 del_cookie = del_colon = NULL;
4143 }
willy tarreau240afa62005-12-17 13:14:35 +01004144 }
willy tarreau12350152005-12-18 01:03:27 +01004145
4146 if ((t->proxy->appsession_name != NULL) &&
4147 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4148 /* first, let's see if the cookie is our appcookie*/
4149
4150 /* Cool... it's the right one */
4151
4152 asession_temp = &local_asession;
4153
4154 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4155 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4156 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4157 return 0;
4158 }
4159
4160 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4161 asession_temp->sessid[t->proxy->appsession_len] = 0;
4162 asession_temp->serverid = NULL;
4163
4164 /* only do insert, if lookup fails */
4165 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4166 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4167 Alert("Not enough memory process_cli():asession:calloc().\n");
4168 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4169 return 0;
4170 }
4171
4172 asession_temp->sessid = local_asession.sessid;
4173 asession_temp->serverid = local_asession.serverid;
4174 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4175 }
4176 else{
4177 /* free wasted memory */
4178 pool_free_to(apools.sessid, local_asession.sessid);
4179 }
4180
4181 if (asession_temp->serverid == NULL) {
4182 Alert("Found Application Session without matching server.\n");
4183 } else {
4184 struct server *srv = t->proxy->srv;
4185 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004186 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004187 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4188 /* we found the server and it's usable */
4189 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004190 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004191 t->srv = srv;
4192 break;
4193 } else {
4194 t->flags &= ~SN_CK_MASK;
4195 t->flags |= SN_CK_DOWN;
4196 }
4197 }
4198 srv = srv->next;
4199 }/* end while(srv) */
4200 }/* end else if server == NULL */
4201
4202 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004203 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004204 }
willy tarreau240afa62005-12-17 13:14:35 +01004205
willy tarreau5cbea6f2005-12-17 12:48:26 +01004206 /* we'll have to look for another cookie ... */
4207 p1 = p4;
4208 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004209
4210 /* There's no more cookie on this line.
4211 * We may have marked the last one(s) for deletion.
4212 * We must do this now in two ways :
4213 * - if there is no app cookie, we simply delete the header ;
4214 * - if there are app cookies, we must delete the end of the
4215 * string properly, including the colon/semi-colon before
4216 * the cookie name.
4217 */
4218 if (del_cookie != NULL) {
4219 if (app_cookies) {
4220 buffer_replace2(req, del_colon, ptr, NULL, 0);
4221 /* WARNING! <ptr> becomes invalid for now. If some code
4222 * below needs to rely on it before the end of the global
4223 * header loop, we need to correct it with this code :
4224 * ptr = del_colon;
4225 */
4226 }
4227 else
4228 delete_header = 1;
4229 }
4230 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004231
4232 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004233 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004234 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004235 }
willy tarreau240afa62005-12-17 13:14:35 +01004236 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4237
willy tarreau5cbea6f2005-12-17 12:48:26 +01004238 req->h = req->lr;
4239 } /* while (req->lr < req->r) */
4240
4241 /* end of header processing (even if incomplete) */
4242
willy tarreauef900ab2005-12-17 12:52:52 +01004243 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4244 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4245 * full. We cannot loop here since event_cli_read will disable it only if
4246 * req->l == rlim-data
4247 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004248 FD_SET(t->cli_fd, StaticReadEvent);
4249 if (t->proxy->clitimeout)
4250 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4251 else
4252 tv_eternity(&t->crexpire);
4253 }
4254
willy tarreaue39cd132005-12-17 13:00:18 +01004255 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004256 * won't be able to free more later, so the session will never terminate.
4257 */
willy tarreaue39cd132005-12-17 13:00:18 +01004258 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004259 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004260 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004261 if (!(t->flags & SN_ERR_MASK))
4262 t->flags |= SN_ERR_PRXCOND;
4263 if (!(t->flags & SN_FINST_MASK))
4264 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004265 return 1;
4266 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004267 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004268 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004269 tv_eternity(&t->crexpire);
4270 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004271 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004272 if (!(t->flags & SN_ERR_MASK))
4273 t->flags |= SN_ERR_CLICL;
4274 if (!(t->flags & SN_FINST_MASK))
4275 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004276 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004277 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004278 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4279
4280 /* read timeout : give up with an error message.
4281 */
4282 t->logs.status = 408;
4283 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004284 if (!(t->flags & SN_ERR_MASK))
4285 t->flags |= SN_ERR_CLITO;
4286 if (!(t->flags & SN_FINST_MASK))
4287 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004288 return 1;
4289 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004290
4291 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004292 }
4293 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004294 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004295 /* FIXME: this error handling is partly buggy because we always report
4296 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4297 * or HEADER phase. BTW, it's not logical to expire the client while
4298 * we're waiting for the server to connect.
4299 */
willy tarreau0f7af912005-12-17 12:21:26 +01004300 /* read or write error */
4301 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004302 tv_eternity(&t->crexpire);
4303 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004304 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004305 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004306 if (!(t->flags & SN_ERR_MASK))
4307 t->flags |= SN_ERR_CLICL;
4308 if (!(t->flags & SN_FINST_MASK))
4309 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004310 return 1;
4311 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004312 /* last read, or end of server write */
4313 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004314 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004315 tv_eternity(&t->crexpire);
4316 shutdown(t->cli_fd, SHUT_RD);
4317 t->cli_state = CL_STSHUTR;
4318 return 1;
4319 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004320 /* last server read and buffer empty */
4321 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004322 FD_CLR(t->cli_fd, StaticWriteEvent);
4323 tv_eternity(&t->cwexpire);
4324 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004325 /* We must ensure that the read part is still alive when switching
4326 * to shutw */
4327 FD_SET(t->cli_fd, StaticReadEvent);
4328 if (t->proxy->clitimeout)
4329 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004330 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004331 //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 +01004332 return 1;
4333 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004334 /* read timeout */
4335 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4336 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004337 tv_eternity(&t->crexpire);
4338 shutdown(t->cli_fd, SHUT_RD);
4339 t->cli_state = CL_STSHUTR;
4340 if (!(t->flags & SN_ERR_MASK))
4341 t->flags |= SN_ERR_CLITO;
4342 if (!(t->flags & SN_FINST_MASK))
4343 t->flags |= SN_FINST_D;
4344 return 1;
4345 }
4346 /* write timeout */
4347 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4348 FD_CLR(t->cli_fd, StaticWriteEvent);
4349 tv_eternity(&t->cwexpire);
4350 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004351 /* We must ensure that the read part is still alive when switching
4352 * to shutw */
4353 FD_SET(t->cli_fd, StaticReadEvent);
4354 if (t->proxy->clitimeout)
4355 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4356
willy tarreau036e1ce2005-12-17 13:46:33 +01004357 t->cli_state = CL_STSHUTW;
4358 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004359 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004360 if (!(t->flags & SN_FINST_MASK))
4361 t->flags |= SN_FINST_D;
4362 return 1;
4363 }
willy tarreau0f7af912005-12-17 12:21:26 +01004364
willy tarreauc58fc692005-12-17 14:13:08 +01004365 if (req->l >= req->rlim - req->data) {
4366 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004367 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004368 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004369 FD_CLR(t->cli_fd, StaticReadEvent);
4370 tv_eternity(&t->crexpire);
4371 }
4372 }
4373 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004374 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004375 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4376 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004377 if (!t->proxy->clitimeout ||
4378 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4379 /* If the client has no timeout, or if the server not ready yet, and we
4380 * know for sure that it can expire, then it's cleaner to disable the
4381 * timeout on the client side so that too low values cannot make the
4382 * sessions abort too early.
4383 */
willy tarreau0f7af912005-12-17 12:21:26 +01004384 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004385 else
4386 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004387 }
4388 }
4389
4390 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004391 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004392 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4393 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4394 tv_eternity(&t->cwexpire);
4395 }
4396 }
4397 else { /* buffer not empty */
4398 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4399 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004400 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004401 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004402 /* FIXME: to prevent the client from expiring read timeouts during writes,
4403 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004404 t->crexpire = t->cwexpire;
4405 }
willy tarreau0f7af912005-12-17 12:21:26 +01004406 else
4407 tv_eternity(&t->cwexpire);
4408 }
4409 }
4410 return 0; /* other cases change nothing */
4411 }
4412 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004413 if (t->res_cw == RES_ERROR) {
4414 tv_eternity(&t->cwexpire);
4415 fd_delete(t->cli_fd);
4416 t->cli_state = CL_STCLOSE;
4417 if (!(t->flags & SN_ERR_MASK))
4418 t->flags |= SN_ERR_CLICL;
4419 if (!(t->flags & SN_FINST_MASK))
4420 t->flags |= SN_FINST_D;
4421 return 1;
4422 }
4423 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004424 tv_eternity(&t->cwexpire);
4425 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004426 t->cli_state = CL_STCLOSE;
4427 return 1;
4428 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004429 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4430 tv_eternity(&t->cwexpire);
4431 fd_delete(t->cli_fd);
4432 t->cli_state = CL_STCLOSE;
4433 if (!(t->flags & SN_ERR_MASK))
4434 t->flags |= SN_ERR_CLITO;
4435 if (!(t->flags & SN_FINST_MASK))
4436 t->flags |= SN_FINST_D;
4437 return 1;
4438 }
willy tarreau0f7af912005-12-17 12:21:26 +01004439 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004440 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004441 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4442 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4443 tv_eternity(&t->cwexpire);
4444 }
4445 }
4446 else { /* buffer not empty */
4447 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4448 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004449 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004450 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004451 /* FIXME: to prevent the client from expiring read timeouts during writes,
4452 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004453 t->crexpire = t->cwexpire;
4454 }
willy tarreau0f7af912005-12-17 12:21:26 +01004455 else
4456 tv_eternity(&t->cwexpire);
4457 }
4458 }
4459 return 0;
4460 }
4461 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004462 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004463 tv_eternity(&t->crexpire);
4464 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004465 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004466 if (!(t->flags & SN_ERR_MASK))
4467 t->flags |= SN_ERR_CLICL;
4468 if (!(t->flags & SN_FINST_MASK))
4469 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004470 return 1;
4471 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004472 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4473 tv_eternity(&t->crexpire);
4474 fd_delete(t->cli_fd);
4475 t->cli_state = CL_STCLOSE;
4476 return 1;
4477 }
4478 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4479 tv_eternity(&t->crexpire);
4480 fd_delete(t->cli_fd);
4481 t->cli_state = CL_STCLOSE;
4482 if (!(t->flags & SN_ERR_MASK))
4483 t->flags |= SN_ERR_CLITO;
4484 if (!(t->flags & SN_FINST_MASK))
4485 t->flags |= SN_FINST_D;
4486 return 1;
4487 }
willy tarreauef900ab2005-12-17 12:52:52 +01004488 else if (req->l >= req->rlim - req->data) {
4489 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004490
4491 /* FIXME-20050705: is it possible for a client to maintain a session
4492 * after the timeout by sending more data after it receives a close ?
4493 */
4494
willy tarreau0f7af912005-12-17 12:21:26 +01004495 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004496 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004497 FD_CLR(t->cli_fd, StaticReadEvent);
4498 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004499 //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 +01004500 }
4501 }
4502 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004503 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004504 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4505 FD_SET(t->cli_fd, StaticReadEvent);
4506 if (t->proxy->clitimeout)
4507 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4508 else
4509 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004510 //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 +01004511 }
4512 }
4513 return 0;
4514 }
4515 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004516 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004517 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004518 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 +01004519 write(1, trash, len);
4520 }
4521 return 0;
4522 }
4523 return 0;
4524}
4525
willy tarreaudfece232006-05-02 00:19:57 +02004526/* This function turns the server state into the SV_STCLOSE, and sets
4527 * indicators accordingly. Note that if <status> is 0, no message is
4528 * returned.
4529 */
4530void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4531 t->srv_state = SV_STCLOSE;
4532 if (status > 0) {
4533 t->logs.status = status;
4534 if (t->proxy->mode == PR_MODE_HTTP)
4535 client_return(t, msglen, msg);
4536 }
4537 if (!(t->flags & SN_ERR_MASK))
4538 t->flags |= err;
4539 if (!(t->flags & SN_FINST_MASK))
4540 t->flags |= finst;
4541}
4542
4543/*
4544 * This function checks the retry count during the connect() job.
4545 * It updates the session's srv_state and retries, so that the caller knows
4546 * what it has to do. It uses the last connection error to set the log when
4547 * it expires. It returns 1 when it has expired, and 0 otherwise.
4548 */
4549int srv_count_retry_down(struct session *t, int conn_err) {
4550 /* we are in front of a retryable error */
4551 t->conn_retries--;
4552 if (t->conn_retries < 0) {
4553 /* if not retryable anymore, let's abort */
4554 tv_eternity(&t->cnexpire);
4555 srv_close_with_err(t, conn_err, SN_FINST_C,
4556 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4557
4558 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004559 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004560 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004561 if (may_dequeue_tasks(t->srv, t->proxy))
4562 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004563 return 1;
4564 }
4565 return 0;
4566}
willy tarreau0f7af912005-12-17 12:21:26 +01004567
4568/*
willy tarreaudfece232006-05-02 00:19:57 +02004569 * This function performs the retryable part of the connect() job.
4570 * It updates the session's srv_state and retries, so that the caller knows
4571 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4572 * it needs to redispatch.
4573 */
4574int srv_retryable_connect(struct session *t) {
4575 int conn_err;
4576
4577 /* This loop ensures that we stop before the last retry in case of a
4578 * redispatchable server.
4579 */
4580 do {
4581 /* initiate a connection to the server */
4582 conn_err = connect_server(t);
4583 switch (conn_err) {
4584
4585 case SN_ERR_NONE:
4586 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4587 t->srv_state = SV_STCONN;
4588 return 1;
4589
4590 case SN_ERR_INTERNAL:
4591 tv_eternity(&t->cnexpire);
4592 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4593 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4594 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004595 if (may_dequeue_tasks(t->srv, t->proxy))
4596 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004597 return 1;
4598 }
4599 /* ensure that we have enough retries left */
willy tarreau59a6cc22006-05-12 01:29:08 +02004600 if (srv_count_retry_down(t, conn_err)) {
4601 /* let's try to offer this slot to anybody */
4602 if (may_dequeue_tasks(t->srv, t->proxy))
4603 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004604 return 1;
willy tarreau59a6cc22006-05-12 01:29:08 +02004605 }
willy tarreaudfece232006-05-02 00:19:57 +02004606 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4607
4608 /* We're on our last chance, and the REDISP option was specified.
4609 * We will ignore cookie and force to balance or use the dispatcher.
4610 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004611 /* let's try to offer this slot to anybody */
4612 if (may_dequeue_tasks(t->srv, t->proxy))
4613 task_wakeup(&rq, t->srv->queue_mgt);
4614
willy tarreaudfece232006-05-02 00:19:57 +02004615 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4616 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4617 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4618 t->flags &= ~SN_CK_MASK;
4619 t->flags |= SN_CK_DOWN;
4620 }
4621 return 0;
4622}
4623
4624/* This function performs the "redispatch" part of a connection attempt. It
4625 * will assign a server if required, queue the connection if required, and
4626 * handle errors that might arise at this level. It can change the server
4627 * state. It will return 1 if it encounters an error, switches the server
4628 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4629 * that the connection is ready to use.
4630 */
4631
4632int srv_redispatch_connect(struct session *t) {
4633 int conn_err;
4634
4635 /* We know that we don't have any connection pending, so we will
4636 * try to get a new one, and wait in this state if it's queued
4637 */
4638 conn_err = assign_server_and_queue(t);
4639 switch (conn_err) {
4640 case SRV_STATUS_OK:
4641 break;
4642
4643 case SRV_STATUS_NOSRV:
willy tarreau59a6cc22006-05-12 01:29:08 +02004644 /* note: it is guaranteed that t->srv == NULL here */
willy tarreaudfece232006-05-02 00:19:57 +02004645 tv_eternity(&t->cnexpire);
4646 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4647 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreaudfece232006-05-02 00:19:57 +02004648 return 1;
4649
4650 case SRV_STATUS_QUEUED:
willy tarreau45526ed2006-05-03 20:11:50 +02004651 /* FIXME-20060503 : we should use the queue timeout instead */
4652 if (t->proxy->contimeout)
4653 tv_delayfrom(&t->cnexpire, &now, t->proxy->contimeout);
4654 else
4655 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004656 t->srv_state = SV_STIDLE;
4657 /* do nothing else and do not wake any other session up */
4658 return 1;
4659
4660 case SRV_STATUS_FULL:
4661 case SRV_STATUS_INTERNAL:
4662 default:
4663 tv_eternity(&t->cnexpire);
4664 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4665 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4666 /* release other sessions waiting for this server */
willy tarreau59a6cc22006-05-12 01:29:08 +02004667 if (may_dequeue_tasks(t->srv, t->proxy))
4668 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004669 return 1;
4670 }
4671 /* if we get here, it's because we got SRV_STATUS_OK, which also
4672 * means that the connection has not been queued.
4673 */
4674 return 0;
4675}
4676
4677
4678/*
willy tarreau0f7af912005-12-17 12:21:26 +01004679 * manages the server FSM and its socket. It returns 1 if a state has changed
4680 * (and a resync may be needed), 0 else.
4681 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004682int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004683 int s = t->srv_state;
4684 int c = t->cli_state;
4685 struct buffer *req = t->req;
4686 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004687 appsess *asession_temp = NULL;
4688 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004689 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004690
willy tarreau750a4722005-12-17 13:21:24 +01004691#ifdef DEBUG_FULL
4692 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4693#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004694 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4695 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4696 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4697 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004698 if (s == SV_STIDLE) {
4699 if (c == CL_STHEADERS)
4700 return 0; /* stay in idle, waiting for data to reach the client side */
4701 else if (c == CL_STCLOSE ||
4702 c == CL_STSHUTW ||
4703 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4704 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004705 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
4706
willy tarreau0f7af912005-12-17 12:21:26 +01004707 return 1;
4708 }
willy tarreaudfece232006-05-02 00:19:57 +02004709 else {
4710 /* Right now, we will need to create a connection to the server.
4711 * We might already have tried, and got a connection pending, in
4712 * which case we will not do anything till it's pending. It's up
4713 * to any other session to release it and wake us up again.
4714 */
willy tarreau45526ed2006-05-03 20:11:50 +02004715 if (t->pend_pos) {
4716 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
4717 return 0;
4718 else {
4719 /* we've been waiting too long here */
4720 tv_eternity(&t->cnexpire);
4721 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4722 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4723 return 1;
4724 }
4725 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004726
willy tarreaudfece232006-05-02 00:19:57 +02004727 do {
4728 /* first, get a connection */
4729 if (srv_redispatch_connect(t))
4730 return t->srv_state != SV_STIDLE;
4731
4732 /* try to (re-)connect to the server, and fail if we expire the
4733 * number of retries.
4734 */
willy tarreauf32f5242006-05-02 22:54:52 +02004735 if (srv_retryable_connect(t)) {
4736 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004737 return t->srv_state != SV_STIDLE;
willy tarreauf32f5242006-05-02 22:54:52 +02004738 }
willy tarreaudfece232006-05-02 00:19:57 +02004739
4740 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004741 }
4742 }
4743 else if (s == SV_STCONN) { /* connection in progress */
4744 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004745 //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 +01004746 return 0; /* nothing changed */
4747 }
4748 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004749 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004750 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004751
willy tarreau0f7af912005-12-17 12:21:26 +01004752 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004753 if (t->srv)
4754 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004755
4756 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004757 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4758 else
willy tarreaudfece232006-05-02 00:19:57 +02004759 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004760
willy tarreaudfece232006-05-02 00:19:57 +02004761 /* ensure that we have enough retries left */
4762 if (srv_count_retry_down(t, conn_err))
4763 return 1;
4764
4765 do {
4766 /* Now we will try to either reconnect to the same server or
4767 * connect to another server. If the connection gets queued
4768 * because all servers are saturated, then we will go back to
4769 * the SV_STIDLE state.
4770 */
willy tarreauf32f5242006-05-02 22:54:52 +02004771 if (srv_retryable_connect(t)) {
4772 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
willy tarreaudfece232006-05-02 00:19:57 +02004773 return t->srv_state != SV_STCONN;
willy tarreauf32f5242006-05-02 22:54:52 +02004774 }
willy tarreaudfece232006-05-02 00:19:57 +02004775
4776 /* we need to redispatch the connection to another server */
4777 if (srv_redispatch_connect(t))
4778 return t->srv_state != SV_STCONN;
4779 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004780 }
4781 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004782 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004783
willy tarreau0f7af912005-12-17 12:21:26 +01004784 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004785 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004786 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004787 tv_eternity(&t->swexpire);
4788 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004789 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004790 if (t->proxy->srvtimeout) {
4791 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004792 /* FIXME: to prevent the server from expiring read timeouts during writes,
4793 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004794 t->srexpire = t->swexpire;
4795 }
4796 else
4797 tv_eternity(&t->swexpire);
4798 }
willy tarreau0f7af912005-12-17 12:21:26 +01004799
4800 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4801 FD_SET(t->srv_fd, StaticReadEvent);
4802 if (t->proxy->srvtimeout)
4803 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4804 else
4805 tv_eternity(&t->srexpire);
4806
4807 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004808 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004809 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004810
4811 /* if the user wants to log as soon as possible, without counting
4812 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004813 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004814 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4815 sess_log(t);
4816 }
willy tarreau0f7af912005-12-17 12:21:26 +01004817 }
willy tarreauef900ab2005-12-17 12:52:52 +01004818 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004819 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004820 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004821 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4822 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004823 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004824 return 1;
4825 }
4826 }
4827 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004828 /* now parse the partial (or complete) headers */
4829 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4830 char *ptr;
4831 int delete_header;
4832
4833 ptr = rep->lr;
4834
4835 /* look for the end of the current header */
4836 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4837 ptr++;
4838
4839 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004840 int line, len;
4841
4842 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004843
4844 /* first, we'll block if security checks have caught nasty things */
4845 if (t->flags & SN_CACHEABLE) {
4846 if ((t->flags & SN_CACHE_COOK) &&
4847 (t->flags & SN_SCK_ANY) &&
4848 (t->proxy->options & PR_O_CHK_CACHE)) {
4849
4850 /* we're in presence of a cacheable response containing
4851 * a set-cookie header. We'll block it as requested by
4852 * the 'checkcache' option, and send an alert.
4853 */
4854 tv_eternity(&t->srexpire);
4855 tv_eternity(&t->swexpire);
4856 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004857 if (t->srv)
4858 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004859 t->srv_state = SV_STCLOSE;
4860 t->logs.status = 502;
4861 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4862 if (!(t->flags & SN_ERR_MASK))
4863 t->flags |= SN_ERR_PRXCOND;
4864 if (!(t->flags & SN_FINST_MASK))
4865 t->flags |= SN_FINST_H;
4866
4867 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4868 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4869
willy tarreaudfece232006-05-02 00:19:57 +02004870 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004871 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004872 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004873 if (may_dequeue_tasks(t->srv, t->proxy))
4874 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004875
willy tarreau97f58572005-12-18 00:53:44 +01004876 return 1;
4877 }
4878 }
4879
willy tarreau982249e2005-12-18 00:57:06 +01004880 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4881 if (t->flags & SN_SVDENY) {
4882 tv_eternity(&t->srexpire);
4883 tv_eternity(&t->swexpire);
4884 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004885 if (t->srv)
4886 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004887 t->srv_state = SV_STCLOSE;
4888 t->logs.status = 502;
4889 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4890 if (!(t->flags & SN_ERR_MASK))
4891 t->flags |= SN_ERR_PRXCOND;
4892 if (!(t->flags & SN_FINST_MASK))
4893 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004894 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02004895 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02004896 */
willy tarreau59a6cc22006-05-12 01:29:08 +02004897 if (may_dequeue_tasks(t->srv, t->proxy))
4898 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02004899
willy tarreau982249e2005-12-18 00:57:06 +01004900 return 1;
4901 }
4902
willy tarreau5cbea6f2005-12-17 12:48:26 +01004903 /* we'll have something else to do here : add new headers ... */
4904
willy tarreaucd878942005-12-17 13:27:43 +01004905 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4906 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004907 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004908 * insert a set-cookie here, except if we want to insert only on POST
willy tarreau4f7a1012006-05-09 23:32:26 +02004909 * requests and this one isn't. Note that servers which don't have cookies
4910 * (eg: some backup servers) will return a full cookie removal request.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004911 */
willy tarreau750a4722005-12-17 13:21:24 +01004912 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004913 t->proxy->cookie_name,
willy tarreau4f7a1012006-05-09 23:32:26 +02004914 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
willy tarreau750a4722005-12-17 13:21:24 +01004915
willy tarreau036e1ce2005-12-17 13:46:33 +01004916 t->flags |= SN_SCK_INSERTED;
4917
willy tarreau750a4722005-12-17 13:21:24 +01004918 /* Here, we will tell an eventual cache on the client side that we don't
4919 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4920 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4921 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4922 */
willy tarreau240afa62005-12-17 13:14:35 +01004923 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004924 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4925 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004926
4927 if (rep->data + rep->l < rep->h)
4928 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4929 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004930 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004931 }
4932
4933 /* headers to be added */
4934 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004935 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4936 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004937 }
4938
willy tarreau25c4ea52005-12-18 00:49:49 +01004939 /* add a "connection: close" line if needed */
4940 if (t->proxy->options & PR_O_HTTP_CLOSE)
4941 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4942
willy tarreau5cbea6f2005-12-17 12:48:26 +01004943 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004944 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004945 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004946
Willy TARREAU767ba712006-03-01 22:40:50 +01004947 /* client connection already closed or option 'httpclose' required :
4948 * we close the server's outgoing connection right now.
4949 */
4950 if ((req->l == 0) &&
4951 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4952 FD_CLR(t->srv_fd, StaticWriteEvent);
4953 tv_eternity(&t->swexpire);
4954
4955 /* We must ensure that the read part is still alive when switching
4956 * to shutw */
4957 FD_SET(t->srv_fd, StaticReadEvent);
4958 if (t->proxy->srvtimeout)
4959 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4960
4961 shutdown(t->srv_fd, SHUT_WR);
4962 t->srv_state = SV_STSHUTW;
4963 }
4964
willy tarreau25c4ea52005-12-18 00:49:49 +01004965 /* if the user wants to log as soon as possible, without counting
4966 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004967 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004968 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4969 t->logs.bytes = rep->h - rep->data;
4970 sess_log(t);
4971 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004972 break;
4973 }
4974
4975 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4976 if (ptr > rep->r - 2) {
4977 /* this is a partial header, let's wait for more to come */
4978 rep->lr = ptr;
4979 break;
4980 }
4981
4982 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4983 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4984
4985 /* now we know that *ptr is either \r or \n,
4986 * and that there are at least 1 char after it.
4987 */
4988 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4989 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4990 else
4991 rep->lr = ptr + 2; /* \r\n or \n\r */
4992
4993 /*
4994 * now we know that we have a full header ; we can do whatever
4995 * we want with these pointers :
4996 * rep->h = beginning of header
4997 * ptr = end of header (first \r or \n)
4998 * rep->lr = beginning of next line (next rep->h)
4999 * rep->r = end of data (not used at this stage)
5000 */
5001
willy tarreaua1598082005-12-17 13:08:06 +01005002
willy tarreau982249e2005-12-18 00:57:06 +01005003 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01005004 t->logs.logwait &= ~LW_RESP;
5005 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01005006 switch (t->logs.status) {
5007 case 200:
5008 case 203:
5009 case 206:
5010 case 300:
5011 case 301:
5012 case 410:
5013 /* RFC2616 @13.4:
5014 * "A response received with a status code of
5015 * 200, 203, 206, 300, 301 or 410 MAY be stored
5016 * by a cache (...) unless a cache-control
5017 * directive prohibits caching."
5018 *
5019 * RFC2616 @9.5: POST method :
5020 * "Responses to this method are not cacheable,
5021 * unless the response includes appropriate
5022 * Cache-Control or Expires header fields."
5023 */
5024 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
5025 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
5026 break;
5027 default:
5028 break;
5029 }
willy tarreau4302f492005-12-18 01:00:37 +01005030 }
5031 else if (t->logs.logwait & LW_RSPHDR) {
5032 struct cap_hdr *h;
5033 int len;
5034 for (h = t->proxy->rsp_cap; h; h = h->next) {
5035 if ((h->namelen + 2 <= ptr - rep->h) &&
5036 (rep->h[h->namelen] == ':') &&
5037 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5038
5039 if (t->rsp_cap[h->index] == NULL)
5040 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5041
5042 len = ptr - (rep->h + h->namelen + 2);
5043 if (len > h->len)
5044 len = h->len;
5045
5046 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5047 t->rsp_cap[h->index][len]=0;
5048 }
5049 }
5050
willy tarreaua1598082005-12-17 13:08:06 +01005051 }
5052
willy tarreau5cbea6f2005-12-17 12:48:26 +01005053 delete_header = 0;
5054
willy tarreau982249e2005-12-18 00:57:06 +01005055 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005057 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 +01005058 max = ptr - rep->h;
5059 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005060 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005061 trash[len++] = '\n';
5062 write(1, trash, len);
5063 }
5064
willy tarreau25c4ea52005-12-18 00:49:49 +01005065 /* remove "connection: " if needed */
5066 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5067 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5068 delete_header = 1;
5069 }
5070
willy tarreau5cbea6f2005-12-17 12:48:26 +01005071 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005072 if (!delete_header && t->proxy->rsp_exp != NULL
5073 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005074 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 char term;
5076
5077 term = *ptr;
5078 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005079 exp = t->proxy->rsp_exp;
5080 do {
5081 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5082 switch (exp->action) {
5083 case ACT_ALLOW:
5084 if (!(t->flags & SN_SVDENY))
5085 t->flags |= SN_SVALLOW;
5086 break;
5087 case ACT_REPLACE:
5088 if (!(t->flags & SN_SVDENY)) {
5089 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5090 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5091 }
5092 break;
5093 case ACT_REMOVE:
5094 if (!(t->flags & SN_SVDENY))
5095 delete_header = 1;
5096 break;
5097 case ACT_DENY:
5098 if (!(t->flags & SN_SVALLOW))
5099 t->flags |= SN_SVDENY;
5100 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005101 case ACT_PASS: /* we simply don't deny this one */
5102 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005103 }
5104 break;
5105 }
willy tarreaue39cd132005-12-17 13:00:18 +01005106 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005107 *ptr = term; /* restore the string terminator */
5108 }
5109
willy tarreau97f58572005-12-18 00:53:44 +01005110 /* check for cache-control: or pragma: headers */
5111 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5112 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5113 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5114 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5115 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005116 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005117 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5118 else {
5119 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005120 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005121 t->flags &= ~SN_CACHE_COOK;
5122 }
5123 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005124 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005125 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005126 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005127 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5128 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005129 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005130 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005131 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5132 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5133 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5134 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5135 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5136 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005137 }
5138 }
5139 }
5140
willy tarreau5cbea6f2005-12-17 12:48:26 +01005141 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005142 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005143 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005144 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005145 char *p1, *p2, *p3, *p4;
5146
willy tarreau97f58572005-12-18 00:53:44 +01005147 t->flags |= SN_SCK_ANY;
5148
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5150
5151 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005152 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005153 p1++;
5154
5155 if (p1 == ptr || *p1 == ';') /* end of cookie */
5156 break;
5157
5158 /* p1 is at the beginning of the cookie name */
5159 p2 = p1;
5160
5161 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5162 p2++;
5163
5164 if (p2 == ptr || *p2 == ';') /* next cookie */
5165 break;
5166
5167 p3 = p2 + 1; /* skips the '=' sign */
5168 if (p3 == ptr)
5169 break;
5170
5171 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005172 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005173 p4++;
5174
5175 /* here, we have the cookie name between p1 and p2,
5176 * and its value between p3 and p4.
5177 * we can process it.
5178 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005179
5180 /* first, let's see if we want to capture it */
5181 if (t->proxy->capture_name != NULL &&
5182 t->logs.srv_cookie == NULL &&
5183 (p4 - p1 >= t->proxy->capture_namelen) &&
5184 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5185 int log_len = p4 - p1;
5186
5187 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5188 Alert("HTTP logging : out of memory.\n");
5189 }
5190
5191 if (log_len > t->proxy->capture_len)
5192 log_len = t->proxy->capture_len;
5193 memcpy(t->logs.srv_cookie, p1, log_len);
5194 t->logs.srv_cookie[log_len] = 0;
5195 }
5196
5197 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5198 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005199 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005200 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005201
5202 /* If the cookie is in insert mode on a known server, we'll delete
5203 * this occurrence because we'll insert another one later.
5204 * We'll delete it too if the "indirect" option is set and we're in
5205 * a direct access. */
5206 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005207 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005208 /* this header must be deleted */
5209 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005210 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005211 }
5212 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5213 /* replace bytes p3->p4 with the cookie name associated
5214 * with this server since we know it.
5215 */
5216 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005217 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005218 }
willy tarreau0174f312005-12-18 01:02:42 +01005219 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5220 /* insert the cookie name associated with this server
5221 * before existing cookie, and insert a delimitor between them..
5222 */
5223 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5224 p3[t->srv->cklen] = COOKIE_DELIM;
5225 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5226 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005227 break;
5228 }
willy tarreau12350152005-12-18 01:03:27 +01005229
5230 /* first, let's see if the cookie is our appcookie*/
5231 if ((t->proxy->appsession_name != NULL) &&
5232 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5233
5234 /* Cool... it's the right one */
5235
willy tarreaub952e1d2005-12-18 01:31:20 +01005236 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005237 asession_temp = &local_asession;
5238
willy tarreaub952e1d2005-12-18 01:31:20 +01005239 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005240 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5241 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5242 }
5243 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5244 asession_temp->sessid[t->proxy->appsession_len] = 0;
5245 asession_temp->serverid = NULL;
5246
5247 /* only do insert, if lookup fails */
5248 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5249 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5250 Alert("Not enought Memory process_srv():asession:calloc().\n");
5251 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5252 return 0;
5253 }
5254 asession_temp->sessid = local_asession.sessid;
5255 asession_temp->serverid = local_asession.serverid;
5256 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005257 }/* end if (chtbl_lookup()) */
5258 else {
willy tarreau12350152005-12-18 01:03:27 +01005259 /* free wasted memory */
5260 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005261 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005262
willy tarreaub952e1d2005-12-18 01:31:20 +01005263 if (asession_temp->serverid == NULL) {
5264 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005265 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5266 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5267 }
5268 asession_temp->serverid[0] = '\0';
5269 }
5270
willy tarreaub952e1d2005-12-18 01:31:20 +01005271 if (asession_temp->serverid[0] == '\0')
5272 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005273
5274 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5275
5276#if defined(DEBUG_HASH)
5277 print_table(&(t->proxy->htbl_proxy));
5278#endif
5279 break;
5280 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005281 else {
5282 // fprintf(stderr,"Ignoring unknown cookie : ");
5283 // write(2, p1, p2-p1);
5284 // fprintf(stderr," = ");
5285 // write(2, p3, p4-p3);
5286 // fprintf(stderr,"\n");
5287 }
5288 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5289 } /* we're now at the end of the cookie value */
5290 } /* end of cookie processing */
5291
willy tarreau97f58572005-12-18 00:53:44 +01005292 /* check for any set-cookie in case we check for cacheability */
5293 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5294 (t->proxy->options & PR_O_CHK_CACHE) &&
5295 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5296 t->flags |= SN_SCK_ANY;
5297 }
5298
willy tarreau5cbea6f2005-12-17 12:48:26 +01005299 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005300 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005301 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005302
willy tarreau5cbea6f2005-12-17 12:48:26 +01005303 rep->h = rep->lr;
5304 } /* while (rep->lr < rep->r) */
5305
5306 /* end of header processing (even if incomplete) */
5307
willy tarreauef900ab2005-12-17 12:52:52 +01005308 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5309 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5310 * full. We cannot loop here since event_srv_read will disable it only if
5311 * rep->l == rlim-data
5312 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005313 FD_SET(t->srv_fd, StaticReadEvent);
5314 if (t->proxy->srvtimeout)
5315 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5316 else
5317 tv_eternity(&t->srexpire);
5318 }
willy tarreau0f7af912005-12-17 12:21:26 +01005319
willy tarreau8337c6b2005-12-17 13:41:01 +01005320 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005321 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005322 tv_eternity(&t->srexpire);
5323 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005324 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005325 if (t->srv)
5326 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005327 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005328 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005329 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005330 if (!(t->flags & SN_ERR_MASK))
5331 t->flags |= SN_ERR_SRVCL;
5332 if (!(t->flags & SN_FINST_MASK))
5333 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005334 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005335 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005336 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005337 if (may_dequeue_tasks(t->srv, t->proxy))
5338 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005339
willy tarreau0f7af912005-12-17 12:21:26 +01005340 return 1;
5341 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005342 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005343 * since we are in header mode, if there's no space left for headers, we
5344 * won't be able to free more later, so the session will never terminate.
5345 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005346 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 +01005347 FD_CLR(t->srv_fd, StaticReadEvent);
5348 tv_eternity(&t->srexpire);
5349 shutdown(t->srv_fd, SHUT_RD);
5350 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005351 //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 +01005352 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005353 }
5354 /* read timeout : return a 504 to the client.
5355 */
5356 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5357 tv_eternity(&t->srexpire);
5358 tv_eternity(&t->swexpire);
5359 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005360 if (t->srv)
5361 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005362 t->srv_state = SV_STCLOSE;
5363 t->logs.status = 504;
5364 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005365 if (!(t->flags & SN_ERR_MASK))
5366 t->flags |= SN_ERR_SRVTO;
5367 if (!(t->flags & SN_FINST_MASK))
5368 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005369 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005370 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005371 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005372 if (may_dequeue_tasks(t->srv, t->proxy))
5373 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005374
willy tarreau8337c6b2005-12-17 13:41:01 +01005375 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005376 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005377 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005378 /* FIXME!!! here, we don't want to switch to SHUTW if the
5379 * client shuts read too early, because we may still have
5380 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005381 * The side-effect is that if the client completely closes its
5382 * connection during SV_STHEADER, the connection to the server
5383 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005384 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005385 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005386 FD_CLR(t->srv_fd, StaticWriteEvent);
5387 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005388
5389 /* We must ensure that the read part is still alive when switching
5390 * to shutw */
5391 FD_SET(t->srv_fd, StaticReadEvent);
5392 if (t->proxy->srvtimeout)
5393 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5394
willy tarreau0f7af912005-12-17 12:21:26 +01005395 shutdown(t->srv_fd, SHUT_WR);
5396 t->srv_state = SV_STSHUTW;
5397 return 1;
5398 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005399 /* write timeout */
5400 /* FIXME!!! here, we don't want to switch to SHUTW if the
5401 * client shuts read too early, because we may still have
5402 * some work to do on the headers.
5403 */
5404 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5405 FD_CLR(t->srv_fd, StaticWriteEvent);
5406 tv_eternity(&t->swexpire);
5407 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005408 /* We must ensure that the read part is still alive when switching
5409 * to shutw */
5410 FD_SET(t->srv_fd, StaticReadEvent);
5411 if (t->proxy->srvtimeout)
5412 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5413
5414 /* We must ensure that the read part is still alive when switching
5415 * to shutw */
5416 FD_SET(t->srv_fd, StaticReadEvent);
5417 if (t->proxy->srvtimeout)
5418 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5419
willy tarreau036e1ce2005-12-17 13:46:33 +01005420 t->srv_state = SV_STSHUTW;
5421 if (!(t->flags & SN_ERR_MASK))
5422 t->flags |= SN_ERR_SRVTO;
5423 if (!(t->flags & SN_FINST_MASK))
5424 t->flags |= SN_FINST_H;
5425 return 1;
5426 }
willy tarreau0f7af912005-12-17 12:21:26 +01005427
5428 if (req->l == 0) {
5429 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5430 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5431 tv_eternity(&t->swexpire);
5432 }
5433 }
5434 else { /* client buffer not empty */
5435 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5436 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005437 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005438 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005439 /* FIXME: to prevent the server from expiring read timeouts during writes,
5440 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005441 t->srexpire = t->swexpire;
5442 }
willy tarreau0f7af912005-12-17 12:21:26 +01005443 else
5444 tv_eternity(&t->swexpire);
5445 }
5446 }
5447
willy tarreau5cbea6f2005-12-17 12:48:26 +01005448 /* be nice with the client side which would like to send a complete header
5449 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5450 * would read all remaining data at once ! The client should not write past rep->lr
5451 * when the server is in header state.
5452 */
5453 //return header_processed;
5454 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005455 }
5456 else if (s == SV_STDATA) {
5457 /* read or write error */
5458 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005459 tv_eternity(&t->srexpire);
5460 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005461 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005462 if (t->srv)
5463 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005464 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005465 if (!(t->flags & SN_ERR_MASK))
5466 t->flags |= SN_ERR_SRVCL;
5467 if (!(t->flags & SN_FINST_MASK))
5468 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005469 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005470 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005471 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005472 if (may_dequeue_tasks(t->srv, t->proxy))
5473 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005474
willy tarreau0f7af912005-12-17 12:21:26 +01005475 return 1;
5476 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005477 /* last read, or end of client write */
5478 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005479 FD_CLR(t->srv_fd, StaticReadEvent);
5480 tv_eternity(&t->srexpire);
5481 shutdown(t->srv_fd, SHUT_RD);
5482 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005483 //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 +01005484 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005485 }
5486 /* end of client read and no more data to send */
5487 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5488 FD_CLR(t->srv_fd, StaticWriteEvent);
5489 tv_eternity(&t->swexpire);
5490 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005491 /* We must ensure that the read part is still alive when switching
5492 * to shutw */
5493 FD_SET(t->srv_fd, StaticReadEvent);
5494 if (t->proxy->srvtimeout)
5495 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5496
willy tarreaua41a8b42005-12-17 14:02:24 +01005497 t->srv_state = SV_STSHUTW;
5498 return 1;
5499 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005500 /* read timeout */
5501 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5502 FD_CLR(t->srv_fd, StaticReadEvent);
5503 tv_eternity(&t->srexpire);
5504 shutdown(t->srv_fd, SHUT_RD);
5505 t->srv_state = SV_STSHUTR;
5506 if (!(t->flags & SN_ERR_MASK))
5507 t->flags |= SN_ERR_SRVTO;
5508 if (!(t->flags & SN_FINST_MASK))
5509 t->flags |= SN_FINST_D;
5510 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005511 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005512 /* write timeout */
5513 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005514 FD_CLR(t->srv_fd, StaticWriteEvent);
5515 tv_eternity(&t->swexpire);
5516 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005517 /* We must ensure that the read part is still alive when switching
5518 * to shutw */
5519 FD_SET(t->srv_fd, StaticReadEvent);
5520 if (t->proxy->srvtimeout)
5521 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005522 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005523 if (!(t->flags & SN_ERR_MASK))
5524 t->flags |= SN_ERR_SRVTO;
5525 if (!(t->flags & SN_FINST_MASK))
5526 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005527 return 1;
5528 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005529
5530 /* recompute request time-outs */
5531 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005532 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5533 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5534 tv_eternity(&t->swexpire);
5535 }
5536 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005537 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005538 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5539 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005540 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005541 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005542 /* FIXME: to prevent the server from expiring read timeouts during writes,
5543 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005544 t->srexpire = t->swexpire;
5545 }
willy tarreau0f7af912005-12-17 12:21:26 +01005546 else
5547 tv_eternity(&t->swexpire);
5548 }
5549 }
5550
willy tarreaub1ff9db2005-12-17 13:51:03 +01005551 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005552 if (rep->l == BUFSIZE) { /* no room to read more data */
5553 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5554 FD_CLR(t->srv_fd, StaticReadEvent);
5555 tv_eternity(&t->srexpire);
5556 }
5557 }
5558 else {
5559 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5560 FD_SET(t->srv_fd, StaticReadEvent);
5561 if (t->proxy->srvtimeout)
5562 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5563 else
5564 tv_eternity(&t->srexpire);
5565 }
5566 }
5567
5568 return 0; /* other cases change nothing */
5569 }
5570 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005571 if (t->res_sw == RES_ERROR) {
5572 //FD_CLR(t->srv_fd, StaticWriteEvent);
5573 tv_eternity(&t->swexpire);
5574 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005575 if (t->srv)
5576 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005577 //close(t->srv_fd);
5578 t->srv_state = SV_STCLOSE;
5579 if (!(t->flags & SN_ERR_MASK))
5580 t->flags |= SN_ERR_SRVCL;
5581 if (!(t->flags & SN_FINST_MASK))
5582 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005583 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005584 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005585 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005586 if (may_dequeue_tasks(t->srv, t->proxy))
5587 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005588
willy tarreau036e1ce2005-12-17 13:46:33 +01005589 return 1;
5590 }
5591 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005592 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005593 tv_eternity(&t->swexpire);
5594 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005595 if (t->srv)
5596 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005597 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005598 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005599 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005600 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005601 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005602 if (may_dequeue_tasks(t->srv, t->proxy))
5603 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005604
willy tarreau0f7af912005-12-17 12:21:26 +01005605 return 1;
5606 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005607 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5608 //FD_CLR(t->srv_fd, StaticWriteEvent);
5609 tv_eternity(&t->swexpire);
5610 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005611 if (t->srv)
5612 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005613 //close(t->srv_fd);
5614 t->srv_state = SV_STCLOSE;
5615 if (!(t->flags & SN_ERR_MASK))
5616 t->flags |= SN_ERR_SRVTO;
5617 if (!(t->flags & SN_FINST_MASK))
5618 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005619 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005620 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005621 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005622 if (may_dequeue_tasks(t->srv, t->proxy))
5623 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005624
willy tarreau036e1ce2005-12-17 13:46:33 +01005625 return 1;
5626 }
willy tarreau0f7af912005-12-17 12:21:26 +01005627 else if (req->l == 0) {
5628 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5629 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5630 tv_eternity(&t->swexpire);
5631 }
5632 }
5633 else { /* buffer not empty */
5634 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5635 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005636 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005637 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005638 /* FIXME: to prevent the server from expiring read timeouts during writes,
5639 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005640 t->srexpire = t->swexpire;
5641 }
willy tarreau0f7af912005-12-17 12:21:26 +01005642 else
5643 tv_eternity(&t->swexpire);
5644 }
5645 }
5646 return 0;
5647 }
5648 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005649 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005650 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005651 tv_eternity(&t->srexpire);
5652 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005653 if (t->srv)
5654 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005655 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005656 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005657 if (!(t->flags & SN_ERR_MASK))
5658 t->flags |= SN_ERR_SRVCL;
5659 if (!(t->flags & SN_FINST_MASK))
5660 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005661 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005662 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005663 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005664 if (may_dequeue_tasks(t->srv, t->proxy))
5665 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005666
willy tarreau0f7af912005-12-17 12:21:26 +01005667 return 1;
5668 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005669 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5670 //FD_CLR(t->srv_fd, StaticReadEvent);
5671 tv_eternity(&t->srexpire);
5672 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005673 if (t->srv)
5674 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005675 //close(t->srv_fd);
5676 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005677 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005678 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005679 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005680 if (may_dequeue_tasks(t->srv, t->proxy))
5681 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005682
willy tarreau036e1ce2005-12-17 13:46:33 +01005683 return 1;
5684 }
5685 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5686 //FD_CLR(t->srv_fd, StaticReadEvent);
5687 tv_eternity(&t->srexpire);
5688 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005689 if (t->srv)
5690 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005691 //close(t->srv_fd);
5692 t->srv_state = SV_STCLOSE;
5693 if (!(t->flags & SN_ERR_MASK))
5694 t->flags |= SN_ERR_SRVTO;
5695 if (!(t->flags & SN_FINST_MASK))
5696 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005697 /* We used to have a free connection slot. Since we'll never use it,
willy tarreau59a6cc22006-05-12 01:29:08 +02005698 * we have to inform the server that it may be used by another session.
willy tarreaudfece232006-05-02 00:19:57 +02005699 */
willy tarreau59a6cc22006-05-12 01:29:08 +02005700 if (may_dequeue_tasks(t->srv, t->proxy))
5701 task_wakeup(&rq, t->srv->queue_mgt);
willy tarreaudfece232006-05-02 00:19:57 +02005702
willy tarreau036e1ce2005-12-17 13:46:33 +01005703 return 1;
5704 }
willy tarreau0f7af912005-12-17 12:21:26 +01005705 else if (rep->l == BUFSIZE) { /* no room to read more data */
5706 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5707 FD_CLR(t->srv_fd, StaticReadEvent);
5708 tv_eternity(&t->srexpire);
5709 }
5710 }
5711 else {
5712 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5713 FD_SET(t->srv_fd, StaticReadEvent);
5714 if (t->proxy->srvtimeout)
5715 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5716 else
5717 tv_eternity(&t->srexpire);
5718 }
5719 }
5720 return 0;
5721 }
5722 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005723 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005724 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005725 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 +01005726 write(1, trash, len);
5727 }
5728 return 0;
5729 }
5730 return 0;
5731}
5732
5733
willy tarreau5cbea6f2005-12-17 12:48:26 +01005734/* Processes the client and server jobs of a session task, then
5735 * puts it back to the wait queue in a clean state, or
5736 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005737 * the time the task accepts to wait, or TIME_ETERNITY for
5738 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005739 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005740int process_session(struct task *t) {
5741 struct session *s = t->context;
5742 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005743
willy tarreau5cbea6f2005-12-17 12:48:26 +01005744 do {
5745 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005746 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005747 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005748 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005749 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005750 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005751 } while (fsm_resync);
5752
5753 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005754 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005755 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005756
willy tarreau5cbea6f2005-12-17 12:48:26 +01005757 tv_min(&min1, &s->crexpire, &s->cwexpire);
5758 tv_min(&min2, &s->srexpire, &s->swexpire);
5759 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005760 tv_min(&t->expire, &min1, &min2);
5761
5762 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005763 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005764
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005765#ifdef DEBUG_FULL
5766 /* DEBUG code : this should never ever happen, otherwise it indicates
5767 * that a task still has something to do and will provoke a quick loop.
5768 */
5769 if (tv_remain2(&now, &t->expire) <= 0)
5770 exit(100);
5771#endif
5772
willy tarreaub952e1d2005-12-18 01:31:20 +01005773 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005774 }
5775
willy tarreau5cbea6f2005-12-17 12:48:26 +01005776 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005777 actconn--;
5778
willy tarreau982249e2005-12-18 00:57:06 +01005779 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005780 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005781 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 +01005782 write(1, trash, len);
5783 }
5784
willy tarreau750a4722005-12-17 13:21:24 +01005785 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005786 if (s->rep != NULL)
5787 s->logs.bytes = s->rep->total;
5788
willy tarreau9fe663a2005-12-17 13:02:59 +01005789 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005790 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005791 sess_log(s);
5792
willy tarreau0f7af912005-12-17 12:21:26 +01005793 /* the task MUST not be in the run queue anymore */
5794 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005795 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005796 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005797 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798}
5799
5800
willy tarreau2812edc2006-05-04 12:09:37 +02005801/* Sets server <s> down, notifies by all available means, recounts the
5802 * remaining servers on the proxy and transfers queued sessions whenever
5803 * possible to other servers.
5804 */
5805void set_server_down(struct server *s) {
5806 struct pendconn *pc, *pc_bck, *pc_end;
5807 struct session *sess;
5808 int xferred;
5809
5810 s->state &= ~SRV_RUNNING;
5811
5812 if (s->health == s->rise) {
5813 recount_servers(s->proxy);
5814 recalc_server_map(s->proxy);
5815
5816 /* we might have sessions queued on this server and waiting for
5817 * a connection. Those which are redispatchable will be queued
5818 * to another server or to the proxy itself.
5819 */
5820 xferred = 0;
5821 FOREACH_ITEM_SAFE(pc, pc_bck, &s->pendconns, pc_end, struct pendconn *, list) {
5822 sess = pc->sess;
5823 if ((sess->proxy->options & PR_O_REDISP)) {
5824 /* The REDISP option was specified. We will ignore
5825 * cookie and force to balance or use the dispatcher.
5826 */
5827 sess->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
5828 sess->srv = NULL; /* it's left to the dispatcher to choose a server */
5829 if ((sess->flags & SN_CK_MASK) == SN_CK_VALID) {
5830 sess->flags &= ~SN_CK_MASK;
5831 sess->flags |= SN_CK_DOWN;
5832 }
5833 pendconn_free(pc);
5834 task_wakeup(&rq, sess->task);
5835 xferred++;
5836 }
5837 }
5838
5839 sprintf(trash, "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s"
5840 " %d sessions active, %d requeued, %d remaining in queue.\n",
5841 s->state & SRV_BACKUP ? "Backup " : "",
5842 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5843 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
5844 s->cur_sess, xferred, s->nbpend);
5845
willy tarreaubc2eda62006-05-04 15:16:23 +02005846 Warning("%s", trash);
5847 send_log(s->proxy, LOG_ALERT, "%s", trash);
willy tarreau2812edc2006-05-04 12:09:37 +02005848
5849 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5850 Alert("Proxy %s has no server available !\n", s->proxy->id);
5851 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5852 }
5853 }
5854 s->health = 0; /* failure */
5855}
5856
5857
willy tarreau5cbea6f2005-12-17 12:48:26 +01005858
5859/*
5860 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005861 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005862 */
5863int process_chk(struct task *t) {
5864 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005865 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005866 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005867
willy tarreauef900ab2005-12-17 12:52:52 +01005868 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005869
willy tarreau25424f82006-03-19 19:37:48 +01005870 new_chk:
5871 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005872 if (fd < 0) { /* no check currently running */
5873 //fprintf(stderr, "process_chk: 2\n");
5874 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5875 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005876 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005877 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005878
5879 /* we don't send any health-checks when the proxy is stopped or when
5880 * the server should not be checked.
5881 */
5882 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005883 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5884 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005885 task_queue(t); /* restore t to its place in the task list */
5886 return tv_remain2(&now, &t->expire);
5887 }
5888
willy tarreau5cbea6f2005-12-17 12:48:26 +01005889 /* we'll initiate a new check */
5890 s->result = 0; /* no result yet */
5891 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005892 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005893 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5894 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5895 //fprintf(stderr, "process_chk: 3\n");
5896
willy tarreaua41a8b42005-12-17 14:02:24 +01005897 /* we'll connect to the check port on the server */
5898 sa = s->addr;
5899 sa.sin_port = htons(s->check_port);
5900
willy tarreau0174f312005-12-18 01:02:42 +01005901 /* allow specific binding :
5902 * - server-specific at first
5903 * - proxy-specific next
5904 */
5905 if (s->state & SRV_BIND_SRC) {
5906 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5907 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5908 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5909 s->proxy->id, s->id);
5910 s->result = -1;
5911 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005912 }
willy tarreau0174f312005-12-18 01:02:42 +01005913 else if (s->proxy->options & PR_O_BIND_SRC) {
5914 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5915 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5916 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5917 s->proxy->id);
5918 s->result = -1;
5919 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005920 }
willy tarreau0174f312005-12-18 01:02:42 +01005921
5922 if (!s->result) {
5923 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5924 /* OK, connection in progress or established */
5925
5926 //fprintf(stderr, "process_chk: 4\n");
5927
5928 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5929 fdtab[fd].owner = t;
5930 fdtab[fd].read = &event_srv_chk_r;
5931 fdtab[fd].write = &event_srv_chk_w;
5932 fdtab[fd].state = FD_STCONN; /* connection in progress */
5933 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005934#ifdef DEBUG_FULL
5935 assert (!FD_ISSET(fd, StaticReadEvent));
5936#endif
willy tarreau0174f312005-12-18 01:02:42 +01005937 fd_insert(fd);
5938 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5939 tv_delayfrom(&t->expire, &now, s->inter);
5940 task_queue(t); /* restore t to its place in the task list */
5941 return tv_remain(&now, &t->expire);
5942 }
5943 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5944 s->result = -1; /* a real error */
5945 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005946 }
5947 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005948 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005949 }
5950
5951 if (!s->result) { /* nothing done */
5952 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005953 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5954 tv_delayfrom(&t->expire, &t->expire, s->inter);
5955 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 }
5957
5958 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005959 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005960 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02005961 else
5962 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005963
5964 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005965 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005966 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5967 tv_delayfrom(&t->expire, &t->expire, s->inter);
5968 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005969 }
5970 else {
5971 //fprintf(stderr, "process_chk: 8\n");
5972 /* there was a test running */
5973 if (s->result > 0) { /* good server detected */
5974 //fprintf(stderr, "process_chk: 9\n");
5975 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005976 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005977 s->state |= SRV_RUNNING;
5978
willy tarreau535ae7a2005-12-17 12:58:00 +01005979 if (s->health == s->rise) {
willy tarreaubc2eda62006-05-04 15:16:23 +02005980 int xferred;
5981
willy tarreau62084d42006-03-24 18:57:41 +01005982 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005983 recalc_server_map(s->proxy);
willy tarreaubc2eda62006-05-04 15:16:23 +02005984
5985 /* check if we can handle some connections queued at the proxy. We
5986 * will take as many as we can handle.
5987 */
5988 for (xferred = 0; !s->maxconn || xferred < s->maxconn; xferred++) {
5989 struct session *sess;
5990 struct pendconn *p;
5991
5992 p = pendconn_from_px(s->proxy);
5993 if (!p)
5994 break;
5995 p->sess->srv = s;
5996 sess = p->sess;
5997 pendconn_free(p);
5998 task_wakeup(&rq, sess->task);
5999 }
6000
6001 sprintf(trash,
6002 "%sServer %s/%s is UP. %d active and %d backup servers online.%s"
6003 " %d sessions requeued, %d total in queue.\n",
6004 s->state & SRV_BACKUP ? "Backup " : "",
6005 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
6006 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
6007 xferred, s->nbpend);
6008
6009 Warning("%s", trash);
6010 send_log(s->proxy, LOG_NOTICE, "%s", trash);
willy tarreau535ae7a2005-12-17 12:58:00 +01006011 }
willy tarreauef900ab2005-12-17 12:52:52 +01006012
willy tarreaue47c8d72005-12-17 12:55:52 +01006013 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006014 }
willy tarreauef900ab2005-12-17 12:52:52 +01006015 s->curfd = -1; /* no check running anymore */
6016 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006018 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6019 tv_delayfrom(&t->expire, &t->expire, s->inter);
6020 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006021 }
6022 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
6023 //fprintf(stderr, "process_chk: 10\n");
6024 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01006025 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01006026 s->health--; /* still good */
willy tarreau2812edc2006-05-04 12:09:37 +02006027 else
6028 set_server_down(s);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006029 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01006030 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006031 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01006032 while (tv_cmp2_ms(&t->expire, &now) <= 0)
6033 tv_delayfrom(&t->expire, &t->expire, s->inter);
6034 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006035 }
6036 /* if result is 0 and there's no timeout, we have to wait again */
6037 }
6038 //fprintf(stderr, "process_chk: 11\n");
6039 s->result = 0;
6040 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01006041 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01006042}
6043
6044
willy tarreau5cbea6f2005-12-17 12:48:26 +01006045
willy tarreau59a6cc22006-05-12 01:29:08 +02006046/*
6047 * Manages a server's connection queue. If woken up, will try to dequeue as
6048 * many pending sessions as possible, and wake them up. The task has nothing
6049 * else to do, so it always returns TIME_ETERNITY.
6050 */
6051int process_srv_queue(struct task *t) {
6052 struct server *s = (struct server*)t->context;
6053 struct proxy *p = s->proxy;
6054 int xferred;
6055
6056 /* First, check if we can handle some connections queued at the proxy. We
6057 * will take as many as we can handle.
6058 */
6059 for (xferred = 0; s->cur_sess + xferred < s->maxconn; xferred++) {
6060 struct session *sess;
6061
6062 sess = pendconn_get_next_sess(s, p);
6063 if (sess == NULL)
6064 break;
6065 task_wakeup(&rq, sess->task);
6066 }
6067
6068 return TIME_ETERNITY;
6069}
6070
willy tarreau0f7af912005-12-17 12:21:26 +01006071#if STATTIME > 0
6072int stats(void);
6073#endif
6074
6075/*
willy tarreau1c2ad212005-12-18 01:11:29 +01006076 * This does 4 things :
6077 * - wake up all expired tasks
6078 * - call all runnable tasks
6079 * - call maintain_proxies() to enable/disable the listeners
6080 * - return the delay till next event in ms, -1 = wait indefinitely
6081 * Note: this part should be rewritten with the O(ln(n)) scheduler.
6082 *
willy tarreau0f7af912005-12-17 12:21:26 +01006083 */
6084
willy tarreau1c2ad212005-12-18 01:11:29 +01006085int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01006086 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01006087 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006088 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006089
willy tarreaub952e1d2005-12-18 01:31:20 +01006090 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006091
willy tarreau1c2ad212005-12-18 01:11:29 +01006092 /* look for expired tasks and add them to the run queue.
6093 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006094 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6095 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006096 tnext = t->next;
6097 if (t->state & TASK_RUNNING)
6098 continue;
6099
willy tarreaub952e1d2005-12-18 01:31:20 +01006100 if (tv_iseternity(&t->expire))
6101 continue;
6102
willy tarreau1c2ad212005-12-18 01:11:29 +01006103 /* wakeup expired entries. It doesn't matter if they are
6104 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006105 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006106 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006107 task_wakeup(&rq, t);
6108 }
6109 else {
6110 /* first non-runnable task. Use its expiration date as an upper bound */
6111 int temp_time = tv_remain(&now, &t->expire);
6112 if (temp_time)
6113 next_time = temp_time;
6114 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006115 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006116 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006117
willy tarreau1c2ad212005-12-18 01:11:29 +01006118 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006119 * since we only use the run queue's head. Note that any task can be
6120 * woken up by any other task and it will be processed immediately
6121 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006122 */
willy tarreau7feab592006-04-22 15:13:16 +02006123 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006124 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006125
willy tarreau1c2ad212005-12-18 01:11:29 +01006126 task_sleep(&rq, t);
6127 temp_time = t->process(t);
6128 next_time = MINTIME(temp_time, next_time);
6129 }
6130
6131 /* maintain all proxies in a consistent state. This should quickly become a task */
6132 time2 = maintain_proxies();
6133 return MINTIME(time2, next_time);
6134}
6135
6136
6137#if defined(ENABLE_EPOLL)
6138
6139/*
6140 * Main epoll() loop.
6141 */
6142
6143/* does 3 actions :
6144 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6145 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6146 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6147 *
6148 * returns 0 if initialization failed, !0 otherwise.
6149 */
6150
6151int epoll_loop(int action) {
6152 int next_time;
6153 int status;
6154 int fd;
6155
6156 int fds, count;
6157 int pr, pw, sr, sw;
6158 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6159 struct epoll_event ev;
6160
6161 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006162 static struct epoll_event *epoll_events = NULL;
6163 static int epoll_fd;
6164
6165 if (action == POLL_LOOP_ACTION_INIT) {
6166 epoll_fd = epoll_create(global.maxsock + 1);
6167 if (epoll_fd < 0)
6168 return 0;
6169 else {
6170 epoll_events = (struct epoll_event*)
6171 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6172 PrevReadEvent = (fd_set *)
6173 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6174 PrevWriteEvent = (fd_set *)
6175 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006176 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006177 return 1;
6178 }
6179 else if (action == POLL_LOOP_ACTION_CLEAN) {
6180 if (PrevWriteEvent) free(PrevWriteEvent);
6181 if (PrevReadEvent) free(PrevReadEvent);
6182 if (epoll_events) free(epoll_events);
6183 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006184 epoll_fd = 0;
6185 return 1;
6186 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006187
willy tarreau1c2ad212005-12-18 01:11:29 +01006188 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006189
willy tarreau1c2ad212005-12-18 01:11:29 +01006190 tv_now(&now);
6191
6192 while (1) {
6193 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006194
6195 /* stop when there's no connection left and we don't allow them anymore */
6196 if (!actconn && listeners == 0)
6197 break;
6198
willy tarreau0f7af912005-12-17 12:21:26 +01006199#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006200 {
6201 int time2;
6202 time2 = stats();
6203 next_time = MINTIME(time2, next_time);
6204 }
willy tarreau0f7af912005-12-17 12:21:26 +01006205#endif
6206
willy tarreau1c2ad212005-12-18 01:11:29 +01006207 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6208
6209 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6210 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6211
6212 if ((ro^rn) | (wo^wn)) {
6213 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6214#define FDSETS_ARE_INT_ALIGNED
6215#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006216
willy tarreauad90a0c2005-12-18 01:09:15 +01006217#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6218#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006219 pr = (ro >> count) & 1;
6220 pw = (wo >> count) & 1;
6221 sr = (rn >> count) & 1;
6222 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006223#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006224 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6225 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6226 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6227 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006228#endif
6229#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006230 pr = FD_ISSET(fd, PrevReadEvent);
6231 pw = FD_ISSET(fd, PrevWriteEvent);
6232 sr = FD_ISSET(fd, StaticReadEvent);
6233 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006234#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006235 if (!((sr^pr) | (sw^pw)))
6236 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006237
willy tarreau1c2ad212005-12-18 01:11:29 +01006238 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6239 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006240
willy tarreaub952e1d2005-12-18 01:31:20 +01006241#ifdef EPOLL_CTL_MOD_WORKAROUND
6242 /* I encountered a rarely reproducible problem with
6243 * EPOLL_CTL_MOD where a modified FD (systematically
6244 * the one in epoll_events[0], fd#7) would sometimes
6245 * be set EPOLL_OUT while asked for a read ! This is
6246 * with the 2.4 epoll patch. The workaround is to
6247 * delete then recreate in case of modification.
6248 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6249 * nor RHEL kernels.
6250 */
6251
6252 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6253 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6254
6255 if ((sr | sw))
6256 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6257#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006258 if ((pr | pw)) {
6259 /* the file-descriptor already exists... */
6260 if ((sr | sw)) {
6261 /* ...and it will still exist */
6262 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6263 // perror("epoll_ctl(MOD)");
6264 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006265 }
6266 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006267 /* ...and it will be removed */
6268 if (fdtab[fd].state != FD_STCLOSE &&
6269 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6270 // perror("epoll_ctl(DEL)");
6271 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006272 }
6273 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006274 } else {
6275 /* the file-descriptor did not exist, let's add it */
6276 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6277 // perror("epoll_ctl(ADD)");
6278 // exit(1);
6279 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006280 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006281#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006282 }
6283 ((int*)PrevReadEvent)[fds] = rn;
6284 ((int*)PrevWriteEvent)[fds] = wn;
6285 }
6286 }
6287
6288 /* now let's wait for events */
6289 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6290 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006291
willy tarreau1c2ad212005-12-18 01:11:29 +01006292 for (count = 0; count < status; count++) {
6293 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006294
6295 if (FD_ISSET(fd, StaticReadEvent)) {
6296 if (fdtab[fd].state == FD_STCLOSE)
6297 continue;
6298 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6299 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006300 }
willy tarreau05be12b2006-03-19 19:35:00 +01006301
6302 if (FD_ISSET(fd, StaticWriteEvent)) {
6303 if (fdtab[fd].state == FD_STCLOSE)
6304 continue;
6305 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6306 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006307 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006308 }
6309 }
6310 return 1;
6311}
6312#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006313
willy tarreauad90a0c2005-12-18 01:09:15 +01006314
willy tarreau5cbea6f2005-12-17 12:48:26 +01006315
willy tarreau1c2ad212005-12-18 01:11:29 +01006316#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006317
willy tarreau1c2ad212005-12-18 01:11:29 +01006318/*
6319 * Main poll() loop.
6320 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006321
willy tarreau1c2ad212005-12-18 01:11:29 +01006322/* does 3 actions :
6323 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6324 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6325 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6326 *
6327 * returns 0 if initialization failed, !0 otherwise.
6328 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006329
willy tarreau1c2ad212005-12-18 01:11:29 +01006330int poll_loop(int action) {
6331 int next_time;
6332 int status;
6333 int fd, nbfd;
6334
6335 int fds, count;
6336 int sr, sw;
6337 unsigned rn, wn; /* read new, write new */
6338
6339 /* private data */
6340 static struct pollfd *poll_events = NULL;
6341
6342 if (action == POLL_LOOP_ACTION_INIT) {
6343 poll_events = (struct pollfd*)
6344 calloc(1, sizeof(struct pollfd) * global.maxsock);
6345 return 1;
6346 }
6347 else if (action == POLL_LOOP_ACTION_CLEAN) {
6348 if (poll_events)
6349 free(poll_events);
6350 return 1;
6351 }
6352
6353 /* OK, it's POLL_LOOP_ACTION_RUN */
6354
6355 tv_now(&now);
6356
6357 while (1) {
6358 next_time = process_runnable_tasks();
6359
6360 /* stop when there's no connection left and we don't allow them anymore */
6361 if (!actconn && listeners == 0)
6362 break;
6363
6364#if STATTIME > 0
6365 {
6366 int time2;
6367 time2 = stats();
6368 next_time = MINTIME(time2, next_time);
6369 }
6370#endif
6371
6372
6373 nbfd = 0;
6374 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6375
6376 rn = ((int*)StaticReadEvent)[fds];
6377 wn = ((int*)StaticWriteEvent)[fds];
6378
6379 if ((rn|wn)) {
6380 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6381#define FDSETS_ARE_INT_ALIGNED
6382#ifdef FDSETS_ARE_INT_ALIGNED
6383
6384#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6385#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6386 sr = (rn >> count) & 1;
6387 sw = (wn >> count) & 1;
6388#else
6389 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6390 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6391#endif
6392#else
6393 sr = FD_ISSET(fd, StaticReadEvent);
6394 sw = FD_ISSET(fd, StaticWriteEvent);
6395#endif
6396 if ((sr|sw)) {
6397 poll_events[nbfd].fd = fd;
6398 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6399 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006400 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006401 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006402 }
6403 }
6404
6405 /* now let's wait for events */
6406 status = poll(poll_events, nbfd, next_time);
6407 tv_now(&now);
6408
6409 for (count = 0; status > 0 && count < nbfd; count++) {
6410 fd = poll_events[count].fd;
6411
6412 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6413 continue;
6414
6415 /* ok, we found one active fd */
6416 status--;
6417
willy tarreau05be12b2006-03-19 19:35:00 +01006418 if (FD_ISSET(fd, StaticReadEvent)) {
6419 if (fdtab[fd].state == FD_STCLOSE)
6420 continue;
6421 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6422 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006423 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006424
willy tarreau05be12b2006-03-19 19:35:00 +01006425 if (FD_ISSET(fd, StaticWriteEvent)) {
6426 if (fdtab[fd].state == FD_STCLOSE)
6427 continue;
6428 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6429 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006430 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006431 }
6432 }
6433 return 1;
6434}
willy tarreauad90a0c2005-12-18 01:09:15 +01006435#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006436
willy tarreauad90a0c2005-12-18 01:09:15 +01006437
willy tarreauad90a0c2005-12-18 01:09:15 +01006438
willy tarreau1c2ad212005-12-18 01:11:29 +01006439/*
6440 * Main select() loop.
6441 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006442
willy tarreau1c2ad212005-12-18 01:11:29 +01006443/* does 3 actions :
6444 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6445 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6446 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6447 *
6448 * returns 0 if initialization failed, !0 otherwise.
6449 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006450
willy tarreauad90a0c2005-12-18 01:09:15 +01006451
willy tarreau1c2ad212005-12-18 01:11:29 +01006452int select_loop(int action) {
6453 int next_time;
6454 int status;
6455 int fd,i;
6456 struct timeval delta;
6457 int readnotnull, writenotnull;
6458 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006459
willy tarreau1c2ad212005-12-18 01:11:29 +01006460 if (action == POLL_LOOP_ACTION_INIT) {
6461 ReadEvent = (fd_set *)
6462 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6463 WriteEvent = (fd_set *)
6464 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6465 return 1;
6466 }
6467 else if (action == POLL_LOOP_ACTION_CLEAN) {
6468 if (WriteEvent) free(WriteEvent);
6469 if (ReadEvent) free(ReadEvent);
6470 return 1;
6471 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006472
willy tarreau1c2ad212005-12-18 01:11:29 +01006473 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006474
willy tarreau1c2ad212005-12-18 01:11:29 +01006475 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006476
willy tarreau1c2ad212005-12-18 01:11:29 +01006477 while (1) {
6478 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006479
willy tarreau1c2ad212005-12-18 01:11:29 +01006480 /* stop when there's no connection left and we don't allow them anymore */
6481 if (!actconn && listeners == 0)
6482 break;
6483
6484#if STATTIME > 0
6485 {
6486 int time2;
6487 time2 = stats();
6488 next_time = MINTIME(time2, next_time);
6489 }
6490#endif
6491
willy tarreau1c2ad212005-12-18 01:11:29 +01006492 if (next_time > 0) { /* FIXME */
6493 /* Convert to timeval */
6494 /* to avoid eventual select loops due to timer precision */
6495 next_time += SCHEDULER_RESOLUTION;
6496 delta.tv_sec = next_time / 1000;
6497 delta.tv_usec = (next_time % 1000) * 1000;
6498 }
6499 else if (next_time == 0) { /* allow select to return immediately when needed */
6500 delta.tv_sec = delta.tv_usec = 0;
6501 }
6502
6503
6504 /* let's restore fdset state */
6505
6506 readnotnull = 0; writenotnull = 0;
6507 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6508 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6509 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6510 }
6511
6512 // /* just a verification code, needs to be removed for performance */
6513 // for (i=0; i<maxfd; i++) {
6514 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6515 // abort();
6516 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6517 // abort();
6518 //
6519 // }
6520
6521 status = select(maxfd,
6522 readnotnull ? ReadEvent : NULL,
6523 writenotnull ? WriteEvent : NULL,
6524 NULL,
6525 (next_time >= 0) ? &delta : NULL);
6526
6527 /* this is an experiment on the separation of the select work */
6528 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6529 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6530
6531 tv_now(&now);
6532
6533 if (status > 0) { /* must proceed with events */
6534
6535 int fds;
6536 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006537
willy tarreau1c2ad212005-12-18 01:11:29 +01006538 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6539 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6540 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6541
6542 /* if we specify read first, the accepts and zero reads will be
6543 * seen first. Moreover, system buffers will be flushed faster.
6544 */
willy tarreau05be12b2006-03-19 19:35:00 +01006545 if (FD_ISSET(fd, ReadEvent)) {
6546 if (fdtab[fd].state == FD_STCLOSE)
6547 continue;
6548 fdtab[fd].read(fd);
6549 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006550
willy tarreau05be12b2006-03-19 19:35:00 +01006551 if (FD_ISSET(fd, WriteEvent)) {
6552 if (fdtab[fd].state == FD_STCLOSE)
6553 continue;
6554 fdtab[fd].write(fd);
6555 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006556 }
6557 }
6558 else {
6559 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006560 }
willy tarreau0f7af912005-12-17 12:21:26 +01006561 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006562 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006563}
6564
6565
6566#if STATTIME > 0
6567/*
6568 * Display proxy statistics regularly. It is designed to be called from the
6569 * select_loop().
6570 */
6571int stats(void) {
6572 static int lines;
6573 static struct timeval nextevt;
6574 static struct timeval lastevt;
6575 static struct timeval starttime = {0,0};
6576 unsigned long totaltime, deltatime;
6577 int ret;
6578
willy tarreau750a4722005-12-17 13:21:24 +01006579 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006580 deltatime = (tv_diff(&lastevt, &now)?:1);
6581 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006582
willy tarreau9fe663a2005-12-17 13:02:59 +01006583 if (global.mode & MODE_STATS) {
6584 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006585 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006586 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6587 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006588 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006589 actconn, totalconn,
6590 stats_tsk_new, stats_tsk_good,
6591 stats_tsk_left, stats_tsk_right,
6592 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6593 }
6594 }
6595
6596 tv_delayfrom(&nextevt, &now, STATTIME);
6597
6598 lastevt=now;
6599 }
6600 ret = tv_remain(&now, &nextevt);
6601 return ret;
6602}
6603#endif
6604
6605
6606/*
6607 * this function enables proxies when there are enough free sessions,
6608 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006609 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006610 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006611 */
6612static int maintain_proxies(void) {
6613 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006614 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006615 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006616
6617 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006618 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006619
6620 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006621 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006622 while (p) {
6623 if (p->nbconn < p->maxconn) {
6624 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006625 for (l = p->listen; l != NULL; l = l->next) {
6626 FD_SET(l->fd, StaticReadEvent);
6627 }
willy tarreau0f7af912005-12-17 12:21:26 +01006628 p->state = PR_STRUN;
6629 }
6630 }
6631 else {
6632 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006633 for (l = p->listen; l != NULL; l = l->next) {
6634 FD_CLR(l->fd, StaticReadEvent);
6635 }
willy tarreau0f7af912005-12-17 12:21:26 +01006636 p->state = PR_STIDLE;
6637 }
6638 }
6639 p = p->next;
6640 }
6641 }
6642 else { /* block all proxies */
6643 while (p) {
6644 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006645 for (l = p->listen; l != NULL; l = l->next) {
6646 FD_CLR(l->fd, StaticReadEvent);
6647 }
willy tarreau0f7af912005-12-17 12:21:26 +01006648 p->state = PR_STIDLE;
6649 }
6650 p = p->next;
6651 }
6652 }
6653
willy tarreau5cbea6f2005-12-17 12:48:26 +01006654 if (stopping) {
6655 p = proxy;
6656 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006657 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006658 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006659 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006660 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006661 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006662 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006663
willy tarreaua41a8b42005-12-17 14:02:24 +01006664 for (l = p->listen; l != NULL; l = l->next) {
6665 fd_delete(l->fd);
6666 listeners--;
6667 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006668 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006669 }
6670 else {
6671 tleft = MINTIME(t, tleft);
6672 }
6673 }
6674 p = p->next;
6675 }
6676 }
6677 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006678}
6679
6680/*
6681 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006682 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6683 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006684 */
6685static void soft_stop(void) {
6686 struct proxy *p;
6687
6688 stopping = 1;
6689 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006690 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006691 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006692 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006693 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006694 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006695 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006696 }
willy tarreau0f7af912005-12-17 12:21:26 +01006697 p = p->next;
6698 }
6699}
6700
willy tarreaudbd3bef2006-01-20 19:35:18 +01006701static void pause_proxy(struct proxy *p) {
6702 struct listener *l;
6703 for (l = p->listen; l != NULL; l = l->next) {
6704 shutdown(l->fd, SHUT_RD);
6705 FD_CLR(l->fd, StaticReadEvent);
6706 p->state = PR_STPAUSED;
6707 }
6708}
6709
6710/*
6711 * This function temporarily disables listening so that another new instance
6712 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006713 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006714 * the proxy, or a SIGTTIN can be sent to listen again.
6715 */
6716static void pause_proxies(void) {
6717 struct proxy *p;
6718
6719 p = proxy;
6720 tv_now(&now); /* else, the old time before select will be used */
6721 while (p) {
6722 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6723 Warning("Pausing proxy %s.\n", p->id);
6724 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6725 pause_proxy(p);
6726 }
6727 p = p->next;
6728 }
6729}
6730
6731
6732/*
6733 * This function reactivates listening. This can be used after a call to
6734 * sig_pause(), for example when a new instance has failed starting up.
6735 * It is designed to be called upon reception of a SIGTTIN.
6736 */
6737static void listen_proxies(void) {
6738 struct proxy *p;
6739 struct listener *l;
6740
6741 p = proxy;
6742 tv_now(&now); /* else, the old time before select will be used */
6743 while (p) {
6744 if (p->state == PR_STPAUSED) {
6745 Warning("Enabling proxy %s.\n", p->id);
6746 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6747
6748 for (l = p->listen; l != NULL; l = l->next) {
6749 if (listen(l->fd, p->maxconn) == 0) {
6750 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6751 FD_SET(l->fd, StaticReadEvent);
6752 p->state = PR_STRUN;
6753 }
6754 else
6755 p->state = PR_STIDLE;
6756 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006757 int port;
6758
6759 if (l->addr.ss_family == AF_INET6)
6760 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6761 else
6762 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6763
willy tarreaudbd3bef2006-01-20 19:35:18 +01006764 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006765 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006766 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006767 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006768 /* Another port might have been enabled. Let's stop everything. */
6769 pause_proxy(p);
6770 break;
6771 }
6772 }
6773 }
6774 p = p->next;
6775 }
6776}
6777
6778
willy tarreau0f7af912005-12-17 12:21:26 +01006779/*
6780 * upon SIGUSR1, let's have a soft stop.
6781 */
6782void sig_soft_stop(int sig) {
6783 soft_stop();
6784 signal(sig, SIG_IGN);
6785}
6786
willy tarreaudbd3bef2006-01-20 19:35:18 +01006787/*
6788 * upon SIGTTOU, we pause everything
6789 */
6790void sig_pause(int sig) {
6791 pause_proxies();
6792 signal(sig, sig_pause);
6793}
willy tarreau0f7af912005-12-17 12:21:26 +01006794
willy tarreau8337c6b2005-12-17 13:41:01 +01006795/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006796 * upon SIGTTIN, let's have a soft stop.
6797 */
6798void sig_listen(int sig) {
6799 listen_proxies();
6800 signal(sig, sig_listen);
6801}
6802
6803/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006804 * this function dumps every server's state when the process receives SIGHUP.
6805 */
6806void sig_dump_state(int sig) {
6807 struct proxy *p = proxy;
6808
6809 Warning("SIGHUP received, dumping servers states.\n");
6810 while (p) {
6811 struct server *s = p->srv;
6812
willy tarreau4632c212006-05-02 23:32:51 +02006813 send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006814 while (s) {
willy tarreau4632c212006-05-02 23:32:51 +02006815 snprintf(trash, sizeof(trash),
6816 "SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %d tot.",
6817 p->id, s->id,
6818 (s->state & SRV_RUNNING) ? "UP" : "DOWN",
6819 s->cur_sess, s->nbpend, s->cum_sess);
willy tarreau14b4d432006-04-07 18:23:29 +02006820 Warning("%s\n", trash);
6821 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006822 s = s->next;
6823 }
willy tarreaudd07e972005-12-18 00:48:48 +01006824
willy tarreau62084d42006-03-24 18:57:41 +01006825 if (p->srv_act == 0) {
willy tarreau4632c212006-05-02 23:32:51 +02006826 snprintf(trash, sizeof(trash),
6827 "SIGHUP: Proxy %s %s ! Conn: %d act, %d pend (%d unass), %d tot.",
6828 p->id,
6829 (p->srv_bck) ? "is running on backup servers" : "has no server available",
6830 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006831 } else {
6832 snprintf(trash, sizeof(trash),
willy tarreau4632c212006-05-02 23:32:51 +02006833 "SIGHUP: Proxy %s has %d active servers and %d backup servers available."
6834 " Conn: %d act, %d pend (%d unass), %d tot.",
6835 p->id, p->srv_act, p->srv_bck,
6836 p->nbconn, p->totpend, p->nbpend, p->cum_conn);
willy tarreau14b4d432006-04-07 18:23:29 +02006837 }
6838 Warning("%s\n", trash);
6839 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006840
willy tarreau8337c6b2005-12-17 13:41:01 +01006841 p = p->next;
6842 }
6843 signal(sig, sig_dump_state);
6844}
6845
willy tarreau0f7af912005-12-17 12:21:26 +01006846void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006847 struct task *t, *tnext;
6848 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006849
willy tarreau5e698ef2006-05-02 14:51:00 +02006850 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6851 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006852 tnext = t->next;
6853 s = t->context;
6854 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6855 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6856 "req=%d, rep=%d, clifd=%d\n",
6857 s, tv_remain(&now, &t->expire),
6858 s->cli_state,
6859 s->srv_state,
6860 FD_ISSET(s->cli_fd, StaticReadEvent),
6861 FD_ISSET(s->cli_fd, StaticWriteEvent),
6862 FD_ISSET(s->srv_fd, StaticReadEvent),
6863 FD_ISSET(s->srv_fd, StaticWriteEvent),
6864 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6865 );
willy tarreau0f7af912005-12-17 12:21:26 +01006866 }
willy tarreau12350152005-12-18 01:03:27 +01006867}
6868
willy tarreau64a3cc32005-12-18 01:13:11 +01006869#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006870static void fast_stop(void)
6871{
6872 struct proxy *p;
6873 p = proxy;
6874 while (p) {
6875 p->grace = 0;
6876 p = p->next;
6877 }
6878 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006879}
6880
willy tarreau12350152005-12-18 01:03:27 +01006881void sig_int(int sig) {
6882 /* This would normally be a hard stop,
6883 but we want to be sure about deallocation,
6884 and so on, so we do a soft stop with
6885 0 GRACE time
6886 */
6887 fast_stop();
6888 /* If we are killed twice, we decide to die*/
6889 signal(sig, SIG_DFL);
6890}
6891
6892void sig_term(int sig) {
6893 /* This would normally be a hard stop,
6894 but we want to be sure about deallocation,
6895 and so on, so we do a soft stop with
6896 0 GRACE time
6897 */
6898 fast_stop();
6899 /* If we are killed twice, we decide to die*/
6900 signal(sig, SIG_DFL);
6901}
willy tarreau64a3cc32005-12-18 01:13:11 +01006902#endif
willy tarreau12350152005-12-18 01:03:27 +01006903
willy tarreauc1f47532005-12-18 01:08:26 +01006904/* returns the pointer to an error in the replacement string, or NULL if OK */
6905char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006906 struct hdr_exp *exp;
6907
willy tarreauc1f47532005-12-18 01:08:26 +01006908 if (replace != NULL) {
6909 char *err;
6910 err = check_replace_string(replace);
6911 if (err)
6912 return err;
6913 }
6914
willy tarreaue39cd132005-12-17 13:00:18 +01006915 while (*head != NULL)
6916 head = &(*head)->next;
6917
6918 exp = calloc(1, sizeof(struct hdr_exp));
6919
6920 exp->preg = preg;
6921 exp->replace = replace;
6922 exp->action = action;
6923 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006924
6925 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006926}
6927
willy tarreau9fe663a2005-12-17 13:02:59 +01006928
willy tarreau0f7af912005-12-17 12:21:26 +01006929/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006931 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006932int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006933
willy tarreau9fe663a2005-12-17 13:02:59 +01006934 if (!strcmp(args[0], "global")) { /* new section */
6935 /* no option, nothing special to do */
6936 return 0;
6937 }
6938 else if (!strcmp(args[0], "daemon")) {
6939 global.mode |= MODE_DAEMON;
6940 }
6941 else if (!strcmp(args[0], "debug")) {
6942 global.mode |= MODE_DEBUG;
6943 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006944 else if (!strcmp(args[0], "noepoll")) {
6945 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6946 }
6947 else if (!strcmp(args[0], "nopoll")) {
6948 cfg_polling_mechanism &= ~POLL_USE_POLL;
6949 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006950 else if (!strcmp(args[0], "quiet")) {
6951 global.mode |= MODE_QUIET;
6952 }
6953 else if (!strcmp(args[0], "stats")) {
6954 global.mode |= MODE_STATS;
6955 }
6956 else if (!strcmp(args[0], "uid")) {
6957 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006958 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006959 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006960 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006961 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006962 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006964 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006965 global.uid = atol(args[1]);
6966 }
6967 else if (!strcmp(args[0], "gid")) {
6968 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006969 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006971 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006972 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006973 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006974 return -1;
6975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006976 global.gid = atol(args[1]);
6977 }
6978 else if (!strcmp(args[0], "nbproc")) {
6979 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006980 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006981 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006982 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006983 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006984 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006986 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006987 global.nbproc = atol(args[1]);
6988 }
6989 else if (!strcmp(args[0], "maxconn")) {
6990 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006991 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006993 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006994 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006995 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006996 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006997 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006999#ifdef SYSTEM_MAXCONN
7000 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
7001 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);
7002 global.maxconn = DEFAULT_MAXCONN;
7003 }
7004#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01007005 }
willy tarreaub1285d52005-12-18 01:20:14 +01007006 else if (!strcmp(args[0], "ulimit-n")) {
7007 if (global.rlimit_nofile != 0) {
7008 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7009 return 0;
7010 }
7011 if (*(args[1]) == 0) {
7012 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
7013 return -1;
7014 }
7015 global.rlimit_nofile = atol(args[1]);
7016 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 else if (!strcmp(args[0], "chroot")) {
7018 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007019 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007020 return 0;
7021 }
7022 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007023 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 return -1;
7025 }
7026 global.chroot = strdup(args[1]);
7027 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007028 else if (!strcmp(args[0], "pidfile")) {
7029 if (global.pidfile != NULL) {
7030 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
7031 return 0;
7032 }
7033 if (*(args[1]) == 0) {
7034 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
7035 return -1;
7036 }
7037 global.pidfile = strdup(args[1]);
7038 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007039 else if (!strcmp(args[0], "log")) { /* syslog server address */
7040 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01007041 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007042
7043 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007044 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007045 return -1;
7046 }
7047
7048 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7049 if (!strcmp(log_facilities[facility], args[2]))
7050 break;
7051
7052 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007053 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007054 exit(1);
7055 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007056
7057 level = 7; /* max syslog level = debug */
7058 if (*(args[3])) {
7059 while (level >= 0 && strcmp(log_levels[level], args[3]))
7060 level--;
7061 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007062 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007063 exit(1);
7064 }
7065 }
7066
willy tarreau9fe663a2005-12-17 13:02:59 +01007067 sa = str2sa(args[1]);
7068 if (!sa->sin_port)
7069 sa->sin_port = htons(SYSLOG_PORT);
7070
7071 if (global.logfac1 == -1) {
7072 global.logsrv1 = *sa;
7073 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007074 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007075 }
7076 else if (global.logfac2 == -1) {
7077 global.logsrv2 = *sa;
7078 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007079 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01007080 }
7081 else {
7082 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7083 return -1;
7084 }
7085
7086 }
7087 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007088 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 return -1;
7090 }
7091 return 0;
7092}
7093
7094
willy tarreaua41a8b42005-12-17 14:02:24 +01007095void init_default_instance() {
7096 memset(&defproxy, 0, sizeof(defproxy));
7097 defproxy.mode = PR_MODE_TCP;
7098 defproxy.state = PR_STNEW;
7099 defproxy.maxconn = cfg_maxpconn;
7100 defproxy.conn_retries = CONN_RETRIES;
7101 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7102}
7103
willy tarreau9fe663a2005-12-17 13:02:59 +01007104/*
7105 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7106 */
7107int cfg_parse_listen(char *file, int linenum, char **args) {
7108 static struct proxy *curproxy = NULL;
7109 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007110 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007111 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007112
7113 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007114 if (!*args[1]) {
7115 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7116 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007117 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 return -1;
7119 }
7120
7121 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007122 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007123 return -1;
7124 }
willy tarreaudfece232006-05-02 00:19:57 +02007125
willy tarreau9fe663a2005-12-17 13:02:59 +01007126 curproxy->next = proxy;
7127 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007128 LIST_INIT(&curproxy->pendconns);
7129
willy tarreau9fe663a2005-12-17 13:02:59 +01007130 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007131
7132 /* parse the listener address if any */
7133 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007134 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007135 if (!curproxy->listen)
7136 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007137 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007138 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007139
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007141 curproxy->state = defproxy.state;
7142 curproxy->maxconn = defproxy.maxconn;
7143 curproxy->conn_retries = defproxy.conn_retries;
7144 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007145
7146 if (defproxy.check_req)
7147 curproxy->check_req = strdup(defproxy.check_req);
7148 curproxy->check_len = defproxy.check_len;
7149
7150 if (defproxy.cookie_name)
7151 curproxy->cookie_name = strdup(defproxy.cookie_name);
7152 curproxy->cookie_len = defproxy.cookie_len;
7153
7154 if (defproxy.capture_name)
7155 curproxy->capture_name = strdup(defproxy.capture_name);
7156 curproxy->capture_namelen = defproxy.capture_namelen;
7157 curproxy->capture_len = defproxy.capture_len;
7158
7159 if (defproxy.errmsg.msg400)
7160 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7161 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7162
7163 if (defproxy.errmsg.msg403)
7164 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7165 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7166
7167 if (defproxy.errmsg.msg408)
7168 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7169 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7170
7171 if (defproxy.errmsg.msg500)
7172 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7173 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7174
7175 if (defproxy.errmsg.msg502)
7176 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7177 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7178
7179 if (defproxy.errmsg.msg503)
7180 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7181 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7182
7183 if (defproxy.errmsg.msg504)
7184 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7185 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7186
willy tarreaua41a8b42005-12-17 14:02:24 +01007187 curproxy->clitimeout = defproxy.clitimeout;
7188 curproxy->contimeout = defproxy.contimeout;
7189 curproxy->srvtimeout = defproxy.srvtimeout;
7190 curproxy->mode = defproxy.mode;
7191 curproxy->logfac1 = defproxy.logfac1;
7192 curproxy->logsrv1 = defproxy.logsrv1;
7193 curproxy->loglev1 = defproxy.loglev1;
7194 curproxy->logfac2 = defproxy.logfac2;
7195 curproxy->logsrv2 = defproxy.logsrv2;
7196 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007197 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007198 curproxy->grace = defproxy.grace;
7199 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007200 curproxy->mon_net = defproxy.mon_net;
7201 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007202 return 0;
7203 }
7204 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007205 /* some variables may have already been initialized earlier */
7206 if (defproxy.check_req) free(defproxy.check_req);
7207 if (defproxy.cookie_name) free(defproxy.cookie_name);
7208 if (defproxy.capture_name) free(defproxy.capture_name);
7209 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7210 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7211 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7212 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7213 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7214 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7215 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7216
7217 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007218 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007219 return 0;
7220 }
7221 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007222 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007223 return -1;
7224 }
7225
willy tarreaua41a8b42005-12-17 14:02:24 +01007226 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7227 if (curproxy == &defproxy) {
7228 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7229 return -1;
7230 }
7231
7232 if (strchr(args[1], ':') == NULL) {
7233 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7234 file, linenum, args[0]);
7235 return -1;
7236 }
7237 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007238 if (!curproxy->listen)
7239 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007240 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007241 return 0;
7242 }
willy tarreaub1285d52005-12-18 01:20:14 +01007243 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7244 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7245 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7246 file, linenum, args[0]);
7247 return -1;
7248 }
7249 /* flush useless bits */
7250 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7251 return 0;
7252 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007253 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007254 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7255 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7256 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7257 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007258 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007259 return -1;
7260 }
7261 }
7262 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007263 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007264 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007265 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7266 curproxy->state = PR_STNEW;
7267 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7269 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007270// if (curproxy == &defproxy) {
7271// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7272// return -1;
7273// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007274
willy tarreau9fe663a2005-12-17 13:02:59 +01007275 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007276// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7277// file, linenum);
7278// return 0;
7279 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007280 }
7281
7282 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007283 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7284 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007285 return -1;
7286 }
7287 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007288 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007289
7290 cur_arg = 2;
7291 while (*(args[cur_arg])) {
7292 if (!strcmp(args[cur_arg], "rewrite")) {
7293 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007294 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007295 else if (!strcmp(args[cur_arg], "indirect")) {
7296 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007297 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007298 else if (!strcmp(args[cur_arg], "insert")) {
7299 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007300 }
willy tarreau240afa62005-12-17 13:14:35 +01007301 else if (!strcmp(args[cur_arg], "nocache")) {
7302 curproxy->options |= PR_O_COOK_NOC;
7303 }
willy tarreaucd878942005-12-17 13:27:43 +01007304 else if (!strcmp(args[cur_arg], "postonly")) {
7305 curproxy->options |= PR_O_COOK_POST;
7306 }
willy tarreau0174f312005-12-18 01:02:42 +01007307 else if (!strcmp(args[cur_arg], "prefix")) {
7308 curproxy->options |= PR_O_COOK_PFX;
7309 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 else {
willy tarreau0174f312005-12-18 01:02:42 +01007311 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007312 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007313 return -1;
7314 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007315 cur_arg++;
7316 }
willy tarreau0174f312005-12-18 01:02:42 +01007317 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7318 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7319 file, linenum);
7320 return -1;
7321 }
7322
7323 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7324 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007325 file, linenum);
7326 return -1;
7327 }
willy tarreau12350152005-12-18 01:03:27 +01007328 }/* end else if (!strcmp(args[0], "cookie")) */
7329 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7330// if (curproxy == &defproxy) {
7331// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7332// return -1;
7333// }
7334
7335 if (curproxy->appsession_name != NULL) {
7336// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7337// file, linenum);
7338// return 0;
7339 free(curproxy->appsession_name);
7340 }
7341
7342 if (*(args[5]) == 0) {
7343 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7344 file, linenum, args[0]);
7345 return -1;
7346 }
7347 have_appsession = 1;
7348 curproxy->appsession_name = strdup(args[1]);
7349 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7350 curproxy->appsession_len = atoi(args[3]);
7351 curproxy->appsession_timeout = atoi(args[5]);
7352 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7353 if (rc) {
7354 Alert("Error Init Appsession Hashtable.\n");
7355 return -1;
7356 }
7357 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007358 else if (!strcmp(args[0], "capture")) {
7359 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7360 // if (curproxy == &defproxy) {
7361 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7362 // return -1;
7363 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007364
willy tarreau4302f492005-12-18 01:00:37 +01007365 if (curproxy->capture_name != NULL) {
7366 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7367 // file, linenum, args[0]);
7368 // return 0;
7369 free(curproxy->capture_name);
7370 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007371
willy tarreau4302f492005-12-18 01:00:37 +01007372 if (*(args[4]) == 0) {
7373 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7374 file, linenum, args[0]);
7375 return -1;
7376 }
7377 curproxy->capture_name = strdup(args[2]);
7378 curproxy->capture_namelen = strlen(curproxy->capture_name);
7379 curproxy->capture_len = atol(args[4]);
7380 if (curproxy->capture_len >= CAPTURE_LEN) {
7381 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7382 file, linenum, CAPTURE_LEN - 1);
7383 curproxy->capture_len = CAPTURE_LEN - 1;
7384 }
7385 curproxy->to_log |= LW_COOKIE;
7386 }
7387 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7388 struct cap_hdr *hdr;
7389
7390 if (curproxy == &defproxy) {
7391 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7392 return -1;
7393 }
7394
7395 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7396 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7397 file, linenum, args[0], args[1]);
7398 return -1;
7399 }
7400
7401 hdr = calloc(sizeof(struct cap_hdr), 1);
7402 hdr->next = curproxy->req_cap;
7403 hdr->name = strdup(args[3]);
7404 hdr->namelen = strlen(args[3]);
7405 hdr->len = atol(args[5]);
7406 hdr->index = curproxy->nb_req_cap++;
7407 curproxy->req_cap = hdr;
7408 curproxy->to_log |= LW_REQHDR;
7409 }
7410 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7411 struct cap_hdr *hdr;
7412
7413 if (curproxy == &defproxy) {
7414 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7415 return -1;
7416 }
7417
7418 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7419 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7420 file, linenum, args[0], args[1]);
7421 return -1;
7422 }
7423 hdr = calloc(sizeof(struct cap_hdr), 1);
7424 hdr->next = curproxy->rsp_cap;
7425 hdr->name = strdup(args[3]);
7426 hdr->namelen = strlen(args[3]);
7427 hdr->len = atol(args[5]);
7428 hdr->index = curproxy->nb_rsp_cap++;
7429 curproxy->rsp_cap = hdr;
7430 curproxy->to_log |= LW_RSPHDR;
7431 }
7432 else {
7433 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007434 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007435 return -1;
7436 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007438 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007439 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007440 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007441 return 0;
7442 }
7443 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007444 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7445 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007446 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007447 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007448 curproxy->contimeout = atol(args[1]);
7449 }
7450 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007451 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007452 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7453 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007454 return 0;
7455 }
7456 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007457 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7458 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007459 return -1;
7460 }
7461 curproxy->clitimeout = atol(args[1]);
7462 }
7463 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007464 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007465 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007466 return 0;
7467 }
7468 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007469 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7470 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007471 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007472 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007473 curproxy->srvtimeout = atol(args[1]);
7474 }
7475 else if (!strcmp(args[0], "retries")) { /* connection retries */
7476 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007477 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7478 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007479 return -1;
7480 }
7481 curproxy->conn_retries = atol(args[1]);
7482 }
7483 else if (!strcmp(args[0], "option")) {
7484 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007485 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007486 return -1;
7487 }
7488 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007489 /* enable reconnections to dispatch */
7490 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007491#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007492 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007493 /* enable transparent proxy connections */
7494 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007495#endif
7496 else if (!strcmp(args[1], "keepalive"))
7497 /* enable keep-alive */
7498 curproxy->options |= PR_O_KEEPALIVE;
7499 else if (!strcmp(args[1], "forwardfor"))
7500 /* insert x-forwarded-for field */
7501 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007502 else if (!strcmp(args[1], "logasap"))
7503 /* log as soon as possible, without waiting for the session to complete */
7504 curproxy->options |= PR_O_LOGASAP;
7505 else if (!strcmp(args[1], "httpclose"))
7506 /* force connection: close in both directions in HTTP mode */
7507 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007508 else if (!strcmp(args[1], "forceclose"))
7509 /* force connection: close in both directions in HTTP mode and enforce end of session */
7510 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007511 else if (!strcmp(args[1], "checkcache"))
7512 /* require examination of cacheability of the 'set-cookie' field */
7513 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007514 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007516 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007517 else if (!strcmp(args[1], "tcplog"))
7518 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007519 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007520 else if (!strcmp(args[1], "dontlognull")) {
7521 /* don't log empty requests */
7522 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007523 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007524 else if (!strcmp(args[1], "tcpka")) {
7525 /* enable TCP keep-alives on client and server sessions */
7526 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7527 }
7528 else if (!strcmp(args[1], "clitcpka")) {
7529 /* enable TCP keep-alives on client sessions */
7530 curproxy->options |= PR_O_TCP_CLI_KA;
7531 }
7532 else if (!strcmp(args[1], "srvtcpka")) {
7533 /* enable TCP keep-alives on server sessions */
7534 curproxy->options |= PR_O_TCP_SRV_KA;
7535 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007536 else if (!strcmp(args[1], "allbackups")) {
7537 /* Use all backup servers simultaneously */
7538 curproxy->options |= PR_O_USE_ALL_BK;
7539 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007540 else if (!strcmp(args[1], "httpchk")) {
7541 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007542 if (curproxy->check_req != NULL) {
7543 free(curproxy->check_req);
7544 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007545 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007546 if (!*args[2]) { /* no argument */
7547 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7548 curproxy->check_len = strlen(DEF_CHECK_REQ);
7549 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007550 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7551 curproxy->check_req = (char *)malloc(reqlen);
7552 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7553 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007554 } else { /* more arguments : METHOD URI [HTTP_VER] */
7555 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7556 if (*args[4])
7557 reqlen += strlen(args[4]);
7558 else
7559 reqlen += strlen("HTTP/1.0");
7560
7561 curproxy->check_req = (char *)malloc(reqlen);
7562 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7563 "%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 +01007564 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007565 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007566 else if (!strcmp(args[1], "persist")) {
7567 /* persist on using the server specified by the cookie, even when it's down */
7568 curproxy->options |= PR_O_PERSIST;
7569 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007570 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007571 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 return -1;
7573 }
7574 return 0;
7575 }
7576 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7577 /* enable reconnections to dispatch */
7578 curproxy->options |= PR_O_REDISP;
7579 }
willy tarreaua1598082005-12-17 13:08:06 +01007580#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007581 else if (!strcmp(args[0], "transparent")) {
7582 /* enable transparent proxy connections */
7583 curproxy->options |= PR_O_TRANSP;
7584 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007585#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007586 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7587 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007588 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007589 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007590 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 curproxy->maxconn = atol(args[1]);
7592 }
7593 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7594 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007595 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007596 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007597 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007598 curproxy->grace = atol(args[1]);
7599 }
7600 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007601 if (curproxy == &defproxy) {
7602 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7603 return -1;
7604 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007605 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007606 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007607 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007609 curproxy->dispatch_addr = *str2sa(args[1]);
7610 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007611 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007612 if (*(args[1])) {
7613 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007614 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007615 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007616 else if (!strcmp(args[1], "source")) {
7617 curproxy->options |= PR_O_BALANCE_SH;
7618 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007619 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007620 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007621 return -1;
7622 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007623 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007624 else /* if no option is set, use round-robin by default */
7625 curproxy->options |= PR_O_BALANCE_RR;
7626 }
7627 else if (!strcmp(args[0], "server")) { /* server address */
7628 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007629 char *rport;
7630 char *raddr;
7631 short realport;
7632 int do_check;
7633
7634 if (curproxy == &defproxy) {
7635 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7636 return -1;
7637 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007638
willy tarreaua41a8b42005-12-17 14:02:24 +01007639 if (!*args[2]) {
7640 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007641 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007642 return -1;
7643 }
7644 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7645 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7646 return -1;
7647 }
willy tarreau0174f312005-12-18 01:02:42 +01007648
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007649 /* the servers are linked backwards first */
7650 newsrv->next = curproxy->srv;
7651 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007652 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007653
willy tarreau18a957c2006-04-12 19:26:23 +02007654 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007655 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007657 newsrv->id = strdup(args[1]);
7658
7659 /* several ways to check the port component :
7660 * - IP => port=+0, relative
7661 * - IP: => port=+0, relative
7662 * - IP:N => port=N, absolute
7663 * - IP:+N => port=+N, relative
7664 * - IP:-N => port=-N, relative
7665 */
7666 raddr = strdup(args[2]);
7667 rport = strchr(raddr, ':');
7668 if (rport) {
7669 *rport++ = 0;
7670 realport = atol(rport);
7671 if (!isdigit((int)*rport))
7672 newsrv->state |= SRV_MAPPORTS;
7673 } else {
7674 realport = 0;
7675 newsrv->state |= SRV_MAPPORTS;
7676 }
7677
7678 newsrv->addr = *str2sa(raddr);
7679 newsrv->addr.sin_port = htons(realport);
7680 free(raddr);
7681
willy tarreau9fe663a2005-12-17 13:02:59 +01007682 newsrv->curfd = -1; /* no health-check in progress */
7683 newsrv->inter = DEF_CHKINTR;
7684 newsrv->rise = DEF_RISETIME;
7685 newsrv->fall = DEF_FALLTIME;
7686 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7687 cur_arg = 3;
7688 while (*args[cur_arg]) {
7689 if (!strcmp(args[cur_arg], "cookie")) {
7690 newsrv->cookie = strdup(args[cur_arg + 1]);
7691 newsrv->cklen = strlen(args[cur_arg + 1]);
7692 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007693 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007694 else if (!strcmp(args[cur_arg], "rise")) {
7695 newsrv->rise = atol(args[cur_arg + 1]);
7696 newsrv->health = newsrv->rise;
7697 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007698 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007699 else if (!strcmp(args[cur_arg], "fall")) {
7700 newsrv->fall = atol(args[cur_arg + 1]);
7701 cur_arg += 2;
7702 }
7703 else if (!strcmp(args[cur_arg], "inter")) {
7704 newsrv->inter = atol(args[cur_arg + 1]);
7705 cur_arg += 2;
7706 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007707 else if (!strcmp(args[cur_arg], "port")) {
7708 newsrv->check_port = atol(args[cur_arg + 1]);
7709 cur_arg += 2;
7710 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007711 else if (!strcmp(args[cur_arg], "backup")) {
7712 newsrv->state |= SRV_BACKUP;
7713 cur_arg ++;
7714 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007715 else if (!strcmp(args[cur_arg], "weight")) {
7716 int w;
7717 w = atol(args[cur_arg + 1]);
7718 if (w < 1 || w > 256) {
7719 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7720 file, linenum, newsrv->id, w);
7721 return -1;
7722 }
7723 newsrv->uweight = w - 1;
7724 cur_arg += 2;
7725 }
willy tarreau18a957c2006-04-12 19:26:23 +02007726 else if (!strcmp(args[cur_arg], "maxconn")) {
7727 newsrv->maxconn = atol(args[cur_arg + 1]);
7728 cur_arg += 2;
7729 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007730 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007731 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007732 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007733 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007734 }
willy tarreau0174f312005-12-18 01:02:42 +01007735 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7736 if (!*args[cur_arg + 1]) {
7737 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7738 file, linenum, "source");
7739 return -1;
7740 }
7741 newsrv->state |= SRV_BIND_SRC;
7742 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7743 cur_arg += 2;
7744 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007745 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007746 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 +01007747 file, linenum, newsrv->id);
7748 return -1;
7749 }
7750 }
7751
7752 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007753 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7754 newsrv->check_port = realport; /* by default */
7755 if (!newsrv->check_port) {
7756 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 +01007757 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007758 return -1;
7759 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007760 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007761 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007762
willy tarreau62084d42006-03-24 18:57:41 +01007763 if (newsrv->state & SRV_BACKUP)
7764 curproxy->srv_bck++;
7765 else
7766 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007767 }
7768 else if (!strcmp(args[0], "log")) { /* syslog server address */
7769 struct sockaddr_in *sa;
7770 int facility;
7771
7772 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7773 curproxy->logfac1 = global.logfac1;
7774 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007775 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007776 curproxy->logfac2 = global.logfac2;
7777 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007778 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007779 }
7780 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007781 int level;
7782
willy tarreau0f7af912005-12-17 12:21:26 +01007783 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7784 if (!strcmp(log_facilities[facility], args[2]))
7785 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007786
willy tarreau0f7af912005-12-17 12:21:26 +01007787 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007788 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007789 exit(1);
7790 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007791
willy tarreau8337c6b2005-12-17 13:41:01 +01007792 level = 7; /* max syslog level = debug */
7793 if (*(args[3])) {
7794 while (level >= 0 && strcmp(log_levels[level], args[3]))
7795 level--;
7796 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007797 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007798 exit(1);
7799 }
7800 }
7801
willy tarreau0f7af912005-12-17 12:21:26 +01007802 sa = str2sa(args[1]);
7803 if (!sa->sin_port)
7804 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007805
willy tarreau0f7af912005-12-17 12:21:26 +01007806 if (curproxy->logfac1 == -1) {
7807 curproxy->logsrv1 = *sa;
7808 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007809 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007810 }
7811 else if (curproxy->logfac2 == -1) {
7812 curproxy->logsrv2 = *sa;
7813 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007814 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007815 }
7816 else {
7817 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007820 }
7821 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007822 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007823 file, linenum);
7824 return -1;
7825 }
7826 }
willy tarreaua1598082005-12-17 13:08:06 +01007827 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007828 if (!*args[1]) {
7829 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007830 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007831 return -1;
7832 }
7833
7834 curproxy->source_addr = *str2sa(args[1]);
7835 curproxy->options |= PR_O_BIND_SRC;
7836 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007837 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7838 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007839 if (curproxy == &defproxy) {
7840 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7841 return -1;
7842 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007843
7844 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007845 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7846 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007847 return -1;
7848 }
7849
7850 preg = calloc(1, sizeof(regex_t));
7851 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007852 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007853 return -1;
7854 }
7855
willy tarreauc1f47532005-12-18 01:08:26 +01007856 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7857 if (err) {
7858 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7859 file, linenum, *err);
7860 return -1;
7861 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007862 }
7863 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7864 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007865 if (curproxy == &defproxy) {
7866 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7867 return -1;
7868 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007869
7870 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007871 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007872 return -1;
7873 }
7874
7875 preg = calloc(1, sizeof(regex_t));
7876 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007877 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007878 return -1;
7879 }
7880
7881 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7882 }
7883 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7884 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007885 if (curproxy == &defproxy) {
7886 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7887 return -1;
7888 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007889
7890 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007891 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007892 return -1;
7893 }
7894
7895 preg = calloc(1, sizeof(regex_t));
7896 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007897 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007898 return -1;
7899 }
7900
7901 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7902 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007903 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7904 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007905 if (curproxy == &defproxy) {
7906 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7907 return -1;
7908 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007909
7910 if (*(args[1]) == 0) {
7911 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7912 return -1;
7913 }
7914
7915 preg = calloc(1, sizeof(regex_t));
7916 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7917 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7918 return -1;
7919 }
7920
7921 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7922 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007923 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7924 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007925 if (curproxy == &defproxy) {
7926 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7927 return -1;
7928 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007929
7930 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007931 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007932 return -1;
7933 }
7934
7935 preg = calloc(1, sizeof(regex_t));
7936 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007937 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007938 return -1;
7939 }
7940
7941 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7942 }
7943 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7944 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007945 if (curproxy == &defproxy) {
7946 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7947 return -1;
7948 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007949
7950 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007951 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7952 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007953 return -1;
7954 }
7955
7956 preg = calloc(1, sizeof(regex_t));
7957 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007958 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007959 return -1;
7960 }
7961
willy tarreauc1f47532005-12-18 01:08:26 +01007962 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7963 if (err) {
7964 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7965 file, linenum, *err);
7966 return -1;
7967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007968 }
7969 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7970 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007971 if (curproxy == &defproxy) {
7972 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7973 return -1;
7974 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007975
7976 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007977 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007978 return -1;
7979 }
7980
7981 preg = calloc(1, sizeof(regex_t));
7982 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007983 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007984 return -1;
7985 }
7986
7987 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7988 }
7989 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7990 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007991 if (curproxy == &defproxy) {
7992 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7993 return -1;
7994 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007995
7996 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007997 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007998 return -1;
7999 }
8000
8001 preg = calloc(1, sizeof(regex_t));
8002 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008003 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008004 return -1;
8005 }
8006
8007 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
8008 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008009 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
8010 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008011 if (curproxy == &defproxy) {
8012 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8013 return -1;
8014 }
willy tarreau036e1ce2005-12-17 13:46:33 +01008015
8016 if (*(args[1]) == 0) {
8017 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
8018 return -1;
8019 }
8020
8021 preg = calloc(1, sizeof(regex_t));
8022 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8023 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8024 return -1;
8025 }
8026
8027 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
8028 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008029 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
8030 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008031 if (curproxy == &defproxy) {
8032 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8033 return -1;
8034 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008035
8036 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008037 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008038 return -1;
8039 }
8040
8041 preg = calloc(1, sizeof(regex_t));
8042 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008043 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008044 return -1;
8045 }
8046
8047 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
8048 }
8049 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008050 if (curproxy == &defproxy) {
8051 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8052 return -1;
8053 }
8054
willy tarreau9fe663a2005-12-17 13:02:59 +01008055 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008056 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008057 return 0;
8058 }
8059
8060 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008061 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008062 return -1;
8063 }
8064
willy tarreau4302f492005-12-18 01:00:37 +01008065 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
8066 }
8067 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
8068 regex_t *preg;
8069
8070 if (*(args[1]) == 0 || *(args[2]) == 0) {
8071 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8072 file, linenum, args[0]);
8073 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008074 }
willy tarreau4302f492005-12-18 01:00:37 +01008075
8076 preg = calloc(1, sizeof(regex_t));
8077 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8078 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8079 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008080 }
willy tarreau4302f492005-12-18 01:00:37 +01008081
willy tarreauc1f47532005-12-18 01:08:26 +01008082 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8083 if (err) {
8084 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8085 file, linenum, *err);
8086 return -1;
8087 }
willy tarreau4302f492005-12-18 01:00:37 +01008088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008089 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8090 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008091 if (curproxy == &defproxy) {
8092 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8093 return -1;
8094 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008095
8096 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008097 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008098 return -1;
8099 }
willy tarreaue39cd132005-12-17 13:00:18 +01008100
willy tarreau9fe663a2005-12-17 13:02:59 +01008101 preg = calloc(1, sizeof(regex_t));
8102 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008103 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008104 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008105 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008106
willy tarreauc1f47532005-12-18 01:08:26 +01008107 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8108 if (err) {
8109 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8110 file, linenum, *err);
8111 return -1;
8112 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008113 }
willy tarreau982249e2005-12-18 00:57:06 +01008114 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8115 regex_t *preg;
8116 if (curproxy == &defproxy) {
8117 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8118 return -1;
8119 }
8120
8121 if (*(args[1]) == 0) {
8122 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8123 return -1;
8124 }
8125
8126 preg = calloc(1, sizeof(regex_t));
8127 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8128 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8129 return -1;
8130 }
8131
willy tarreauc1f47532005-12-18 01:08:26 +01008132 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8133 if (err) {
8134 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8135 file, linenum, *err);
8136 return -1;
8137 }
willy tarreau982249e2005-12-18 00:57:06 +01008138 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008139 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008140 regex_t *preg;
8141 if (curproxy == &defproxy) {
8142 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8143 return -1;
8144 }
willy tarreaue39cd132005-12-17 13:00:18 +01008145
willy tarreaua41a8b42005-12-17 14:02:24 +01008146 if (*(args[1]) == 0 || *(args[2]) == 0) {
8147 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8148 file, linenum, args[0]);
8149 return -1;
8150 }
willy tarreaue39cd132005-12-17 13:00:18 +01008151
willy tarreaua41a8b42005-12-17 14:02:24 +01008152 preg = calloc(1, sizeof(regex_t));
8153 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8154 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8155 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008156 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008157
willy tarreauc1f47532005-12-18 01:08:26 +01008158 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8159 if (err) {
8160 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8161 file, linenum, *err);
8162 return -1;
8163 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008165 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8166 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008167 if (curproxy == &defproxy) {
8168 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8169 return -1;
8170 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008171
8172 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008173 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008174 return -1;
8175 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008176
willy tarreau9fe663a2005-12-17 13:02:59 +01008177 preg = calloc(1, sizeof(regex_t));
8178 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008179 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008180 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008181 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008182
willy tarreauc1f47532005-12-18 01:08:26 +01008183 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8184 if (err) {
8185 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8186 file, linenum, *err);
8187 return -1;
8188 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008189 }
willy tarreau982249e2005-12-18 00:57:06 +01008190 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8191 regex_t *preg;
8192 if (curproxy == &defproxy) {
8193 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8194 return -1;
8195 }
8196
8197 if (*(args[1]) == 0) {
8198 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8199 return -1;
8200 }
8201
8202 preg = calloc(1, sizeof(regex_t));
8203 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8204 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8205 return -1;
8206 }
8207
willy tarreauc1f47532005-12-18 01:08:26 +01008208 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8209 if (err) {
8210 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8211 file, linenum, *err);
8212 return -1;
8213 }
willy tarreau982249e2005-12-18 00:57:06 +01008214 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008215 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008216 if (curproxy == &defproxy) {
8217 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8218 return -1;
8219 }
8220
willy tarreau9fe663a2005-12-17 13:02:59 +01008221 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008222 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008223 return 0;
8224 }
8225
8226 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008227 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008228 return -1;
8229 }
8230
8231 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8232 }
willy tarreauc1f47532005-12-18 01:08:26 +01008233 else if (!strcmp(args[0], "errorloc") ||
8234 !strcmp(args[0], "errorloc302") ||
8235 !strcmp(args[0], "errorloc303")) { /* error location */
8236 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008237 char *err;
8238
willy tarreaueedaa9f2005-12-17 14:08:03 +01008239 // if (curproxy == &defproxy) {
8240 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8241 // return -1;
8242 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008243
willy tarreau8337c6b2005-12-17 13:41:01 +01008244 if (*(args[2]) == 0) {
8245 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8246 return -1;
8247 }
8248
8249 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008250 if (!strcmp(args[0], "errorloc303")) {
8251 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8252 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8253 } else {
8254 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8255 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8256 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008257
8258 if (errnum == 400) {
8259 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008260 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008261 free(curproxy->errmsg.msg400);
8262 }
8263 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008264 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008265 }
8266 else if (errnum == 403) {
8267 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008268 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008269 free(curproxy->errmsg.msg403);
8270 }
8271 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008272 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008273 }
8274 else if (errnum == 408) {
8275 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008276 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008277 free(curproxy->errmsg.msg408);
8278 }
8279 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008280 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008281 }
8282 else if (errnum == 500) {
8283 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008284 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008285 free(curproxy->errmsg.msg500);
8286 }
8287 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008288 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008289 }
8290 else if (errnum == 502) {
8291 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008292 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008293 free(curproxy->errmsg.msg502);
8294 }
8295 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008296 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008297 }
8298 else if (errnum == 503) {
8299 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008300 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008301 free(curproxy->errmsg.msg503);
8302 }
8303 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008304 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008305 }
8306 else if (errnum == 504) {
8307 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008308 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008309 free(curproxy->errmsg.msg504);
8310 }
8311 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008312 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008313 }
8314 else {
8315 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8316 free(err);
8317 }
8318 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008319 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008320 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008321 return -1;
8322 }
8323 return 0;
8324}
willy tarreaue39cd132005-12-17 13:00:18 +01008325
willy tarreau5cbea6f2005-12-17 12:48:26 +01008326
willy tarreau9fe663a2005-12-17 13:02:59 +01008327/*
8328 * This function reads and parses the configuration file given in the argument.
8329 * returns 0 if OK, -1 if error.
8330 */
8331int readcfgfile(char *file) {
8332 char thisline[256];
8333 char *line;
8334 FILE *f;
8335 int linenum = 0;
8336 char *end;
8337 char *args[MAX_LINE_ARGS];
8338 int arg;
8339 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008340 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008341 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008342
willy tarreau9fe663a2005-12-17 13:02:59 +01008343 struct proxy *curproxy = NULL;
8344 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008345
willy tarreau9fe663a2005-12-17 13:02:59 +01008346 if ((f=fopen(file,"r")) == NULL)
8347 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008348
willy tarreaueedaa9f2005-12-17 14:08:03 +01008349 init_default_instance();
8350
willy tarreau9fe663a2005-12-17 13:02:59 +01008351 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8352 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008353
willy tarreau9fe663a2005-12-17 13:02:59 +01008354 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008355
willy tarreau9fe663a2005-12-17 13:02:59 +01008356 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008357 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008358 line++;
8359
8360 arg = 0;
8361 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008362
willy tarreau9fe663a2005-12-17 13:02:59 +01008363 while (*line && arg < MAX_LINE_ARGS) {
8364 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8365 * C equivalent value. Other combinations left unchanged (eg: \1).
8366 */
8367 if (*line == '\\') {
8368 int skip = 0;
8369 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8370 *line = line[1];
8371 skip = 1;
8372 }
8373 else if (line[1] == 'r') {
8374 *line = '\r';
8375 skip = 1;
8376 }
8377 else if (line[1] == 'n') {
8378 *line = '\n';
8379 skip = 1;
8380 }
8381 else if (line[1] == 't') {
8382 *line = '\t';
8383 skip = 1;
8384 }
willy tarreauc1f47532005-12-18 01:08:26 +01008385 else if (line[1] == 'x') {
8386 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8387 unsigned char hex1, hex2;
8388 hex1 = toupper(line[2]) - '0';
8389 hex2 = toupper(line[3]) - '0';
8390 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8391 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8392 *line = (hex1<<4) + hex2;
8393 skip = 3;
8394 }
8395 else {
8396 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8397 return -1;
8398 }
8399 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008400 if (skip) {
8401 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8402 end -= skip;
8403 }
8404 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008405 }
willy tarreaua1598082005-12-17 13:08:06 +01008406 else if (*line == '#' || *line == '\n' || *line == '\r') {
8407 /* end of string, end of loop */
8408 *line = 0;
8409 break;
8410 }
willy tarreauc29948c2005-12-17 13:10:27 +01008411 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008412 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008413 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008414 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008415 line++;
8416 args[++arg] = line;
8417 }
8418 else {
8419 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008420 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008421 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008422
willy tarreau9fe663a2005-12-17 13:02:59 +01008423 /* empty line */
8424 if (!**args)
8425 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008426
willy tarreau9fe663a2005-12-17 13:02:59 +01008427 /* zero out remaining args */
8428 while (++arg < MAX_LINE_ARGS) {
8429 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008430 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008431
willy tarreaua41a8b42005-12-17 14:02:24 +01008432 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008433 confsect = CFG_LISTEN;
8434 else if (!strcmp(args[0], "global")) /* global config */
8435 confsect = CFG_GLOBAL;
8436 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008437
willy tarreau9fe663a2005-12-17 13:02:59 +01008438 switch (confsect) {
8439 case CFG_LISTEN:
8440 if (cfg_parse_listen(file, linenum, args) < 0)
8441 return -1;
8442 break;
8443 case CFG_GLOBAL:
8444 if (cfg_parse_global(file, linenum, args) < 0)
8445 return -1;
8446 break;
8447 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008448 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008449 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008450 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008451
8452
willy tarreau0f7af912005-12-17 12:21:26 +01008453 }
8454 fclose(f);
8455
8456 /*
8457 * Now, check for the integrity of all that we have collected.
8458 */
8459
Willy TARREAU3759f982006-03-01 22:44:17 +01008460 /* will be needed further to delay some tasks */
8461 tv_now(&now);
8462
willy tarreau0f7af912005-12-17 12:21:26 +01008463 if ((curproxy = proxy) == NULL) {
8464 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8465 file);
8466 return -1;
8467 }
8468
8469 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008470 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008471 curproxy = curproxy->next;
8472 continue;
8473 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008474
8475 if (curproxy->listen == NULL) {
8476 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);
8477 cfgerr++;
8478 }
8479 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008480 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008481 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008482 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8483 file, curproxy->id);
8484 cfgerr++;
8485 }
8486 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8487 if (curproxy->options & PR_O_TRANSP) {
8488 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8489 file, curproxy->id);
8490 cfgerr++;
8491 }
8492 else if (curproxy->srv == NULL) {
8493 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8494 file, curproxy->id);
8495 cfgerr++;
8496 }
willy tarreaua1598082005-12-17 13:08:06 +01008497 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008498 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8499 file, curproxy->id);
8500 }
8501 }
8502 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008503 if (curproxy->cookie_name != NULL) {
8504 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8505 file, curproxy->id);
8506 }
8507 if ((newsrv = curproxy->srv) != NULL) {
8508 Warning("parsing %s : servers will be ignored for listener %s.\n",
8509 file, curproxy->id);
8510 }
willy tarreaue39cd132005-12-17 13:00:18 +01008511 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008512 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8513 file, curproxy->id);
8514 }
willy tarreaue39cd132005-12-17 13:00:18 +01008515 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008516 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8517 file, curproxy->id);
8518 }
8519 }
8520 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8521 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8522 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8523 file, curproxy->id);
8524 cfgerr++;
8525 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008526 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008527
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008528 /* first, we will invert the servers list order */
8529 newsrv = NULL;
8530 while (curproxy->srv) {
8531 struct server *next;
8532
8533 next = curproxy->srv->next;
8534 curproxy->srv->next = newsrv;
8535 newsrv = curproxy->srv;
8536 if (!next)
8537 break;
8538 curproxy->srv = next;
8539 }
8540
8541 /* now, newsrv == curproxy->srv */
8542 if (newsrv) {
8543 struct server *srv;
8544 int pgcd;
8545 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008546
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008547 /* We will factor the weights to reduce the table,
8548 * using Euclide's largest common divisor algorithm
8549 */
8550 pgcd = newsrv->uweight + 1;
8551 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8552 int t, w;
8553
8554 w = srv->uweight + 1;
8555 while (w) {
8556 t = pgcd % w;
8557 pgcd = w;
8558 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008559 }
willy tarreau0f7af912005-12-17 12:21:26 +01008560 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008561
8562 act = bck = 0;
8563 for (srv = newsrv; srv; srv = srv->next) {
8564 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8565 if (srv->state & SRV_BACKUP)
8566 bck += srv->eweight + 1;
8567 else
8568 act += srv->eweight + 1;
8569 }
8570
8571 /* this is the largest map we will ever need for this servers list */
8572 if (act < bck)
8573 act = bck;
8574
8575 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8576 /* recounts servers and their weights */
8577 recount_servers(curproxy);
8578 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008579 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008580
8581 if (curproxy->options & PR_O_LOGASAP)
8582 curproxy->to_log &= ~LW_BYTES;
8583
willy tarreau8337c6b2005-12-17 13:41:01 +01008584 if (curproxy->errmsg.msg400 == NULL) {
8585 curproxy->errmsg.msg400 = (char *)HTTP_400;
8586 curproxy->errmsg.len400 = strlen(HTTP_400);
8587 }
8588 if (curproxy->errmsg.msg403 == NULL) {
8589 curproxy->errmsg.msg403 = (char *)HTTP_403;
8590 curproxy->errmsg.len403 = strlen(HTTP_403);
8591 }
8592 if (curproxy->errmsg.msg408 == NULL) {
8593 curproxy->errmsg.msg408 = (char *)HTTP_408;
8594 curproxy->errmsg.len408 = strlen(HTTP_408);
8595 }
8596 if (curproxy->errmsg.msg500 == NULL) {
8597 curproxy->errmsg.msg500 = (char *)HTTP_500;
8598 curproxy->errmsg.len500 = strlen(HTTP_500);
8599 }
8600 if (curproxy->errmsg.msg502 == NULL) {
8601 curproxy->errmsg.msg502 = (char *)HTTP_502;
8602 curproxy->errmsg.len502 = strlen(HTTP_502);
8603 }
8604 if (curproxy->errmsg.msg503 == NULL) {
8605 curproxy->errmsg.msg503 = (char *)HTTP_503;
8606 curproxy->errmsg.len503 = strlen(HTTP_503);
8607 }
8608 if (curproxy->errmsg.msg504 == NULL) {
8609 curproxy->errmsg.msg504 = (char *)HTTP_504;
8610 curproxy->errmsg.len504 = strlen(HTTP_504);
8611 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008612
willy tarreau59a6cc22006-05-12 01:29:08 +02008613 /*
8614 * If this server supports a maxconn parameter, it needs a dedicated
8615 * tasks to fill the emptied slots when a connection leaves.
8616 */
8617 newsrv = curproxy->srv;
8618 while (newsrv != NULL) {
8619 if (newsrv->maxconn > 0) {
8620 struct task *t;
8621
8622 if ((t = pool_alloc(task)) == NULL) {
8623 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8624 return -1;
8625 }
8626
8627 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8628 t->wq = LIST_HEAD(wait_queue[1]); /* already assigned to the eternity queue */
8629 t->state = TASK_IDLE;
8630 t->process = process_srv_queue;
8631 t->context = newsrv;
8632 newsrv->queue_mgt = t;
8633
8634 /* never run it unless specifically woken up */
8635 tv_eternity(&t->expire);
8636 task_queue(t);
8637 }
8638 newsrv = newsrv->next;
8639 }
8640
Willy TARREAU3759f982006-03-01 22:44:17 +01008641 /* now we'll start this proxy's health checks if any */
8642 /* 1- count the checkers to run simultaneously */
8643 nbchk = 0;
8644 mininter = 0;
8645 newsrv = curproxy->srv;
8646 while (newsrv != NULL) {
8647 if (newsrv->state & SRV_CHECKED) {
8648 if (!mininter || mininter > newsrv->inter)
8649 mininter = newsrv->inter;
8650 nbchk++;
8651 }
8652 newsrv = newsrv->next;
8653 }
8654
8655 /* 2- start them as far as possible from each others while respecting
8656 * their own intervals. For this, we will start them after their own
8657 * interval added to the min interval divided by the number of servers,
8658 * weighted by the server's position in the list.
8659 */
8660 if (nbchk > 0) {
8661 struct task *t;
8662 int srvpos;
8663
8664 newsrv = curproxy->srv;
8665 srvpos = 0;
8666 while (newsrv != NULL) {
8667 /* should this server be checked ? */
8668 if (newsrv->state & SRV_CHECKED) {
8669 if ((t = pool_alloc(task)) == NULL) {
8670 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8671 return -1;
8672 }
8673
8674 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008675 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008676 t->state = TASK_IDLE;
8677 t->process = process_chk;
8678 t->context = newsrv;
8679
8680 /* check this every ms */
8681 tv_delayfrom(&t->expire, &now,
8682 newsrv->inter + mininter * srvpos / nbchk);
8683 task_queue(t);
8684 //task_wakeup(&rq, t);
8685 srvpos++;
8686 }
8687 newsrv = newsrv->next;
8688 }
8689 }
8690
willy tarreau0f7af912005-12-17 12:21:26 +01008691 curproxy = curproxy->next;
8692 }
8693 if (cfgerr > 0) {
8694 Alert("Errors found in configuration file, aborting.\n");
8695 return -1;
8696 }
8697 else
8698 return 0;
8699}
8700
8701
8702/*
8703 * This function initializes all the necessary variables. It only returns
8704 * if everything is OK. If something fails, it exits.
8705 */
8706void init(int argc, char **argv) {
8707 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008708 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008709 char *old_argv = *argv;
8710 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008711 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008712
8713 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008714 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008715 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008716 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008717 exit(1);
8718 }
8719
willy tarreau746e26b2006-03-25 11:14:35 +01008720#ifdef HAPROXY_MEMMAX
8721 global.rlimit_memmax = HAPROXY_MEMMAX;
8722#endif
8723
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008724 /* initialize the libc's localtime structures once for all so that we
8725 * won't be missing memory if we want to send alerts under OOM conditions.
8726 */
8727 tv_now(&now);
8728 localtime(&now.tv_sec);
8729
willy tarreau4302f492005-12-18 01:00:37 +01008730 /* initialize the log header encoding map : '{|}"#' should be encoded with
8731 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8732 * URL encoding only requires '"', '#' to be encoded as well as non-
8733 * printable characters above.
8734 */
8735 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8736 memset(url_encode_map, 0, sizeof(url_encode_map));
8737 for (i = 0; i < 32; i++) {
8738 FD_SET(i, hdr_encode_map);
8739 FD_SET(i, url_encode_map);
8740 }
8741 for (i = 127; i < 256; i++) {
8742 FD_SET(i, hdr_encode_map);
8743 FD_SET(i, url_encode_map);
8744 }
8745
8746 tmp = "\"#{|}";
8747 while (*tmp) {
8748 FD_SET(*tmp, hdr_encode_map);
8749 tmp++;
8750 }
8751
8752 tmp = "\"#";
8753 while (*tmp) {
8754 FD_SET(*tmp, url_encode_map);
8755 tmp++;
8756 }
8757
willy tarreau64a3cc32005-12-18 01:13:11 +01008758 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8759#if defined(ENABLE_POLL)
8760 cfg_polling_mechanism |= POLL_USE_POLL;
8761#endif
8762#if defined(ENABLE_EPOLL)
8763 cfg_polling_mechanism |= POLL_USE_EPOLL;
8764#endif
8765
willy tarreau0f7af912005-12-17 12:21:26 +01008766 pid = getpid();
8767 progname = *argv;
8768 while ((tmp = strchr(progname, '/')) != NULL)
8769 progname = tmp + 1;
8770
8771 argc--; argv++;
8772 while (argc > 0) {
8773 char *flag;
8774
8775 if (**argv == '-') {
8776 flag = *argv+1;
8777
8778 /* 1 arg */
8779 if (*flag == 'v') {
8780 display_version();
8781 exit(0);
8782 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008783#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008784 else if (*flag == 'd' && flag[1] == 'e')
8785 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008786#endif
8787#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008788 else if (*flag == 'd' && flag[1] == 'p')
8789 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008790#endif
willy tarreau982249e2005-12-18 00:57:06 +01008791 else if (*flag == 'V')
8792 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008793 else if (*flag == 'd' && flag[1] == 'b')
8794 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008795 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008796 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008797 else if (*flag == 'c')
8798 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008799 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008800 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008801 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008802 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008803 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8804 /* list of pids to finish ('f') or terminate ('t') */
8805
8806 if (flag[1] == 'f')
8807 oldpids_sig = SIGUSR1; /* finish then exit */
8808 else
8809 oldpids_sig = SIGTERM; /* terminate immediately */
8810 argv++; argc--;
8811
8812 if (argc > 0) {
8813 oldpids = calloc(argc, sizeof(int));
8814 while (argc > 0) {
8815 oldpids[nb_oldpids] = atol(*argv);
8816 if (oldpids[nb_oldpids] <= 0)
8817 usage(old_argv);
8818 argc--; argv++;
8819 nb_oldpids++;
8820 }
8821 }
8822 }
willy tarreau2c513732006-04-15 19:25:16 +02008823#if STATTIME > 0
8824 else if (*flag == 's')
8825 arg_mode |= MODE_STATS;
8826 else if (*flag == 'l')
8827 arg_mode |= MODE_LOG;
8828#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008829 else { /* >=2 args */
8830 argv++; argc--;
8831 if (argc == 0)
8832 usage(old_argv);
8833
8834 switch (*flag) {
8835 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008836 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008837 case 'N' : cfg_maxpconn = atol(*argv); break;
8838 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008839 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008840 default: usage(old_argv);
8841 }
8842 }
8843 }
8844 else
8845 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008846 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008847 }
8848
willy tarreaud0fb4652005-12-18 01:32:04 +01008849 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008850 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8851 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008852
willy tarreau0f7af912005-12-17 12:21:26 +01008853 if (!cfg_cfgfile)
8854 usage(old_argv);
8855
8856 gethostname(hostname, MAX_HOSTNAME_LEN);
8857
willy tarreau12350152005-12-18 01:03:27 +01008858 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008859 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008860 if (readcfgfile(cfg_cfgfile) < 0) {
8861 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8862 exit(1);
8863 }
willy tarreau12350152005-12-18 01:03:27 +01008864 if (have_appsession)
8865 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008866
willy tarreau982249e2005-12-18 00:57:06 +01008867 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008868 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8869 exit(0);
8870 }
8871
willy tarreau9fe663a2005-12-17 13:02:59 +01008872 if (cfg_maxconn > 0)
8873 global.maxconn = cfg_maxconn;
8874
willy tarreaufe2c5c12005-12-17 14:14:34 +01008875 if (cfg_pidfile) {
8876 if (global.pidfile)
8877 free(global.pidfile);
8878 global.pidfile = strdup(cfg_pidfile);
8879 }
8880
willy tarreau9fe663a2005-12-17 13:02:59 +01008881 if (global.maxconn == 0)
8882 global.maxconn = DEFAULT_MAXCONN;
8883
Willy TARREAU203b0b62006-03-12 18:00:28 +01008884 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008885
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008886 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008887 /* command line debug mode inhibits configuration mode */
8888 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8889 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008890 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8891 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008892
8893 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8894 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8895 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8896 }
8897
8898 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008899 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8900 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008901 global.nbproc = 1;
8902 }
8903
8904 if (global.nbproc < 1)
8905 global.nbproc = 1;
8906
willy tarreau0f7af912005-12-17 12:21:26 +01008907 StaticReadEvent = (fd_set *)calloc(1,
8908 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008909 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008910 StaticWriteEvent = (fd_set *)calloc(1,
8911 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008912 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008913
8914 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008915 sizeof(struct fdtab) * (global.maxsock));
8916 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008917 fdtab[i].state = FD_STCLOSE;
8918 }
8919}
8920
8921/*
willy tarreau41310e72006-03-25 18:17:56 +01008922 * this function starts all the proxies. Its return value is composed from
8923 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8924 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008925 */
willy tarreau41310e72006-03-25 18:17:56 +01008926int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008927 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008928 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008929 int err = ERR_NONE;
8930 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008931
8932 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008933 if (curproxy->state != PR_STNEW)
8934 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008935
willy tarreau41310e72006-03-25 18:17:56 +01008936 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008937 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008938 if (listener->fd != -1)
8939 continue; /* already initialized */
8940
8941 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8942 if (verbose)
8943 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8944 curproxy->id);
8945 err |= ERR_RETRYABLE;
8946 pxerr |= 1;
8947 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008948 }
willy tarreau0f7af912005-12-17 12:21:26 +01008949
willy tarreaua41a8b42005-12-17 14:02:24 +01008950 if (fd >= global.maxsock) {
8951 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8952 curproxy->id);
8953 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008954 err |= ERR_FATAL;
8955 pxerr |= 1;
8956 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008957 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008958
willy tarreaua41a8b42005-12-17 14:02:24 +01008959 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8960 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8961 (char *) &one, sizeof(one)) == -1)) {
8962 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8963 curproxy->id);
8964 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008965 err |= ERR_FATAL;
8966 pxerr |= 1;
8967 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008968 }
willy tarreau0f7af912005-12-17 12:21:26 +01008969
willy tarreaua41a8b42005-12-17 14:02:24 +01008970 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8971 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8972 curproxy->id);
8973 }
willy tarreau0f7af912005-12-17 12:21:26 +01008974
willy tarreaua41a8b42005-12-17 14:02:24 +01008975 if (bind(fd,
8976 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008977 listener->addr.ss_family == AF_INET6 ?
8978 sizeof(struct sockaddr_in6) :
8979 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008980 if (verbose)
8981 Alert("cannot bind socket for proxy %s. Aborting.\n",
8982 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008983 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008984 err |= ERR_RETRYABLE;
8985 pxerr |= 1;
8986 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008987 }
willy tarreau0f7af912005-12-17 12:21:26 +01008988
willy tarreaua41a8b42005-12-17 14:02:24 +01008989 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008990 if (verbose)
8991 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8992 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008993 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008994 err |= ERR_RETRYABLE;
8995 pxerr |= 1;
8996 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008997 }
willy tarreau0f7af912005-12-17 12:21:26 +01008998
willy tarreau41310e72006-03-25 18:17:56 +01008999 /* the socket is ready */
9000 listener->fd = fd;
9001
willy tarreaua41a8b42005-12-17 14:02:24 +01009002 /* the function for the accept() event */
9003 fdtab[fd].read = &event_accept;
9004 fdtab[fd].write = NULL; /* never called */
9005 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01009006 fdtab[fd].state = FD_STLISTEN;
9007 FD_SET(fd, StaticReadEvent);
9008 fd_insert(fd);
9009 listeners++;
9010 }
willy tarreau41310e72006-03-25 18:17:56 +01009011
9012 if (!pxerr) {
9013 curproxy->state = PR_STRUN;
9014 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
9015 }
willy tarreau0f7af912005-12-17 12:21:26 +01009016 }
willy tarreau41310e72006-03-25 18:17:56 +01009017
9018 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01009019}
9020
willy tarreaub952e1d2005-12-18 01:31:20 +01009021int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01009022
9023 appsess *temp1,*temp2;
9024 temp1 = (appsess *)key1;
9025 temp2 = (appsess *)key2;
9026
9027 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
9028 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
9029
9030 return (strcmp(temp1->sessid,temp2->sessid) == 0);
9031}/* end match_str */
9032
willy tarreaub952e1d2005-12-18 01:31:20 +01009033void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01009034 appsess *temp1;
9035
9036 //printf("destroy called\n");
9037 temp1 = (appsess *)data;
9038
9039 if (temp1->sessid)
9040 pool_free_to(apools.sessid, temp1->sessid);
9041
9042 if (temp1->serverid)
9043 pool_free_to(apools.serverid, temp1->serverid);
9044
9045 pool_free(appsess, temp1);
9046} /* end destroy */
9047
9048void appsession_cleanup( void )
9049{
9050 struct proxy *p = proxy;
9051
9052 while(p) {
9053 chtbl_destroy(&(p->htbl_proxy));
9054 p = p->next;
9055 }
9056}/* end appsession_cleanup() */
9057
9058void pool_destroy(void **pool)
9059{
9060 void *temp, *next;
9061 next = pool;
9062 while (next) {
9063 temp = next;
9064 next = *(void **)temp;
9065 free(temp);
9066 }
9067}/* end pool_destroy() */
9068
willy tarreaub952e1d2005-12-18 01:31:20 +01009069void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01009070 struct proxy *p = proxy;
9071 struct cap_hdr *h,*h_next;
9072 struct server *s,*s_next;
9073 struct listener *l,*l_next;
9074
9075 while (p) {
9076 if (p->id)
9077 free(p->id);
9078
9079 if (p->check_req)
9080 free(p->check_req);
9081
9082 if (p->cookie_name)
9083 free(p->cookie_name);
9084
9085 if (p->capture_name)
9086 free(p->capture_name);
9087
9088 /* only strup if the user have set in config.
9089 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01009090 if (p->errmsg.msg400) free(p->errmsg.msg400);
9091 if (p->errmsg.msg403) free(p->errmsg.msg403);
9092 if (p->errmsg.msg408) free(p->errmsg.msg408);
9093 if (p->errmsg.msg500) free(p->errmsg.msg500);
9094 if (p->errmsg.msg502) free(p->errmsg.msg502);
9095 if (p->errmsg.msg503) free(p->errmsg.msg503);
9096 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01009097 */
9098 if (p->appsession_name)
9099 free(p->appsession_name);
9100
9101 h = p->req_cap;
9102 while (h) {
9103 h_next = h->next;
9104 if (h->name)
9105 free(h->name);
9106 pool_destroy(h->pool);
9107 free(h);
9108 h = h_next;
9109 }/* end while(h) */
9110
9111 h = p->rsp_cap;
9112 while (h) {
9113 h_next = h->next;
9114 if (h->name)
9115 free(h->name);
9116
9117 pool_destroy(h->pool);
9118 free(h);
9119 h = h_next;
9120 }/* end while(h) */
9121
9122 s = p->srv;
9123 while (s) {
9124 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009125 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009126 free(s->id);
9127
willy tarreaub952e1d2005-12-18 01:31:20 +01009128 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009129 free(s->cookie);
9130
9131 free(s);
9132 s = s_next;
9133 }/* end while(s) */
9134
9135 l = p->listen;
9136 while (l) {
9137 l_next = l->next;
9138 free(l);
9139 l = l_next;
9140 }/* end while(l) */
9141
9142 pool_destroy((void **) p->req_cap_pool);
9143 pool_destroy((void **) p->rsp_cap_pool);
9144 p = p->next;
9145 }/* end while(p) */
9146
9147 if (global.chroot) free(global.chroot);
9148 if (global.pidfile) free(global.pidfile);
9149
willy tarreau12350152005-12-18 01:03:27 +01009150 if (StaticReadEvent) free(StaticReadEvent);
9151 if (StaticWriteEvent) free(StaticWriteEvent);
9152 if (fdtab) free(fdtab);
9153
9154 pool_destroy(pool_session);
9155 pool_destroy(pool_buffer);
9156 pool_destroy(pool_fdtab);
9157 pool_destroy(pool_requri);
9158 pool_destroy(pool_task);
9159 pool_destroy(pool_capture);
9160 pool_destroy(pool_appsess);
9161
9162 if (have_appsession) {
9163 pool_destroy(apools.serverid);
9164 pool_destroy(apools.sessid);
9165 }
9166} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009167
willy tarreau41310e72006-03-25 18:17:56 +01009168/* sends the signal <sig> to all pids found in <oldpids> */
9169static void tell_old_pids(int sig) {
9170 int p;
9171 for (p = 0; p < nb_oldpids; p++)
9172 kill(oldpids[p], sig);
9173}
9174
willy tarreau0f7af912005-12-17 12:21:26 +01009175int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009176 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009177 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009178 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009179 init(argc, argv);
9180
willy tarreau0f7af912005-12-17 12:21:26 +01009181 signal(SIGQUIT, dump);
9182 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009183 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009184#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009185 signal(SIGINT, sig_int);
9186 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009187#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009188
9189 /* on very high loads, a sigpipe sometimes happen just between the
9190 * getsockopt() which tells "it's OK to write", and the following write :-(
9191 */
willy tarreau3242e862005-12-17 12:27:53 +01009192#ifndef MSG_NOSIGNAL
9193 signal(SIGPIPE, SIG_IGN);
9194#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009195
willy tarreau41310e72006-03-25 18:17:56 +01009196 /* We will loop at most 100 times with 10 ms delay each time.
9197 * That's at most 1 second. We only send a signal to old pids
9198 * if we cannot grab at least one port.
9199 */
9200 retry = MAX_START_RETRIES;
9201 err = ERR_NONE;
9202 while (retry >= 0) {
9203 struct timeval w;
9204 err = start_proxies(retry == 0 || nb_oldpids == 0);
9205 if (err != ERR_RETRYABLE)
9206 break;
9207 if (nb_oldpids == 0)
9208 break;
9209
9210 tell_old_pids(SIGTTOU);
9211 /* give some time to old processes to stop listening */
9212 w.tv_sec = 0;
9213 w.tv_usec = 10*1000;
9214 select(0, NULL, NULL, NULL, &w);
9215 retry--;
9216 }
9217
9218 /* Note: start_proxies() sends an alert when it fails. */
9219 if (err != ERR_NONE) {
9220 if (retry != MAX_START_RETRIES && nb_oldpids)
9221 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009222 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009223 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009224
9225 if (listeners == 0) {
9226 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009227 /* Note: we don't have to send anything to the old pids because we
9228 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009229 exit(1);
9230 }
9231
willy tarreaudbd3bef2006-01-20 19:35:18 +01009232 /* prepare pause/play signals */
9233 signal(SIGTTOU, sig_pause);
9234 signal(SIGTTIN, sig_listen);
9235
Willy TARREAUe3283d12006-03-01 22:15:29 +01009236 if (global.mode & MODE_DAEMON) {
9237 global.mode &= ~MODE_VERBOSE;
9238 global.mode |= MODE_QUIET;
9239 }
9240
willy tarreaud0fb4652005-12-18 01:32:04 +01009241 /* MODE_QUIET can inhibit alerts and warnings below this line */
9242
9243 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009244 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009245 /* detach from the tty */
9246 fclose(stdin); fclose(stdout); fclose(stderr);
9247 close(0); close(1); close(2);
9248 }
willy tarreau0f7af912005-12-17 12:21:26 +01009249
willy tarreaufe2c5c12005-12-17 14:14:34 +01009250 /* open log & pid files before the chroot */
9251 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9252 int pidfd;
9253 unlink(global.pidfile);
9254 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9255 if (pidfd < 0) {
9256 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009257 if (nb_oldpids)
9258 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009259 exit(1);
9260 }
9261 pidfile = fdopen(pidfd, "w");
9262 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009263
9264 /* chroot if needed */
9265 if (global.chroot != NULL) {
9266 if (chroot(global.chroot) == -1) {
9267 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009268 if (nb_oldpids)
9269 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009270 }
9271 chdir("/");
9272 }
9273
willy tarreaub1285d52005-12-18 01:20:14 +01009274 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009275 if (!global.rlimit_nofile)
9276 global.rlimit_nofile = global.maxsock;
9277
willy tarreaub1285d52005-12-18 01:20:14 +01009278 if (global.rlimit_nofile) {
9279 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9280 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9281 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9282 }
willy tarreau746e26b2006-03-25 11:14:35 +01009283 }
9284
9285 if (global.rlimit_memmax) {
9286 limit.rlim_cur = limit.rlim_max =
9287 global.rlimit_memmax * 1048576 / global.nbproc;
9288#ifdef RLIMIT_AS
9289 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9290 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9291 argv[0], global.rlimit_memmax);
9292 }
9293#else
9294 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9295 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9296 argv[0], global.rlimit_memmax);
9297 }
9298#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009299 }
9300
willy tarreau41310e72006-03-25 18:17:56 +01009301 if (nb_oldpids)
9302 tell_old_pids(oldpids_sig);
9303
9304 /* Note that any error at this stage will be fatal because we will not
9305 * be able to restart the old pids.
9306 */
9307
willy tarreau9fe663a2005-12-17 13:02:59 +01009308 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009309 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009310 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9311 exit(1);
9312 }
9313
willy tarreau036e1ce2005-12-17 13:46:33 +01009314 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009315 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9316 exit(1);
9317 }
9318
willy tarreaub1285d52005-12-18 01:20:14 +01009319 /* check ulimits */
9320 limit.rlim_cur = limit.rlim_max = 0;
9321 getrlimit(RLIMIT_NOFILE, &limit);
9322 if (limit.rlim_cur < global.maxsock) {
9323 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",
9324 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9325 }
9326
willy tarreau9fe663a2005-12-17 13:02:59 +01009327 if (global.mode & MODE_DAEMON) {
9328 int ret = 0;
9329 int proc;
9330
9331 /* the father launches the required number of processes */
9332 for (proc = 0; proc < global.nbproc; proc++) {
9333 ret = fork();
9334 if (ret < 0) {
9335 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009336 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009337 exit(1); /* there has been an error */
9338 }
9339 else if (ret == 0) /* child breaks here */
9340 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009341 if (pidfile != NULL) {
9342 fprintf(pidfile, "%d\n", ret);
9343 fflush(pidfile);
9344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009345 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009346 /* close the pidfile both in children and father */
9347 if (pidfile != NULL)
9348 fclose(pidfile);
9349 free(global.pidfile);
9350
willy tarreau9fe663a2005-12-17 13:02:59 +01009351 if (proc == global.nbproc)
9352 exit(0); /* parent must leave */
9353
willy tarreau750a4722005-12-17 13:21:24 +01009354 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9355 * that we can detach from the TTY. We MUST NOT do it in other cases since
9356 * it would have already be done, and 0-2 would have been affected to listening
9357 * sockets
9358 */
9359 if (!(global.mode & MODE_QUIET)) {
9360 /* detach from the tty */
9361 fclose(stdin); fclose(stdout); fclose(stderr);
9362 close(0); close(1); close(2); /* close all fd's */
9363 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9364 }
willy tarreaua1598082005-12-17 13:08:06 +01009365 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009366 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009367 }
9368
willy tarreau1c2ad212005-12-18 01:11:29 +01009369#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009370 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009371 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9372 epoll_loop(POLL_LOOP_ACTION_RUN);
9373 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009374 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009375 }
9376 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009377 Warning("epoll() is not available. Using poll()/select() instead.\n");
9378 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009379 }
9380 }
9381#endif
9382
9383#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009384 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009385 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9386 poll_loop(POLL_LOOP_ACTION_RUN);
9387 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009388 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009389 }
9390 else {
9391 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009392 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009393 }
9394 }
9395#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009396 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009397 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9398 select_loop(POLL_LOOP_ACTION_RUN);
9399 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009400 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009401 }
9402 }
9403
willy tarreau0f7af912005-12-17 12:21:26 +01009404
willy tarreau12350152005-12-18 01:03:27 +01009405 /* Free all Hash Keys and all Hash elements */
9406 appsession_cleanup();
9407 /* Do some cleanup */
9408 deinit();
9409
willy tarreau0f7af912005-12-17 12:21:26 +01009410 exit(0);
9411}
willy tarreau12350152005-12-18 01:03:27 +01009412
9413#if defined(DEBUG_HASH)
9414static void print_table(const CHTbl *htbl) {
9415
9416 ListElmt *element;
9417 int i;
9418 appsess *asession;
9419
9420 /*****************************************************************************
9421 * *
9422 * Display the chained hash table. *
9423 * *
9424 *****************************************************************************/
9425
9426 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9427
9428 for (i = 0; i < TBLSIZ; i++) {
9429 fprintf(stdout, "Bucket[%03d]\n", i);
9430
9431 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9432 //fprintf(stdout, "%c", *(char *)list_data(element));
9433 asession = (appsess *)list_data(element);
9434 fprintf(stdout, "ELEM :%s:", asession->sessid);
9435 fprintf(stdout, " Server :%s: \n", asession->serverid);
9436 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9437 }
9438
9439 fprintf(stdout, "\n");
9440 }
9441 return;
9442} /* end print_table */
9443#endif
9444
9445static int appsession_init(void)
9446{
9447 static int initialized = 0;
9448 int idlen;
9449 struct server *s;
9450 struct proxy *p = proxy;
9451
9452 if (!initialized) {
9453 if (!appsession_task_init()) {
9454 apools.sessid = NULL;
9455 apools.serverid = NULL;
9456 apools.ser_waste = 0;
9457 apools.ser_use = 0;
9458 apools.ser_msize = sizeof(void *);
9459 apools.ses_waste = 0;
9460 apools.ses_use = 0;
9461 apools.ses_msize = sizeof(void *);
9462 while (p) {
9463 s = p->srv;
9464 if (apools.ses_msize < p->appsession_len)
9465 apools.ses_msize = p->appsession_len;
9466 while (s) {
9467 idlen = strlen(s->id);
9468 if (apools.ser_msize < idlen)
9469 apools.ser_msize = idlen;
9470 s = s->next;
9471 }
9472 p = p->next;
9473 }
9474 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9475 apools.ses_msize ++;
9476 }
9477 else {
9478 fprintf(stderr, "appsession_task_init failed\n");
9479 return -1;
9480 }
9481 initialized ++;
9482 }
9483 return 0;
9484}
9485
9486static int appsession_task_init(void)
9487{
9488 static int initialized = 0;
9489 struct task *t;
9490 if (!initialized) {
9491 if ((t = pool_alloc(task)) == NULL)
9492 return -1;
9493 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009494 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009495 t->state = TASK_IDLE;
9496 t->context = NULL;
9497 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9498 task_queue(t);
9499 t->process = appsession_refresh;
9500 initialized ++;
9501 }
9502 return 0;
9503}
9504
9505static int appsession_refresh(struct task *t) {
9506 struct proxy *p = proxy;
9507 CHTbl *htbl;
9508 ListElmt *element, *last;
9509 int i;
9510 appsess *asession;
9511 void *data;
9512
9513 while (p) {
9514 if (p->appsession_name != NULL) {
9515 htbl = &p->htbl_proxy;
9516 /* if we ever give up the use of TBLSIZ, we need to change this */
9517 for (i = 0; i < TBLSIZ; i++) {
9518 last = NULL;
9519 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9520 asession = (appsess *)list_data(element);
9521 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9522 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9523 int len;
9524 /*
9525 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9526 */
9527 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9528 asession->sessid, asession->serverid?asession->serverid:"(null)");
9529 write(1, trash, len);
9530 }
9531 /* delete the expired element from within the hash table */
9532 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9533 && (htbl->table[i].destroy != NULL)) {
9534 htbl->table[i].destroy(data);
9535 }
9536 if (last == NULL) {/* patient lost his head, get a new one */
9537 element = list_head(&htbl->table[i]);
9538 if (element == NULL) break; /* no heads left, go to next patient */
9539 }
9540 else
9541 element = last;
9542 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9543 else
9544 last = element;
9545 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9546 }
9547 }
9548 p = p->next;
9549 }
9550 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9551 return TBLCHKINT;
9552} /* end appsession_refresh */
9553
willy tarreau18a957c2006-04-12 19:26:23 +02009554
9555/*
9556 * Local variables:
9557 * c-indent-level: 4
9558 * c-basic-offset: 4
9559 * End:
9560 */