blob: 5a3f1cb237bc292ad0f18e7bce747e518ed57b7d [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau779dc892006-03-19 19:32:29 +010084#ifdef DEBUG_FULL
85#include <assert.h>
86#endif
87
willy tarreau598da412005-12-18 01:07:29 +010088#include "include/appsession.h"
willy tarreau18a957c2006-04-12 19:26:23 +020089#include "include/mini-clist.h"
willy tarreau12350152005-12-18 01:03:27 +010090
willy tarreaubfad5742006-03-23 14:19:11 +010091#ifndef HAPROXY_VERSION
willy tarreauc0d4bbd2006-04-15 21:47:50 +020092#define HAPROXY_VERSION "1.2.12"
willy tarreaubfad5742006-03-23 14:19:11 +010093#endif
94
95#ifndef HAPROXY_DATE
willy tarreauc0d4bbd2006-04-15 21:47:50 +020096#define HAPROXY_DATE "2006/04/15"
willy tarreaubfad5742006-03-23 14:19:11 +010097#endif
willy tarreau0f7af912005-12-17 12:21:26 +010098
99/* this is for libc5 for example */
100#ifndef TCP_NODELAY
101#define TCP_NODELAY 1
102#endif
103
104#ifndef SHUT_RD
105#define SHUT_RD 0
106#endif
107
108#ifndef SHUT_WR
109#define SHUT_WR 1
110#endif
111
willy tarreau0174f312005-12-18 01:02:42 +0100112/*
113 * BUFSIZE defines the size of a read and write buffer. It is the maximum
114 * amount of bytes which can be stored by the proxy for each session. However,
115 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
116 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
117 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
118 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
119 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
120 */
121#ifndef BUFSIZE
122#define BUFSIZE 16384
123#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100124
125// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100126#ifndef MAXREWRITE
127#define MAXREWRITE (BUFSIZE / 2)
128#endif
129
willy tarreau9fe663a2005-12-17 13:02:59 +0100130#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100131#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100132
willy tarreau5cbea6f2005-12-17 12:48:26 +0100133// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100134#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135
willy tarreaue39cd132005-12-17 13:00:18 +0100136// max # of added headers per request
137#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100138
139// max # of matches per regexp
140#define MAX_MATCH 10
141
willy tarreau0174f312005-12-18 01:02:42 +0100142// cookie delimitor in "prefix" mode. This character is inserted between the
143// persistence cookie and the original value. The '~' is allowed by RFC2965,
144// and should not be too common in server names.
145#ifndef COOKIE_DELIM
146#define COOKIE_DELIM '~'
147#endif
148
willy tarreau0f7af912005-12-17 12:21:26 +0100149#define CONN_RETRIES 3
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100152#define DEF_CHKINTR 2000
153#define DEF_FALLTIME 3
154#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100155#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100156
Willy TARREAU13032e72006-03-12 17:31:45 +0100157/* Default connections limit.
158 *
159 * A system limit can be enforced at build time in order to avoid using haproxy
160 * beyond reasonable system limits. For this, just define SYSTEM_MAXCONN to the
161 * absolute limit accepted by the system. If the configuration specifies a
162 * higher value, it will be capped to SYSTEM_MAXCONN and a warning will be
163 * emitted. The only way to override this limit will be to set it via the
164 * command-line '-n' argument.
165 */
166#ifndef SYSTEM_MAXCONN
willy tarreau9fe663a2005-12-17 13:02:59 +0100167#define DEFAULT_MAXCONN 2000
Willy TARREAU13032e72006-03-12 17:31:45 +0100168#else
169#define DEFAULT_MAXCONN SYSTEM_MAXCONN
170#endif
willy tarreau9fe663a2005-12-17 13:02:59 +0100171
willy tarreau0f7af912005-12-17 12:21:26 +0100172/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
173#define INTBITS 5
174
175/* show stats this every millisecond, 0 to disable */
176#ifndef STATTIME
177#define STATTIME 2000
178#endif
179
willy tarreau5cbea6f2005-12-17 12:48:26 +0100180/* this reduces the number of calls to select() by choosing appropriate
181 * sheduler precision in milliseconds. It should be near the minimum
182 * time that is needed by select() to collect all events. All timeouts
183 * are rounded up by adding this value prior to pass it to select().
184 */
185#define SCHEDULER_RESOLUTION 9
186
willy tarreaub952e1d2005-12-18 01:31:20 +0100187#define TIME_ETERNITY -1
188/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100189#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
190#define SETNOW(a) (*a=now)
191
willy tarreau9da061b2005-12-17 12:29:56 +0100192/****** string-specific macros and functions ******/
193/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
194#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
195
196/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
197#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
198
willy tarreau0174f312005-12-18 01:02:42 +0100199/* returns 1 only if only zero or one bit is set in X, which means that X is a
200 * power of 2, and 0 otherwise */
201#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100202/*
203 * copies at most <size-1> chars from <src> to <dst>. Last char is always
204 * set to 0, unless <size> is 0. The number of chars copied is returned
205 * (excluding the terminating zero).
206 * This code has been optimized for size and speed : on x86, it's 45 bytes
207 * long, uses only registers, and consumes only 4 cycles per char.
208 */
willy tarreau750a4722005-12-17 13:21:24 +0100209int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100210 char *orig = dst;
211 if (size) {
212 while (--size && (*dst = *src)) {
213 src++; dst++;
214 }
215 *dst = 0;
216 }
217 return dst - orig;
218}
willy tarreau9da061b2005-12-17 12:29:56 +0100219
willy tarreau4302f492005-12-18 01:00:37 +0100220/*
221 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
222 * dynamically allocated. In the first case, <__pool> is updated to point to
223 * the next element in the list.
224 */
225#define pool_alloc_from(__pool, __len) ({ \
226 void *__p; \
227 if ((__p = (__pool)) == NULL) \
228 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
229 else { \
230 __pool = *(void **)(__pool); \
231 } \
232 __p; \
233})
234
235/*
236 * Puts a memory area back to the corresponding pool.
237 * Items are chained directly through a pointer that
238 * is written in the beginning of the memory area, so
239 * there's no need for any carrier cell. This implies
240 * that each memory area is at least as big as one
241 * pointer.
242 */
243#define pool_free_to(__pool, __ptr) ({ \
244 *(void **)(__ptr) = (void *)(__pool); \
245 __pool = (void *)(__ptr); \
246})
247
248
willy tarreau0f7af912005-12-17 12:21:26 +0100249#define MEM_OPTIM
250#ifdef MEM_OPTIM
251/*
252 * Returns a pointer to type <type> taken from the
253 * pool <pool_type> or dynamically allocated. In the
254 * first case, <pool_type> is updated to point to the
255 * next element in the list.
256 */
257#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100258 void *__p; \
259 if ((__p = pool_##type) == NULL) \
260 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100261 else { \
262 pool_##type = *(void **)pool_##type; \
263 } \
willy tarreau4302f492005-12-18 01:00:37 +0100264 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100265})
266
267/*
268 * Puts a memory area back to the corresponding pool.
269 * Items are chained directly through a pointer that
270 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100271 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100272 * that each memory area is at least as big as one
273 * pointer.
274 */
275#define pool_free(type, ptr) ({ \
276 *(void **)ptr = (void *)pool_##type; \
277 pool_##type = (void *)ptr; \
278})
279
280#else
281#define pool_alloc(type) (calloc(1,sizeof_##type));
282#define pool_free(type, ptr) (free(ptr));
283#endif /* MEM_OPTIM */
284
willy tarreau5cbea6f2005-12-17 12:48:26 +0100285#define sizeof_task sizeof(struct task)
286#define sizeof_session sizeof(struct session)
willy tarreau18a957c2006-04-12 19:26:23 +0200287#define sizeof_pendconn sizeof(struct pendconn)
willy tarreau0f7af912005-12-17 12:21:26 +0100288#define sizeof_buffer sizeof(struct buffer)
289#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100290#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100291#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100292#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100293#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100296#define FD_STCLOSE 0
297#define FD_STLISTEN 1
298#define FD_STCONN 2
299#define FD_STREADY 3
300#define FD_STERROR 4
301
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100303#define TASK_IDLE 0
304#define TASK_RUNNING 1
305
willy tarreau5cbea6f2005-12-17 12:48:26 +0100306/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100307#define PR_STNEW 0
308#define PR_STIDLE 1
309#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100310#define PR_STSTOPPED 3
311#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100312
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100314#define PR_MODE_TCP 0
315#define PR_MODE_HTTP 1
316#define PR_MODE_HEALTH 2
317
willy tarreau1c2ad212005-12-18 01:11:29 +0100318/* possible actions for the *poll() loops */
319#define POLL_LOOP_ACTION_INIT 0
320#define POLL_LOOP_ACTION_RUN 1
321#define POLL_LOOP_ACTION_CLEAN 2
322
willy tarreau64a3cc32005-12-18 01:13:11 +0100323/* poll mechanisms available */
324#define POLL_USE_SELECT (1<<0)
325#define POLL_USE_POLL (1<<1)
326#define POLL_USE_EPOLL (1<<2)
327
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100329#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
330#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
331#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
332#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
333#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
334#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
335#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
336#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau0174f312005-12-18 01:02:42 +0100337#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
338#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
339#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
340#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
341#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
342#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
343#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
344#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
345#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
346#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
347#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100348#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
349#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100350#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100351#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau1a3442d2006-03-24 21:03:20 +0100352#define PR_O_BALANCE_SH 0x00400000 /* balance on source IP hash */
353#define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
willy tarreaua5e8c662006-04-29 10:43:46 +0200355/* various session flags, bits values 0x01 to 0x20 (shift 0) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100356#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
357#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
358#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
359#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
360#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
361#define SN_POST 0x00000020 /* the request was an HTTP POST */
362
willy tarreaua5e8c662006-04-29 10:43:46 +0200363/* session flags dedicated to cookies : bits values 0x40, 0x80 (0-3 shift 6) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100364#define SN_CK_NONE 0x00000000 /* this session had no cookie */
365#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
366#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
367#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
368#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
369#define SN_CK_SHIFT 6 /* bit shift */
370
willy tarreaua5e8c662006-04-29 10:43:46 +0200371/* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */
willy tarreaub1285d52005-12-18 01:20:14 +0100372#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100373#define SN_ERR_CLITO 0x00000100 /* client time-out */
374#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
375#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
376#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
377#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100378#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
379#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100380#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
381#define SN_ERR_SHIFT 8 /* bit shift */
382
willy tarreaua5e8c662006-04-29 10:43:46 +0200383/* session state at termination, bits values 0x1000 to 0x7000 (0-7 shift 12) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100384#define SN_FINST_R 0x00001000 /* session ended during client request */
385#define SN_FINST_C 0x00002000 /* session ended during server connect */
386#define SN_FINST_H 0x00003000 /* session ended during server headers */
387#define SN_FINST_D 0x00004000 /* session ended during data phase */
388#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
389#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
390#define SN_FINST_SHIFT 12 /* bit shift */
391
willy tarreaua5e8c662006-04-29 10:43:46 +0200392/* cookie information, bits values 0x10000 to 0x80000 (0-8 shift 16) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100393#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
394#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
395#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
396#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
397#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100398#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100399#define SN_SCK_SHIFT 16 /* bit shift */
400
willy tarreaua5e8c662006-04-29 10:43:46 +0200401/* cacheability management, bits values 0x100000 to 0x300000 (0-3 shift 20) */
willy tarreau97f58572005-12-18 00:53:44 +0100402#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
403#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
404#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100405
willy tarreaua5e8c662006-04-29 10:43:46 +0200406/* various other session flags, bits values 0x400000 and above */
407#define SN_MONITOR 0x00400000 /* this session comes from a monitoring system */
willy tarreaudfece232006-05-02 00:19:57 +0200408#define SN_ASSIGNED 0x00800000 /* no need to assign a server to this session */
409#define SN_ADDR_SET 0x01000000 /* this session's server address has been set */
willy tarreaua5e8c662006-04-29 10:43:46 +0200410
411
willy tarreau5cbea6f2005-12-17 12:48:26 +0100412/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100413#define CL_STHEADERS 0
414#define CL_STDATA 1
415#define CL_STSHUTR 2
416#define CL_STSHUTW 3
417#define CL_STCLOSE 4
418
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100420#define SV_STIDLE 0
willy tarreau18a957c2006-04-12 19:26:23 +0200421#define SV_STCPEND 1
422#define SV_STCONN 2
423#define SV_STHEADERS 3
424#define SV_STDATA 4
425#define SV_STSHUTR 5
426#define SV_STSHUTW 6
427#define SV_STCLOSE 7
willy tarreau0f7af912005-12-17 12:21:26 +0100428
429/* result of an I/O event */
430#define RES_SILENT 0 /* didn't happen */
431#define RES_DATA 1 /* data were sent or received */
432#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
433#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
434
willy tarreau9fe663a2005-12-17 13:02:59 +0100435/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100436#define MODE_DEBUG 1
437#define MODE_STATS 2
438#define MODE_LOG 4
439#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100440#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100441#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100442#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100443#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100444#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100445
446/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100447#define SRV_RUNNING 1 /* the server is UP */
448#define SRV_BACKUP 2 /* this server is a backup server */
449#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100450#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100451#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100452
willy tarreaudfece232006-05-02 00:19:57 +0200453/* function which act on servers need to return various errors */
454#define SRV_STATUS_OK 0 /* everything is OK. */
455#define SRV_STATUS_INTERNAL 1 /* other unrecoverable errors. */
456#define SRV_STATUS_NOSRV 2 /* no server is available */
457#define SRV_STATUS_FULL 3 /* the/all server(s) are saturated */
458#define SRV_STATUS_QUEUED 4 /* the/all server(s) are saturated but the connection was queued */
459
willy tarreaue39cd132005-12-17 13:00:18 +0100460/* what to do when a header matches a regex */
461#define ACT_ALLOW 0 /* allow the request */
462#define ACT_REPLACE 1 /* replace the matching header */
463#define ACT_REMOVE 2 /* remove the matching header */
464#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100465#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100466
willy tarreau9fe663a2005-12-17 13:02:59 +0100467/* configuration sections */
468#define CFG_NONE 0
469#define CFG_GLOBAL 1
470#define CFG_LISTEN 2
471
willy tarreaua1598082005-12-17 13:08:06 +0100472/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100473#define LW_DATE 1 /* date */
474#define LW_CLIP 2 /* CLient IP */
475#define LW_SVIP 4 /* SerVer IP */
476#define LW_SVID 8 /* server ID */
477#define LW_REQ 16 /* http REQuest */
478#define LW_RESP 32 /* http RESPonse */
479#define LW_PXIP 64 /* proxy IP */
480#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100481#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100482#define LW_COOKIE 512 /* captured cookie */
483#define LW_REQHDR 1024 /* request header(s) */
484#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100485
willy tarreau41310e72006-03-25 18:17:56 +0100486#define ERR_NONE 0 /* no error */
487#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
488#define ERR_FATAL 2 /* fatal error, may be cumulated */
489
willy tarreau0f7af912005-12-17 12:21:26 +0100490/*********************************************************************/
491
492#define LIST_HEAD(a) ((void *)(&(a)))
493
494/*********************************************************************/
495
willy tarreau4302f492005-12-18 01:00:37 +0100496struct cap_hdr {
497 struct cap_hdr *next;
498 char *name; /* header name, case insensitive */
499 int namelen; /* length of the header name, to speed-up lookups */
500 int len; /* capture length, not including terminal zero */
501 int index; /* index in the output array */
502 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
503};
504
willy tarreau0f7af912005-12-17 12:21:26 +0100505struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100506 struct hdr_exp *next;
507 regex_t *preg; /* expression to look for */
508 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
509 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100510};
511
512struct buffer {
513 unsigned int l; /* data length */
514 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100515 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100516 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 char data[BUFSIZE];
518};
519
willy tarreau18a957c2006-04-12 19:26:23 +0200520struct pendconn {
521 struct list list; /* chaining ... */
522 struct session *sess; /* the session waiting for a connection */
523 struct server *srv; /* the server we are waiting for */
524};
525
willy tarreau0f7af912005-12-17 12:21:26 +0100526struct server {
527 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100528 int state; /* server state (SRV_*) */
529 int cklen; /* the len of the cookie, to speed up checks */
530 char *cookie; /* the id set in the cookie */
531 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200532 struct list pendconns; /* pending connections */
533 int nbpend; /* number of pending connections */
willy tarreau0f7af912005-12-17 12:21:26 +0100534 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100535 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100536 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100537 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100538 int rise, fall; /* time in iterations */
539 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100540 int result; /* 0 = connect OK, -1 = connect KO */
541 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200542 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200543 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200544 int cur_sess; /* number of currently active sessions (including syn_sent) */
545 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200546 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100547 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100548};
549
willy tarreau5cbea6f2005-12-17 12:48:26 +0100550/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100551struct task {
552 struct task *next, *prev; /* chaining ... */
553 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100554 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100555 int state; /* task state : IDLE or RUNNING */
556 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100557 int (*process)(struct task *t); /* the function which processes the task */
558 void *context; /* the task's context */
559};
560
561/* WARNING: if new fields are added, they must be initialized in event_accept() */
562struct session {
563 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 /* application specific below */
565 struct timeval crexpire; /* expiration date for a client read */
566 struct timeval cwexpire; /* expiration date for a client write */
567 struct timeval srexpire; /* expiration date for a server read */
568 struct timeval swexpire; /* expiration date for a server write */
569 struct timeval cnexpire; /* expiration date for a connect */
570 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
571 struct proxy *proxy; /* the proxy this socket belongs to */
572 int cli_fd; /* the client side fd */
573 int srv_fd; /* the server side fd */
574 int cli_state; /* state of the client side */
575 int srv_state; /* state of the server side */
576 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100577 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100578 struct buffer *req; /* request buffer */
579 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100580 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100581 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100582 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200583 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100584 char **req_cap; /* array of captured request headers (may be NULL) */
585 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100586 struct {
587 int logwait; /* log fields waiting to be collected : LW_* */
588 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
589 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
590 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
591 long t_data; /* delay before the first data byte from the server ... */
592 unsigned long t_close; /* total session duration */
593 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100594 char *cli_cookie; /* cookie presented by the client, in capture mode */
595 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100596 int status; /* HTTP status from the server, negative if from proxy */
597 long long bytes; /* number of bytes transferred from the server */
598 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100599 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100600};
601
willy tarreaua41a8b42005-12-17 14:02:24 +0100602struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100603 int fd; /* the listen socket */
604 struct sockaddr_storage addr; /* the address we listen to */
605 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100606};
607
608
willy tarreau0f7af912005-12-17 12:21:26 +0100609struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100610 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100611 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 +0100612 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100613 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200614 struct server *srv; /* known servers */
615 int srv_act, srv_bck; /* # of running servers */
616 int tot_wact, tot_wbck; /* total weights of active and backup servers */
617 struct server **srv_map; /* the server map used to apply weights */
618 int srv_map_sz; /* the size of the effective server map */
619 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100620 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100621 int cookie_len; /* strlen(cookie_name), computed only once */
622 char *appsession_name; /* name of the cookie to look for */
623 int appsession_name_len; /* strlen(appsession_name), computed only once */
624 int appsession_len; /* length of the appsession cookie value to be used */
625 int appsession_timeout;
626 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100627 char *capture_name; /* beginning of the name of the cookie to capture */
628 int capture_namelen; /* length of the cookie name to match */
629 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100630 int clitimeout; /* client I/O timeout (in milliseconds) */
631 int srvtimeout; /* server I/O timeout (in milliseconds) */
632 int contimeout; /* connect timeout (in milliseconds) */
633 char *id; /* proxy id */
willy tarreaudfece232006-05-02 00:19:57 +0200634 struct list pendconns; /* pending connections with no server assigned yet */
635 int nbpend; /* number of pending connections with no server assigned yet */
willy tarreau0f7af912005-12-17 12:21:26 +0100636 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200637 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100638 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100639 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100640 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100641 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100642 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100643 struct proxy *next;
644 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100645 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100646 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100647 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100648 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100649 int nb_reqadd, nb_rspadd;
650 struct hdr_exp *req_exp; /* regular expressions for request headers */
651 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100652 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
653 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
654 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
655 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100656 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100657 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100658 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
659 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100660 struct {
661 char *msg400; /* message for error 400 */
662 int len400; /* message length for error 400 */
663 char *msg403; /* message for error 403 */
664 int len403; /* message length for error 403 */
665 char *msg408; /* message for error 408 */
666 int len408; /* message length for error 408 */
667 char *msg500; /* message for error 500 */
668 int len500; /* message length for error 500 */
669 char *msg502; /* message for error 502 */
670 int len502; /* message length for error 502 */
671 char *msg503; /* message for error 503 */
672 int len503; /* message length for error 503 */
673 char *msg504; /* message for error 504 */
674 int len504; /* message length for error 504 */
675 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100676};
677
678/* info about one given fd */
679struct fdtab {
680 int (*read)(int fd); /* read function */
681 int (*write)(int fd); /* write function */
682 struct task *owner; /* the session (or proxy) associated with this fd */
683 int state; /* the state of this fd */
684};
685
686/*********************************************************************/
687
willy tarreaub952e1d2005-12-18 01:31:20 +0100688int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100689int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100690char *cfg_cfgfile = NULL; /* configuration file */
691char *progname = NULL; /* program name */
692int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100693
694/* global options */
695static struct {
696 int uid;
697 int gid;
698 int nbproc;
699 int maxconn;
700 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100701 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100702 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100703 int mode;
704 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100705 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100706 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100707 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100708 struct sockaddr_in logsrv1, logsrv2;
709} global = {
710 logfac1 : -1,
711 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100712 loglev1 : 7, /* max syslog level : debug */
713 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100714 /* others NULL OK */
715};
716
willy tarreau0f7af912005-12-17 12:21:26 +0100717/*********************************************************************/
718
willy tarreau1c2ad212005-12-18 01:11:29 +0100719fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100720 *StaticWriteEvent;
721
willy tarreau64a3cc32005-12-18 01:13:11 +0100722int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100723
willy tarreau0f7af912005-12-17 12:21:26 +0100724void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200725 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100726 **pool_buffer = NULL,
727 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100728 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100729 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100730 **pool_capture = NULL,
731 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100732
733struct proxy *proxy = NULL; /* list of all existing proxies */
734struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100735struct task *rq = NULL; /* global run queue */
willy tarreau5e698ef2006-05-02 14:51:00 +0200736struct task wait_queue[2] = { /* global wait queue */
737 {
738 prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */
739 next:LIST_HEAD(wait_queue[0]),
740 },
741 {
742 prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */
743 next:LIST_HEAD(wait_queue[1]),
744 },
willy tarreau5cbea6f2005-12-17 12:48:26 +0100745};
willy tarreau0f7af912005-12-17 12:21:26 +0100746
willy tarreau0f7af912005-12-17 12:21:26 +0100747static int totalconn = 0; /* total # of terminated sessions */
748static int actconn = 0; /* # of active sessions */
749static int maxfd = 0; /* # of the highest fd + 1 */
750static int listeners = 0; /* # of listeners */
751static int stopping = 0; /* non zero means stopping in progress */
752static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100753static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100754
willy tarreau53e99702006-03-25 18:53:50 +0100755/* Here we store informations about the pids of the processes we may pause
756 * or kill. We will send them a signal every 10 ms until we can bind to all
757 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100758 */
willy tarreau53e99702006-03-25 18:53:50 +0100759#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100760static int nb_oldpids = 0;
761static int *oldpids = NULL;
762static int oldpids_sig; /* use USR1 or TERM */
763
willy tarreau08dedbe2005-12-18 01:13:48 +0100764#if defined(ENABLE_EPOLL)
765/* FIXME: this is dirty, but at the moment, there's no other solution to remove
766 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
767 * structure with pointers to functions such as init_fd() and close_fd(), plus
768 * a private structure with several pointers to places such as below.
769 */
770
771static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
772#endif
773
willy tarreau0f7af912005-12-17 12:21:26 +0100774static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100775/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100776static char trash[BUFSIZE];
777
willy tarreaudd07e972005-12-18 00:48:48 +0100778const int zero = 0;
779const int one = 1;
780
willy tarreau0f7af912005-12-17 12:21:26 +0100781/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100782 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100783 */
784
785#define MAX_SYSLOG_LEN 1024
786#define NB_LOG_FACILITIES 24
787const char *log_facilities[NB_LOG_FACILITIES] = {
788 "kern", "user", "mail", "daemon",
789 "auth", "syslog", "lpr", "news",
790 "uucp", "cron", "auth2", "ftp",
791 "ntp", "audit", "alert", "cron2",
792 "local0", "local1", "local2", "local3",
793 "local4", "local5", "local6", "local7"
794};
795
796
797#define NB_LOG_LEVELS 8
798const char *log_levels[NB_LOG_LEVELS] = {
799 "emerg", "alert", "crit", "err",
800 "warning", "notice", "info", "debug"
801};
802
803#define SYSLOG_PORT 514
804
805const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
806 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100807
willy tarreaub1285d52005-12-18 01:20:14 +0100808const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100809const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
810const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
811const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
812 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
813 unknown, Set-cookie Rewritten */
814
willy tarreau0f7af912005-12-17 12:21:26 +0100815#define MAX_HOSTNAME_LEN 32
816static char hostname[MAX_HOSTNAME_LEN] = "";
817
willy tarreau8337c6b2005-12-17 13:41:01 +0100818const char *HTTP_302 =
819 "HTTP/1.0 302 Found\r\n"
820 "Cache-Control: no-cache\r\n"
821 "Connection: close\r\n"
822 "Location: "; /* not terminated since it will be concatenated with the URL */
823
willy tarreauc1f47532005-12-18 01:08:26 +0100824/* same as 302 except that the browser MUST retry with the GET method */
825const char *HTTP_303 =
826 "HTTP/1.0 303 See Other\r\n"
827 "Cache-Control: no-cache\r\n"
828 "Connection: close\r\n"
829 "Location: "; /* not terminated since it will be concatenated with the URL */
830
willy tarreaua1598082005-12-17 13:08:06 +0100831const char *HTTP_400 =
832 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100833 "Cache-Control: no-cache\r\n"
834 "Connection: close\r\n"
835 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100836 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100837
willy tarreaua1598082005-12-17 13:08:06 +0100838const char *HTTP_403 =
839 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100840 "Cache-Control: no-cache\r\n"
841 "Connection: close\r\n"
842 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100843 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
844
willy tarreau8337c6b2005-12-17 13:41:01 +0100845const char *HTTP_408 =
846 "HTTP/1.0 408 Request Time-out\r\n"
847 "Cache-Control: no-cache\r\n"
848 "Connection: close\r\n"
849 "\r\n"
850 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
851
willy tarreau750a4722005-12-17 13:21:24 +0100852const char *HTTP_500 =
853 "HTTP/1.0 500 Server Error\r\n"
854 "Cache-Control: no-cache\r\n"
855 "Connection: close\r\n"
856 "\r\n"
857 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100858
859const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100860 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100861 "Cache-Control: no-cache\r\n"
862 "Connection: close\r\n"
863 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100864 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
865
866const char *HTTP_503 =
867 "HTTP/1.0 503 Service Unavailable\r\n"
868 "Cache-Control: no-cache\r\n"
869 "Connection: close\r\n"
870 "\r\n"
871 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
872
873const char *HTTP_504 =
874 "HTTP/1.0 504 Gateway Time-out\r\n"
875 "Cache-Control: no-cache\r\n"
876 "Connection: close\r\n"
877 "\r\n"
878 "<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 +0100879
willy tarreau0f7af912005-12-17 12:21:26 +0100880/*********************************************************************/
881/* statistics ******************************************************/
882/*********************************************************************/
883
willy tarreau750a4722005-12-17 13:21:24 +0100884#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100885static int stats_tsk_lsrch, stats_tsk_rsrch,
886 stats_tsk_good, stats_tsk_right, stats_tsk_left,
887 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100888#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100889
890
891/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100892/* debugging *******************************************************/
893/*********************************************************************/
894#ifdef DEBUG_FULL
895static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200896static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100897#endif
898
899/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100900/* function prototypes *********************************************/
901/*********************************************************************/
902
903int event_accept(int fd);
904int event_cli_read(int fd);
905int event_cli_write(int fd);
906int event_srv_read(int fd);
907int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100908int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100909
willy tarreau12350152005-12-18 01:03:27 +0100910static int appsession_task_init(void);
911static int appsession_init(void);
912static int appsession_refresh(struct task *t);
913
willy tarreau0f7af912005-12-17 12:21:26 +0100914/*********************************************************************/
915/* general purpose functions ***************************************/
916/*********************************************************************/
917
918void display_version() {
919 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100920 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100921}
922
923/*
924 * This function prints the command line usage and exits
925 */
926void usage(char *name) {
927 display_version();
928 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100929 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100930#if STATTIME > 0
931 "sl"
932#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100933 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
934 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100935 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100936 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100937 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100938#if STATTIME > 0
939 " -s enables statistics output\n"
940 " -l enables long statistics format\n"
941#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100942 " -D goes daemon ; implies -q\n"
943 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100944 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100945 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100946 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100947 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100948 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100949#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100950 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100951#endif
952#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100953 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100954#endif
willy tarreau53e99702006-03-25 18:53:50 +0100955 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100956 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100957 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100958 exit(1);
959}
960
961
962/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100963 * Displays the message on stderr with the date and pid. Overrides the quiet
964 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100965 */
966void Alert(char *fmt, ...) {
967 va_list argp;
968 struct timeval tv;
969 struct tm *tm;
970
willy tarreaud0fb4652005-12-18 01:32:04 +0100971 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100972 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100973
willy tarreau5cbea6f2005-12-17 12:48:26 +0100974 gettimeofday(&tv, NULL);
975 tm=localtime(&tv.tv_sec);
976 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100977 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100978 vfprintf(stderr, fmt, argp);
979 fflush(stderr);
980 va_end(argp);
981 }
willy tarreau0f7af912005-12-17 12:21:26 +0100982}
983
984
985/*
986 * Displays the message on stderr with the date and pid.
987 */
988void Warning(char *fmt, ...) {
989 va_list argp;
990 struct timeval tv;
991 struct tm *tm;
992
willy tarreau982249e2005-12-18 00:57:06 +0100993 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100994 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100995
willy tarreau5cbea6f2005-12-17 12:48:26 +0100996 gettimeofday(&tv, NULL);
997 tm=localtime(&tv.tv_sec);
998 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100999 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +01001000 vfprintf(stderr, fmt, argp);
1001 fflush(stderr);
1002 va_end(argp);
1003 }
1004}
1005
1006/*
1007 * Displays the message on <out> only if quiet mode is not set.
1008 */
1009void qfprintf(FILE *out, char *fmt, ...) {
1010 va_list argp;
1011
willy tarreau982249e2005-12-18 00:57:06 +01001012 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001013 va_start(argp, fmt);
1014 vfprintf(out, fmt, argp);
1015 fflush(out);
1016 va_end(argp);
1017 }
willy tarreau0f7af912005-12-17 12:21:26 +01001018}
1019
1020
1021/*
1022 * converts <str> to a struct sockaddr_in* which is locally allocated.
1023 * The format is "addr:port", where "addr" can be empty or "*" to indicate
1024 * INADDR_ANY.
1025 */
1026struct sockaddr_in *str2sa(char *str) {
1027 static struct sockaddr_in sa;
1028 char *c;
1029 int port;
1030
willy tarreaua1598082005-12-17 13:08:06 +01001031 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001032 str=strdup(str);
1033
1034 if ((c=strrchr(str,':')) != NULL) {
1035 *c++=0;
1036 port=atol(c);
1037 }
1038 else
1039 port=0;
1040
1041 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1042 sa.sin_addr.s_addr = INADDR_ANY;
1043 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001044 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001045 struct hostent *he;
1046
1047 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001048 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001049 }
1050 else
1051 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1052 }
1053 sa.sin_port=htons(port);
1054 sa.sin_family=AF_INET;
1055
1056 free(str);
1057 return &sa;
1058}
1059
willy tarreaub1285d52005-12-18 01:20:14 +01001060/*
1061 * converts <str> to a two struct in_addr* which are locally allocated.
1062 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1063 * is optionnal and either in the dotted or CIDR notation.
1064 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1065 */
1066int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1067 char *c;
1068 unsigned long len;
1069
1070 memset(mask, 0, sizeof(*mask));
1071 memset(addr, 0, sizeof(*addr));
1072 str=strdup(str);
1073
1074 if ((c = strrchr(str, '/')) != NULL) {
1075 *c++ = 0;
1076 /* c points to the mask */
1077 if (strchr(c, '.') != NULL) { /* dotted notation */
1078 if (!inet_pton(AF_INET, c, mask))
1079 return 0;
1080 }
1081 else { /* mask length */
1082 char *err;
1083 len = strtol(c, &err, 10);
1084 if (!*c || (err && *err) || (unsigned)len > 32)
1085 return 0;
1086 if (len)
1087 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1088 else
1089 mask->s_addr = 0;
1090 }
1091 }
1092 else {
1093 mask->s_addr = 0xFFFFFFFF;
1094 }
1095 if (!inet_pton(AF_INET, str, addr)) {
1096 struct hostent *he;
1097
1098 if ((he = gethostbyname(str)) == NULL) {
1099 return 0;
1100 }
1101 else
1102 *addr = *(struct in_addr *) *(he->h_addr_list);
1103 }
1104 free(str);
1105 return 1;
1106}
1107
willy tarreau9fe663a2005-12-17 13:02:59 +01001108
1109/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001110 * converts <str> to a list of listeners which are dynamically allocated.
1111 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1112 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1113 * - <port> is a numerical port from 1 to 65535 ;
1114 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1115 * This can be repeated as many times as necessary, separated by a coma.
1116 * The <tail> argument is a pointer to a current list which should be appended
1117 * to the tail of the new list. The pointer to the new list is returned.
1118 */
1119struct listener *str2listener(char *str, struct listener *tail) {
1120 struct listener *l;
1121 char *c, *next, *range, *dupstr;
1122 int port, end;
1123
1124 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001125
willy tarreaua41a8b42005-12-17 14:02:24 +01001126 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001127 struct sockaddr_storage ss;
1128
willy tarreaua41a8b42005-12-17 14:02:24 +01001129 str = next;
1130 /* 1) look for the end of the first address */
1131 if ((next = strrchr(str, ',')) != NULL) {
1132 *next++ = 0;
1133 }
1134
willy tarreau8a86dbf2005-12-18 00:45:59 +01001135 /* 2) look for the addr/port delimiter, it's the last colon. */
1136 if ((range = strrchr(str, ':')) == NULL) {
1137 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001138 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001139 }
1140
1141 *range++ = 0;
1142
1143 if (strrchr(str, ':') != NULL) {
1144 /* IPv6 address contains ':' */
1145 memset(&ss, 0, sizeof(ss));
1146 ss.ss_family = AF_INET6;
1147
1148 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1149 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001150 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001151 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001152 }
1153 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001154 memset(&ss, 0, sizeof(ss));
1155 ss.ss_family = AF_INET;
1156
1157 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1158 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1159 }
1160 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1161 struct hostent *he;
1162
1163 if ((he = gethostbyname(str)) == NULL) {
1164 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001165 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001166 }
1167 else
1168 ((struct sockaddr_in *)&ss)->sin_addr =
1169 *(struct in_addr *) *(he->h_addr_list);
1170 }
1171 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001172
1173 /* 3) look for the port-end delimiter */
1174 if ((c = strchr(range, '-')) != NULL) {
1175 *c++ = 0;
1176 end = atol(c);
1177 }
1178 else {
1179 end = atol(range);
1180 }
1181
willy tarreaud0fb4652005-12-18 01:32:04 +01001182 port = atol(range);
1183
1184 if (port < 1 || port > 65535) {
1185 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1186 goto fail;
1187 }
1188
1189 if (end < 1 || end > 65535) {
1190 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1191 goto fail;
1192 }
1193
1194 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001195 l = (struct listener *)calloc(1, sizeof(struct listener));
1196 l->next = tail;
1197 tail = l;
1198
willy tarreau41310e72006-03-25 18:17:56 +01001199 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001200 l->addr = ss;
1201 if (ss.ss_family == AF_INET6)
1202 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1203 else
1204 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1205
willy tarreaua41a8b42005-12-17 14:02:24 +01001206 } /* end for(port) */
1207 } /* end while(next) */
1208 free(dupstr);
1209 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001210 fail:
1211 free(dupstr);
1212 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001213}
1214
willy tarreau4302f492005-12-18 01:00:37 +01001215
1216#define FD_SETS_ARE_BITFIELDS
1217#ifdef FD_SETS_ARE_BITFIELDS
1218/*
1219 * This map is used with all the FD_* macros to check whether a particular bit
1220 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1221 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1222 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1223 * exclusively to the macros.
1224 */
1225fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1226fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1227
1228#else
1229#error "Check if your OS uses bitfields for fd_sets"
1230#endif
1231
1232/* will try to encode the string <string> replacing all characters tagged in
1233 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1234 * prefixed by <escape>, and will store the result between <start> (included
1235 *) and <stop> (excluded), and will always terminate the string with a '\0'
1236 * before <stop>. The position of the '\0' is returned if the conversion
1237 * completes. If bytes are missing between <start> and <stop>, then the
1238 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1239 * cannot even be stored so we return <start> without writing the 0.
1240 * The input string must also be zero-terminated.
1241 */
1242char hextab[16] = "0123456789ABCDEF";
1243char *encode_string(char *start, char *stop,
1244 const char escape, const fd_set *map,
1245 const char *string)
1246{
1247 if (start < stop) {
1248 stop--; /* reserve one byte for the final '\0' */
1249 while (start < stop && *string != 0) {
1250 if (!FD_ISSET((unsigned char)(*string), map))
1251 *start++ = *string;
1252 else {
1253 if (start + 3 >= stop)
1254 break;
1255 *start++ = escape;
1256 *start++ = hextab[(*string >> 4) & 15];
1257 *start++ = hextab[*string & 15];
1258 }
1259 string++;
1260 }
1261 *start = '\0';
1262 }
1263 return start;
1264}
willy tarreaua41a8b42005-12-17 14:02:24 +01001265
1266/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001267 * This function sends a syslog message to both log servers of a proxy,
1268 * or to global log servers if the proxy is NULL.
1269 * It also tries not to waste too much time computing the message header.
1270 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 */
1272void send_log(struct proxy *p, int level, char *message, ...) {
1273 static int logfd = -1; /* syslog UDP socket */
1274 static long tvsec = -1; /* to force the string to be initialized */
1275 struct timeval tv;
1276 va_list argp;
1277 static char logmsg[MAX_SYSLOG_LEN];
1278 static char *dataptr = NULL;
1279 int fac_level;
1280 int hdr_len, data_len;
1281 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001282 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001283 int nbloggers = 0;
1284 char *log_ptr;
1285
1286 if (logfd < 0) {
1287 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1288 return;
1289 }
1290
1291 if (level < 0 || progname == NULL || message == NULL)
1292 return;
1293
1294 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001295 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001296 /* this string is rebuild only once a second */
1297 struct tm *tm = localtime(&tv.tv_sec);
1298 tvsec = tv.tv_sec;
1299
willy tarreauc29948c2005-12-17 13:10:27 +01001300 hdr_len = snprintf(logmsg, sizeof(logmsg),
1301 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1302 monthname[tm->tm_mon],
1303 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1304 progname, pid);
1305 /* WARNING: depending upon implementations, snprintf may return
1306 * either -1 or the number of bytes that would be needed to store
1307 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001308 */
willy tarreauc29948c2005-12-17 13:10:27 +01001309 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1310 hdr_len = sizeof(logmsg);
1311
1312 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001313 }
1314
1315 va_start(argp, message);
1316 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001317 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1318 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001319 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001320 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001321
1322 if (p == NULL) {
1323 if (global.logfac1 >= 0) {
1324 sa[nbloggers] = &global.logsrv1;
1325 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001326 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001327 nbloggers++;
1328 }
1329 if (global.logfac2 >= 0) {
1330 sa[nbloggers] = &global.logsrv2;
1331 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001332 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001333 nbloggers++;
1334 }
1335 } else {
1336 if (p->logfac1 >= 0) {
1337 sa[nbloggers] = &p->logsrv1;
1338 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001339 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001340 nbloggers++;
1341 }
1342 if (p->logfac2 >= 0) {
1343 sa[nbloggers] = &p->logsrv2;
1344 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001345 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001346 nbloggers++;
1347 }
1348 }
1349
1350 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001351 /* we can filter the level of the messages that are sent to each logger */
1352 if (level > loglevel[nbloggers])
1353 continue;
1354
willy tarreauc29948c2005-12-17 13:10:27 +01001355 /* For each target, we may have a different facility.
1356 * We can also have a different log level for each message.
1357 * This induces variations in the message header length.
1358 * Since we don't want to recompute it each time, nor copy it every
1359 * time, we only change the facility in the pre-computed header,
1360 * and we change the pointer to the header accordingly.
1361 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001362 fac_level = (facilities[nbloggers] << 3) + level;
1363 log_ptr = logmsg + 3; /* last digit of the log level */
1364 do {
1365 *log_ptr = '0' + fac_level % 10;
1366 fac_level /= 10;
1367 log_ptr--;
1368 } while (fac_level && log_ptr > logmsg);
1369 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001370
willy tarreauc29948c2005-12-17 13:10:27 +01001371 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001372
1373#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001374 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001375 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1376#else
willy tarreauc29948c2005-12-17 13:10:27 +01001377 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001378 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1379#endif
1380 }
willy tarreau0f7af912005-12-17 12:21:26 +01001381}
1382
1383
1384/* sets <tv> to the current time */
1385static inline struct timeval *tv_now(struct timeval *tv) {
1386 if (tv)
1387 gettimeofday(tv, NULL);
1388 return tv;
1389}
1390
1391/*
1392 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1393 */
1394static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1395 if (!tv || !from)
1396 return NULL;
1397 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1398 tv->tv_sec = from->tv_sec + (ms/1000);
1399 while (tv->tv_usec >= 1000000) {
1400 tv->tv_usec -= 1000000;
1401 tv->tv_sec++;
1402 }
1403 return tv;
1404}
1405
1406/*
1407 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001408 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001409 */
1410static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001411 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001412 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001413 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001414 return 1;
1415 else if (tv1->tv_usec < tv2->tv_usec)
1416 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001417 else if (tv1->tv_usec > tv2->tv_usec)
1418 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001419 else
1420 return 0;
1421}
1422
1423/*
1424 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001425 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001426 */
1427unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1428 int cmp;
1429 unsigned long ret;
1430
1431
willy tarreauef900ab2005-12-17 12:52:52 +01001432 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001433 if (!cmp)
1434 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001435 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001436 struct timeval *tmp = tv1;
1437 tv1 = tv2;
1438 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001439 }
willy tarreauef900ab2005-12-17 12:52:52 +01001440 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001441 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001442 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001443 else
willy tarreauef900ab2005-12-17 12:52:52 +01001444 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 return (unsigned long) ret;
1446}
1447
1448/*
willy tarreau750a4722005-12-17 13:21:24 +01001449 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001450 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001451 */
1452static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1453 unsigned long ret;
1454
willy tarreau6e682ce2005-12-17 13:26:49 +01001455 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1456 if (tv2->tv_usec > tv1->tv_usec)
1457 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001458 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001459 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001460 return (unsigned long) ret;
1461}
1462
1463/*
willy tarreau0f7af912005-12-17 12:21:26 +01001464 * 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 +01001465 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001466 */
1467static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001468 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001469 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001470 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001471 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001472 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001473 else
1474 return 0;
1475 }
willy tarreau0f7af912005-12-17 12:21:26 +01001476 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001477 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001478 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001479 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001480 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001481 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001482 else
1483 return 0;
1484}
1485
1486/*
1487 * returns the remaining time between tv1=now and event=tv2
1488 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001489 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001490 */
1491static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1492 unsigned long ret;
1493
willy tarreau0f7af912005-12-17 12:21:26 +01001494 if (tv_cmp_ms(tv1, tv2) >= 0)
1495 return 0; /* event elapsed */
1496
willy tarreauef900ab2005-12-17 12:52:52 +01001497 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001498 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001499 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001500 else
willy tarreauef900ab2005-12-17 12:52:52 +01001501 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001502 return (unsigned long) ret;
1503}
1504
1505
1506/*
1507 * zeroes a struct timeval
1508 */
1509
1510static inline struct timeval *tv_eternity(struct timeval *tv) {
1511 tv->tv_sec = tv->tv_usec = 0;
1512 return tv;
1513}
1514
1515/*
1516 * returns 1 if tv is null, else 0
1517 */
1518static inline int tv_iseternity(struct timeval *tv) {
1519 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1520 return 1;
1521 else
1522 return 0;
1523}
1524
1525/*
1526 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1527 * considering that 0 is the eternity.
1528 */
1529static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1530 if (tv_iseternity(tv1))
1531 if (tv_iseternity(tv2))
1532 return 0; /* same */
1533 else
1534 return 1; /* tv1 later than tv2 */
1535 else if (tv_iseternity(tv2))
1536 return -1; /* tv2 later than tv1 */
1537
1538 if (tv1->tv_sec > tv2->tv_sec)
1539 return 1;
1540 else if (tv1->tv_sec < tv2->tv_sec)
1541 return -1;
1542 else if (tv1->tv_usec > tv2->tv_usec)
1543 return 1;
1544 else if (tv1->tv_usec < tv2->tv_usec)
1545 return -1;
1546 else
1547 return 0;
1548}
1549
1550/*
1551 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1552 * considering that 0 is the eternity.
1553 */
1554static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1555 if (tv_iseternity(tv1))
1556 if (tv_iseternity(tv2))
1557 return 0; /* same */
1558 else
1559 return 1; /* tv1 later than tv2 */
1560 else if (tv_iseternity(tv2))
1561 return -1; /* tv2 later than tv1 */
1562
willy tarreauefae1842005-12-17 12:51:03 +01001563 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001564 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001565 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001566 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001567 return -1;
1568 else
1569 return 0;
1570 }
1571 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001572 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001573 return 1;
1574 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001575 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001576 return -1;
1577 else
1578 return 0;
1579}
1580
1581/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001582 * returns the remaining time between tv1=now and event=tv2
1583 * if tv2 is passed, 0 is returned.
1584 * Returns TIME_ETERNITY if tv2 is eternity.
1585 */
1586static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1587 unsigned long ret;
1588
1589 if (tv_iseternity(tv2))
1590 return TIME_ETERNITY;
1591
1592 if (tv_cmp_ms(tv1, tv2) >= 0)
1593 return 0; /* event elapsed */
1594
1595 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1596 if (tv2->tv_usec > tv1->tv_usec)
1597 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1598 else
1599 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1600 return (unsigned long) ret;
1601}
1602
1603/*
willy tarreau0f7af912005-12-17 12:21:26 +01001604 * returns the first event between tv1 and tv2 into tvmin.
1605 * a zero tv is ignored. tvmin is returned.
1606 */
1607static inline struct timeval *tv_min(struct timeval *tvmin,
1608 struct timeval *tv1, struct timeval *tv2) {
1609
1610 if (tv_cmp2(tv1, tv2) <= 0)
1611 *tvmin = *tv1;
1612 else
1613 *tvmin = *tv2;
1614
1615 return tvmin;
1616}
1617
1618
1619
1620/***********************************************************/
1621/* fd management ***************************************/
1622/***********************************************************/
1623
1624
1625
willy tarreau5cbea6f2005-12-17 12:48:26 +01001626/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1627 * The file descriptor is also closed.
1628 */
willy tarreau0f7af912005-12-17 12:21:26 +01001629static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001630 FD_CLR(fd, StaticReadEvent);
1631 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001632#if defined(ENABLE_EPOLL)
1633 if (PrevReadEvent) {
1634 FD_CLR(fd, PrevReadEvent);
1635 FD_CLR(fd, PrevWriteEvent);
1636 }
1637#endif
1638
willy tarreau5cbea6f2005-12-17 12:48:26 +01001639 close(fd);
1640 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001641
1642 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1643 maxfd--;
1644}
1645
1646/* recomputes the maxfd limit from the fd */
1647static inline void fd_insert(int fd) {
1648 if (fd+1 > maxfd)
1649 maxfd = fd+1;
1650}
1651
1652/*************************************************************/
1653/* task management ***************************************/
1654/*************************************************************/
1655
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656/* puts the task <t> in run queue <q>, and returns <t> */
1657static inline struct task *task_wakeup(struct task **q, struct task *t) {
1658 if (t->state == TASK_RUNNING)
1659 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001660 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001661 t->rqnext = *q;
1662 t->state = TASK_RUNNING;
1663 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001664 }
1665}
1666
willy tarreau5cbea6f2005-12-17 12:48:26 +01001667/* removes the task <t> from the queue <q>
1668 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001669 * set the run queue to point to the next one, and return it
1670 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671static inline struct task *task_sleep(struct task **q, struct task *t) {
1672 if (t->state == TASK_RUNNING) {
1673 *q = t->rqnext;
1674 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001675 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001676 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001677}
1678
1679/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001680 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001681 * from the run queue. A pointer to the task itself is returned.
1682 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001683static inline struct task *task_delete(struct task *t) {
1684 t->prev->next = t->next;
1685 t->next->prev = t->prev;
1686 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001687}
1688
1689/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001690 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001691 */
1692static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001693 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001694}
1695
willy tarreau5cbea6f2005-12-17 12:48:26 +01001696/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001697 * may be only moved or left where it was, depending on its timing requirements.
1698 * <task> is returned.
1699 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001700struct task *task_queue(struct task *task) {
1701 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001702 struct task *start_from;
1703
willy tarreau5e698ef2006-05-02 14:51:00 +02001704 /* This is a very dirty hack to queue non-expirable tasks in another queue
1705 * in order to avoid pulluting the tail of the standard queue. This will go
1706 * away with the new O(log(n)) scheduler anyway.
1707 */
1708 if (tv_iseternity(&task->expire)) {
1709 /* if the task was queued in the standard wait queue, we must dequeue it */
1710 if (task->prev) {
1711 if (task->wq == LIST_HEAD(wait_queue[1]))
1712 return task;
1713 else {
1714 task_delete(task);
1715 task->prev = NULL;
1716 }
1717 }
1718 list = task->wq = LIST_HEAD(wait_queue[1]);
1719 } else {
1720 /* if the task was queued in the eternity queue, we must dequeue it */
1721 if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) {
1722 task_delete(task);
1723 task->prev = NULL;
1724 list = task->wq = LIST_HEAD(wait_queue[0]);
1725 }
1726 }
1727
1728 /* next, test if the task was already in a list */
willy tarreau0f7af912005-12-17 12:21:26 +01001729 if (task->prev == NULL) {
1730 // start_from = list;
1731 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001732#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001733 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001734#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001735 /* insert the unlinked <task> into the list, searching back from the last entry */
1736 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1737 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001738#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001739 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001740#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001741 }
1742
1743 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1744 // start_from = start_from->next;
1745 // stats_tsk_nsrch++;
1746 // }
1747 }
1748 else if (task->prev == list ||
1749 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1750 start_from = task->next;
1751 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001752#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001753 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001754#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001755 return task; /* it's already in the right place */
1756 }
1757
willy tarreau750a4722005-12-17 13:21:24 +01001758#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001759 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001760#endif
1761
1762 /* if the task is not at the right place, there's little chance that
1763 * it has only shifted a bit, and it will nearly always be queued
1764 * at the end of the list because of constant timeouts
1765 * (observed in real case).
1766 */
1767#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1768 start_from = list->prev; /* assume we'll queue to the end of the list */
1769 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1770 start_from = start_from->prev;
1771#if STATTIME > 0
1772 stats_tsk_lsrch++;
1773#endif
1774 }
1775#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001776 /* insert the unlinked <task> into the list, searching after position <start_from> */
1777 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1778 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001779#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001780 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001781#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001782 }
willy tarreau750a4722005-12-17 13:21:24 +01001783#endif /* WE_REALLY_... */
1784
willy tarreau0f7af912005-12-17 12:21:26 +01001785 /* we need to unlink it now */
1786 task_delete(task);
1787 }
1788 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001789#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001790 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001791#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001792#ifdef LEFT_TO_TOP /* not very good */
1793 start_from = list;
1794 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1795 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001796#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001797 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001798#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001799 }
1800#else
1801 start_from = task->prev->prev; /* valid because of the previous test above */
1802 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1803 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001804#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001805 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001806#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001807 }
1808#endif
1809 /* we need to unlink it now */
1810 task_delete(task);
1811 }
1812 task->prev = start_from;
1813 task->next = start_from->next;
1814 task->next->prev = task;
1815 start_from->next = task;
1816 return task;
1817}
1818
1819
1820/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001821/* pending connections queues **************************************/
1822/*********************************************************************/
1823
1824/*
willy tarreaudfece232006-05-02 00:19:57 +02001825 * Detaches pending connection <p>, decreases the pending count, and frees
1826 * the pending connection. The connection might have been queued to a specific
1827 * server as well as to the proxy. The session also gets marked unqueued.
willy tarreau18a957c2006-04-12 19:26:23 +02001828 */
willy tarreaudfece232006-05-02 00:19:57 +02001829static void pendconn_free(struct pendconn *p) {
1830 LIST_DEL(&p->list);
1831 p->sess->pend_pos = NULL;
1832 if (p->srv)
1833 p->srv->nbpend--;
1834 else
1835 p->sess->proxy->nbpend--;
1836 pool_free(pendconn, p);
1837}
1838
1839/* Returns the first pending connection for server <s>, which may be NULL if
1840 * nothing is pending.
1841 */
1842static inline struct pendconn *pendconn_from_srv(struct server *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001843 if (!s->nbpend)
1844 return NULL;
1845
1846 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1847}
1848
willy tarreaudfece232006-05-02 00:19:57 +02001849/* Returns the first pending connection for proxy <px>, which may be NULL if
1850 * nothing is pending.
willy tarreau18a957c2006-04-12 19:26:23 +02001851 */
willy tarreaudfece232006-05-02 00:19:57 +02001852static inline struct pendconn *pendconn_from_px(struct proxy *px) {
1853 if (!px->nbpend)
1854 return NULL;
1855
1856 return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
willy tarreau18a957c2006-04-12 19:26:23 +02001857}
1858
willy tarreaudfece232006-05-02 00:19:57 +02001859/* Detaches the next pending connection for either current session's server or
1860 * current session's proxy, and returns its associated session. If no pending
1861 * connection is found, NULL is returned. Note that cur->srv cannot be NULL.
willy tarreau18a957c2006-04-12 19:26:23 +02001862 */
willy tarreaudfece232006-05-02 00:19:57 +02001863static struct session *pendconn_get_next_sess(struct session *cur) {
willy tarreau18a957c2006-04-12 19:26:23 +02001864 struct pendconn *p;
1865 struct session *sess;
1866
willy tarreaudfece232006-05-02 00:19:57 +02001867 p = pendconn_from_srv(cur->srv);
1868 if (!p) {
1869 p = pendconn_from_px(cur->proxy);
1870 if (!p)
1871 return NULL;
1872 p->sess->srv = cur->srv;
1873 }
willy tarreau18a957c2006-04-12 19:26:23 +02001874 sess = p->sess;
1875 pendconn_free(p);
1876 return sess;
1877}
1878
willy tarreaudfece232006-05-02 00:19:57 +02001879/* Checks if other sessions are waiting for the same server, and wakes the
1880 * first one up. Note that cur->srv cannot be NULL.
1881 */
1882void offer_connection_slot(struct session *cur) {
1883 struct session *sess;
1884
1885 sess = pendconn_get_next_sess(cur);
1886 if (sess == NULL)
1887 return;
1888 task_wakeup(&rq, sess->task);
1889}
1890
1891/* Adds the session <sess> to the pending connection list of server <sess>->srv
1892 * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers
1893 * are updated accordingly. Returns NULL if no memory is available, otherwise the
1894 * pendconn itself.
willy tarreau18a957c2006-04-12 19:26:23 +02001895 */
willy tarreaudfece232006-05-02 00:19:57 +02001896static struct pendconn *pendconn_add(struct session *sess) {
willy tarreau18a957c2006-04-12 19:26:23 +02001897 struct pendconn *p;
1898
1899 p = pool_alloc(pendconn);
1900 if (!p)
1901 return NULL;
1902
willy tarreau18a957c2006-04-12 19:26:23 +02001903 sess->pend_pos = p;
willy tarreaudfece232006-05-02 00:19:57 +02001904 p->sess = sess;
1905 p->srv = sess->srv;
1906 if (sess->srv) {
1907 LIST_ADDQ(&sess->srv->pendconns, &p->list);
1908 sess->srv->nbpend++;
1909 } else {
1910 LIST_ADDQ(&sess->proxy->pendconns, &p->list);
1911 sess->proxy->nbpend++;
1912 }
willy tarreau18a957c2006-04-12 19:26:23 +02001913 return p;
1914}
1915
1916/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001917/* more specific functions ***************************************/
1918/*********************************************************************/
1919
1920/* some prototypes */
1921static int maintain_proxies(void);
1922
willy tarreaub952e1d2005-12-18 01:31:20 +01001923/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001924 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1925 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001926static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001927#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1929#else
willy tarreaua1598082005-12-17 13:08:06 +01001930#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001931 return getsockname(fd, (struct sockaddr *)sa, salen);
1932#else
1933 return -1;
1934#endif
1935#endif
1936}
1937
1938/*
1939 * frees the context associated to a session. It must have been removed first.
1940 */
willy tarreaudfece232006-05-02 00:19:57 +02001941static void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001942 if (s->pend_pos)
1943 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001944 if (s->req)
1945 pool_free(buffer, s->req);
1946 if (s->rep)
1947 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001948
1949 if (s->rsp_cap != NULL) {
1950 struct cap_hdr *h;
1951 for (h = s->proxy->rsp_cap; h; h = h->next) {
1952 if (s->rsp_cap[h->index] != NULL)
1953 pool_free_to(h->pool, s->rsp_cap[h->index]);
1954 }
1955 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1956 }
1957 if (s->req_cap != NULL) {
1958 struct cap_hdr *h;
1959 for (h = s->proxy->req_cap; h; h = h->next) {
1960 if (s->req_cap[h->index] != NULL)
1961 pool_free_to(h->pool, s->req_cap[h->index]);
1962 }
1963 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1964 }
1965
willy tarreaua1598082005-12-17 13:08:06 +01001966 if (s->logs.uri)
1967 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001968 if (s->logs.cli_cookie)
1969 pool_free(capture, s->logs.cli_cookie);
1970 if (s->logs.srv_cookie)
1971 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001972
willy tarreau5cbea6f2005-12-17 12:48:26 +01001973 pool_free(session, s);
1974}
1975
willy tarreau0f7af912005-12-17 12:21:26 +01001976
1977/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001978 * This function recounts the number of usable active and backup servers for
1979 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001980 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001981 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001982static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001983 struct server *srv;
1984
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001985 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001986 for (srv = px->srv; srv != NULL; srv = srv->next) {
1987 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001988 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001989 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001990 px->tot_wbck += srv->eweight + 1;
1991 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001992 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001993 px->tot_wact += srv->eweight + 1;
1994 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001995 }
1996 }
1997}
1998
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001999/* This function recomputes the server map for proxy px. It
2000 * relies on px->tot_wact and px->tot_wbck, so it must be
2001 * called after recount_servers(). It also expects px->srv_map
2002 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01002003 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002004static void recalc_server_map(struct proxy *px) {
2005 int o, tot, flag;
2006 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01002007
willy tarreau4c8c2b52006-03-24 19:36:41 +01002008 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002009 flag = SRV_RUNNING;
2010 tot = px->tot_wact;
2011 } else if (px->srv_bck) {
2012 flag = SRV_RUNNING | SRV_BACKUP;
2013 if (px->options & PR_O_USE_ALL_BK)
2014 tot = px->tot_wbck;
2015 else
2016 tot = 1; /* the first server is enough */
2017 } else {
2018 px->srv_map_sz = 0;
2019 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002020 }
Willy TARREAU3481c462006-03-01 22:37:57 +01002021
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002022 /* this algorithm gives priority to the first server, which means that
2023 * it will respect the declaration order for equivalent weights, and
2024 * that whatever the weights, the first server called will always be
2025 * the first declard. This is an important asumption for the backup
2026 * case, where we want the first server only.
2027 */
2028 for (cur = px->srv; cur; cur = cur->next)
2029 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002030
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002031 for (o = 0; o < tot; o++) {
2032 int max = 0;
2033 best = NULL;
2034 for (cur = px->srv; cur; cur = cur->next) {
2035 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
2036 int v;
2037
2038 /* If we are forced to return only one server, we don't want to
2039 * go further, because we would return the wrong one due to
2040 * divide overflow.
2041 */
2042 if (tot == 1) {
2043 best = cur;
2044 break;
2045 }
2046
2047 cur->wscore += cur->eweight + 1;
2048 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
2049 if (best == NULL || v > max) {
2050 max = v;
2051 best = cur;
2052 }
2053 }
2054 }
2055 px->srv_map[o] = best;
2056 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002057 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002058 px->srv_map_sz = tot;
2059}
Willy TARREAU3481c462006-03-01 22:37:57 +01002060
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002061/*
willy tarreau898db9d2006-04-12 20:29:08 +02002062 * This function tries to find a running server with free connection slots for
2063 * the proxy <px> following the round-robin method.
2064 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2065 * to point to the next server. If no valid server is found, NULL is returned.
2066 */
2067static inline struct server *get_server_rr_with_conns(struct proxy *px) {
2068 int newidx;
2069 struct server *srv;
2070
2071 if (px->srv_map_sz == 0)
2072 return NULL;
2073
2074 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2075 px->srv_rr_idx = 0;
2076 newidx = px->srv_rr_idx;
2077
2078 do {
2079 srv = px->srv_map[newidx++];
2080 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
2081 px->srv_rr_idx = newidx;
2082 return srv;
2083 }
2084 if (newidx == px->srv_map_sz)
2085 newidx = 0;
2086 } while (newidx != px->srv_rr_idx);
2087
2088 return NULL;
2089}
2090
2091
2092/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002093 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002094 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002095 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2096 * to point to the next server. If no valid server is found, NULL is returned.
2097 */
2098static inline struct server *get_server_rr(struct proxy *px) {
2099 if (px->srv_map_sz == 0)
2100 return NULL;
2101
2102 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2103 px->srv_rr_idx = 0;
2104 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002105}
2106
willy tarreau62084d42006-03-24 18:57:41 +01002107
2108/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002109 * This function tries to find a running server for the proxy <px> following
2110 * the source hash method. Depending on the number of active/backup servers,
2111 * it will either look for active servers, or for backup servers.
2112 * If any server is found, it will be returned. If no valid server is found,
2113 * NULL is returned.
2114 */
2115static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002116 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002117
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002118 if (px->srv_map_sz == 0)
2119 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002120
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002121 l = h = 0;
willy tarreaucd655352006-04-29 12:11:46 +02002122 if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002123 while ((l + sizeof (int)) <= len) {
2124 h ^= ntohl(*(unsigned int *)(&addr[l]));
2125 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002126 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002127 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002128 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002129 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002130}
2131
2132
2133/*
willy tarreaudfece232006-05-02 00:19:57 +02002134 * This function marks the session as 'assigned' in direct or dispatch modes,
2135 * or tries to assign one in balance mode, according to the algorithm. It does
2136 * nothing if the session had already been assigned a server.
2137 *
2138 * It may return :
2139 * SRV_STATUS_OK if everything is OK.
2140 * SRV_STATUS_NOSRV if no server is available
2141 * SRV_STATUS_FULL if all servers are saturated
2142 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2143 *
2144 * Upon successful return, the session flag SN_ASSIGNED to indicate that it does
2145 * not need to be called anymore. This usually means that s->srv can be trusted
2146 * in balance and direct modes. This flag is not cleared, so it's to the caller
2147 * to clear it if required (eg: redispatch).
2148 *
willy tarreau0f7af912005-12-17 12:21:26 +01002149 */
willy tarreau0f7af912005-12-17 12:21:26 +01002150
willy tarreaudfece232006-05-02 00:19:57 +02002151int assign_server(struct session *s) {
willy tarreau12350152005-12-18 01:03:27 +01002152#ifdef DEBUG_FULL
willy tarreaudfece232006-05-02 00:19:57 +02002153 fprintf(stderr,"assign_server : s=%p\n",s);
willy tarreau12350152005-12-18 01:03:27 +01002154#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002155
willy tarreaudfece232006-05-02 00:19:57 +02002156 if (s->pend_pos)
2157 return SRV_STATUS_INTERNAL;
willy tarreau4c8c2b52006-03-24 19:36:41 +01002158
willy tarreaudfece232006-05-02 00:19:57 +02002159 if (!(s->flags & SN_ASSIGNED)) {
2160 if ((s->proxy->options & PR_O_BALANCE) && !(s->flags & SN_DIRECT)) {
2161 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2162 return SRV_STATUS_NOSRV;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002163
willy tarreaudfece232006-05-02 00:19:57 +02002164 if (s->proxy->options & PR_O_BALANCE_RR) {
2165 s->srv = get_server_rr_with_conns(s->proxy);
2166 if (!s->srv)
2167 return SRV_STATUS_FULL;
2168 }
2169 else if (s->proxy->options & PR_O_BALANCE_SH) {
2170 int len;
2171
2172 if (s->cli_addr.ss_family == AF_INET)
2173 len = 4;
2174 else if (s->cli_addr.ss_family == AF_INET6)
2175 len = 16;
2176 else /* unknown IP family */
2177 return SRV_STATUS_INTERNAL;
2178
2179 s->srv = get_server_sh(s->proxy,
2180 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2181 len);
2182 }
2183 else /* unknown balancing algorithm */
2184 return SRV_STATUS_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002185 }
willy tarreaudfece232006-05-02 00:19:57 +02002186 s->flags |= SN_ASSIGNED;
2187 }
2188 return SRV_STATUS_OK;
2189}
willy tarreau1a3442d2006-03-24 21:03:20 +01002190
willy tarreaudfece232006-05-02 00:19:57 +02002191/*
2192 * This function assigns a server address to a session, and sets SN_ADDR_SET.
2193 * The address is taken from the currently assigned server, or from the
2194 * dispatch or transparent address.
2195 *
2196 * It may return :
2197 * SRV_STATUS_OK if everything is OK.
2198 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2199 *
2200 * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
2201 * not cleared, so it's to the caller to clear it if required.
2202 *
2203 */
2204int assign_server_address(struct session *s) {
2205#ifdef DEBUG_FULL
2206 fprintf(stderr,"assign_server_address : s=%p\n",s);
2207#endif
2208
2209 if (s->flags & SN_DIRECT || s->proxy->options & PR_O_BALANCE) {
2210 /* A server is necessarily known for this session */
2211 if (!(s->flags & SN_ASSIGNED))
2212 return SRV_STATUS_INTERNAL;
2213
2214 s->srv_addr = s->srv->addr;
willy tarreau1a3442d2006-03-24 21:03:20 +01002215
willy tarreaudfece232006-05-02 00:19:57 +02002216 /* if this server remaps proxied ports, we'll use
2217 * the port the client connected to with an offset. */
2218 if (s->srv->state & SRV_MAPPORTS) {
2219 struct sockaddr_in sockname;
2220 socklen_t namelen = sizeof(sockname);
2221
2222 if (!(s->proxy->options & PR_O_TRANSP) ||
2223 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
2224 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2225 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
willy tarreau1a3442d2006-03-24 21:03:20 +01002226 }
willy tarreau0f7af912005-12-17 12:21:26 +01002227 }
willy tarreaua1598082005-12-17 13:08:06 +01002228 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002229 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002230 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002231 }
2232 else if (s->proxy->options & PR_O_TRANSP) {
2233 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002234 socklen_t salen = sizeof(s->srv_addr);
2235
willy tarreau5cbea6f2005-12-17 12:48:26 +01002236 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2237 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaudfece232006-05-02 00:19:57 +02002238 return SRV_STATUS_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002239 }
2240 }
willy tarreau0f7af912005-12-17 12:21:26 +01002241
willy tarreaudfece232006-05-02 00:19:57 +02002242 s->flags |= SN_ADDR_SET;
2243 return SRV_STATUS_OK;
2244}
willy tarreaua41a8b42005-12-17 14:02:24 +01002245
willy tarreaudfece232006-05-02 00:19:57 +02002246/* This function assigns a server to session <s> if required, and can add the
2247 * connection to either the assigned server's queue or to the proxy's queue.
2248 *
2249 * Returns :
2250 *
2251 * SRV_STATUS_OK if everything is OK.
2252 * SRV_STATUS_NOSRV if no server is available
2253 * SRV_STATUS_QUEUED if the connection has been queued.
2254 * SRV_STATUS_FULL if the server(s) is/are saturated and the
2255 * connection could not be queued.
2256 * SRV_STATUS_INTERNAL for other unrecoverable errors.
2257 *
2258 */
2259int assign_server_and_queue(struct session *s) {
2260 struct pendconn *p;
2261 int err;
2262
2263 if (s->pend_pos)
2264 return SRV_STATUS_INTERNAL;
2265
2266 if (s->flags & SN_ASSIGNED) {
2267 /* a server does not need to be assigned, perhaps because we're in
2268 * direct mode, or in dispatch or transparent modes where the server
2269 * is not needed.
2270 */
2271 if (s->srv &&
2272 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2273 p = pendconn_add(s);
2274 if (p)
2275 return SRV_STATUS_QUEUED;
2276 else
2277 return SRV_STATUS_FULL;
2278 }
2279 return SRV_STATUS_OK;
2280 }
2281
2282 /* a server needs to be assigned */
2283 err = assign_server(s);
2284 switch (err) {
2285 case SRV_STATUS_OK:
2286 /* in balance mode, we might have servers with connection limits */
2287 if (s->srv != NULL &&
2288 s->srv->maxconn && s->srv->cur_sess >= s->srv->maxconn) {
2289 p = pendconn_add(s);
2290 if (p)
2291 return SRV_STATUS_QUEUED;
2292 else
2293 return SRV_STATUS_FULL;
2294 }
2295 return SRV_STATUS_OK;
2296
2297 case SRV_STATUS_FULL:
2298 /* queue this session into the proxy's queue */
2299 p = pendconn_add(s);
2300 if (p)
2301 return SRV_STATUS_QUEUED;
2302 else
2303 return SRV_STATUS_FULL;
2304
2305 case SRV_STATUS_NOSRV:
2306 case SRV_STATUS_INTERNAL:
2307 return err;
2308 default:
2309 return SRV_STATUS_INTERNAL;
willy tarreaua41a8b42005-12-17 14:02:24 +01002310 }
willy tarreaudfece232006-05-02 00:19:57 +02002311}
2312
2313
2314/*
2315 * This function initiates a connection to the server assigned to this session
2316 * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
2317 * It can return one of :
2318 * - SN_ERR_NONE if everything's OK
2319 * - SN_ERR_SRVTO if there are no more servers
2320 * - SN_ERR_SRVCL if the connection was refused by the server
2321 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2322 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2323 * - SN_ERR_INTERNAL for any other purely internal errors
2324 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
2325 */
2326int connect_server(struct session *s) {
2327 int fd, err;
2328
2329 if (!(s->flags & SN_ADDR_SET)) {
2330 err = assign_server_address(s);
2331 if (err != SRV_STATUS_OK)
2332 return SN_ERR_INTERNAL;
2333 }
willy tarreaua41a8b42005-12-17 14:02:24 +01002334
willy tarreau0f7af912005-12-17 12:21:26 +01002335 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002336 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002337
2338 if (errno == ENFILE)
2339 send_log(s->proxy, LOG_EMERG,
2340 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2341 s->proxy->id, maxfd);
2342 else if (errno == EMFILE)
2343 send_log(s->proxy, LOG_EMERG,
2344 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2345 s->proxy->id, maxfd);
2346 else if (errno == ENOBUFS || errno == ENOMEM)
2347 send_log(s->proxy, LOG_EMERG,
2348 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2349 s->proxy->id, maxfd);
2350 /* this is a resource error */
2351 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002352 }
2353
willy tarreau9fe663a2005-12-17 13:02:59 +01002354 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002355 /* do not log anything there, it's a normal condition when this option
2356 * is used to serialize connections to a server !
2357 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002358 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2359 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002360 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002361 }
2362
willy tarreau0f7af912005-12-17 12:21:26 +01002363 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2364 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002365 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002366 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002367 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002368 }
2369
willy tarreaub952e1d2005-12-18 01:31:20 +01002370 if (s->proxy->options & PR_O_TCP_SRV_KA)
2371 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2372
willy tarreau0174f312005-12-18 01:02:42 +01002373 /* allow specific binding :
2374 * - server-specific at first
2375 * - proxy-specific next
2376 */
2377 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2378 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2379 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2380 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2381 s->proxy->id, s->srv->id);
2382 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002383 send_log(s->proxy, LOG_EMERG,
2384 "Cannot bind to source address before connect() for server %s/%s.\n",
2385 s->proxy->id, s->srv->id);
2386 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002387 }
2388 }
2389 else if (s->proxy->options & PR_O_BIND_SRC) {
2390 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2391 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2392 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2393 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002394 send_log(s->proxy, LOG_EMERG,
2395 "Cannot bind to source address before connect() for server %s/%s.\n",
2396 s->proxy->id, s->srv->id);
2397 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002398 }
willy tarreaua1598082005-12-17 13:08:06 +01002399 }
2400
willy tarreaub1285d52005-12-18 01:20:14 +01002401 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2402 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2403
2404 if (errno == EAGAIN || errno == EADDRINUSE) {
2405 char *msg;
2406 if (errno == EAGAIN) /* no free ports left, try again later */
2407 msg = "no free ports";
2408 else
2409 msg = "local address already in use";
2410
2411 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002412 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002413 send_log(s->proxy, LOG_EMERG,
2414 "Connect() failed for server %s/%s: %s.\n",
2415 s->proxy->id, s->srv->id, msg);
2416 return SN_ERR_RESOURCE;
2417 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002418 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002419 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002420 return SN_ERR_SRVTO;
2421 } else {
2422 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002423 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002424 close(fd);
2425 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002426 }
2427 }
2428
willy tarreau5cbea6f2005-12-17 12:48:26 +01002429 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002430 fdtab[fd].read = &event_srv_read;
2431 fdtab[fd].write = &event_srv_write;
2432 fdtab[fd].state = FD_STCONN; /* connection in progress */
2433
2434 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002435#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2436 if (PrevReadEvent) {
2437 assert(!(FD_ISSET(fd, PrevReadEvent)));
2438 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2439 }
2440#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002441
2442 fd_insert(fd);
willy tarreau926a3572006-05-01 15:26:35 +02002443 if (s->srv)
2444 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002445
2446 if (s->proxy->contimeout)
2447 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2448 else
2449 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002450 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002451}
2452
2453/*
2454 * this function is called on a read event from a client socket.
2455 * It returns 0.
2456 */
2457int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002458 struct task *t = fdtab[fd].owner;
2459 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002460 struct buffer *b = s->req;
2461 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002462
willy tarreau12350152005-12-18 01:03:27 +01002463#ifdef DEBUG_FULL
2464 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2465#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002466
willy tarreau0f7af912005-12-17 12:21:26 +01002467 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002468#ifdef FILL_BUFFERS
2469 while (1)
2470#else
2471 do
2472#endif
2473 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002474 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2475 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002476 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002477 }
2478 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002479 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002480 }
2481 else {
2482 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002483 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2484 * since it means that the rewrite protection has been removed. This
2485 * implies that the if statement can be removed.
2486 */
2487 if (max > b->rlim - b->data)
2488 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002489 }
2490
2491 if (max == 0) { /* not anymore room to store data */
2492 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002493 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002494 }
2495
willy tarreau3242e862005-12-17 12:27:53 +01002496#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002497 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002498 int skerr;
2499 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2502 if (skerr)
2503 ret = -1;
2504 else
2505 ret = recv(fd, b->r, max, 0);
2506 }
willy tarreau3242e862005-12-17 12:27:53 +01002507#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002508 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002509#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002510 if (ret > 0) {
2511 b->r += ret;
2512 b->l += ret;
2513 s->res_cr = RES_DATA;
2514
2515 if (b->r == b->data + BUFSIZE) {
2516 b->r = b->data; /* wrap around the buffer */
2517 }
willy tarreaua1598082005-12-17 13:08:06 +01002518
2519 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002520 /* we hope to read more data or to get a close on next round */
2521 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002522 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 else if (ret == 0) {
2524 s->res_cr = RES_NULL;
2525 break;
2526 }
2527 else if (errno == EAGAIN) {/* ignore EAGAIN */
2528 break;
2529 }
2530 else {
2531 s->res_cr = RES_ERROR;
2532 fdtab[fd].state = FD_STERROR;
2533 break;
2534 }
2535 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002536#ifndef FILL_BUFFERS
2537 while (0);
2538#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002539 }
2540 else {
2541 s->res_cr = RES_ERROR;
2542 fdtab[fd].state = FD_STERROR;
2543 }
2544
willy tarreau5cbea6f2005-12-17 12:48:26 +01002545 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002546 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002547 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2548 else
2549 tv_eternity(&s->crexpire);
2550
2551 task_wakeup(&rq, t);
2552 }
willy tarreau0f7af912005-12-17 12:21:26 +01002553
willy tarreau0f7af912005-12-17 12:21:26 +01002554 return 0;
2555}
2556
2557
2558/*
2559 * this function is called on a read event from a server socket.
2560 * It returns 0.
2561 */
2562int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002563 struct task *t = fdtab[fd].owner;
2564 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002565 struct buffer *b = s->rep;
2566 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002567
willy tarreau12350152005-12-18 01:03:27 +01002568#ifdef DEBUG_FULL
2569 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2570#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002571
willy tarreau0f7af912005-12-17 12:21:26 +01002572 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002573#ifdef FILL_BUFFERS
2574 while (1)
2575#else
2576 do
2577#endif
2578 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2580 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002581 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 }
2583 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002584 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 }
2586 else {
2587 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002588 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2589 * since it means that the rewrite protection has been removed. This
2590 * implies that the if statement can be removed.
2591 */
2592 if (max > b->rlim - b->data)
2593 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 }
2595
2596 if (max == 0) { /* not anymore room to store data */
2597 FD_CLR(fd, StaticReadEvent);
2598 break;
2599 }
2600
willy tarreau3242e862005-12-17 12:27:53 +01002601#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002602 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002603 int skerr;
2604 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002605
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2607 if (skerr)
2608 ret = -1;
2609 else
2610 ret = recv(fd, b->r, max, 0);
2611 }
willy tarreau3242e862005-12-17 12:27:53 +01002612#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002614#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002615 if (ret > 0) {
2616 b->r += ret;
2617 b->l += ret;
2618 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002619
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620 if (b->r == b->data + BUFSIZE) {
2621 b->r = b->data; /* wrap around the buffer */
2622 }
willy tarreaua1598082005-12-17 13:08:06 +01002623
2624 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002625 /* we hope to read more data or to get a close on next round */
2626 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002627 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002628 else if (ret == 0) {
2629 s->res_sr = RES_NULL;
2630 break;
2631 }
2632 else if (errno == EAGAIN) {/* ignore EAGAIN */
2633 break;
2634 }
2635 else {
2636 s->res_sr = RES_ERROR;
2637 fdtab[fd].state = FD_STERROR;
2638 break;
2639 }
2640 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002641#ifndef FILL_BUFFERS
2642 while (0);
2643#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002644 }
2645 else {
2646 s->res_sr = RES_ERROR;
2647 fdtab[fd].state = FD_STERROR;
2648 }
2649
willy tarreau5cbea6f2005-12-17 12:48:26 +01002650 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002651 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002652 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2653 else
2654 tv_eternity(&s->srexpire);
2655
2656 task_wakeup(&rq, t);
2657 }
willy tarreau0f7af912005-12-17 12:21:26 +01002658
willy tarreau0f7af912005-12-17 12:21:26 +01002659 return 0;
2660}
2661
2662/*
2663 * this function is called on a write event from a client socket.
2664 * It returns 0.
2665 */
2666int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002667 struct task *t = fdtab[fd].owner;
2668 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002669 struct buffer *b = s->rep;
2670 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002671
willy tarreau12350152005-12-18 01:03:27 +01002672#ifdef DEBUG_FULL
2673 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2674#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002675
2676 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002677 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002678 // max = BUFSIZE; BUG !!!!
2679 max = 0;
2680 }
2681 else if (b->r > b->w) {
2682 max = b->r - b->w;
2683 }
2684 else
2685 max = b->data + BUFSIZE - b->w;
2686
willy tarreau0f7af912005-12-17 12:21:26 +01002687 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002688 if (max == 0) {
2689 s->res_cw = RES_NULL;
2690 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002691 tv_eternity(&s->cwexpire);
2692 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002693 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002694 }
2695
willy tarreau3242e862005-12-17 12:27:53 +01002696#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002697 {
2698 int skerr;
2699 socklen_t lskerr = sizeof(skerr);
2700
2701 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2702 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002703 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002704 else
willy tarreau3242e862005-12-17 12:27:53 +01002705 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002706 }
willy tarreau3242e862005-12-17 12:27:53 +01002707#else
willy tarreau0f7af912005-12-17 12:21:26 +01002708 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002709#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002710
2711 if (ret > 0) {
2712 b->l -= ret;
2713 b->w += ret;
2714
2715 s->res_cw = RES_DATA;
2716
2717 if (b->w == b->data + BUFSIZE) {
2718 b->w = b->data; /* wrap around the buffer */
2719 }
2720 }
2721 else if (ret == 0) {
2722 /* nothing written, just make as if we were never called */
2723// s->res_cw = RES_NULL;
2724 return 0;
2725 }
2726 else if (errno == EAGAIN) /* ignore EAGAIN */
2727 return 0;
2728 else {
2729 s->res_cw = RES_ERROR;
2730 fdtab[fd].state = FD_STERROR;
2731 }
2732 }
2733 else {
2734 s->res_cw = RES_ERROR;
2735 fdtab[fd].state = FD_STERROR;
2736 }
2737
willy tarreaub1ff9db2005-12-17 13:51:03 +01002738 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002739 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002740 /* FIXME: to prevent the client from expiring read timeouts during writes,
2741 * we refresh it. A solution would be to merge read+write timeouts into a
2742 * unique one, although that needs some study particularly on full-duplex
2743 * TCP connections. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01002744 s->crexpire = s->cwexpire;
2745 }
willy tarreau0f7af912005-12-17 12:21:26 +01002746 else
2747 tv_eternity(&s->cwexpire);
2748
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002750 return 0;
2751}
2752
2753
2754/*
2755 * this function is called on a write event from a server socket.
2756 * It returns 0.
2757 */
2758int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002759 struct task *t = fdtab[fd].owner;
2760 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002761 struct buffer *b = s->req;
2762 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002763
willy tarreau12350152005-12-18 01:03:27 +01002764#ifdef DEBUG_FULL
2765 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2766#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002767
2768 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002769 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002770 // max = BUFSIZE; BUG !!!!
2771 max = 0;
2772 }
2773 else if (b->r > b->w) {
2774 max = b->r - b->w;
2775 }
2776 else
2777 max = b->data + BUFSIZE - b->w;
2778
willy tarreau0f7af912005-12-17 12:21:26 +01002779 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002780 if (max == 0) {
2781 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002782 if (s->srv_state == SV_STCONN) {
2783 int skerr;
2784 socklen_t lskerr = sizeof(skerr);
2785 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2786 if (skerr) {
2787 s->res_sw = RES_ERROR;
2788 fdtab[fd].state = FD_STERROR;
2789 task_wakeup(&rq, t);
2790 tv_eternity(&s->swexpire);
2791 FD_CLR(fd, StaticWriteEvent);
2792 return 0;
2793 }
2794 }
2795
willy tarreau0f7af912005-12-17 12:21:26 +01002796 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002797 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002798 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002799 tv_eternity(&s->swexpire);
2800 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002801 return 0;
2802 }
2803
willy tarreau3242e862005-12-17 12:27:53 +01002804#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002805 {
2806 int skerr;
2807 socklen_t lskerr = sizeof(skerr);
2808 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2809 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002810 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002811 else
willy tarreau3242e862005-12-17 12:27:53 +01002812 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002813 }
willy tarreau3242e862005-12-17 12:27:53 +01002814#else
willy tarreau0f7af912005-12-17 12:21:26 +01002815 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002816#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002817 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002818 if (ret > 0) {
2819 b->l -= ret;
2820 b->w += ret;
2821
2822 s->res_sw = RES_DATA;
2823
2824 if (b->w == b->data + BUFSIZE) {
2825 b->w = b->data; /* wrap around the buffer */
2826 }
2827 }
2828 else if (ret == 0) {
2829 /* nothing written, just make as if we were never called */
2830 // s->res_sw = RES_NULL;
2831 return 0;
2832 }
2833 else if (errno == EAGAIN) /* ignore EAGAIN */
2834 return 0;
2835 else {
2836 s->res_sw = RES_ERROR;
2837 fdtab[fd].state = FD_STERROR;
2838 }
2839 }
2840 else {
2841 s->res_sw = RES_ERROR;
2842 fdtab[fd].state = FD_STERROR;
2843 }
2844
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002845 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2846 * otherwise it could loop indefinitely !
2847 */
2848 if (s->srv_state != SV_STCONN) {
2849 if (s->proxy->srvtimeout) {
2850 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02002851 /* FIXME: to prevent the server from expiring read timeouts during writes,
2852 * we refresh it. A solution would be to merge read+write+connect timeouts
2853 * into a unique one since we don't mind expiring on read or write, and none
2854 * of them is enabled while waiting for connect(), although that needs some
2855 * study particularly on full-duplex TCP connections. */
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002856 s->srexpire = s->swexpire;
2857 }
2858 else
2859 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002860 }
willy tarreau0f7af912005-12-17 12:21:26 +01002861
willy tarreau5cbea6f2005-12-17 12:48:26 +01002862 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002863 return 0;
2864}
2865
2866
2867/*
willy tarreaue39cd132005-12-17 13:00:18 +01002868 * returns a message to the client ; the connection is shut down for read,
2869 * and the request is cleared so that no server connection can be initiated.
2870 * The client must be in a valid state for this (HEADER, DATA ...).
2871 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002872 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002873 */
2874void client_retnclose(struct session *s, int len, const char *msg) {
2875 FD_CLR(s->cli_fd, StaticReadEvent);
2876 FD_SET(s->cli_fd, StaticWriteEvent);
2877 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002878 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002879 shutdown(s->cli_fd, SHUT_RD);
2880 s->cli_state = CL_STSHUTR;
2881 strcpy(s->rep->data, msg);
2882 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002883 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002884 s->rep->r += len;
2885 s->req->l = 0;
2886}
2887
2888
2889/*
2890 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002891 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002892 */
2893void client_return(struct session *s, int len, const char *msg) {
2894 strcpy(s->rep->data, msg);
2895 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002896 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002897 s->rep->r += len;
2898 s->req->l = 0;
2899}
2900
willy tarreau9fe663a2005-12-17 13:02:59 +01002901/*
2902 * send a log for the session when we have enough info about it
2903 */
2904void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002905 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002906 struct proxy *p = s->proxy;
2907 int log;
2908 char *uri;
2909 char *pxid;
2910 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002911 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002912
2913 /* This is a first attempt at a better logging system.
2914 * For now, we rely on send_log() to provide the date, although it obviously
2915 * is the date of the log and not of the request, and most fields are not
2916 * computed.
2917 */
2918
willy tarreaua1598082005-12-17 13:08:06 +01002919 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002920
willy tarreau8a86dbf2005-12-18 00:45:59 +01002921 if (s->cli_addr.ss_family == AF_INET)
2922 inet_ntop(AF_INET,
2923 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2924 pn, sizeof(pn));
2925 else
2926 inet_ntop(AF_INET6,
2927 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2928 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002929
willy tarreauc1cae632005-12-17 14:12:23 +01002930 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002931 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002932 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002933
willy tarreauc1cae632005-12-17 14:12:23 +01002934 tm = localtime(&s->logs.tv_accept.tv_sec);
2935 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002936 char tmpline[MAX_SYSLOG_LEN], *h;
2937 int hdr;
2938
2939 h = tmpline;
2940 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2941 *(h++) = ' ';
2942 *(h++) = '{';
2943 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2944 if (hdr)
2945 *(h++) = '|';
2946 if (s->req_cap[hdr] != NULL)
2947 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2948 }
2949 *(h++) = '}';
2950 }
2951
2952 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2953 *(h++) = ' ';
2954 *(h++) = '{';
2955 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2956 if (hdr)
2957 *(h++) = '|';
2958 if (s->rsp_cap[hdr] != NULL)
2959 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2960 }
2961 *(h++) = '}';
2962 }
2963
2964 if (h < tmpline + sizeof(tmpline) - 4) {
2965 *(h++) = ' ';
2966 *(h++) = '"';
2967 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2968 *(h++) = '"';
2969 }
2970 *h = '\0';
2971
willy tarreaua647c702006-04-15 22:45:52 +02002972 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002973 pn,
2974 (s->cli_addr.ss_family == AF_INET) ?
2975 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2976 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002977 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2978 tm->tm_hour, tm->tm_min, tm->tm_sec,
2979 pxid, srv,
2980 s->logs.t_request,
2981 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2982 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002983 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2984 s->logs.status,
2985 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002986 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2987 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002988 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2989 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2990 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2991 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua647c702006-04-15 22:45:52 +02002992 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002993 }
2994 else {
willy tarreaua647c702006-04-15 22:45:52 +02002995 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\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002996 pn,
2997 (s->cli_addr.ss_family == AF_INET) ?
2998 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2999 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01003000 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
3001 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01003002 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01003003 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01003004 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
3005 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01003006 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01003007 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreaua647c702006-04-15 22:45:52 +02003008 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01003009 }
3010
3011 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003012}
3013
willy tarreaue39cd132005-12-17 13:00:18 +01003014
3015/*
willy tarreau0f7af912005-12-17 12:21:26 +01003016 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01003017 * to an accept. It tries to accept as many connections as possible.
3018 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01003019 */
3020int event_accept(int fd) {
3021 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003022 struct session *s;
3023 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01003024 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01003025 int max_accept;
3026
3027 if (global.nbproc > 1)
3028 max_accept = 8; /* let other processes catch some connections too */
3029 else
3030 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01003031
willy tarreauc2becdc2006-03-19 19:36:48 +01003032 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003033 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003034 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01003035
willy tarreaub1285d52005-12-18 01:20:14 +01003036 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
3037 switch (errno) {
3038 case EAGAIN:
3039 case EINTR:
3040 case ECONNABORTED:
3041 return 0; /* nothing more to accept */
3042 case ENFILE:
3043 send_log(p, LOG_EMERG,
3044 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
3045 p->id, maxfd);
3046 return 0;
3047 case EMFILE:
3048 send_log(p, LOG_EMERG,
3049 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
3050 p->id, maxfd);
3051 return 0;
3052 case ENOBUFS:
3053 case ENOMEM:
3054 send_log(p, LOG_EMERG,
3055 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
3056 p->id, maxfd);
3057 return 0;
3058 default:
3059 return 0;
3060 }
3061 }
willy tarreau0f7af912005-12-17 12:21:26 +01003062
willy tarreau5cbea6f2005-12-17 12:48:26 +01003063 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
3064 Alert("out of memory in event_accept().\n");
3065 FD_CLR(fd, StaticReadEvent);
3066 p->state = PR_STIDLE;
3067 close(cfd);
3068 return 0;
3069 }
willy tarreau0f7af912005-12-17 12:21:26 +01003070
willy tarreaub1285d52005-12-18 01:20:14 +01003071 /* if this session comes from a known monitoring system, we want to ignore
3072 * it as soon as possible, which means closing it immediately for TCP.
3073 */
3074 s->flags = 0;
3075 if (addr.ss_family == AF_INET &&
3076 p->mon_mask.s_addr &&
3077 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
3078 if (p->mode == PR_MODE_TCP) {
3079 close(cfd);
3080 pool_free(session, s);
3081 continue;
3082 }
3083 s->flags |= SN_MONITOR;
3084 }
3085
willy tarreau5cbea6f2005-12-17 12:48:26 +01003086 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3087 Alert("out of memory in event_accept().\n");
3088 FD_CLR(fd, StaticReadEvent);
3089 p->state = PR_STIDLE;
3090 close(cfd);
3091 pool_free(session, s);
3092 return 0;
3093 }
willy tarreau0f7af912005-12-17 12:21:26 +01003094
willy tarreau5cbea6f2005-12-17 12:48:26 +01003095 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01003096 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
3098 close(cfd);
3099 pool_free(task, t);
3100 pool_free(session, s);
3101 return 0;
3102 }
willy tarreau0f7af912005-12-17 12:21:26 +01003103
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
3105 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
3106 (char *) &one, sizeof(one)) == -1)) {
3107 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
3108 close(cfd);
3109 pool_free(task, t);
3110 pool_free(session, s);
3111 return 0;
3112 }
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreaub952e1d2005-12-18 01:31:20 +01003114 if (p->options & PR_O_TCP_CLI_KA)
3115 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
3116
willy tarreau9fe663a2005-12-17 13:02:59 +01003117 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02003118 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
willy tarreau9fe663a2005-12-17 13:02:59 +01003119 t->state = TASK_IDLE;
3120 t->process = process_session;
3121 t->context = s;
3122
3123 s->task = t;
3124 s->proxy = p;
3125 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
3126 s->srv_state = SV_STIDLE;
3127 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01003128
willy tarreau9fe663a2005-12-17 13:02:59 +01003129 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
3130 s->cli_fd = cfd;
3131 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01003132 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01003133 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01003134
willy tarreaub1285d52005-12-18 01:20:14 +01003135 if (s->flags & SN_MONITOR)
3136 s->logs.logwait = 0;
3137 else
3138 s->logs.logwait = p->to_log;
3139
willy tarreaua1598082005-12-17 13:08:06 +01003140 s->logs.tv_accept = now;
3141 s->logs.t_request = -1;
3142 s->logs.t_connect = -1;
3143 s->logs.t_data = -1;
3144 s->logs.t_close = 0;
3145 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01003146 s->logs.cli_cookie = NULL;
3147 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01003148 s->logs.status = -1;
3149 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003150
willy tarreau2f6ba652005-12-17 13:57:42 +01003151 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02003152 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01003153
willy tarreau4302f492005-12-18 01:00:37 +01003154 if (p->nb_req_cap > 0) {
3155 if ((s->req_cap =
3156 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
3157 == NULL) { /* no memory */
3158 close(cfd); /* nothing can be done for this fd without memory */
3159 pool_free(task, t);
3160 pool_free(session, s);
3161 return 0;
3162 }
3163 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
3164 }
3165 else
3166 s->req_cap = NULL;
3167
3168 if (p->nb_rsp_cap > 0) {
3169 if ((s->rsp_cap =
3170 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
3171 == NULL) { /* no memory */
3172 if (s->req_cap != NULL)
3173 pool_free_to(p->req_cap_pool, s->req_cap);
3174 close(cfd); /* nothing can be done for this fd without memory */
3175 pool_free(task, t);
3176 pool_free(session, s);
3177 return 0;
3178 }
3179 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
3180 }
3181 else
3182 s->rsp_cap = NULL;
3183
willy tarreau5cbea6f2005-12-17 12:48:26 +01003184 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
3185 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003186 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003187 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01003188
willy tarreau8a86dbf2005-12-18 00:45:59 +01003189 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003190 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003191 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003192 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01003193
willy tarreau9fe663a2005-12-17 13:02:59 +01003194 if (p->to_log) {
3195 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01003196 if (s->logs.logwait & LW_CLIP)
3197 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01003198 sess_log(s);
3199 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01003200 else if (s->cli_addr.ss_family == AF_INET) {
3201 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
3202 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
3203 sn, sizeof(sn)) &&
3204 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3205 pn, sizeof(pn))) {
3206 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3207 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
3208 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
3209 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3210 }
3211 }
3212 else {
3213 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3214 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3215 sn, sizeof(sn)) &&
3216 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3217 pn, sizeof(pn))) {
3218 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3219 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3220 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3221 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3222 }
3223 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003224 }
willy tarreau0f7af912005-12-17 12:21:26 +01003225
willy tarreau982249e2005-12-18 00:57:06 +01003226 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003227 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003228 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003229 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003230 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003231 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003232 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003233 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003234
willy tarreau8a86dbf2005-12-18 00:45:59 +01003235 if (s->cli_addr.ss_family == AF_INET) {
3236 char pn[INET_ADDRSTRLEN];
3237 inet_ntop(AF_INET,
3238 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3239 pn, sizeof(pn));
3240
3241 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3242 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3243 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3244 }
3245 else {
3246 char pn[INET6_ADDRSTRLEN];
3247 inet_ntop(AF_INET6,
3248 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3249 pn, sizeof(pn));
3250
3251 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3252 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3253 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3254 }
3255
willy tarreauef900ab2005-12-17 12:52:52 +01003256 write(1, trash, len);
3257 }
willy tarreau0f7af912005-12-17 12:21:26 +01003258
willy tarreau5cbea6f2005-12-17 12:48:26 +01003259 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003260 if (s->rsp_cap != NULL)
3261 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3262 if (s->req_cap != NULL)
3263 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003264 close(cfd); /* nothing can be done for this fd without memory */
3265 pool_free(task, t);
3266 pool_free(session, s);
3267 return 0;
3268 }
willy tarreau4302f492005-12-18 01:00:37 +01003269
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003271 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003272 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3273 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003274 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003275 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003276
willy tarreau5cbea6f2005-12-17 12:48:26 +01003277 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3278 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003279 if (s->rsp_cap != NULL)
3280 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3281 if (s->req_cap != NULL)
3282 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003283 close(cfd); /* nothing can be done for this fd without memory */
3284 pool_free(task, t);
3285 pool_free(session, s);
3286 return 0;
3287 }
3288 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003289 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003290 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 +01003291
willy tarreau5cbea6f2005-12-17 12:48:26 +01003292 fdtab[cfd].read = &event_cli_read;
3293 fdtab[cfd].write = &event_cli_write;
3294 fdtab[cfd].owner = t;
3295 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003296
willy tarreaub1285d52005-12-18 01:20:14 +01003297 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3298 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3299 /* Either we got a request from a monitoring system on an HTTP instance,
3300 * or we're in health check mode with the 'httpchk' option enabled. In
3301 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3302 */
3303 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3304 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3305 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 }
3307 else {
3308 FD_SET(cfd, StaticReadEvent);
3309 }
3310
willy tarreaub952e1d2005-12-18 01:31:20 +01003311#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3312 if (PrevReadEvent) {
3313 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3314 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3315 }
3316#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 fd_insert(cfd);
3318
3319 tv_eternity(&s->cnexpire);
3320 tv_eternity(&s->srexpire);
3321 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003322 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003323 tv_eternity(&s->cwexpire);
3324
willy tarreaub1285d52005-12-18 01:20:14 +01003325 if (s->proxy->clitimeout) {
3326 if (FD_ISSET(cfd, StaticReadEvent))
3327 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3328 if (FD_ISSET(cfd, StaticWriteEvent))
3329 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3330 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003331
willy tarreaub1285d52005-12-18 01:20:14 +01003332 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003333
3334 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003335
3336 if (p->mode != PR_MODE_HEALTH)
3337 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003338
3339 p->nbconn++;
3340 actconn++;
3341 totalconn++;
3342
willy tarreaub952e1d2005-12-18 01:31:20 +01003343 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 } /* end of while (p->nbconn < p->maxconn) */
3345 return 0;
3346}
willy tarreau0f7af912005-12-17 12:21:26 +01003347
willy tarreau0f7af912005-12-17 12:21:26 +01003348
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349/*
3350 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003351 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3352 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 * or -1 if an error occured.
3354 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003355int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003356 struct task *t = fdtab[fd].owner;
3357 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003358 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003359 socklen_t lskerr = sizeof(skerr);
3360
willy tarreau05be12b2006-03-19 19:35:00 +01003361 skerr = 1;
3362 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3363 || (skerr != 0)) {
3364 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003366 fdtab[fd].state = FD_STERROR;
3367 FD_CLR(fd, StaticWriteEvent);
3368 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003369 else if (s->result != -1) {
3370 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003371 if (s->proxy->options & PR_O_HTTP_CHK) {
3372 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003373 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003374 * so we'll send the request, and won't wake the checker up now.
3375 */
3376#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003377 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003378#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003379 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003380#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003381 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003382 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3383 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3384 return 0;
3385 }
willy tarreau05be12b2006-03-19 19:35:00 +01003386 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003387 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003388 FD_CLR(fd, StaticWriteEvent);
3389 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003390 }
3391 else {
3392 /* good TCP connection is enough */
3393 s->result = 1;
3394 }
3395 }
3396
3397 task_wakeup(&rq, t);
3398 return 0;
3399}
3400
willy tarreau0f7af912005-12-17 12:21:26 +01003401
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003402/*
3403 * This function is used only for server health-checks. It handles
3404 * the server's reply to an HTTP request. It returns 1 if the server replies
3405 * 2xx or 3xx (valid responses), or -1 in other cases.
3406 */
3407int event_srv_chk_r(int fd) {
3408 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003409 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003410 struct task *t = fdtab[fd].owner;
3411 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003412 int skerr;
3413 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003414
willy tarreaua4a583a2005-12-18 01:39:19 +01003415 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003416
willy tarreau05be12b2006-03-19 19:35:00 +01003417 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3418 if (!skerr) {
3419#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003420 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003421#else
willy tarreau05be12b2006-03-19 19:35:00 +01003422 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3423 * but the connection was closed on the remote end. Fortunately, recv still
3424 * works correctly and we don't need to do the getsockopt() on linux.
3425 */
3426 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003427#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003428
3429 if ((len >= sizeof("HTTP/1.0 000")) &&
3430 !memcmp(reply, "HTTP/1.", 7) &&
3431 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3432 result = 1;
3433 }
3434
3435 if (result == -1)
3436 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003437
3438 if (s->result != -1)
3439 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003440
3441 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003442 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003443 return 0;
3444}
3445
3446
3447/*
3448 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3449 * and moves <end> just after the end of <str>.
3450 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3451 * the shift value (positive or negative) is returned.
3452 * If there's no space left, the move is not done.
3453 *
3454 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003456 int delta;
3457 int len;
3458
3459 len = strlen(str);
3460 delta = len - (end - pos);
3461
3462 if (delta + b->r >= b->data + BUFSIZE)
3463 return 0; /* no space left */
3464
3465 /* first, protect the end of the buffer */
3466 memmove(end + delta, end, b->data + b->l - end);
3467
3468 /* now, copy str over pos */
3469 memcpy(pos, str,len);
3470
willy tarreau5cbea6f2005-12-17 12:48:26 +01003471 /* we only move data after the displaced zone */
3472 if (b->r > pos) b->r += delta;
3473 if (b->w > pos) b->w += delta;
3474 if (b->h > pos) b->h += delta;
3475 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003476 b->l += delta;
3477
3478 return delta;
3479}
3480
willy tarreau8337c6b2005-12-17 13:41:01 +01003481/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003482 * len is 0.
3483 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003484int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003485 int delta;
3486
3487 delta = len - (end - pos);
3488
3489 if (delta + b->r >= b->data + BUFSIZE)
3490 return 0; /* no space left */
3491
Willy TARREAUe78ae262006-01-08 01:24:12 +01003492 if (b->data + b->l < end)
3493 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3494 return 0;
3495
willy tarreau0f7af912005-12-17 12:21:26 +01003496 /* first, protect the end of the buffer */
3497 memmove(end + delta, end, b->data + b->l - end);
3498
3499 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003500 if (len)
3501 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003502
willy tarreau5cbea6f2005-12-17 12:48:26 +01003503 /* we only move data after the displaced zone */
3504 if (b->r > pos) b->r += delta;
3505 if (b->w > pos) b->w += delta;
3506 if (b->h > pos) b->h += delta;
3507 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003508 b->l += delta;
3509
3510 return delta;
3511}
3512
3513
3514int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3515 char *old_dst = dst;
3516
3517 while (*str) {
3518 if (*str == '\\') {
3519 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003520 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003521 int len, num;
3522
3523 num = *str - '0';
3524 str++;
3525
willy tarreau8a86dbf2005-12-18 00:45:59 +01003526 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003527 len = matches[num].rm_eo - matches[num].rm_so;
3528 memcpy(dst, src + matches[num].rm_so, len);
3529 dst += len;
3530 }
3531
3532 }
3533 else if (*str == 'x') {
3534 unsigned char hex1, hex2;
3535 str++;
3536
willy tarreauc1f47532005-12-18 01:08:26 +01003537 hex1 = toupper(*str++) - '0';
3538 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003539
3540 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3541 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3542 *dst++ = (hex1<<4) + hex2;
3543 }
3544 else
3545 *dst++ = *str++;
3546 }
3547 else
3548 *dst++ = *str++;
3549 }
3550 *dst = 0;
3551 return dst - old_dst;
3552}
3553
willy tarreauc1f47532005-12-18 01:08:26 +01003554static int ishex(char s)
3555{
3556 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3557}
3558
3559/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3560char *check_replace_string(char *str)
3561{
3562 char *err = NULL;
3563 while (*str) {
3564 if (*str == '\\') {
3565 err = str; /* in case of a backslash, we return the pointer to it */
3566 str++;
3567 if (!*str)
3568 return err;
3569 else if (isdigit((int)*str))
3570 err = NULL;
3571 else if (*str == 'x') {
3572 str++;
3573 if (!ishex(*str))
3574 return err;
3575 str++;
3576 if (!ishex(*str))
3577 return err;
3578 err = NULL;
3579 }
3580 else {
3581 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3582 err = NULL;
3583 }
3584 }
3585 str++;
3586 }
3587 return err;
3588}
3589
3590
willy tarreau9fe663a2005-12-17 13:02:59 +01003591
willy tarreau0f7af912005-12-17 12:21:26 +01003592/*
3593 * manages the client FSM and its socket. BTW, it also tries to handle the
3594 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3595 * 0 else.
3596 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003597int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003598 int s = t->srv_state;
3599 int c = t->cli_state;
3600 struct buffer *req = t->req;
3601 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003602 int method_checked = 0;
3603 appsess *asession_temp = NULL;
3604 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003605
willy tarreau750a4722005-12-17 13:21:24 +01003606#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003607 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3608 cli_stnames[c], srv_stnames[s],
3609 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3610 t->crexpire.tv_sec, t->crexpire.tv_usec,
3611 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003612#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003613 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3614 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3615 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3616 //);
3617 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003618 /* now parse the partial (or complete) headers */
3619 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3620 char *ptr;
3621 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003622 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003623
willy tarreau5cbea6f2005-12-17 12:48:26 +01003624 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003625
willy tarreau0f7af912005-12-17 12:21:26 +01003626 /* look for the end of the current header */
3627 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3628 ptr++;
3629
willy tarreau5cbea6f2005-12-17 12:48:26 +01003630 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003632
3633 /*
3634 * first, let's check that it's not a leading empty line, in
3635 * which case we'll ignore and remove it (according to RFC2616).
3636 */
3637 if (req->h == req->data) {
3638 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3639 if (ptr > req->r - 2) {
3640 /* this is a partial header, let's wait for more to come */
3641 req->lr = ptr;
3642 break;
3643 }
3644
3645 /* now we know that *ptr is either \r or \n,
3646 * and that there are at least 1 char after it.
3647 */
3648 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3649 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3650 else
3651 req->lr = ptr + 2; /* \r\n or \n\r */
3652 /* ignore empty leading lines */
3653 buffer_replace2(req, req->h, req->lr, NULL, 0);
3654 req->h = req->lr;
3655 continue;
3656 }
3657
willy tarreau5cbea6f2005-12-17 12:48:26 +01003658 /* we can only get here after an end of headers */
3659 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003660
willy tarreaue39cd132005-12-17 13:00:18 +01003661 if (t->flags & SN_CLDENY) {
3662 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003663 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003664 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003665 if (!(t->flags & SN_ERR_MASK))
3666 t->flags |= SN_ERR_PRXCOND;
3667 if (!(t->flags & SN_FINST_MASK))
3668 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003669 return 1;
3670 }
3671
willy tarreau5cbea6f2005-12-17 12:48:26 +01003672 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003673 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3674 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003675 }
willy tarreau0f7af912005-12-17 12:21:26 +01003676
willy tarreau9fe663a2005-12-17 13:02:59 +01003677 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003678 if (t->cli_addr.ss_family == AF_INET) {
3679 unsigned char *pn;
3680 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3681 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3682 pn[0], pn[1], pn[2], pn[3]);
3683 buffer_replace2(req, req->h, req->h, trash, len);
3684 }
3685 else if (t->cli_addr.ss_family == AF_INET6) {
3686 char pn[INET6_ADDRSTRLEN];
3687 inet_ntop(AF_INET6,
3688 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3689 pn, sizeof(pn));
3690 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3691 buffer_replace2(req, req->h, req->h, trash, len);
3692 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003693 }
3694
willy tarreau25c4ea52005-12-18 00:49:49 +01003695 /* add a "connection: close" line if needed */
3696 if (t->proxy->options & PR_O_HTTP_CLOSE)
3697 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3698
willy tarreau982249e2005-12-18 00:57:06 +01003699 if (!memcmp(req->data, "POST ", 5)) {
3700 /* this is a POST request, which is not cacheable by default */
3701 t->flags |= SN_POST;
3702 }
willy tarreaucd878942005-12-17 13:27:43 +01003703
willy tarreau5cbea6f2005-12-17 12:48:26 +01003704 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003705 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003706
willy tarreau750a4722005-12-17 13:21:24 +01003707 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003708 /* FIXME: we'll set the client in a wait state while we try to
3709 * connect to the server. Is this really needed ? wouldn't it be
willy tarreau0889c962006-04-24 14:36:48 +02003710 * better to release the maximum of system buffers instead ?
3711 * The solution is to enable the FD but set its time-out to
3712 * eternity as long as the server-side does not enable data xfer.
3713 * CL_STDATA also has to take care of this, which is done below.
3714 */
willy tarreauef900ab2005-12-17 12:52:52 +01003715 //FD_CLR(t->cli_fd, StaticReadEvent);
3716 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003717
3718 /* FIXME: if we break here (as up to 1.1.23), having the client
3719 * shutdown its connection can lead to an abort further.
3720 * it's better to either return 1 or even jump directly to the
3721 * data state which will save one schedule.
3722 */
3723 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003724
3725 if (!t->proxy->clitimeout ||
3726 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3727 /* If the client has no timeout, or if the server is not ready yet,
3728 * and we know for sure that it can expire, then it's cleaner to
3729 * disable the timeout on the client side so that too low values
3730 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003731 *
3732 * FIXME-20050705: the server needs a way to re-enable this time-out
3733 * when it switches its state, otherwise a client can stay connected
3734 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003735 */
3736 tv_eternity(&t->crexpire);
3737
willy tarreau197e8ec2005-12-17 14:10:59 +01003738 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 }
willy tarreau0f7af912005-12-17 12:21:26 +01003740
Willy TARREAU13032e72006-03-12 17:31:45 +01003741 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3742 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003743 /* this is a partial header, let's wait for more to come */
3744 req->lr = ptr;
3745 break;
3746 }
willy tarreau0f7af912005-12-17 12:21:26 +01003747
willy tarreau5cbea6f2005-12-17 12:48:26 +01003748 /* now we know that *ptr is either \r or \n,
3749 * and that there are at least 1 char after it.
3750 */
3751 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3752 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3753 else
3754 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003755
willy tarreau5cbea6f2005-12-17 12:48:26 +01003756 /*
3757 * now we know that we have a full header ; we can do whatever
3758 * we want with these pointers :
3759 * req->h = beginning of header
3760 * ptr = end of header (first \r or \n)
3761 * req->lr = beginning of next line (next rep->h)
3762 * req->r = end of data (not used at this stage)
3763 */
willy tarreau0f7af912005-12-17 12:21:26 +01003764
willy tarreau12350152005-12-18 01:03:27 +01003765 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3766 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3767 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3768
3769 /* skip ; */
3770 request_line++;
3771
3772 /* look if we have a jsessionid */
3773
3774 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3775
3776 /* skip jsessionid= */
3777 request_line += t->proxy->appsession_name_len + 1;
3778
3779 /* First try if we allready have an appsession */
3780 asession_temp = &local_asession;
3781
3782 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3783 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3784 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3785 return 0;
3786 }
3787
3788 /* Copy the sessionid */
3789 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3790 asession_temp->sessid[t->proxy->appsession_len] = 0;
3791 asession_temp->serverid = NULL;
3792
3793 /* only do insert, if lookup fails */
3794 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3795 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3796 Alert("Not enough memory process_cli():asession:calloc().\n");
3797 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3798 return 0;
3799 }
3800 asession_temp->sessid = local_asession.sessid;
3801 asession_temp->serverid = local_asession.serverid;
3802 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003803 } /* end if (chtbl_lookup()) */
3804 else {
willy tarreau12350152005-12-18 01:03:27 +01003805 /*free wasted memory;*/
3806 pool_free_to(apools.sessid, local_asession.sessid);
3807 }
3808
3809 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3810 asession_temp->request_count++;
3811
3812#if defined(DEBUG_HASH)
3813 print_table(&(t->proxy->htbl_proxy));
3814#endif
3815
3816 if (asession_temp->serverid == NULL) {
3817 Alert("Found Application Session without matching server.\n");
3818 } else {
3819 struct server *srv = t->proxy->srv;
3820 while (srv) {
3821 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3822 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3823 /* we found the server and it's usable */
3824 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02003825 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01003826 t->srv = srv;
3827 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003828 } else {
willy tarreau12350152005-12-18 01:03:27 +01003829 t->flags &= ~SN_CK_MASK;
3830 t->flags |= SN_CK_DOWN;
3831 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003832 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003833 srv = srv->next;
3834 }/* end while(srv) */
3835 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003836 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003837 else {
3838 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3839 }
willy tarreau598da412005-12-18 01:07:29 +01003840 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003841 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003842 else{
3843 //printf("No Methode-Header with Session-String\n");
3844 }
3845
willy tarreau8337c6b2005-12-17 13:41:01 +01003846 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003847 /* we have a complete HTTP request that we must log */
3848 int urilen;
3849
willy tarreaua1598082005-12-17 13:08:06 +01003850 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003851 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003852 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003853 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003854 if (!(t->flags & SN_ERR_MASK))
3855 t->flags |= SN_ERR_PRXCOND;
3856 if (!(t->flags & SN_FINST_MASK))
3857 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003858 return 1;
3859 }
3860
3861 urilen = ptr - req->h;
3862 if (urilen >= REQURI_LEN)
3863 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003864 memcpy(t->logs.uri, req->h, urilen);
3865 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003866
willy tarreaua1598082005-12-17 13:08:06 +01003867 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003868 sess_log(t);
3869 }
willy tarreau4302f492005-12-18 01:00:37 +01003870 else if (t->logs.logwait & LW_REQHDR) {
3871 struct cap_hdr *h;
3872 int len;
3873 for (h = t->proxy->req_cap; h; h = h->next) {
3874 if ((h->namelen + 2 <= ptr - req->h) &&
3875 (req->h[h->namelen] == ':') &&
3876 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3877
3878 if (t->req_cap[h->index] == NULL)
3879 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3880
3881 len = ptr - (req->h + h->namelen + 2);
3882 if (len > h->len)
3883 len = h->len;
3884
3885 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3886 t->req_cap[h->index][len]=0;
3887 }
3888 }
3889
3890 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003891
willy tarreau5cbea6f2005-12-17 12:48:26 +01003892 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003893
willy tarreau982249e2005-12-18 00:57:06 +01003894 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003895 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003896 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 +01003897 max = ptr - req->h;
3898 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003899 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003900 trash[len++] = '\n';
3901 write(1, trash, len);
3902 }
willy tarreau0f7af912005-12-17 12:21:26 +01003903
willy tarreau25c4ea52005-12-18 00:49:49 +01003904
3905 /* remove "connection: " if needed */
3906 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3907 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3908 delete_header = 1;
3909 }
3910
willy tarreau5cbea6f2005-12-17 12:48:26 +01003911 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003912 if (!delete_header && t->proxy->req_exp != NULL
3913 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003914 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003915 char term;
3916
3917 term = *ptr;
3918 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003919 exp = t->proxy->req_exp;
3920 do {
3921 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3922 switch (exp->action) {
3923 case ACT_ALLOW:
3924 if (!(t->flags & SN_CLDENY))
3925 t->flags |= SN_CLALLOW;
3926 break;
3927 case ACT_REPLACE:
3928 if (!(t->flags & SN_CLDENY)) {
3929 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3930 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3931 }
3932 break;
3933 case ACT_REMOVE:
3934 if (!(t->flags & SN_CLDENY))
3935 delete_header = 1;
3936 break;
3937 case ACT_DENY:
3938 if (!(t->flags & SN_CLALLOW))
3939 t->flags |= SN_CLDENY;
3940 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003941 case ACT_PASS: /* we simply don't deny this one */
3942 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003943 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003944 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003945 }
willy tarreaue39cd132005-12-17 13:00:18 +01003946 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003947 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003948 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003949
willy tarreau240afa62005-12-17 13:14:35 +01003950 /* Now look for cookies. Conforming to RFC2109, we have to support
3951 * attributes whose name begin with a '$', and associate them with
3952 * the right cookie, if we want to delete this cookie.
3953 * So there are 3 cases for each cookie read :
3954 * 1) it's a special attribute, beginning with a '$' : ignore it.
3955 * 2) it's a server id cookie that we *MAY* want to delete : save
3956 * some pointers on it (last semi-colon, beginning of cookie...)
3957 * 3) it's an application cookie : we *MAY* have to delete a previous
3958 * "special" cookie.
3959 * At the end of loop, if a "special" cookie remains, we may have to
3960 * remove it. If no application cookie persists in the header, we
3961 * *MUST* delete it
3962 */
willy tarreau12350152005-12-18 01:03:27 +01003963 if (!delete_header &&
3964 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003965 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003966 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003967 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003968 char *del_colon, *del_cookie, *colon;
3969 int app_cookies;
3970
willy tarreau5cbea6f2005-12-17 12:48:26 +01003971 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003972 colon = p1;
3973 /* del_cookie == NULL => nothing to be deleted */
3974 del_colon = del_cookie = NULL;
3975 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003976
3977 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003978 /* skip spaces and colons, but keep an eye on these ones */
3979 while (p1 < ptr) {
3980 if (*p1 == ';' || *p1 == ',')
3981 colon = p1;
3982 else if (!isspace((int)*p1))
3983 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003984 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003985 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003986
3987 if (p1 == ptr)
3988 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003989
3990 /* p1 is at the beginning of the cookie name */
3991 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003992 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 p2++;
3994
3995 if (p2 == ptr)
3996 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003997
3998 p3 = p2 + 1; /* skips the '=' sign */
3999 if (p3 == ptr)
4000 break;
4001
willy tarreau240afa62005-12-17 13:14:35 +01004002 p4 = p3;
4003 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 p4++;
4005
4006 /* here, we have the cookie name between p1 and p2,
4007 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01004008 * we can process it :
4009 *
4010 * Cookie: NAME=VALUE;
4011 * | || || |
4012 * | || || +--> p4
4013 * | || |+-------> p3
4014 * | || +--------> p2
4015 * | |+------------> p1
4016 * | +-------------> colon
4017 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01004018 */
4019
willy tarreau240afa62005-12-17 13:14:35 +01004020 if (*p1 == '$') {
4021 /* skip this one */
4022 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004023 else {
4024 /* first, let's see if we want to capture it */
4025 if (t->proxy->capture_name != NULL &&
4026 t->logs.cli_cookie == NULL &&
4027 (p4 - p1 >= t->proxy->capture_namelen) &&
4028 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4029 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004030
willy tarreau8337c6b2005-12-17 13:41:01 +01004031 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4032 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01004033 } else {
4034 if (log_len > t->proxy->capture_len)
4035 log_len = t->proxy->capture_len;
4036 memcpy(t->logs.cli_cookie, p1, log_len);
4037 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01004038 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004039 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004040
4041 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4042 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
4043 /* Cool... it's the right one */
4044 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01004045 char *delim;
4046
4047 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4048 * have the server ID betweek p3 and delim, and the original cookie between
4049 * delim+1 and p4. Otherwise, delim==p4 :
4050 *
4051 * Cookie: NAME=SRV~VALUE;
4052 * | || || | |
4053 * | || || | +--> p4
4054 * | || || +--------> delim
4055 * | || |+-----------> p3
4056 * | || +------------> p2
4057 * | |+----------------> p1
4058 * | +-----------------> colon
4059 * +------------------------> req->h
4060 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004061
willy tarreau0174f312005-12-18 01:02:42 +01004062 if (t->proxy->options & PR_O_COOK_PFX) {
4063 for (delim = p3; delim < p4; delim++)
4064 if (*delim == COOKIE_DELIM)
4065 break;
4066 }
4067 else
4068 delim = p4;
4069
4070
4071 /* Here, we'll look for the first running server which supports the cookie.
4072 * This allows to share a same cookie between several servers, for example
4073 * to dedicate backup servers to specific servers only.
4074 */
4075 while (srv) {
4076 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
4077 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4078 /* we found the server and it's usable */
4079 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004080 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau0174f312005-12-18 01:02:42 +01004081 t->srv = srv;
4082 break;
willy tarreau12350152005-12-18 01:03:27 +01004083 } else {
willy tarreau0174f312005-12-18 01:02:42 +01004084 /* we found a server, but it's down */
4085 t->flags &= ~SN_CK_MASK;
4086 t->flags |= SN_CK_DOWN;
4087 }
4088 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004089 srv = srv->next;
4090 }
4091
willy tarreau0174f312005-12-18 01:02:42 +01004092 if (!srv && !(t->flags & SN_CK_DOWN)) {
4093 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01004094 t->flags &= ~SN_CK_MASK;
4095 t->flags |= SN_CK_INVALID;
4096 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004097
willy tarreau0174f312005-12-18 01:02:42 +01004098 /* depending on the cookie mode, we may have to either :
4099 * - delete the complete cookie if we're in insert+indirect mode, so that
4100 * the server never sees it ;
4101 * - remove the server id from the cookie value, and tag the cookie as an
4102 * application cookie so that it does not get accidentely removed later,
4103 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01004104 */
willy tarreau0174f312005-12-18 01:02:42 +01004105 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
4106 buffer_replace2(req, p3, delim + 1, NULL, 0);
4107 p4 -= (delim + 1 - p3);
4108 ptr -= (delim + 1 - p3);
4109 del_cookie = del_colon = NULL;
4110 app_cookies++; /* protect the header from deletion */
4111 }
4112 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01004113 (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 +01004114 del_cookie = p1;
4115 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01004116 }
willy tarreau12350152005-12-18 01:03:27 +01004117 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01004118 /* now we know that we must keep this cookie since it's
4119 * not ours. But if we wanted to delete our cookie
4120 * earlier, we cannot remove the complete header, but we
4121 * can remove the previous block itself.
4122 */
4123 app_cookies++;
4124
4125 if (del_cookie != NULL) {
4126 buffer_replace2(req, del_cookie, p1, NULL, 0);
4127 p4 -= (p1 - del_cookie);
4128 ptr -= (p1 - del_cookie);
4129 del_cookie = del_colon = NULL;
4130 }
willy tarreau240afa62005-12-17 13:14:35 +01004131 }
willy tarreau12350152005-12-18 01:03:27 +01004132
4133 if ((t->proxy->appsession_name != NULL) &&
4134 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4135 /* first, let's see if the cookie is our appcookie*/
4136
4137 /* Cool... it's the right one */
4138
4139 asession_temp = &local_asession;
4140
4141 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4142 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4143 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4144 return 0;
4145 }
4146
4147 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4148 asession_temp->sessid[t->proxy->appsession_len] = 0;
4149 asession_temp->serverid = NULL;
4150
4151 /* only do insert, if lookup fails */
4152 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4153 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4154 Alert("Not enough memory process_cli():asession:calloc().\n");
4155 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4156 return 0;
4157 }
4158
4159 asession_temp->sessid = local_asession.sessid;
4160 asession_temp->serverid = local_asession.serverid;
4161 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4162 }
4163 else{
4164 /* free wasted memory */
4165 pool_free_to(apools.sessid, local_asession.sessid);
4166 }
4167
4168 if (asession_temp->serverid == NULL) {
4169 Alert("Found Application Session without matching server.\n");
4170 } else {
4171 struct server *srv = t->proxy->srv;
4172 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01004173 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01004174 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
4175 /* we found the server and it's usable */
4176 t->flags &= ~SN_CK_MASK;
willy tarreaudfece232006-05-02 00:19:57 +02004177 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
willy tarreau12350152005-12-18 01:03:27 +01004178 t->srv = srv;
4179 break;
4180 } else {
4181 t->flags &= ~SN_CK_MASK;
4182 t->flags |= SN_CK_DOWN;
4183 }
4184 }
4185 srv = srv->next;
4186 }/* end while(srv) */
4187 }/* end else if server == NULL */
4188
4189 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01004190 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004191 }
willy tarreau240afa62005-12-17 13:14:35 +01004192
willy tarreau5cbea6f2005-12-17 12:48:26 +01004193 /* we'll have to look for another cookie ... */
4194 p1 = p4;
4195 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01004196
4197 /* There's no more cookie on this line.
4198 * We may have marked the last one(s) for deletion.
4199 * We must do this now in two ways :
4200 * - if there is no app cookie, we simply delete the header ;
4201 * - if there are app cookies, we must delete the end of the
4202 * string properly, including the colon/semi-colon before
4203 * the cookie name.
4204 */
4205 if (del_cookie != NULL) {
4206 if (app_cookies) {
4207 buffer_replace2(req, del_colon, ptr, NULL, 0);
4208 /* WARNING! <ptr> becomes invalid for now. If some code
4209 * below needs to rely on it before the end of the global
4210 * header loop, we need to correct it with this code :
4211 * ptr = del_colon;
4212 */
4213 }
4214 else
4215 delete_header = 1;
4216 }
4217 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004218
4219 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004220 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004221 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004222 }
willy tarreau240afa62005-12-17 13:14:35 +01004223 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4224
willy tarreau5cbea6f2005-12-17 12:48:26 +01004225 req->h = req->lr;
4226 } /* while (req->lr < req->r) */
4227
4228 /* end of header processing (even if incomplete) */
4229
willy tarreauef900ab2005-12-17 12:52:52 +01004230 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4231 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4232 * full. We cannot loop here since event_cli_read will disable it only if
4233 * req->l == rlim-data
4234 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004235 FD_SET(t->cli_fd, StaticReadEvent);
4236 if (t->proxy->clitimeout)
4237 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4238 else
4239 tv_eternity(&t->crexpire);
4240 }
4241
willy tarreaue39cd132005-12-17 13:00:18 +01004242 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004243 * won't be able to free more later, so the session will never terminate.
4244 */
willy tarreaue39cd132005-12-17 13:00:18 +01004245 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004246 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004247 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004248 if (!(t->flags & SN_ERR_MASK))
4249 t->flags |= SN_ERR_PRXCOND;
4250 if (!(t->flags & SN_FINST_MASK))
4251 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004252 return 1;
4253 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004254 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004255 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004256 tv_eternity(&t->crexpire);
4257 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004258 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004259 if (!(t->flags & SN_ERR_MASK))
4260 t->flags |= SN_ERR_CLICL;
4261 if (!(t->flags & SN_FINST_MASK))
4262 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004263 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004264 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004265 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4266
4267 /* read timeout : give up with an error message.
4268 */
4269 t->logs.status = 408;
4270 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004271 if (!(t->flags & SN_ERR_MASK))
4272 t->flags |= SN_ERR_CLITO;
4273 if (!(t->flags & SN_FINST_MASK))
4274 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004275 return 1;
4276 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004277
4278 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004279 }
4280 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004281 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004282 /* FIXME: this error handling is partly buggy because we always report
4283 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4284 * or HEADER phase. BTW, it's not logical to expire the client while
4285 * we're waiting for the server to connect.
4286 */
willy tarreau0f7af912005-12-17 12:21:26 +01004287 /* read or write error */
4288 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004289 tv_eternity(&t->crexpire);
4290 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004291 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004292 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004293 if (!(t->flags & SN_ERR_MASK))
4294 t->flags |= SN_ERR_CLICL;
4295 if (!(t->flags & SN_FINST_MASK))
4296 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004297 return 1;
4298 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004299 /* last read, or end of server write */
4300 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004301 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004302 tv_eternity(&t->crexpire);
4303 shutdown(t->cli_fd, SHUT_RD);
4304 t->cli_state = CL_STSHUTR;
4305 return 1;
4306 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004307 /* last server read and buffer empty */
4308 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004309 FD_CLR(t->cli_fd, StaticWriteEvent);
4310 tv_eternity(&t->cwexpire);
4311 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004312 /* We must ensure that the read part is still alive when switching
4313 * to shutw */
4314 FD_SET(t->cli_fd, StaticReadEvent);
4315 if (t->proxy->clitimeout)
4316 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004317 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004318 //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 +01004319 return 1;
4320 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004321 /* read timeout */
4322 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4323 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004324 tv_eternity(&t->crexpire);
4325 shutdown(t->cli_fd, SHUT_RD);
4326 t->cli_state = CL_STSHUTR;
4327 if (!(t->flags & SN_ERR_MASK))
4328 t->flags |= SN_ERR_CLITO;
4329 if (!(t->flags & SN_FINST_MASK))
4330 t->flags |= SN_FINST_D;
4331 return 1;
4332 }
4333 /* write timeout */
4334 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4335 FD_CLR(t->cli_fd, StaticWriteEvent);
4336 tv_eternity(&t->cwexpire);
4337 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004338 /* We must ensure that the read part is still alive when switching
4339 * to shutw */
4340 FD_SET(t->cli_fd, StaticReadEvent);
4341 if (t->proxy->clitimeout)
4342 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4343
willy tarreau036e1ce2005-12-17 13:46:33 +01004344 t->cli_state = CL_STSHUTW;
4345 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004346 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004347 if (!(t->flags & SN_FINST_MASK))
4348 t->flags |= SN_FINST_D;
4349 return 1;
4350 }
willy tarreau0f7af912005-12-17 12:21:26 +01004351
willy tarreauc58fc692005-12-17 14:13:08 +01004352 if (req->l >= req->rlim - req->data) {
4353 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004354 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004355 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004356 FD_CLR(t->cli_fd, StaticReadEvent);
4357 tv_eternity(&t->crexpire);
4358 }
4359 }
4360 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004361 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004362 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4363 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004364 if (!t->proxy->clitimeout ||
4365 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4366 /* If the client has no timeout, or if the server not ready yet, and we
4367 * know for sure that it can expire, then it's cleaner to disable the
4368 * timeout on the client side so that too low values cannot make the
4369 * sessions abort too early.
4370 */
willy tarreau0f7af912005-12-17 12:21:26 +01004371 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004372 else
4373 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004374 }
4375 }
4376
4377 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004378 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004379 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4380 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4381 tv_eternity(&t->cwexpire);
4382 }
4383 }
4384 else { /* buffer not empty */
4385 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4386 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004387 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004388 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004389 /* FIXME: to prevent the client from expiring read timeouts during writes,
4390 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004391 t->crexpire = t->cwexpire;
4392 }
willy tarreau0f7af912005-12-17 12:21:26 +01004393 else
4394 tv_eternity(&t->cwexpire);
4395 }
4396 }
4397 return 0; /* other cases change nothing */
4398 }
4399 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004400 if (t->res_cw == RES_ERROR) {
4401 tv_eternity(&t->cwexpire);
4402 fd_delete(t->cli_fd);
4403 t->cli_state = CL_STCLOSE;
4404 if (!(t->flags & SN_ERR_MASK))
4405 t->flags |= SN_ERR_CLICL;
4406 if (!(t->flags & SN_FINST_MASK))
4407 t->flags |= SN_FINST_D;
4408 return 1;
4409 }
4410 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004411 tv_eternity(&t->cwexpire);
4412 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004413 t->cli_state = CL_STCLOSE;
4414 return 1;
4415 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004416 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4417 tv_eternity(&t->cwexpire);
4418 fd_delete(t->cli_fd);
4419 t->cli_state = CL_STCLOSE;
4420 if (!(t->flags & SN_ERR_MASK))
4421 t->flags |= SN_ERR_CLITO;
4422 if (!(t->flags & SN_FINST_MASK))
4423 t->flags |= SN_FINST_D;
4424 return 1;
4425 }
willy tarreau0f7af912005-12-17 12:21:26 +01004426 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004427 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004428 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4429 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4430 tv_eternity(&t->cwexpire);
4431 }
4432 }
4433 else { /* buffer not empty */
4434 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4435 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004436 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004437 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004438 /* FIXME: to prevent the client from expiring read timeouts during writes,
4439 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004440 t->crexpire = t->cwexpire;
4441 }
willy tarreau0f7af912005-12-17 12:21:26 +01004442 else
4443 tv_eternity(&t->cwexpire);
4444 }
4445 }
4446 return 0;
4447 }
4448 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004449 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004450 tv_eternity(&t->crexpire);
4451 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004452 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004453 if (!(t->flags & SN_ERR_MASK))
4454 t->flags |= SN_ERR_CLICL;
4455 if (!(t->flags & SN_FINST_MASK))
4456 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004457 return 1;
4458 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004459 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4460 tv_eternity(&t->crexpire);
4461 fd_delete(t->cli_fd);
4462 t->cli_state = CL_STCLOSE;
4463 return 1;
4464 }
4465 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4466 tv_eternity(&t->crexpire);
4467 fd_delete(t->cli_fd);
4468 t->cli_state = CL_STCLOSE;
4469 if (!(t->flags & SN_ERR_MASK))
4470 t->flags |= SN_ERR_CLITO;
4471 if (!(t->flags & SN_FINST_MASK))
4472 t->flags |= SN_FINST_D;
4473 return 1;
4474 }
willy tarreauef900ab2005-12-17 12:52:52 +01004475 else if (req->l >= req->rlim - req->data) {
4476 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004477
4478 /* FIXME-20050705: is it possible for a client to maintain a session
4479 * after the timeout by sending more data after it receives a close ?
4480 */
4481
willy tarreau0f7af912005-12-17 12:21:26 +01004482 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004483 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004484 FD_CLR(t->cli_fd, StaticReadEvent);
4485 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004486 //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 +01004487 }
4488 }
4489 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004490 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004491 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4492 FD_SET(t->cli_fd, StaticReadEvent);
4493 if (t->proxy->clitimeout)
4494 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4495 else
4496 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004497 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004498 }
4499 }
4500 return 0;
4501 }
4502 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004503 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004504 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004505 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 +01004506 write(1, trash, len);
4507 }
4508 return 0;
4509 }
4510 return 0;
4511}
4512
willy tarreaudfece232006-05-02 00:19:57 +02004513/* This function turns the server state into the SV_STCLOSE, and sets
4514 * indicators accordingly. Note that if <status> is 0, no message is
4515 * returned.
4516 */
4517void srv_close_with_err(struct session *t, int err, int finst, int status, int msglen, char *msg) {
4518 t->srv_state = SV_STCLOSE;
4519 if (status > 0) {
4520 t->logs.status = status;
4521 if (t->proxy->mode == PR_MODE_HTTP)
4522 client_return(t, msglen, msg);
4523 }
4524 if (!(t->flags & SN_ERR_MASK))
4525 t->flags |= err;
4526 if (!(t->flags & SN_FINST_MASK))
4527 t->flags |= finst;
4528}
4529
4530/*
4531 * This function checks the retry count during the connect() job.
4532 * It updates the session's srv_state and retries, so that the caller knows
4533 * what it has to do. It uses the last connection error to set the log when
4534 * it expires. It returns 1 when it has expired, and 0 otherwise.
4535 */
4536int srv_count_retry_down(struct session *t, int conn_err) {
4537 /* we are in front of a retryable error */
4538 t->conn_retries--;
4539 if (t->conn_retries < 0) {
4540 /* if not retryable anymore, let's abort */
4541 tv_eternity(&t->cnexpire);
4542 srv_close_with_err(t, conn_err, SN_FINST_C,
4543 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4544
4545 /* We used to have a free connection slot. Since we'll never use it,
4546 * we have to pass it on to another session.
4547 */
4548 if (t->srv)
4549 offer_connection_slot(t);
4550 return 1;
4551 }
4552 return 0;
4553}
willy tarreau0f7af912005-12-17 12:21:26 +01004554
4555/*
willy tarreaudfece232006-05-02 00:19:57 +02004556 * This function performs the retryable part of the connect() job.
4557 * It updates the session's srv_state and retries, so that the caller knows
4558 * what it has to do. It returns 1 when it breaks out of the loop, or 0 if
4559 * it needs to redispatch.
4560 */
4561int srv_retryable_connect(struct session *t) {
4562 int conn_err;
4563
4564 /* This loop ensures that we stop before the last retry in case of a
4565 * redispatchable server.
4566 */
4567 do {
4568 /* initiate a connection to the server */
4569 conn_err = connect_server(t);
4570 switch (conn_err) {
4571
4572 case SN_ERR_NONE:
4573 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4574 t->srv_state = SV_STCONN;
4575 return 1;
4576
4577 case SN_ERR_INTERNAL:
4578 tv_eternity(&t->cnexpire);
4579 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4580 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4581 /* release other sessions waiting for this server */
4582 if (t->srv)
4583 offer_connection_slot(t);
4584 return 1;
4585 }
4586 /* ensure that we have enough retries left */
4587 if (srv_count_retry_down(t, conn_err))
4588 return 1;
4589 } while (t->srv == NULL || t->conn_retries > 0 || !(t->proxy->options & PR_O_REDISP));
4590
4591 /* We're on our last chance, and the REDISP option was specified.
4592 * We will ignore cookie and force to balance or use the dispatcher.
4593 */
4594 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
4595 t->srv = NULL; /* it's left to the dispatcher to choose a server */
4596 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4597 t->flags &= ~SN_CK_MASK;
4598 t->flags |= SN_CK_DOWN;
4599 }
4600 return 0;
4601}
4602
4603/* This function performs the "redispatch" part of a connection attempt. It
4604 * will assign a server if required, queue the connection if required, and
4605 * handle errors that might arise at this level. It can change the server
4606 * state. It will return 1 if it encounters an error, switches the server
4607 * state, or has to queue a connection. Otherwise, it will return 0 indicating
4608 * that the connection is ready to use.
4609 */
4610
4611int srv_redispatch_connect(struct session *t) {
4612 int conn_err;
4613
4614 /* We know that we don't have any connection pending, so we will
4615 * try to get a new one, and wait in this state if it's queued
4616 */
4617 conn_err = assign_server_and_queue(t);
4618 switch (conn_err) {
4619 case SRV_STATUS_OK:
4620 break;
4621
4622 case SRV_STATUS_NOSRV:
4623 tv_eternity(&t->cnexpire);
4624 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_C,
4625 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
4626
4627 /* FIXME-20060501: we should not need this once we flush every session
4628 * when the last server goes down.
4629 */
4630 /* release other sessions waiting for this server */
4631 if (t->srv)
4632 offer_connection_slot(t);
4633 return 1;
4634
4635 case SRV_STATUS_QUEUED:
4636 t->srv_state = SV_STIDLE;
4637 /* do nothing else and do not wake any other session up */
4638 return 1;
4639
4640 case SRV_STATUS_FULL:
4641 case SRV_STATUS_INTERNAL:
4642 default:
4643 tv_eternity(&t->cnexpire);
4644 srv_close_with_err(t, SN_ERR_INTERNAL, SN_FINST_C,
4645 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
4646 /* release other sessions waiting for this server */
4647 if (t->srv)
4648 offer_connection_slot(t);
4649 return 1;
4650 }
4651 /* if we get here, it's because we got SRV_STATUS_OK, which also
4652 * means that the connection has not been queued.
4653 */
4654 return 0;
4655}
4656
4657
4658/*
willy tarreau0f7af912005-12-17 12:21:26 +01004659 * manages the server FSM and its socket. It returns 1 if a state has changed
4660 * (and a resync may be needed), 0 else.
4661 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004662int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004663 int s = t->srv_state;
4664 int c = t->cli_state;
4665 struct buffer *req = t->req;
4666 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004667 appsess *asession_temp = NULL;
4668 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004669 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004670
willy tarreau750a4722005-12-17 13:21:24 +01004671#ifdef DEBUG_FULL
4672 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4673#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004674 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4675 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4676 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4677 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004678 if (s == SV_STIDLE) {
4679 if (c == CL_STHEADERS)
4680 return 0; /* stay in idle, waiting for data to reach the client side */
4681 else if (c == CL_STCLOSE ||
4682 c == CL_STSHUTW ||
4683 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4684 tv_eternity(&t->cnexpire);
willy tarreaudfece232006-05-02 00:19:57 +02004685 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
4686
4687 /* it might be possible that we have been granted an access to the
4688 * server while waiting for a free slot. Since we'll never use it,
4689 * we have to pass it on to another session.
4690 */
4691 if (t->srv)
4692 offer_connection_slot(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004693 return 1;
4694 }
willy tarreaudfece232006-05-02 00:19:57 +02004695 else {
4696 /* Right now, we will need to create a connection to the server.
4697 * We might already have tried, and got a connection pending, in
4698 * which case we will not do anything till it's pending. It's up
4699 * to any other session to release it and wake us up again.
4700 */
4701 if (t->pend_pos)
4702 return 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004703
willy tarreaudfece232006-05-02 00:19:57 +02004704 do {
4705 /* first, get a connection */
4706 if (srv_redispatch_connect(t))
4707 return t->srv_state != SV_STIDLE;
4708
4709 /* try to (re-)connect to the server, and fail if we expire the
4710 * number of retries.
4711 */
4712 if (srv_retryable_connect(t))
4713 return t->srv_state != SV_STIDLE;
4714
4715 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004716 }
4717 }
4718 else if (s == SV_STCONN) { /* connection in progress */
4719 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004720 //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 +01004721 return 0; /* nothing changed */
4722 }
4723 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
willy tarreaudfece232006-05-02 00:19:57 +02004724 /* timeout, asynchronous connect error or first write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004725 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
willy tarreaudfece232006-05-02 00:19:57 +02004726
willy tarreau0f7af912005-12-17 12:21:26 +01004727 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004728 if (t->srv)
4729 t->srv->cur_sess--;
willy tarreaudfece232006-05-02 00:19:57 +02004730
4731 if (t->res_sw == RES_SILENT)
willy tarreaub1285d52005-12-18 01:20:14 +01004732 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4733 else
willy tarreaudfece232006-05-02 00:19:57 +02004734 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
willy tarreaub1285d52005-12-18 01:20:14 +01004735
willy tarreaudfece232006-05-02 00:19:57 +02004736 /* ensure that we have enough retries left */
4737 if (srv_count_retry_down(t, conn_err))
4738 return 1;
4739
4740 do {
4741 /* Now we will try to either reconnect to the same server or
4742 * connect to another server. If the connection gets queued
4743 * because all servers are saturated, then we will go back to
4744 * the SV_STIDLE state.
4745 */
4746 if (srv_retryable_connect(t))
4747 return t->srv_state != SV_STCONN;
4748
4749 /* we need to redispatch the connection to another server */
4750 if (srv_redispatch_connect(t))
4751 return t->srv_state != SV_STCONN;
4752 } while (1);
willy tarreau0f7af912005-12-17 12:21:26 +01004753 }
4754 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004755 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004756
willy tarreau0f7af912005-12-17 12:21:26 +01004757 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004758 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004759 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004760 tv_eternity(&t->swexpire);
4761 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004762 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004763 if (t->proxy->srvtimeout) {
4764 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02004765 /* FIXME: to prevent the server from expiring read timeouts during writes,
4766 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004767 t->srexpire = t->swexpire;
4768 }
4769 else
4770 tv_eternity(&t->swexpire);
4771 }
willy tarreau0f7af912005-12-17 12:21:26 +01004772
4773 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4774 FD_SET(t->srv_fd, StaticReadEvent);
4775 if (t->proxy->srvtimeout)
4776 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4777 else
4778 tv_eternity(&t->srexpire);
4779
4780 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004781 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004782 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004783
4784 /* if the user wants to log as soon as possible, without counting
4785 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004786 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004787 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4788 sess_log(t);
4789 }
willy tarreau0f7af912005-12-17 12:21:26 +01004790 }
willy tarreauef900ab2005-12-17 12:52:52 +01004791 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004792 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004793 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004794 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4795 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004796 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004797 return 1;
4798 }
4799 }
4800 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004801 /* now parse the partial (or complete) headers */
4802 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4803 char *ptr;
4804 int delete_header;
4805
4806 ptr = rep->lr;
4807
4808 /* look for the end of the current header */
4809 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4810 ptr++;
4811
4812 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004813 int line, len;
4814
4815 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004816
4817 /* first, we'll block if security checks have caught nasty things */
4818 if (t->flags & SN_CACHEABLE) {
4819 if ((t->flags & SN_CACHE_COOK) &&
4820 (t->flags & SN_SCK_ANY) &&
4821 (t->proxy->options & PR_O_CHK_CACHE)) {
4822
4823 /* we're in presence of a cacheable response containing
4824 * a set-cookie header. We'll block it as requested by
4825 * the 'checkcache' option, and send an alert.
4826 */
4827 tv_eternity(&t->srexpire);
4828 tv_eternity(&t->swexpire);
4829 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004830 if (t->srv)
4831 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004832 t->srv_state = SV_STCLOSE;
4833 t->logs.status = 502;
4834 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4835 if (!(t->flags & SN_ERR_MASK))
4836 t->flags |= SN_ERR_PRXCOND;
4837 if (!(t->flags & SN_FINST_MASK))
4838 t->flags |= SN_FINST_H;
4839
4840 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4841 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4842
willy tarreaudfece232006-05-02 00:19:57 +02004843 /* We used to have a free connection slot. Since we'll never use it,
4844 * we have to pass it on to another session.
4845 */
4846 if (t->srv)
4847 offer_connection_slot(t);
4848
willy tarreau97f58572005-12-18 00:53:44 +01004849 return 1;
4850 }
4851 }
4852
willy tarreau982249e2005-12-18 00:57:06 +01004853 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4854 if (t->flags & SN_SVDENY) {
4855 tv_eternity(&t->srexpire);
4856 tv_eternity(&t->swexpire);
4857 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02004858 if (t->srv)
4859 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004860 t->srv_state = SV_STCLOSE;
4861 t->logs.status = 502;
4862 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4863 if (!(t->flags & SN_ERR_MASK))
4864 t->flags |= SN_ERR_PRXCOND;
4865 if (!(t->flags & SN_FINST_MASK))
4866 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02004867 /* We used to have a free connection slot. Since we'll never use it,
4868 * we have to pass it on to another session.
4869 */
4870 if (t->srv)
4871 offer_connection_slot(t);
4872
willy tarreau982249e2005-12-18 00:57:06 +01004873 return 1;
4874 }
4875
willy tarreau5cbea6f2005-12-17 12:48:26 +01004876 /* we'll have something else to do here : add new headers ... */
4877
willy tarreaucd878942005-12-17 13:27:43 +01004878 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4879 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004880 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004881 * insert a set-cookie here, except if we want to insert only on POST
4882 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004883 */
willy tarreau750a4722005-12-17 13:21:24 +01004884 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004885 t->proxy->cookie_name,
4886 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004887
willy tarreau036e1ce2005-12-17 13:46:33 +01004888 t->flags |= SN_SCK_INSERTED;
4889
willy tarreau750a4722005-12-17 13:21:24 +01004890 /* Here, we will tell an eventual cache on the client side that we don't
4891 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4892 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4893 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4894 */
willy tarreau240afa62005-12-17 13:14:35 +01004895 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004896 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4897 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004898
4899 if (rep->data + rep->l < rep->h)
4900 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4901 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004902 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004903 }
4904
4905 /* headers to be added */
4906 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004907 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4908 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004909 }
4910
willy tarreau25c4ea52005-12-18 00:49:49 +01004911 /* add a "connection: close" line if needed */
4912 if (t->proxy->options & PR_O_HTTP_CLOSE)
4913 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4914
willy tarreau5cbea6f2005-12-17 12:48:26 +01004915 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004916 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004917 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004918
Willy TARREAU767ba712006-03-01 22:40:50 +01004919 /* client connection already closed or option 'httpclose' required :
4920 * we close the server's outgoing connection right now.
4921 */
4922 if ((req->l == 0) &&
4923 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4924 FD_CLR(t->srv_fd, StaticWriteEvent);
4925 tv_eternity(&t->swexpire);
4926
4927 /* We must ensure that the read part is still alive when switching
4928 * to shutw */
4929 FD_SET(t->srv_fd, StaticReadEvent);
4930 if (t->proxy->srvtimeout)
4931 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4932
4933 shutdown(t->srv_fd, SHUT_WR);
4934 t->srv_state = SV_STSHUTW;
4935 }
4936
willy tarreau25c4ea52005-12-18 00:49:49 +01004937 /* if the user wants to log as soon as possible, without counting
4938 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004939 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004940 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4941 t->logs.bytes = rep->h - rep->data;
4942 sess_log(t);
4943 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944 break;
4945 }
4946
4947 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4948 if (ptr > rep->r - 2) {
4949 /* this is a partial header, let's wait for more to come */
4950 rep->lr = ptr;
4951 break;
4952 }
4953
4954 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4955 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4956
4957 /* now we know that *ptr is either \r or \n,
4958 * and that there are at least 1 char after it.
4959 */
4960 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4961 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4962 else
4963 rep->lr = ptr + 2; /* \r\n or \n\r */
4964
4965 /*
4966 * now we know that we have a full header ; we can do whatever
4967 * we want with these pointers :
4968 * rep->h = beginning of header
4969 * ptr = end of header (first \r or \n)
4970 * rep->lr = beginning of next line (next rep->h)
4971 * rep->r = end of data (not used at this stage)
4972 */
4973
willy tarreaua1598082005-12-17 13:08:06 +01004974
willy tarreau982249e2005-12-18 00:57:06 +01004975 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004976 t->logs.logwait &= ~LW_RESP;
4977 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004978 switch (t->logs.status) {
4979 case 200:
4980 case 203:
4981 case 206:
4982 case 300:
4983 case 301:
4984 case 410:
4985 /* RFC2616 @13.4:
4986 * "A response received with a status code of
4987 * 200, 203, 206, 300, 301 or 410 MAY be stored
4988 * by a cache (...) unless a cache-control
4989 * directive prohibits caching."
4990 *
4991 * RFC2616 @9.5: POST method :
4992 * "Responses to this method are not cacheable,
4993 * unless the response includes appropriate
4994 * Cache-Control or Expires header fields."
4995 */
4996 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4997 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4998 break;
4999 default:
5000 break;
5001 }
willy tarreau4302f492005-12-18 01:00:37 +01005002 }
5003 else if (t->logs.logwait & LW_RSPHDR) {
5004 struct cap_hdr *h;
5005 int len;
5006 for (h = t->proxy->rsp_cap; h; h = h->next) {
5007 if ((h->namelen + 2 <= ptr - rep->h) &&
5008 (rep->h[h->namelen] == ':') &&
5009 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
5010
5011 if (t->rsp_cap[h->index] == NULL)
5012 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
5013
5014 len = ptr - (rep->h + h->namelen + 2);
5015 if (len > h->len)
5016 len = h->len;
5017
5018 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
5019 t->rsp_cap[h->index][len]=0;
5020 }
5021 }
5022
willy tarreaua1598082005-12-17 13:08:06 +01005023 }
5024
willy tarreau5cbea6f2005-12-17 12:48:26 +01005025 delete_header = 0;
5026
willy tarreau982249e2005-12-18 00:57:06 +01005027 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005028 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01005029 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 +01005030 max = ptr - rep->h;
5031 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01005032 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005033 trash[len++] = '\n';
5034 write(1, trash, len);
5035 }
5036
willy tarreau25c4ea52005-12-18 00:49:49 +01005037 /* remove "connection: " if needed */
5038 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
5039 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
5040 delete_header = 1;
5041 }
5042
willy tarreau5cbea6f2005-12-17 12:48:26 +01005043 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01005044 if (!delete_header && t->proxy->rsp_exp != NULL
5045 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01005046 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005047 char term;
5048
5049 term = *ptr;
5050 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01005051 exp = t->proxy->rsp_exp;
5052 do {
5053 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
5054 switch (exp->action) {
5055 case ACT_ALLOW:
5056 if (!(t->flags & SN_SVDENY))
5057 t->flags |= SN_SVALLOW;
5058 break;
5059 case ACT_REPLACE:
5060 if (!(t->flags & SN_SVDENY)) {
5061 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
5062 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
5063 }
5064 break;
5065 case ACT_REMOVE:
5066 if (!(t->flags & SN_SVDENY))
5067 delete_header = 1;
5068 break;
5069 case ACT_DENY:
5070 if (!(t->flags & SN_SVALLOW))
5071 t->flags |= SN_SVDENY;
5072 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01005073 case ACT_PASS: /* we simply don't deny this one */
5074 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 }
5076 break;
5077 }
willy tarreaue39cd132005-12-17 13:00:18 +01005078 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 *ptr = term; /* restore the string terminator */
5080 }
5081
willy tarreau97f58572005-12-18 00:53:44 +01005082 /* check for cache-control: or pragma: headers */
5083 if (!delete_header && (t->flags & SN_CACHEABLE)) {
5084 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
5085 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5086 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
5087 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01005088 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01005089 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5090 else {
5091 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01005092 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005093 t->flags &= ~SN_CACHE_COOK;
5094 }
5095 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005096 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01005097 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005098 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01005099 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5100 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01005101 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01005102 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01005103 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
5104 (rep->h + 25 == ptr || rep->h[25] == ',')) {
5105 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
5106 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
5107 (rep->h + 21 == ptr || rep->h[21] == ',')) {
5108 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01005109 }
5110 }
5111 }
5112
willy tarreau5cbea6f2005-12-17 12:48:26 +01005113 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01005114 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01005115 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01005116 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005117 char *p1, *p2, *p3, *p4;
5118
willy tarreau97f58572005-12-18 00:53:44 +01005119 t->flags |= SN_SCK_ANY;
5120
willy tarreau5cbea6f2005-12-17 12:48:26 +01005121 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
5122
5123 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01005124 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005125 p1++;
5126
5127 if (p1 == ptr || *p1 == ';') /* end of cookie */
5128 break;
5129
5130 /* p1 is at the beginning of the cookie name */
5131 p2 = p1;
5132
5133 while (p2 < ptr && *p2 != '=' && *p2 != ';')
5134 p2++;
5135
5136 if (p2 == ptr || *p2 == ';') /* next cookie */
5137 break;
5138
5139 p3 = p2 + 1; /* skips the '=' sign */
5140 if (p3 == ptr)
5141 break;
5142
5143 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01005144 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01005145 p4++;
5146
5147 /* here, we have the cookie name between p1 and p2,
5148 * and its value between p3 and p4.
5149 * we can process it.
5150 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005151
5152 /* first, let's see if we want to capture it */
5153 if (t->proxy->capture_name != NULL &&
5154 t->logs.srv_cookie == NULL &&
5155 (p4 - p1 >= t->proxy->capture_namelen) &&
5156 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
5157 int log_len = p4 - p1;
5158
5159 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
5160 Alert("HTTP logging : out of memory.\n");
5161 }
5162
5163 if (log_len > t->proxy->capture_len)
5164 log_len = t->proxy->capture_len;
5165 memcpy(t->logs.srv_cookie, p1, log_len);
5166 t->logs.srv_cookie[log_len] = 0;
5167 }
5168
5169 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
5170 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01005172 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005173
5174 /* If the cookie is in insert mode on a known server, we'll delete
5175 * this occurrence because we'll insert another one later.
5176 * We'll delete it too if the "indirect" option is set and we're in
5177 * a direct access. */
5178 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01005179 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005180 /* this header must be deleted */
5181 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01005182 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005183 }
5184 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
5185 /* replace bytes p3->p4 with the cookie name associated
5186 * with this server since we know it.
5187 */
5188 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01005189 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005190 }
willy tarreau0174f312005-12-18 01:02:42 +01005191 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
5192 /* insert the cookie name associated with this server
5193 * before existing cookie, and insert a delimitor between them..
5194 */
5195 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5196 p3[t->srv->cklen] = COOKIE_DELIM;
5197 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
5198 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005199 break;
5200 }
willy tarreau12350152005-12-18 01:03:27 +01005201
5202 /* first, let's see if the cookie is our appcookie*/
5203 if ((t->proxy->appsession_name != NULL) &&
5204 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
5205
5206 /* Cool... it's the right one */
5207
willy tarreaub952e1d2005-12-18 01:31:20 +01005208 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01005209 asession_temp = &local_asession;
5210
willy tarreaub952e1d2005-12-18 01:31:20 +01005211 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005212 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5213 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5214 }
5215 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
5216 asession_temp->sessid[t->proxy->appsession_len] = 0;
5217 asession_temp->serverid = NULL;
5218
5219 /* only do insert, if lookup fails */
5220 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
5221 if ((asession_temp = pool_alloc(appsess)) == NULL) {
5222 Alert("Not enought Memory process_srv():asession:calloc().\n");
5223 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
5224 return 0;
5225 }
5226 asession_temp->sessid = local_asession.sessid;
5227 asession_temp->serverid = local_asession.serverid;
5228 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01005229 }/* end if (chtbl_lookup()) */
5230 else {
willy tarreau12350152005-12-18 01:03:27 +01005231 /* free wasted memory */
5232 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01005233 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01005234
willy tarreaub952e1d2005-12-18 01:31:20 +01005235 if (asession_temp->serverid == NULL) {
5236 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01005237 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
5238 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
5239 }
5240 asession_temp->serverid[0] = '\0';
5241 }
5242
willy tarreaub952e1d2005-12-18 01:31:20 +01005243 if (asession_temp->serverid[0] == '\0')
5244 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01005245
5246 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
5247
5248#if defined(DEBUG_HASH)
5249 print_table(&(t->proxy->htbl_proxy));
5250#endif
5251 break;
5252 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005253 else {
5254 // fprintf(stderr,"Ignoring unknown cookie : ");
5255 // write(2, p1, p2-p1);
5256 // fprintf(stderr," = ");
5257 // write(2, p3, p4-p3);
5258 // fprintf(stderr,"\n");
5259 }
5260 break; /* we don't want to loop again since there cannot be another cookie on the same line */
5261 } /* we're now at the end of the cookie value */
5262 } /* end of cookie processing */
5263
willy tarreau97f58572005-12-18 00:53:44 +01005264 /* check for any set-cookie in case we check for cacheability */
5265 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
5266 (t->proxy->options & PR_O_CHK_CACHE) &&
5267 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
5268 t->flags |= SN_SCK_ANY;
5269 }
5270
willy tarreau5cbea6f2005-12-17 12:48:26 +01005271 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01005272 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005273 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01005274
willy tarreau5cbea6f2005-12-17 12:48:26 +01005275 rep->h = rep->lr;
5276 } /* while (rep->lr < rep->r) */
5277
5278 /* end of header processing (even if incomplete) */
5279
willy tarreauef900ab2005-12-17 12:52:52 +01005280 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5281 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
5282 * full. We cannot loop here since event_srv_read will disable it only if
5283 * rep->l == rlim-data
5284 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 FD_SET(t->srv_fd, StaticReadEvent);
5286 if (t->proxy->srvtimeout)
5287 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5288 else
5289 tv_eternity(&t->srexpire);
5290 }
willy tarreau0f7af912005-12-17 12:21:26 +01005291
willy tarreau8337c6b2005-12-17 13:41:01 +01005292 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01005293 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005294 tv_eternity(&t->srexpire);
5295 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005296 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005297 if (t->srv)
5298 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005299 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01005300 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01005301 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01005302 if (!(t->flags & SN_ERR_MASK))
5303 t->flags |= SN_ERR_SRVCL;
5304 if (!(t->flags & SN_FINST_MASK))
5305 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005306 /* We used to have a free connection slot. Since we'll never use it,
5307 * we have to pass it on to another session.
5308 */
5309 if (t->srv)
5310 offer_connection_slot(t);
5311
willy tarreau0f7af912005-12-17 12:21:26 +01005312 return 1;
5313 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005314 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01005315 * since we are in header mode, if there's no space left for headers, we
5316 * won't be able to free more later, so the session will never terminate.
5317 */
willy tarreau8337c6b2005-12-17 13:41:01 +01005318 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 +01005319 FD_CLR(t->srv_fd, StaticReadEvent);
5320 tv_eternity(&t->srexpire);
5321 shutdown(t->srv_fd, SHUT_RD);
5322 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005323 //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 +01005324 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01005325 }
5326 /* read timeout : return a 504 to the client.
5327 */
5328 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5329 tv_eternity(&t->srexpire);
5330 tv_eternity(&t->swexpire);
5331 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005332 if (t->srv)
5333 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01005334 t->srv_state = SV_STCLOSE;
5335 t->logs.status = 504;
5336 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01005337 if (!(t->flags & SN_ERR_MASK))
5338 t->flags |= SN_ERR_SRVTO;
5339 if (!(t->flags & SN_FINST_MASK))
5340 t->flags |= SN_FINST_H;
willy tarreaudfece232006-05-02 00:19:57 +02005341 /* We used to have a free connection slot. Since we'll never use it,
5342 * we have to pass it on to another session.
5343 */
5344 if (t->srv)
5345 offer_connection_slot(t);
5346
willy tarreau8337c6b2005-12-17 13:41:01 +01005347 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005348 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005349 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01005350 /* FIXME!!! here, we don't want to switch to SHUTW if the
5351 * client shuts read too early, because we may still have
5352 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01005353 * The side-effect is that if the client completely closes its
5354 * connection during SV_STHEADER, the connection to the server
5355 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01005356 */
willy tarreau036e1ce2005-12-17 13:46:33 +01005357 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01005358 FD_CLR(t->srv_fd, StaticWriteEvent);
5359 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01005360
5361 /* We must ensure that the read part is still alive when switching
5362 * to shutw */
5363 FD_SET(t->srv_fd, StaticReadEvent);
5364 if (t->proxy->srvtimeout)
5365 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5366
willy tarreau0f7af912005-12-17 12:21:26 +01005367 shutdown(t->srv_fd, SHUT_WR);
5368 t->srv_state = SV_STSHUTW;
5369 return 1;
5370 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005371 /* write timeout */
5372 /* FIXME!!! here, we don't want to switch to SHUTW if the
5373 * client shuts read too early, because we may still have
5374 * some work to do on the headers.
5375 */
5376 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5377 FD_CLR(t->srv_fd, StaticWriteEvent);
5378 tv_eternity(&t->swexpire);
5379 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005380 /* We must ensure that the read part is still alive when switching
5381 * to shutw */
5382 FD_SET(t->srv_fd, StaticReadEvent);
5383 if (t->proxy->srvtimeout)
5384 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5385
5386 /* We must ensure that the read part is still alive when switching
5387 * to shutw */
5388 FD_SET(t->srv_fd, StaticReadEvent);
5389 if (t->proxy->srvtimeout)
5390 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5391
willy tarreau036e1ce2005-12-17 13:46:33 +01005392 t->srv_state = SV_STSHUTW;
5393 if (!(t->flags & SN_ERR_MASK))
5394 t->flags |= SN_ERR_SRVTO;
5395 if (!(t->flags & SN_FINST_MASK))
5396 t->flags |= SN_FINST_H;
5397 return 1;
5398 }
willy tarreau0f7af912005-12-17 12:21:26 +01005399
5400 if (req->l == 0) {
5401 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5402 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5403 tv_eternity(&t->swexpire);
5404 }
5405 }
5406 else { /* client buffer not empty */
5407 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5408 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005409 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005410 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005411 /* FIXME: to prevent the server from expiring read timeouts during writes,
5412 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005413 t->srexpire = t->swexpire;
5414 }
willy tarreau0f7af912005-12-17 12:21:26 +01005415 else
5416 tv_eternity(&t->swexpire);
5417 }
5418 }
5419
willy tarreau5cbea6f2005-12-17 12:48:26 +01005420 /* be nice with the client side which would like to send a complete header
5421 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5422 * would read all remaining data at once ! The client should not write past rep->lr
5423 * when the server is in header state.
5424 */
5425 //return header_processed;
5426 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005427 }
5428 else if (s == SV_STDATA) {
5429 /* read or write error */
5430 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005431 tv_eternity(&t->srexpire);
5432 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005433 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005434 if (t->srv)
5435 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005436 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005437 if (!(t->flags & SN_ERR_MASK))
5438 t->flags |= SN_ERR_SRVCL;
5439 if (!(t->flags & SN_FINST_MASK))
5440 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005441 /* We used to have a free connection slot. Since we'll never use it,
5442 * we have to pass it on to another session.
5443 */
5444 if (t->srv)
5445 offer_connection_slot(t);
5446
willy tarreau0f7af912005-12-17 12:21:26 +01005447 return 1;
5448 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005449 /* last read, or end of client write */
5450 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005451 FD_CLR(t->srv_fd, StaticReadEvent);
5452 tv_eternity(&t->srexpire);
5453 shutdown(t->srv_fd, SHUT_RD);
5454 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005455 //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 +01005456 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005457 }
5458 /* end of client read and no more data to send */
5459 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5460 FD_CLR(t->srv_fd, StaticWriteEvent);
5461 tv_eternity(&t->swexpire);
5462 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005463 /* We must ensure that the read part is still alive when switching
5464 * to shutw */
5465 FD_SET(t->srv_fd, StaticReadEvent);
5466 if (t->proxy->srvtimeout)
5467 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5468
willy tarreaua41a8b42005-12-17 14:02:24 +01005469 t->srv_state = SV_STSHUTW;
5470 return 1;
5471 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005472 /* read timeout */
5473 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5474 FD_CLR(t->srv_fd, StaticReadEvent);
5475 tv_eternity(&t->srexpire);
5476 shutdown(t->srv_fd, SHUT_RD);
5477 t->srv_state = SV_STSHUTR;
5478 if (!(t->flags & SN_ERR_MASK))
5479 t->flags |= SN_ERR_SRVTO;
5480 if (!(t->flags & SN_FINST_MASK))
5481 t->flags |= SN_FINST_D;
5482 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005483 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005484 /* write timeout */
5485 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005486 FD_CLR(t->srv_fd, StaticWriteEvent);
5487 tv_eternity(&t->swexpire);
5488 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005489 /* We must ensure that the read part is still alive when switching
5490 * to shutw */
5491 FD_SET(t->srv_fd, StaticReadEvent);
5492 if (t->proxy->srvtimeout)
5493 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005494 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005495 if (!(t->flags & SN_ERR_MASK))
5496 t->flags |= SN_ERR_SRVTO;
5497 if (!(t->flags & SN_FINST_MASK))
5498 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005499 return 1;
5500 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005501
5502 /* recompute request time-outs */
5503 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005504 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5505 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5506 tv_eternity(&t->swexpire);
5507 }
5508 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005509 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005510 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5511 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005512 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005513 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005514 /* FIXME: to prevent the server from expiring read timeouts during writes,
5515 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005516 t->srexpire = t->swexpire;
5517 }
willy tarreau0f7af912005-12-17 12:21:26 +01005518 else
5519 tv_eternity(&t->swexpire);
5520 }
5521 }
5522
willy tarreaub1ff9db2005-12-17 13:51:03 +01005523 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005524 if (rep->l == BUFSIZE) { /* no room to read more data */
5525 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5526 FD_CLR(t->srv_fd, StaticReadEvent);
5527 tv_eternity(&t->srexpire);
5528 }
5529 }
5530 else {
5531 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5532 FD_SET(t->srv_fd, StaticReadEvent);
5533 if (t->proxy->srvtimeout)
5534 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5535 else
5536 tv_eternity(&t->srexpire);
5537 }
5538 }
5539
5540 return 0; /* other cases change nothing */
5541 }
5542 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005543 if (t->res_sw == RES_ERROR) {
5544 //FD_CLR(t->srv_fd, StaticWriteEvent);
5545 tv_eternity(&t->swexpire);
5546 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005547 if (t->srv)
5548 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005549 //close(t->srv_fd);
5550 t->srv_state = SV_STCLOSE;
5551 if (!(t->flags & SN_ERR_MASK))
5552 t->flags |= SN_ERR_SRVCL;
5553 if (!(t->flags & SN_FINST_MASK))
5554 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005555 /* We used to have a free connection slot. Since we'll never use it,
5556 * we have to pass it on to another session.
5557 */
5558 if (t->srv)
5559 offer_connection_slot(t);
5560
willy tarreau036e1ce2005-12-17 13:46:33 +01005561 return 1;
5562 }
5563 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005564 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005565 tv_eternity(&t->swexpire);
5566 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005567 if (t->srv)
5568 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005569 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005570 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005571 /* We used to have a free connection slot. Since we'll never use it,
5572 * we have to pass it on to another session.
5573 */
5574 if (t->srv)
5575 offer_connection_slot(t);
5576
willy tarreau0f7af912005-12-17 12:21:26 +01005577 return 1;
5578 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005579 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5580 //FD_CLR(t->srv_fd, StaticWriteEvent);
5581 tv_eternity(&t->swexpire);
5582 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005583 if (t->srv)
5584 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005585 //close(t->srv_fd);
5586 t->srv_state = SV_STCLOSE;
5587 if (!(t->flags & SN_ERR_MASK))
5588 t->flags |= SN_ERR_SRVTO;
5589 if (!(t->flags & SN_FINST_MASK))
5590 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005591 /* We used to have a free connection slot. Since we'll never use it,
5592 * we have to pass it on to another session.
5593 */
5594 if (t->srv)
5595 offer_connection_slot(t);
5596
willy tarreau036e1ce2005-12-17 13:46:33 +01005597 return 1;
5598 }
willy tarreau0f7af912005-12-17 12:21:26 +01005599 else if (req->l == 0) {
5600 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5601 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5602 tv_eternity(&t->swexpire);
5603 }
5604 }
5605 else { /* buffer not empty */
5606 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5607 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005608 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005609 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreau0889c962006-04-24 14:36:48 +02005610 /* FIXME: to prevent the server from expiring read timeouts during writes,
5611 * we refresh it. */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005612 t->srexpire = t->swexpire;
5613 }
willy tarreau0f7af912005-12-17 12:21:26 +01005614 else
5615 tv_eternity(&t->swexpire);
5616 }
5617 }
5618 return 0;
5619 }
5620 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005621 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005622 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005623 tv_eternity(&t->srexpire);
5624 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005625 if (t->srv)
5626 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005627 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005628 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005629 if (!(t->flags & SN_ERR_MASK))
5630 t->flags |= SN_ERR_SRVCL;
5631 if (!(t->flags & SN_FINST_MASK))
5632 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005633 /* We used to have a free connection slot. Since we'll never use it,
5634 * we have to pass it on to another session.
5635 */
5636 if (t->srv)
5637 offer_connection_slot(t);
5638
willy tarreau0f7af912005-12-17 12:21:26 +01005639 return 1;
5640 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005641 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5642 //FD_CLR(t->srv_fd, StaticReadEvent);
5643 tv_eternity(&t->srexpire);
5644 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005645 if (t->srv)
5646 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005647 //close(t->srv_fd);
5648 t->srv_state = SV_STCLOSE;
willy tarreaudfece232006-05-02 00:19:57 +02005649 /* We used to have a free connection slot. Since we'll never use it,
5650 * we have to pass it on to another session.
5651 */
5652 if (t->srv)
5653 offer_connection_slot(t);
5654
willy tarreau036e1ce2005-12-17 13:46:33 +01005655 return 1;
5656 }
5657 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5658 //FD_CLR(t->srv_fd, StaticReadEvent);
5659 tv_eternity(&t->srexpire);
5660 fd_delete(t->srv_fd);
willy tarreau926a3572006-05-01 15:26:35 +02005661 if (t->srv)
5662 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005663 //close(t->srv_fd);
5664 t->srv_state = SV_STCLOSE;
5665 if (!(t->flags & SN_ERR_MASK))
5666 t->flags |= SN_ERR_SRVTO;
5667 if (!(t->flags & SN_FINST_MASK))
5668 t->flags |= SN_FINST_D;
willy tarreaudfece232006-05-02 00:19:57 +02005669 /* We used to have a free connection slot. Since we'll never use it,
5670 * we have to pass it on to another session.
5671 */
5672 if (t->srv)
5673 offer_connection_slot(t);
5674
willy tarreau036e1ce2005-12-17 13:46:33 +01005675 return 1;
5676 }
willy tarreau0f7af912005-12-17 12:21:26 +01005677 else if (rep->l == BUFSIZE) { /* no room to read more data */
5678 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5679 FD_CLR(t->srv_fd, StaticReadEvent);
5680 tv_eternity(&t->srexpire);
5681 }
5682 }
5683 else {
5684 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5685 FD_SET(t->srv_fd, StaticReadEvent);
5686 if (t->proxy->srvtimeout)
5687 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5688 else
5689 tv_eternity(&t->srexpire);
5690 }
5691 }
5692 return 0;
5693 }
5694 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005695 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005696 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005697 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 +01005698 write(1, trash, len);
5699 }
5700 return 0;
5701 }
5702 return 0;
5703}
5704
5705
willy tarreau5cbea6f2005-12-17 12:48:26 +01005706/* Processes the client and server jobs of a session task, then
5707 * puts it back to the wait queue in a clean state, or
5708 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005709 * the time the task accepts to wait, or TIME_ETERNITY for
5710 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005711 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005712int process_session(struct task *t) {
5713 struct session *s = t->context;
5714 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005715
willy tarreau5cbea6f2005-12-17 12:48:26 +01005716 do {
5717 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005718 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005719 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005720 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005721 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005722 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005723 } while (fsm_resync);
5724
5725 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005726 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005727 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005728
willy tarreau5cbea6f2005-12-17 12:48:26 +01005729 tv_min(&min1, &s->crexpire, &s->cwexpire);
5730 tv_min(&min2, &s->srexpire, &s->swexpire);
5731 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005732 tv_min(&t->expire, &min1, &min2);
5733
5734 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005735 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005736
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005737#ifdef DEBUG_FULL
5738 /* DEBUG code : this should never ever happen, otherwise it indicates
5739 * that a task still has something to do and will provoke a quick loop.
5740 */
5741 if (tv_remain2(&now, &t->expire) <= 0)
5742 exit(100);
5743#endif
5744
willy tarreaub952e1d2005-12-18 01:31:20 +01005745 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005746 }
5747
willy tarreau5cbea6f2005-12-17 12:48:26 +01005748 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005749 actconn--;
5750
willy tarreau982249e2005-12-18 00:57:06 +01005751 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005752 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005753 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 +01005754 write(1, trash, len);
5755 }
5756
willy tarreau750a4722005-12-17 13:21:24 +01005757 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005758 if (s->rep != NULL)
5759 s->logs.bytes = s->rep->total;
5760
willy tarreau9fe663a2005-12-17 13:02:59 +01005761 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005762 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005763 sess_log(s);
5764
willy tarreau0f7af912005-12-17 12:21:26 +01005765 /* the task MUST not be in the run queue anymore */
5766 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005767 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005768 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005769 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005770}
5771
5772
5773
5774/*
5775 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005776 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005777 */
5778int process_chk(struct task *t) {
5779 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005780 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005781 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005782
willy tarreauef900ab2005-12-17 12:52:52 +01005783 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005784
willy tarreau25424f82006-03-19 19:37:48 +01005785 new_chk:
5786 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005787 if (fd < 0) { /* no check currently running */
5788 //fprintf(stderr, "process_chk: 2\n");
5789 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5790 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005791 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005792 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005793
5794 /* we don't send any health-checks when the proxy is stopped or when
5795 * the server should not be checked.
5796 */
5797 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005798 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5799 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005800 task_queue(t); /* restore t to its place in the task list */
5801 return tv_remain2(&now, &t->expire);
5802 }
5803
willy tarreau5cbea6f2005-12-17 12:48:26 +01005804 /* we'll initiate a new check */
5805 s->result = 0; /* no result yet */
5806 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005807 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005808 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5809 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5810 //fprintf(stderr, "process_chk: 3\n");
5811
willy tarreaua41a8b42005-12-17 14:02:24 +01005812 /* we'll connect to the check port on the server */
5813 sa = s->addr;
5814 sa.sin_port = htons(s->check_port);
5815
willy tarreau0174f312005-12-18 01:02:42 +01005816 /* allow specific binding :
5817 * - server-specific at first
5818 * - proxy-specific next
5819 */
5820 if (s->state & SRV_BIND_SRC) {
5821 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5822 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5823 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5824 s->proxy->id, s->id);
5825 s->result = -1;
5826 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005827 }
willy tarreau0174f312005-12-18 01:02:42 +01005828 else if (s->proxy->options & PR_O_BIND_SRC) {
5829 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5830 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5831 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5832 s->proxy->id);
5833 s->result = -1;
5834 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005835 }
willy tarreau0174f312005-12-18 01:02:42 +01005836
5837 if (!s->result) {
5838 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5839 /* OK, connection in progress or established */
5840
5841 //fprintf(stderr, "process_chk: 4\n");
5842
5843 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5844 fdtab[fd].owner = t;
5845 fdtab[fd].read = &event_srv_chk_r;
5846 fdtab[fd].write = &event_srv_chk_w;
5847 fdtab[fd].state = FD_STCONN; /* connection in progress */
5848 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005849#ifdef DEBUG_FULL
5850 assert (!FD_ISSET(fd, StaticReadEvent));
5851#endif
willy tarreau0174f312005-12-18 01:02:42 +01005852 fd_insert(fd);
5853 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5854 tv_delayfrom(&t->expire, &now, s->inter);
5855 task_queue(t); /* restore t to its place in the task list */
5856 return tv_remain(&now, &t->expire);
5857 }
5858 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5859 s->result = -1; /* a real error */
5860 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005861 }
5862 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005863 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005864 }
5865
5866 if (!s->result) { /* nothing done */
5867 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005868 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5869 tv_delayfrom(&t->expire, &t->expire, s->inter);
5870 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005871 }
5872
5873 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005874 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005875 s->health--; /* still good */
5876 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005877 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005878 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005879 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005880 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005881 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5882 s->state & SRV_BACKUP ? "Backup " : "",
5883 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5884 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5885 send_log(s->proxy, LOG_ALERT,
5886 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5887 s->state & SRV_BACKUP ? "Backup " : "",
5888 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5889 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005890
willy tarreau62084d42006-03-24 18:57:41 +01005891 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005892 Alert("Proxy %s has no server available !\n", s->proxy->id);
5893 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5894 }
5895 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005896 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005897 }
5898
5899 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005900 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005901 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5902 tv_delayfrom(&t->expire, &t->expire, s->inter);
5903 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005904 }
5905 else {
5906 //fprintf(stderr, "process_chk: 8\n");
5907 /* there was a test running */
5908 if (s->result > 0) { /* good server detected */
5909 //fprintf(stderr, "process_chk: 9\n");
5910 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005911 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005912 s->state |= SRV_RUNNING;
5913
willy tarreau535ae7a2005-12-17 12:58:00 +01005914 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005915 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005916 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005917 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5918 s->state & SRV_BACKUP ? "Backup " : "",
5919 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5920 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5921 send_log(s->proxy, LOG_NOTICE,
5922 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5923 s->state & SRV_BACKUP ? "Backup " : "",
5924 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5925 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005926 }
willy tarreauef900ab2005-12-17 12:52:52 +01005927
willy tarreaue47c8d72005-12-17 12:55:52 +01005928 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005929 }
willy tarreauef900ab2005-12-17 12:52:52 +01005930 s->curfd = -1; /* no check running anymore */
5931 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005932 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005933 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5934 tv_delayfrom(&t->expire, &t->expire, s->inter);
5935 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005936 }
5937 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5938 //fprintf(stderr, "process_chk: 10\n");
5939 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005940 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005941 s->health--; /* still good */
5942 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005943 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005944
willy tarreau62084d42006-03-24 18:57:41 +01005945 if (s->health == s->rise) {
5946 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005947 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005948 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5949 s->state & SRV_BACKUP ? "Backup " : "",
5950 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5951 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5952 send_log(s->proxy, LOG_ALERT,
5953 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5954 s->state & SRV_BACKUP ? "Backup " : "",
5955 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5956 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5957
5958 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5959 Alert("Proxy %s has no server available !\n", s->proxy->id);
5960 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5961 }
5962 }
willy tarreauef900ab2005-12-17 12:52:52 +01005963
willy tarreau5cbea6f2005-12-17 12:48:26 +01005964 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005965 }
5966 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005967 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005968 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005969 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5970 tv_delayfrom(&t->expire, &t->expire, s->inter);
5971 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005972 }
5973 /* if result is 0 and there's no timeout, we have to wait again */
5974 }
5975 //fprintf(stderr, "process_chk: 11\n");
5976 s->result = 0;
5977 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005978 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005979}
5980
5981
willy tarreau5cbea6f2005-12-17 12:48:26 +01005982
willy tarreau0f7af912005-12-17 12:21:26 +01005983#if STATTIME > 0
5984int stats(void);
5985#endif
5986
5987/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005988 * This does 4 things :
5989 * - wake up all expired tasks
5990 * - call all runnable tasks
5991 * - call maintain_proxies() to enable/disable the listeners
5992 * - return the delay till next event in ms, -1 = wait indefinitely
5993 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5994 *
willy tarreau0f7af912005-12-17 12:21:26 +01005995 */
5996
willy tarreau1c2ad212005-12-18 01:11:29 +01005997int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005998 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005999 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006000 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01006001
willy tarreaub952e1d2005-12-18 01:31:20 +01006002 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01006003
willy tarreau1c2ad212005-12-18 01:11:29 +01006004 /* look for expired tasks and add them to the run queue.
6005 */
willy tarreau5e698ef2006-05-02 14:51:00 +02006006 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6007 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau1c2ad212005-12-18 01:11:29 +01006008 tnext = t->next;
6009 if (t->state & TASK_RUNNING)
6010 continue;
6011
willy tarreaub952e1d2005-12-18 01:31:20 +01006012 if (tv_iseternity(&t->expire))
6013 continue;
6014
willy tarreau1c2ad212005-12-18 01:11:29 +01006015 /* wakeup expired entries. It doesn't matter if they are
6016 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01006017 */
willy tarreaub952e1d2005-12-18 01:31:20 +01006018 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006019 task_wakeup(&rq, t);
6020 }
6021 else {
6022 /* first non-runnable task. Use its expiration date as an upper bound */
6023 int temp_time = tv_remain(&now, &t->expire);
6024 if (temp_time)
6025 next_time = temp_time;
6026 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006027 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006028 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006029
willy tarreau1c2ad212005-12-18 01:11:29 +01006030 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02006031 * since we only use the run queue's head. Note that any task can be
6032 * woken up by any other task and it will be processed immediately
6033 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01006034 */
willy tarreau7feab592006-04-22 15:13:16 +02006035 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01006036 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02006037
willy tarreau1c2ad212005-12-18 01:11:29 +01006038 task_sleep(&rq, t);
6039 temp_time = t->process(t);
6040 next_time = MINTIME(temp_time, next_time);
6041 }
6042
6043 /* maintain all proxies in a consistent state. This should quickly become a task */
6044 time2 = maintain_proxies();
6045 return MINTIME(time2, next_time);
6046}
6047
6048
6049#if defined(ENABLE_EPOLL)
6050
6051/*
6052 * Main epoll() loop.
6053 */
6054
6055/* does 3 actions :
6056 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6057 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6058 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6059 *
6060 * returns 0 if initialization failed, !0 otherwise.
6061 */
6062
6063int epoll_loop(int action) {
6064 int next_time;
6065 int status;
6066 int fd;
6067
6068 int fds, count;
6069 int pr, pw, sr, sw;
6070 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
6071 struct epoll_event ev;
6072
6073 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01006074 static struct epoll_event *epoll_events = NULL;
6075 static int epoll_fd;
6076
6077 if (action == POLL_LOOP_ACTION_INIT) {
6078 epoll_fd = epoll_create(global.maxsock + 1);
6079 if (epoll_fd < 0)
6080 return 0;
6081 else {
6082 epoll_events = (struct epoll_event*)
6083 calloc(1, sizeof(struct epoll_event) * global.maxsock);
6084 PrevReadEvent = (fd_set *)
6085 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6086 PrevWriteEvent = (fd_set *)
6087 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006088 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006089 return 1;
6090 }
6091 else if (action == POLL_LOOP_ACTION_CLEAN) {
6092 if (PrevWriteEvent) free(PrevWriteEvent);
6093 if (PrevReadEvent) free(PrevReadEvent);
6094 if (epoll_events) free(epoll_events);
6095 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01006096 epoll_fd = 0;
6097 return 1;
6098 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006099
willy tarreau1c2ad212005-12-18 01:11:29 +01006100 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006101
willy tarreau1c2ad212005-12-18 01:11:29 +01006102 tv_now(&now);
6103
6104 while (1) {
6105 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01006106
6107 /* stop when there's no connection left and we don't allow them anymore */
6108 if (!actconn && listeners == 0)
6109 break;
6110
willy tarreau0f7af912005-12-17 12:21:26 +01006111#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01006112 {
6113 int time2;
6114 time2 = stats();
6115 next_time = MINTIME(time2, next_time);
6116 }
willy tarreau0f7af912005-12-17 12:21:26 +01006117#endif
6118
willy tarreau1c2ad212005-12-18 01:11:29 +01006119 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6120
6121 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
6122 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
6123
6124 if ((ro^rn) | (wo^wn)) {
6125 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6126#define FDSETS_ARE_INT_ALIGNED
6127#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01006128
willy tarreauad90a0c2005-12-18 01:09:15 +01006129#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6130#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01006131 pr = (ro >> count) & 1;
6132 pw = (wo >> count) & 1;
6133 sr = (rn >> count) & 1;
6134 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01006135#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006136 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
6137 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
6138 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6139 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01006140#endif
6141#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006142 pr = FD_ISSET(fd, PrevReadEvent);
6143 pw = FD_ISSET(fd, PrevWriteEvent);
6144 sr = FD_ISSET(fd, StaticReadEvent);
6145 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01006146#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01006147 if (!((sr^pr) | (sw^pw)))
6148 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01006149
willy tarreau1c2ad212005-12-18 01:11:29 +01006150 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
6151 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01006152
willy tarreaub952e1d2005-12-18 01:31:20 +01006153#ifdef EPOLL_CTL_MOD_WORKAROUND
6154 /* I encountered a rarely reproducible problem with
6155 * EPOLL_CTL_MOD where a modified FD (systematically
6156 * the one in epoll_events[0], fd#7) would sometimes
6157 * be set EPOLL_OUT while asked for a read ! This is
6158 * with the 2.4 epoll patch. The workaround is to
6159 * delete then recreate in case of modification.
6160 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
6161 * nor RHEL kernels.
6162 */
6163
6164 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
6165 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
6166
6167 if ((sr | sw))
6168 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
6169#else
willy tarreau1c2ad212005-12-18 01:11:29 +01006170 if ((pr | pw)) {
6171 /* the file-descriptor already exists... */
6172 if ((sr | sw)) {
6173 /* ...and it will still exist */
6174 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
6175 // perror("epoll_ctl(MOD)");
6176 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006177 }
6178 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01006179 /* ...and it will be removed */
6180 if (fdtab[fd].state != FD_STCLOSE &&
6181 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
6182 // perror("epoll_ctl(DEL)");
6183 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01006184 }
6185 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006186 } else {
6187 /* the file-descriptor did not exist, let's add it */
6188 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
6189 // perror("epoll_ctl(ADD)");
6190 // exit(1);
6191 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006192 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006193#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01006194 }
6195 ((int*)PrevReadEvent)[fds] = rn;
6196 ((int*)PrevWriteEvent)[fds] = wn;
6197 }
6198 }
6199
6200 /* now let's wait for events */
6201 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
6202 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006203
willy tarreau1c2ad212005-12-18 01:11:29 +01006204 for (count = 0; count < status; count++) {
6205 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01006206
6207 if (FD_ISSET(fd, StaticReadEvent)) {
6208 if (fdtab[fd].state == FD_STCLOSE)
6209 continue;
6210 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
6211 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006212 }
willy tarreau05be12b2006-03-19 19:35:00 +01006213
6214 if (FD_ISSET(fd, StaticWriteEvent)) {
6215 if (fdtab[fd].state == FD_STCLOSE)
6216 continue;
6217 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
6218 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006219 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006220 }
6221 }
6222 return 1;
6223}
6224#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006225
willy tarreauad90a0c2005-12-18 01:09:15 +01006226
willy tarreau5cbea6f2005-12-17 12:48:26 +01006227
willy tarreau1c2ad212005-12-18 01:11:29 +01006228#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01006229
willy tarreau1c2ad212005-12-18 01:11:29 +01006230/*
6231 * Main poll() loop.
6232 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006233
willy tarreau1c2ad212005-12-18 01:11:29 +01006234/* does 3 actions :
6235 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6236 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6237 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6238 *
6239 * returns 0 if initialization failed, !0 otherwise.
6240 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006241
willy tarreau1c2ad212005-12-18 01:11:29 +01006242int poll_loop(int action) {
6243 int next_time;
6244 int status;
6245 int fd, nbfd;
6246
6247 int fds, count;
6248 int sr, sw;
6249 unsigned rn, wn; /* read new, write new */
6250
6251 /* private data */
6252 static struct pollfd *poll_events = NULL;
6253
6254 if (action == POLL_LOOP_ACTION_INIT) {
6255 poll_events = (struct pollfd*)
6256 calloc(1, sizeof(struct pollfd) * global.maxsock);
6257 return 1;
6258 }
6259 else if (action == POLL_LOOP_ACTION_CLEAN) {
6260 if (poll_events)
6261 free(poll_events);
6262 return 1;
6263 }
6264
6265 /* OK, it's POLL_LOOP_ACTION_RUN */
6266
6267 tv_now(&now);
6268
6269 while (1) {
6270 next_time = process_runnable_tasks();
6271
6272 /* stop when there's no connection left and we don't allow them anymore */
6273 if (!actconn && listeners == 0)
6274 break;
6275
6276#if STATTIME > 0
6277 {
6278 int time2;
6279 time2 = stats();
6280 next_time = MINTIME(time2, next_time);
6281 }
6282#endif
6283
6284
6285 nbfd = 0;
6286 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
6287
6288 rn = ((int*)StaticReadEvent)[fds];
6289 wn = ((int*)StaticWriteEvent)[fds];
6290
6291 if ((rn|wn)) {
6292 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
6293#define FDSETS_ARE_INT_ALIGNED
6294#ifdef FDSETS_ARE_INT_ALIGNED
6295
6296#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6297#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
6298 sr = (rn >> count) & 1;
6299 sw = (wn >> count) & 1;
6300#else
6301 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
6302 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
6303#endif
6304#else
6305 sr = FD_ISSET(fd, StaticReadEvent);
6306 sw = FD_ISSET(fd, StaticWriteEvent);
6307#endif
6308 if ((sr|sw)) {
6309 poll_events[nbfd].fd = fd;
6310 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
6311 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01006312 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006313 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006314 }
6315 }
6316
6317 /* now let's wait for events */
6318 status = poll(poll_events, nbfd, next_time);
6319 tv_now(&now);
6320
6321 for (count = 0; status > 0 && count < nbfd; count++) {
6322 fd = poll_events[count].fd;
6323
6324 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
6325 continue;
6326
6327 /* ok, we found one active fd */
6328 status--;
6329
willy tarreau05be12b2006-03-19 19:35:00 +01006330 if (FD_ISSET(fd, StaticReadEvent)) {
6331 if (fdtab[fd].state == FD_STCLOSE)
6332 continue;
6333 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
6334 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006335 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006336
willy tarreau05be12b2006-03-19 19:35:00 +01006337 if (FD_ISSET(fd, StaticWriteEvent)) {
6338 if (fdtab[fd].state == FD_STCLOSE)
6339 continue;
6340 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
6341 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01006342 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006343 }
6344 }
6345 return 1;
6346}
willy tarreauad90a0c2005-12-18 01:09:15 +01006347#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01006348
willy tarreauad90a0c2005-12-18 01:09:15 +01006349
willy tarreauad90a0c2005-12-18 01:09:15 +01006350
willy tarreau1c2ad212005-12-18 01:11:29 +01006351/*
6352 * Main select() loop.
6353 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006354
willy tarreau1c2ad212005-12-18 01:11:29 +01006355/* does 3 actions :
6356 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
6357 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
6358 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
6359 *
6360 * returns 0 if initialization failed, !0 otherwise.
6361 */
willy tarreauad90a0c2005-12-18 01:09:15 +01006362
willy tarreauad90a0c2005-12-18 01:09:15 +01006363
willy tarreau1c2ad212005-12-18 01:11:29 +01006364int select_loop(int action) {
6365 int next_time;
6366 int status;
6367 int fd,i;
6368 struct timeval delta;
6369 int readnotnull, writenotnull;
6370 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01006371
willy tarreau1c2ad212005-12-18 01:11:29 +01006372 if (action == POLL_LOOP_ACTION_INIT) {
6373 ReadEvent = (fd_set *)
6374 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6375 WriteEvent = (fd_set *)
6376 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
6377 return 1;
6378 }
6379 else if (action == POLL_LOOP_ACTION_CLEAN) {
6380 if (WriteEvent) free(WriteEvent);
6381 if (ReadEvent) free(ReadEvent);
6382 return 1;
6383 }
willy tarreauad90a0c2005-12-18 01:09:15 +01006384
willy tarreau1c2ad212005-12-18 01:11:29 +01006385 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01006386
willy tarreau1c2ad212005-12-18 01:11:29 +01006387 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01006388
willy tarreau1c2ad212005-12-18 01:11:29 +01006389 while (1) {
6390 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01006391
willy tarreau1c2ad212005-12-18 01:11:29 +01006392 /* stop when there's no connection left and we don't allow them anymore */
6393 if (!actconn && listeners == 0)
6394 break;
6395
6396#if STATTIME > 0
6397 {
6398 int time2;
6399 time2 = stats();
6400 next_time = MINTIME(time2, next_time);
6401 }
6402#endif
6403
willy tarreau1c2ad212005-12-18 01:11:29 +01006404 if (next_time > 0) { /* FIXME */
6405 /* Convert to timeval */
6406 /* to avoid eventual select loops due to timer precision */
6407 next_time += SCHEDULER_RESOLUTION;
6408 delta.tv_sec = next_time / 1000;
6409 delta.tv_usec = (next_time % 1000) * 1000;
6410 }
6411 else if (next_time == 0) { /* allow select to return immediately when needed */
6412 delta.tv_sec = delta.tv_usec = 0;
6413 }
6414
6415
6416 /* let's restore fdset state */
6417
6418 readnotnull = 0; writenotnull = 0;
6419 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6420 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6421 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6422 }
6423
6424 // /* just a verification code, needs to be removed for performance */
6425 // for (i=0; i<maxfd; i++) {
6426 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6427 // abort();
6428 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6429 // abort();
6430 //
6431 // }
6432
6433 status = select(maxfd,
6434 readnotnull ? ReadEvent : NULL,
6435 writenotnull ? WriteEvent : NULL,
6436 NULL,
6437 (next_time >= 0) ? &delta : NULL);
6438
6439 /* this is an experiment on the separation of the select work */
6440 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6441 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6442
6443 tv_now(&now);
6444
6445 if (status > 0) { /* must proceed with events */
6446
6447 int fds;
6448 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006449
willy tarreau1c2ad212005-12-18 01:11:29 +01006450 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6451 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6452 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6453
6454 /* if we specify read first, the accepts and zero reads will be
6455 * seen first. Moreover, system buffers will be flushed faster.
6456 */
willy tarreau05be12b2006-03-19 19:35:00 +01006457 if (FD_ISSET(fd, ReadEvent)) {
6458 if (fdtab[fd].state == FD_STCLOSE)
6459 continue;
6460 fdtab[fd].read(fd);
6461 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006462
willy tarreau05be12b2006-03-19 19:35:00 +01006463 if (FD_ISSET(fd, WriteEvent)) {
6464 if (fdtab[fd].state == FD_STCLOSE)
6465 continue;
6466 fdtab[fd].write(fd);
6467 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006468 }
6469 }
6470 else {
6471 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006472 }
willy tarreau0f7af912005-12-17 12:21:26 +01006473 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006474 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006475}
6476
6477
6478#if STATTIME > 0
6479/*
6480 * Display proxy statistics regularly. It is designed to be called from the
6481 * select_loop().
6482 */
6483int stats(void) {
6484 static int lines;
6485 static struct timeval nextevt;
6486 static struct timeval lastevt;
6487 static struct timeval starttime = {0,0};
6488 unsigned long totaltime, deltatime;
6489 int ret;
6490
willy tarreau750a4722005-12-17 13:21:24 +01006491 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006492 deltatime = (tv_diff(&lastevt, &now)?:1);
6493 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006494
willy tarreau9fe663a2005-12-17 13:02:59 +01006495 if (global.mode & MODE_STATS) {
6496 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006497 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006498 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6499 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006500 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006501 actconn, totalconn,
6502 stats_tsk_new, stats_tsk_good,
6503 stats_tsk_left, stats_tsk_right,
6504 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6505 }
6506 }
6507
6508 tv_delayfrom(&nextevt, &now, STATTIME);
6509
6510 lastevt=now;
6511 }
6512 ret = tv_remain(&now, &nextevt);
6513 return ret;
6514}
6515#endif
6516
6517
6518/*
6519 * this function enables proxies when there are enough free sessions,
6520 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006521 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006522 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006523 */
6524static int maintain_proxies(void) {
6525 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006526 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006527 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006528
6529 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006530 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006531
6532 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006533 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006534 while (p) {
6535 if (p->nbconn < p->maxconn) {
6536 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006537 for (l = p->listen; l != NULL; l = l->next) {
6538 FD_SET(l->fd, StaticReadEvent);
6539 }
willy tarreau0f7af912005-12-17 12:21:26 +01006540 p->state = PR_STRUN;
6541 }
6542 }
6543 else {
6544 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006545 for (l = p->listen; l != NULL; l = l->next) {
6546 FD_CLR(l->fd, StaticReadEvent);
6547 }
willy tarreau0f7af912005-12-17 12:21:26 +01006548 p->state = PR_STIDLE;
6549 }
6550 }
6551 p = p->next;
6552 }
6553 }
6554 else { /* block all proxies */
6555 while (p) {
6556 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006557 for (l = p->listen; l != NULL; l = l->next) {
6558 FD_CLR(l->fd, StaticReadEvent);
6559 }
willy tarreau0f7af912005-12-17 12:21:26 +01006560 p->state = PR_STIDLE;
6561 }
6562 p = p->next;
6563 }
6564 }
6565
willy tarreau5cbea6f2005-12-17 12:48:26 +01006566 if (stopping) {
6567 p = proxy;
6568 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006569 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006570 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006571 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006572 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006573 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006574 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006575
willy tarreaua41a8b42005-12-17 14:02:24 +01006576 for (l = p->listen; l != NULL; l = l->next) {
6577 fd_delete(l->fd);
6578 listeners--;
6579 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006580 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006581 }
6582 else {
6583 tleft = MINTIME(t, tleft);
6584 }
6585 }
6586 p = p->next;
6587 }
6588 }
6589 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006590}
6591
6592/*
6593 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006594 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6595 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006596 */
6597static void soft_stop(void) {
6598 struct proxy *p;
6599
6600 stopping = 1;
6601 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006602 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006603 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006604 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006605 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006606 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006607 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006608 }
willy tarreau0f7af912005-12-17 12:21:26 +01006609 p = p->next;
6610 }
6611}
6612
willy tarreaudbd3bef2006-01-20 19:35:18 +01006613static void pause_proxy(struct proxy *p) {
6614 struct listener *l;
6615 for (l = p->listen; l != NULL; l = l->next) {
6616 shutdown(l->fd, SHUT_RD);
6617 FD_CLR(l->fd, StaticReadEvent);
6618 p->state = PR_STPAUSED;
6619 }
6620}
6621
6622/*
6623 * This function temporarily disables listening so that another new instance
6624 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006625 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006626 * the proxy, or a SIGTTIN can be sent to listen again.
6627 */
6628static void pause_proxies(void) {
6629 struct proxy *p;
6630
6631 p = proxy;
6632 tv_now(&now); /* else, the old time before select will be used */
6633 while (p) {
6634 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6635 Warning("Pausing proxy %s.\n", p->id);
6636 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6637 pause_proxy(p);
6638 }
6639 p = p->next;
6640 }
6641}
6642
6643
6644/*
6645 * This function reactivates listening. This can be used after a call to
6646 * sig_pause(), for example when a new instance has failed starting up.
6647 * It is designed to be called upon reception of a SIGTTIN.
6648 */
6649static void listen_proxies(void) {
6650 struct proxy *p;
6651 struct listener *l;
6652
6653 p = proxy;
6654 tv_now(&now); /* else, the old time before select will be used */
6655 while (p) {
6656 if (p->state == PR_STPAUSED) {
6657 Warning("Enabling proxy %s.\n", p->id);
6658 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6659
6660 for (l = p->listen; l != NULL; l = l->next) {
6661 if (listen(l->fd, p->maxconn) == 0) {
6662 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6663 FD_SET(l->fd, StaticReadEvent);
6664 p->state = PR_STRUN;
6665 }
6666 else
6667 p->state = PR_STIDLE;
6668 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006669 int port;
6670
6671 if (l->addr.ss_family == AF_INET6)
6672 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6673 else
6674 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6675
willy tarreaudbd3bef2006-01-20 19:35:18 +01006676 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006677 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006678 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006679 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006680 /* Another port might have been enabled. Let's stop everything. */
6681 pause_proxy(p);
6682 break;
6683 }
6684 }
6685 }
6686 p = p->next;
6687 }
6688}
6689
6690
willy tarreau0f7af912005-12-17 12:21:26 +01006691/*
6692 * upon SIGUSR1, let's have a soft stop.
6693 */
6694void sig_soft_stop(int sig) {
6695 soft_stop();
6696 signal(sig, SIG_IGN);
6697}
6698
willy tarreaudbd3bef2006-01-20 19:35:18 +01006699/*
6700 * upon SIGTTOU, we pause everything
6701 */
6702void sig_pause(int sig) {
6703 pause_proxies();
6704 signal(sig, sig_pause);
6705}
willy tarreau0f7af912005-12-17 12:21:26 +01006706
willy tarreau8337c6b2005-12-17 13:41:01 +01006707/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006708 * upon SIGTTIN, let's have a soft stop.
6709 */
6710void sig_listen(int sig) {
6711 listen_proxies();
6712 signal(sig, sig_listen);
6713}
6714
6715/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006716 * this function dumps every server's state when the process receives SIGHUP.
6717 */
6718void sig_dump_state(int sig) {
6719 struct proxy *p = proxy;
6720
6721 Warning("SIGHUP received, dumping servers states.\n");
6722 while (p) {
6723 struct server *s = p->srv;
6724
willy tarreaufd5c8792006-05-01 15:28:01 +02006725 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states for proxy %s.\n", p->id);
willy tarreau8337c6b2005-12-17 13:41:01 +01006726 while (s) {
6727 if (s->state & SRV_RUNNING) {
willy tarreau14b4d432006-04-07 18:23:29 +02006728 snprintf(trash, sizeof(trash),
6729 "SIGHUP: Server %s/%s is UP. Conn: %d act, %d tot.",
6730 p->id, s->id, s->cur_sess, s->cum_sess);
6731 } else {
6732 snprintf(trash, sizeof(trash),
6733 "SIGHUP: Server %s/%s is DOWN. Conn: %d act, %d tot.",
6734 p->id, s->id, s->cur_sess, s->cum_sess);
willy tarreau8337c6b2005-12-17 13:41:01 +01006735 }
willy tarreau14b4d432006-04-07 18:23:29 +02006736 Warning("%s\n", trash);
6737 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006738 s = s->next;
6739 }
willy tarreaudd07e972005-12-18 00:48:48 +01006740
willy tarreau62084d42006-03-24 18:57:41 +01006741 if (p->srv_act == 0) {
6742 if (p->srv_bck) {
willy tarreau14b4d432006-04-07 18:23:29 +02006743 snprintf(trash, sizeof(trash),
6744 "SIGHUP: Proxy %s is running on backup servers ! Conn: %d act, %d tot.",
6745 p->id, p->nbconn, p->cum_conn);
6746 } else {
6747 snprintf(trash, sizeof(trash),
6748 "SIGHUP: Proxy %s has no server availble ! Conn: %d act, %d tot.",
6749 p->id, p->nbconn, p->cum_conn);
6750 }
6751 } else {
6752 snprintf(trash, sizeof(trash),
6753 "SIGHUP: Proxy %s has %d active servers and %d backup servers availble. Conn: %d act, %d tot.",
6754 p->id, p->srv_act, p->srv_bck, p->nbconn, p->cum_conn);
6755 }
6756 Warning("%s\n", trash);
6757 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006758
willy tarreau8337c6b2005-12-17 13:41:01 +01006759 p = p->next;
6760 }
6761 signal(sig, sig_dump_state);
6762}
6763
willy tarreau0f7af912005-12-17 12:21:26 +01006764void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006765 struct task *t, *tnext;
6766 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006767
willy tarreau5e698ef2006-05-02 14:51:00 +02006768 tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next;
6769 while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006770 tnext = t->next;
6771 s = t->context;
6772 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6773 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6774 "req=%d, rep=%d, clifd=%d\n",
6775 s, tv_remain(&now, &t->expire),
6776 s->cli_state,
6777 s->srv_state,
6778 FD_ISSET(s->cli_fd, StaticReadEvent),
6779 FD_ISSET(s->cli_fd, StaticWriteEvent),
6780 FD_ISSET(s->srv_fd, StaticReadEvent),
6781 FD_ISSET(s->srv_fd, StaticWriteEvent),
6782 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6783 );
willy tarreau0f7af912005-12-17 12:21:26 +01006784 }
willy tarreau12350152005-12-18 01:03:27 +01006785}
6786
willy tarreau64a3cc32005-12-18 01:13:11 +01006787#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006788static void fast_stop(void)
6789{
6790 struct proxy *p;
6791 p = proxy;
6792 while (p) {
6793 p->grace = 0;
6794 p = p->next;
6795 }
6796 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006797}
6798
willy tarreau12350152005-12-18 01:03:27 +01006799void sig_int(int sig) {
6800 /* This would normally be a hard stop,
6801 but we want to be sure about deallocation,
6802 and so on, so we do a soft stop with
6803 0 GRACE time
6804 */
6805 fast_stop();
6806 /* If we are killed twice, we decide to die*/
6807 signal(sig, SIG_DFL);
6808}
6809
6810void sig_term(int sig) {
6811 /* This would normally be a hard stop,
6812 but we want to be sure about deallocation,
6813 and so on, so we do a soft stop with
6814 0 GRACE time
6815 */
6816 fast_stop();
6817 /* If we are killed twice, we decide to die*/
6818 signal(sig, SIG_DFL);
6819}
willy tarreau64a3cc32005-12-18 01:13:11 +01006820#endif
willy tarreau12350152005-12-18 01:03:27 +01006821
willy tarreauc1f47532005-12-18 01:08:26 +01006822/* returns the pointer to an error in the replacement string, or NULL if OK */
6823char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006824 struct hdr_exp *exp;
6825
willy tarreauc1f47532005-12-18 01:08:26 +01006826 if (replace != NULL) {
6827 char *err;
6828 err = check_replace_string(replace);
6829 if (err)
6830 return err;
6831 }
6832
willy tarreaue39cd132005-12-17 13:00:18 +01006833 while (*head != NULL)
6834 head = &(*head)->next;
6835
6836 exp = calloc(1, sizeof(struct hdr_exp));
6837
6838 exp->preg = preg;
6839 exp->replace = replace;
6840 exp->action = action;
6841 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006842
6843 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006844}
6845
willy tarreau9fe663a2005-12-17 13:02:59 +01006846
willy tarreau0f7af912005-12-17 12:21:26 +01006847/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006849 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006850int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006851
willy tarreau9fe663a2005-12-17 13:02:59 +01006852 if (!strcmp(args[0], "global")) { /* new section */
6853 /* no option, nothing special to do */
6854 return 0;
6855 }
6856 else if (!strcmp(args[0], "daemon")) {
6857 global.mode |= MODE_DAEMON;
6858 }
6859 else if (!strcmp(args[0], "debug")) {
6860 global.mode |= MODE_DEBUG;
6861 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006862 else if (!strcmp(args[0], "noepoll")) {
6863 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6864 }
6865 else if (!strcmp(args[0], "nopoll")) {
6866 cfg_polling_mechanism &= ~POLL_USE_POLL;
6867 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006868 else if (!strcmp(args[0], "quiet")) {
6869 global.mode |= MODE_QUIET;
6870 }
6871 else if (!strcmp(args[0], "stats")) {
6872 global.mode |= MODE_STATS;
6873 }
6874 else if (!strcmp(args[0], "uid")) {
6875 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006876 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006877 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006878 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006879 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006880 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006881 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006882 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006883 global.uid = atol(args[1]);
6884 }
6885 else if (!strcmp(args[0], "gid")) {
6886 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006887 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006889 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006890 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006891 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006892 return -1;
6893 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006894 global.gid = atol(args[1]);
6895 }
6896 else if (!strcmp(args[0], "nbproc")) {
6897 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006898 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006899 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006901 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006902 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006903 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006904 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006905 global.nbproc = atol(args[1]);
6906 }
6907 else if (!strcmp(args[0], "maxconn")) {
6908 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006909 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006910 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006913 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006914 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006915 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006916 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006917#ifdef SYSTEM_MAXCONN
6918 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6919 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);
6920 global.maxconn = DEFAULT_MAXCONN;
6921 }
6922#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006923 }
willy tarreaub1285d52005-12-18 01:20:14 +01006924 else if (!strcmp(args[0], "ulimit-n")) {
6925 if (global.rlimit_nofile != 0) {
6926 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6927 return 0;
6928 }
6929 if (*(args[1]) == 0) {
6930 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6931 return -1;
6932 }
6933 global.rlimit_nofile = atol(args[1]);
6934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006935 else if (!strcmp(args[0], "chroot")) {
6936 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006937 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 return 0;
6939 }
6940 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006941 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006942 return -1;
6943 }
6944 global.chroot = strdup(args[1]);
6945 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006946 else if (!strcmp(args[0], "pidfile")) {
6947 if (global.pidfile != NULL) {
6948 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6949 return 0;
6950 }
6951 if (*(args[1]) == 0) {
6952 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6953 return -1;
6954 }
6955 global.pidfile = strdup(args[1]);
6956 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 else if (!strcmp(args[0], "log")) { /* syslog server address */
6958 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006959 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006960
6961 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006962 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 return -1;
6964 }
6965
6966 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6967 if (!strcmp(log_facilities[facility], args[2]))
6968 break;
6969
6970 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006971 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006972 exit(1);
6973 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006974
6975 level = 7; /* max syslog level = debug */
6976 if (*(args[3])) {
6977 while (level >= 0 && strcmp(log_levels[level], args[3]))
6978 level--;
6979 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006980 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006981 exit(1);
6982 }
6983 }
6984
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 sa = str2sa(args[1]);
6986 if (!sa->sin_port)
6987 sa->sin_port = htons(SYSLOG_PORT);
6988
6989 if (global.logfac1 == -1) {
6990 global.logsrv1 = *sa;
6991 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006992 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006993 }
6994 else if (global.logfac2 == -1) {
6995 global.logsrv2 = *sa;
6996 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006997 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 }
6999 else {
7000 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
7001 return -1;
7002 }
7003
7004 }
7005 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007006 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01007007 return -1;
7008 }
7009 return 0;
7010}
7011
7012
willy tarreaua41a8b42005-12-17 14:02:24 +01007013void init_default_instance() {
7014 memset(&defproxy, 0, sizeof(defproxy));
7015 defproxy.mode = PR_MODE_TCP;
7016 defproxy.state = PR_STNEW;
7017 defproxy.maxconn = cfg_maxpconn;
7018 defproxy.conn_retries = CONN_RETRIES;
7019 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
7020}
7021
willy tarreau9fe663a2005-12-17 13:02:59 +01007022/*
7023 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
7024 */
7025int cfg_parse_listen(char *file, int linenum, char **args) {
7026 static struct proxy *curproxy = NULL;
7027 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01007028 char *err;
willy tarreau12350152005-12-18 01:03:27 +01007029 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01007030
7031 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01007032 if (!*args[1]) {
7033 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
7034 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007035 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007036 return -1;
7037 }
7038
7039 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007040 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007041 return -1;
7042 }
willy tarreaudfece232006-05-02 00:19:57 +02007043
willy tarreau9fe663a2005-12-17 13:02:59 +01007044 curproxy->next = proxy;
7045 proxy = curproxy;
willy tarreaudfece232006-05-02 00:19:57 +02007046 LIST_INIT(&curproxy->pendconns);
7047
willy tarreau9fe663a2005-12-17 13:02:59 +01007048 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01007049
7050 /* parse the listener address if any */
7051 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007052 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007053 if (!curproxy->listen)
7054 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007055 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01007056 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007057
willy tarreau9fe663a2005-12-17 13:02:59 +01007058 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01007059 curproxy->state = defproxy.state;
7060 curproxy->maxconn = defproxy.maxconn;
7061 curproxy->conn_retries = defproxy.conn_retries;
7062 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007063
7064 if (defproxy.check_req)
7065 curproxy->check_req = strdup(defproxy.check_req);
7066 curproxy->check_len = defproxy.check_len;
7067
7068 if (defproxy.cookie_name)
7069 curproxy->cookie_name = strdup(defproxy.cookie_name);
7070 curproxy->cookie_len = defproxy.cookie_len;
7071
7072 if (defproxy.capture_name)
7073 curproxy->capture_name = strdup(defproxy.capture_name);
7074 curproxy->capture_namelen = defproxy.capture_namelen;
7075 curproxy->capture_len = defproxy.capture_len;
7076
7077 if (defproxy.errmsg.msg400)
7078 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
7079 curproxy->errmsg.len400 = defproxy.errmsg.len400;
7080
7081 if (defproxy.errmsg.msg403)
7082 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
7083 curproxy->errmsg.len403 = defproxy.errmsg.len403;
7084
7085 if (defproxy.errmsg.msg408)
7086 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
7087 curproxy->errmsg.len408 = defproxy.errmsg.len408;
7088
7089 if (defproxy.errmsg.msg500)
7090 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
7091 curproxy->errmsg.len500 = defproxy.errmsg.len500;
7092
7093 if (defproxy.errmsg.msg502)
7094 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
7095 curproxy->errmsg.len502 = defproxy.errmsg.len502;
7096
7097 if (defproxy.errmsg.msg503)
7098 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
7099 curproxy->errmsg.len503 = defproxy.errmsg.len503;
7100
7101 if (defproxy.errmsg.msg504)
7102 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
7103 curproxy->errmsg.len504 = defproxy.errmsg.len504;
7104
willy tarreaua41a8b42005-12-17 14:02:24 +01007105 curproxy->clitimeout = defproxy.clitimeout;
7106 curproxy->contimeout = defproxy.contimeout;
7107 curproxy->srvtimeout = defproxy.srvtimeout;
7108 curproxy->mode = defproxy.mode;
7109 curproxy->logfac1 = defproxy.logfac1;
7110 curproxy->logsrv1 = defproxy.logsrv1;
7111 curproxy->loglev1 = defproxy.loglev1;
7112 curproxy->logfac2 = defproxy.logfac2;
7113 curproxy->logsrv2 = defproxy.logsrv2;
7114 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01007115 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01007116 curproxy->grace = defproxy.grace;
7117 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01007118 curproxy->mon_net = defproxy.mon_net;
7119 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01007120 return 0;
7121 }
7122 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007123 /* some variables may have already been initialized earlier */
7124 if (defproxy.check_req) free(defproxy.check_req);
7125 if (defproxy.cookie_name) free(defproxy.cookie_name);
7126 if (defproxy.capture_name) free(defproxy.capture_name);
7127 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
7128 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
7129 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
7130 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
7131 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
7132 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
7133 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
7134
7135 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01007136 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01007137 return 0;
7138 }
7139 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007140 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007141 return -1;
7142 }
7143
willy tarreaua41a8b42005-12-17 14:02:24 +01007144 if (!strcmp(args[0], "bind")) { /* new listen addresses */
7145 if (curproxy == &defproxy) {
7146 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7147 return -1;
7148 }
7149
7150 if (strchr(args[1], ':') == NULL) {
7151 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
7152 file, linenum, args[0]);
7153 return -1;
7154 }
7155 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01007156 if (!curproxy->listen)
7157 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01007158 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007159 return 0;
7160 }
willy tarreaub1285d52005-12-18 01:20:14 +01007161 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
7162 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
7163 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
7164 file, linenum, args[0]);
7165 return -1;
7166 }
7167 /* flush useless bits */
7168 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
7169 return 0;
7170 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007171 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01007172 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
7173 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
7174 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
7175 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007176 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007177 return -1;
7178 }
7179 }
7180 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01007181 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007182 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007183 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
7184 curproxy->state = PR_STNEW;
7185 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007186 else if (!strcmp(args[0], "cookie")) { /* cookie name */
7187 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007188// if (curproxy == &defproxy) {
7189// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7190// return -1;
7191// }
willy tarreaua41a8b42005-12-17 14:02:24 +01007192
willy tarreau9fe663a2005-12-17 13:02:59 +01007193 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007194// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7195// file, linenum);
7196// return 0;
7197 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007198 }
7199
7200 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007201 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
7202 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007203 return -1;
7204 }
7205 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007206 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01007207
7208 cur_arg = 2;
7209 while (*(args[cur_arg])) {
7210 if (!strcmp(args[cur_arg], "rewrite")) {
7211 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01007212 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 else if (!strcmp(args[cur_arg], "indirect")) {
7214 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01007215 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 else if (!strcmp(args[cur_arg], "insert")) {
7217 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01007218 }
willy tarreau240afa62005-12-17 13:14:35 +01007219 else if (!strcmp(args[cur_arg], "nocache")) {
7220 curproxy->options |= PR_O_COOK_NOC;
7221 }
willy tarreaucd878942005-12-17 13:27:43 +01007222 else if (!strcmp(args[cur_arg], "postonly")) {
7223 curproxy->options |= PR_O_COOK_POST;
7224 }
willy tarreau0174f312005-12-18 01:02:42 +01007225 else if (!strcmp(args[cur_arg], "prefix")) {
7226 curproxy->options |= PR_O_COOK_PFX;
7227 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007228 else {
willy tarreau0174f312005-12-18 01:02:42 +01007229 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007230 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007231 return -1;
7232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007233 cur_arg++;
7234 }
willy tarreau0174f312005-12-18 01:02:42 +01007235 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
7236 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
7237 file, linenum);
7238 return -1;
7239 }
7240
7241 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
7242 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007243 file, linenum);
7244 return -1;
7245 }
willy tarreau12350152005-12-18 01:03:27 +01007246 }/* end else if (!strcmp(args[0], "cookie")) */
7247 else if (!strcmp(args[0], "appsession")) { /* cookie name */
7248// if (curproxy == &defproxy) {
7249// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7250// return -1;
7251// }
7252
7253 if (curproxy->appsession_name != NULL) {
7254// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
7255// file, linenum);
7256// return 0;
7257 free(curproxy->appsession_name);
7258 }
7259
7260 if (*(args[5]) == 0) {
7261 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
7262 file, linenum, args[0]);
7263 return -1;
7264 }
7265 have_appsession = 1;
7266 curproxy->appsession_name = strdup(args[1]);
7267 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
7268 curproxy->appsession_len = atoi(args[3]);
7269 curproxy->appsession_timeout = atoi(args[5]);
7270 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
7271 if (rc) {
7272 Alert("Error Init Appsession Hashtable.\n");
7273 return -1;
7274 }
7275 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01007276 else if (!strcmp(args[0], "capture")) {
7277 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
7278 // if (curproxy == &defproxy) {
7279 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7280 // return -1;
7281 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007282
willy tarreau4302f492005-12-18 01:00:37 +01007283 if (curproxy->capture_name != NULL) {
7284 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7285 // file, linenum, args[0]);
7286 // return 0;
7287 free(curproxy->capture_name);
7288 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007289
willy tarreau4302f492005-12-18 01:00:37 +01007290 if (*(args[4]) == 0) {
7291 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
7292 file, linenum, args[0]);
7293 return -1;
7294 }
7295 curproxy->capture_name = strdup(args[2]);
7296 curproxy->capture_namelen = strlen(curproxy->capture_name);
7297 curproxy->capture_len = atol(args[4]);
7298 if (curproxy->capture_len >= CAPTURE_LEN) {
7299 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
7300 file, linenum, CAPTURE_LEN - 1);
7301 curproxy->capture_len = CAPTURE_LEN - 1;
7302 }
7303 curproxy->to_log |= LW_COOKIE;
7304 }
7305 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
7306 struct cap_hdr *hdr;
7307
7308 if (curproxy == &defproxy) {
7309 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7310 return -1;
7311 }
7312
7313 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7314 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7315 file, linenum, args[0], args[1]);
7316 return -1;
7317 }
7318
7319 hdr = calloc(sizeof(struct cap_hdr), 1);
7320 hdr->next = curproxy->req_cap;
7321 hdr->name = strdup(args[3]);
7322 hdr->namelen = strlen(args[3]);
7323 hdr->len = atol(args[5]);
7324 hdr->index = curproxy->nb_req_cap++;
7325 curproxy->req_cap = hdr;
7326 curproxy->to_log |= LW_REQHDR;
7327 }
7328 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
7329 struct cap_hdr *hdr;
7330
7331 if (curproxy == &defproxy) {
7332 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
7333 return -1;
7334 }
7335
7336 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
7337 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
7338 file, linenum, args[0], args[1]);
7339 return -1;
7340 }
7341 hdr = calloc(sizeof(struct cap_hdr), 1);
7342 hdr->next = curproxy->rsp_cap;
7343 hdr->name = strdup(args[3]);
7344 hdr->namelen = strlen(args[3]);
7345 hdr->len = atol(args[5]);
7346 hdr->index = curproxy->nb_rsp_cap++;
7347 curproxy->rsp_cap = hdr;
7348 curproxy->to_log |= LW_RSPHDR;
7349 }
7350 else {
7351 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007352 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007353 return -1;
7354 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007356 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007357 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007358 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 return 0;
7360 }
7361 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007362 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7363 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007364 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007365 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 curproxy->contimeout = atol(args[1]);
7367 }
7368 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007369 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007370 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
7371 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007372 return 0;
7373 }
7374 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007375 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7376 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007377 return -1;
7378 }
7379 curproxy->clitimeout = atol(args[1]);
7380 }
7381 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01007382 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007383 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007384 return 0;
7385 }
7386 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007387 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
7388 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01007389 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007390 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007391 curproxy->srvtimeout = atol(args[1]);
7392 }
7393 else if (!strcmp(args[0], "retries")) { /* connection retries */
7394 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007395 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
7396 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007397 return -1;
7398 }
7399 curproxy->conn_retries = atol(args[1]);
7400 }
7401 else if (!strcmp(args[0], "option")) {
7402 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007403 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007404 return -1;
7405 }
7406 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007407 /* enable reconnections to dispatch */
7408 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01007409#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007410 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01007411 /* enable transparent proxy connections */
7412 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01007413#endif
7414 else if (!strcmp(args[1], "keepalive"))
7415 /* enable keep-alive */
7416 curproxy->options |= PR_O_KEEPALIVE;
7417 else if (!strcmp(args[1], "forwardfor"))
7418 /* insert x-forwarded-for field */
7419 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007420 else if (!strcmp(args[1], "logasap"))
7421 /* log as soon as possible, without waiting for the session to complete */
7422 curproxy->options |= PR_O_LOGASAP;
7423 else if (!strcmp(args[1], "httpclose"))
7424 /* force connection: close in both directions in HTTP mode */
7425 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007426 else if (!strcmp(args[1], "forceclose"))
7427 /* force connection: close in both directions in HTTP mode and enforce end of session */
7428 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007429 else if (!strcmp(args[1], "checkcache"))
7430 /* require examination of cacheability of the 'set-cookie' field */
7431 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007432 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007434 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007435 else if (!strcmp(args[1], "tcplog"))
7436 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007437 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007438 else if (!strcmp(args[1], "dontlognull")) {
7439 /* don't log empty requests */
7440 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007441 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007442 else if (!strcmp(args[1], "tcpka")) {
7443 /* enable TCP keep-alives on client and server sessions */
7444 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7445 }
7446 else if (!strcmp(args[1], "clitcpka")) {
7447 /* enable TCP keep-alives on client sessions */
7448 curproxy->options |= PR_O_TCP_CLI_KA;
7449 }
7450 else if (!strcmp(args[1], "srvtcpka")) {
7451 /* enable TCP keep-alives on server sessions */
7452 curproxy->options |= PR_O_TCP_SRV_KA;
7453 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007454 else if (!strcmp(args[1], "allbackups")) {
7455 /* Use all backup servers simultaneously */
7456 curproxy->options |= PR_O_USE_ALL_BK;
7457 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007458 else if (!strcmp(args[1], "httpchk")) {
7459 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007460 if (curproxy->check_req != NULL) {
7461 free(curproxy->check_req);
7462 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007463 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007464 if (!*args[2]) { /* no argument */
7465 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7466 curproxy->check_len = strlen(DEF_CHECK_REQ);
7467 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007468 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7469 curproxy->check_req = (char *)malloc(reqlen);
7470 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7471 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007472 } else { /* more arguments : METHOD URI [HTTP_VER] */
7473 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7474 if (*args[4])
7475 reqlen += strlen(args[4]);
7476 else
7477 reqlen += strlen("HTTP/1.0");
7478
7479 curproxy->check_req = (char *)malloc(reqlen);
7480 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7481 "%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 +01007482 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007483 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007484 else if (!strcmp(args[1], "persist")) {
7485 /* persist on using the server specified by the cookie, even when it's down */
7486 curproxy->options |= PR_O_PERSIST;
7487 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007488 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007489 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007490 return -1;
7491 }
7492 return 0;
7493 }
7494 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7495 /* enable reconnections to dispatch */
7496 curproxy->options |= PR_O_REDISP;
7497 }
willy tarreaua1598082005-12-17 13:08:06 +01007498#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007499 else if (!strcmp(args[0], "transparent")) {
7500 /* enable transparent proxy connections */
7501 curproxy->options |= PR_O_TRANSP;
7502 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007503#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007504 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7505 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007506 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007507 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007508 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007509 curproxy->maxconn = atol(args[1]);
7510 }
7511 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7512 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007513 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007514 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007515 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007516 curproxy->grace = atol(args[1]);
7517 }
7518 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007519 if (curproxy == &defproxy) {
7520 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7521 return -1;
7522 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007523 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007524 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007525 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007526 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007527 curproxy->dispatch_addr = *str2sa(args[1]);
7528 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007529 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 if (*(args[1])) {
7531 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007532 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007533 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007534 else if (!strcmp(args[1], "source")) {
7535 curproxy->options |= PR_O_BALANCE_SH;
7536 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007537 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007538 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007539 return -1;
7540 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007541 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007542 else /* if no option is set, use round-robin by default */
7543 curproxy->options |= PR_O_BALANCE_RR;
7544 }
7545 else if (!strcmp(args[0], "server")) { /* server address */
7546 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007547 char *rport;
7548 char *raddr;
7549 short realport;
7550 int do_check;
7551
7552 if (curproxy == &defproxy) {
7553 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7554 return -1;
7555 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007556
willy tarreaua41a8b42005-12-17 14:02:24 +01007557 if (!*args[2]) {
7558 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007559 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007560 return -1;
7561 }
7562 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7563 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7564 return -1;
7565 }
willy tarreau0174f312005-12-18 01:02:42 +01007566
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007567 /* the servers are linked backwards first */
7568 newsrv->next = curproxy->srv;
7569 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007570 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007571
willy tarreau18a957c2006-04-12 19:26:23 +02007572 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007573 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007574 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007575 newsrv->id = strdup(args[1]);
7576
7577 /* several ways to check the port component :
7578 * - IP => port=+0, relative
7579 * - IP: => port=+0, relative
7580 * - IP:N => port=N, absolute
7581 * - IP:+N => port=+N, relative
7582 * - IP:-N => port=-N, relative
7583 */
7584 raddr = strdup(args[2]);
7585 rport = strchr(raddr, ':');
7586 if (rport) {
7587 *rport++ = 0;
7588 realport = atol(rport);
7589 if (!isdigit((int)*rport))
7590 newsrv->state |= SRV_MAPPORTS;
7591 } else {
7592 realport = 0;
7593 newsrv->state |= SRV_MAPPORTS;
7594 }
7595
7596 newsrv->addr = *str2sa(raddr);
7597 newsrv->addr.sin_port = htons(realport);
7598 free(raddr);
7599
willy tarreau9fe663a2005-12-17 13:02:59 +01007600 newsrv->curfd = -1; /* no health-check in progress */
7601 newsrv->inter = DEF_CHKINTR;
7602 newsrv->rise = DEF_RISETIME;
7603 newsrv->fall = DEF_FALLTIME;
7604 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7605 cur_arg = 3;
7606 while (*args[cur_arg]) {
7607 if (!strcmp(args[cur_arg], "cookie")) {
7608 newsrv->cookie = strdup(args[cur_arg + 1]);
7609 newsrv->cklen = strlen(args[cur_arg + 1]);
7610 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007611 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007612 else if (!strcmp(args[cur_arg], "rise")) {
7613 newsrv->rise = atol(args[cur_arg + 1]);
7614 newsrv->health = newsrv->rise;
7615 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007616 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007617 else if (!strcmp(args[cur_arg], "fall")) {
7618 newsrv->fall = atol(args[cur_arg + 1]);
7619 cur_arg += 2;
7620 }
7621 else if (!strcmp(args[cur_arg], "inter")) {
7622 newsrv->inter = atol(args[cur_arg + 1]);
7623 cur_arg += 2;
7624 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007625 else if (!strcmp(args[cur_arg], "port")) {
7626 newsrv->check_port = atol(args[cur_arg + 1]);
7627 cur_arg += 2;
7628 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007629 else if (!strcmp(args[cur_arg], "backup")) {
7630 newsrv->state |= SRV_BACKUP;
7631 cur_arg ++;
7632 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007633 else if (!strcmp(args[cur_arg], "weight")) {
7634 int w;
7635 w = atol(args[cur_arg + 1]);
7636 if (w < 1 || w > 256) {
7637 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7638 file, linenum, newsrv->id, w);
7639 return -1;
7640 }
7641 newsrv->uweight = w - 1;
7642 cur_arg += 2;
7643 }
willy tarreau18a957c2006-04-12 19:26:23 +02007644 else if (!strcmp(args[cur_arg], "maxconn")) {
7645 newsrv->maxconn = atol(args[cur_arg + 1]);
7646 cur_arg += 2;
7647 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007648 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007649 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007650 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007651 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007652 }
willy tarreau0174f312005-12-18 01:02:42 +01007653 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7654 if (!*args[cur_arg + 1]) {
7655 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7656 file, linenum, "source");
7657 return -1;
7658 }
7659 newsrv->state |= SRV_BIND_SRC;
7660 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7661 cur_arg += 2;
7662 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007663 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007664 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 +01007665 file, linenum, newsrv->id);
7666 return -1;
7667 }
7668 }
7669
7670 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007671 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7672 newsrv->check_port = realport; /* by default */
7673 if (!newsrv->check_port) {
7674 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 +01007675 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007676 return -1;
7677 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007678 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007679 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007680
willy tarreau62084d42006-03-24 18:57:41 +01007681 if (newsrv->state & SRV_BACKUP)
7682 curproxy->srv_bck++;
7683 else
7684 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007685 }
7686 else if (!strcmp(args[0], "log")) { /* syslog server address */
7687 struct sockaddr_in *sa;
7688 int facility;
7689
7690 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7691 curproxy->logfac1 = global.logfac1;
7692 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007693 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007694 curproxy->logfac2 = global.logfac2;
7695 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007696 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007697 }
7698 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007699 int level;
7700
willy tarreau0f7af912005-12-17 12:21:26 +01007701 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7702 if (!strcmp(log_facilities[facility], args[2]))
7703 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007704
willy tarreau0f7af912005-12-17 12:21:26 +01007705 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007706 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007707 exit(1);
7708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007709
willy tarreau8337c6b2005-12-17 13:41:01 +01007710 level = 7; /* max syslog level = debug */
7711 if (*(args[3])) {
7712 while (level >= 0 && strcmp(log_levels[level], args[3]))
7713 level--;
7714 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007715 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007716 exit(1);
7717 }
7718 }
7719
willy tarreau0f7af912005-12-17 12:21:26 +01007720 sa = str2sa(args[1]);
7721 if (!sa->sin_port)
7722 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007723
willy tarreau0f7af912005-12-17 12:21:26 +01007724 if (curproxy->logfac1 == -1) {
7725 curproxy->logsrv1 = *sa;
7726 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007727 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007728 }
7729 else if (curproxy->logfac2 == -1) {
7730 curproxy->logsrv2 = *sa;
7731 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007732 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007733 }
7734 else {
7735 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007736 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007738 }
7739 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007740 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007741 file, linenum);
7742 return -1;
7743 }
7744 }
willy tarreaua1598082005-12-17 13:08:06 +01007745 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007746 if (!*args[1]) {
7747 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007748 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007749 return -1;
7750 }
7751
7752 curproxy->source_addr = *str2sa(args[1]);
7753 curproxy->options |= PR_O_BIND_SRC;
7754 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007755 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7756 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007757 if (curproxy == &defproxy) {
7758 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7759 return -1;
7760 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007761
7762 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007763 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7764 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007765 return -1;
7766 }
7767
7768 preg = calloc(1, sizeof(regex_t));
7769 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007770 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007771 return -1;
7772 }
7773
willy tarreauc1f47532005-12-18 01:08:26 +01007774 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7775 if (err) {
7776 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7777 file, linenum, *err);
7778 return -1;
7779 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007780 }
7781 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7782 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007783 if (curproxy == &defproxy) {
7784 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7785 return -1;
7786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007787
7788 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007789 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007790 return -1;
7791 }
7792
7793 preg = calloc(1, sizeof(regex_t));
7794 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007795 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 return -1;
7797 }
7798
7799 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7800 }
7801 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7802 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007803 if (curproxy == &defproxy) {
7804 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7805 return -1;
7806 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007807
7808 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007809 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007810 return -1;
7811 }
7812
7813 preg = calloc(1, sizeof(regex_t));
7814 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007815 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007816 return -1;
7817 }
7818
7819 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7820 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007821 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7822 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007823 if (curproxy == &defproxy) {
7824 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7825 return -1;
7826 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007827
7828 if (*(args[1]) == 0) {
7829 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7830 return -1;
7831 }
7832
7833 preg = calloc(1, sizeof(regex_t));
7834 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7835 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7836 return -1;
7837 }
7838
7839 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7840 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007841 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7842 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007843 if (curproxy == &defproxy) {
7844 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7845 return -1;
7846 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007847
7848 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007849 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007850 return -1;
7851 }
7852
7853 preg = calloc(1, sizeof(regex_t));
7854 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007855 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007856 return -1;
7857 }
7858
7859 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7860 }
7861 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7862 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007863 if (curproxy == &defproxy) {
7864 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7865 return -1;
7866 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007867
7868 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007869 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7870 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007871 return -1;
7872 }
7873
7874 preg = calloc(1, sizeof(regex_t));
7875 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007876 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007877 return -1;
7878 }
7879
willy tarreauc1f47532005-12-18 01:08:26 +01007880 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7881 if (err) {
7882 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7883 file, linenum, *err);
7884 return -1;
7885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007886 }
7887 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7888 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007889 if (curproxy == &defproxy) {
7890 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7891 return -1;
7892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007893
7894 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007895 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007896 return -1;
7897 }
7898
7899 preg = calloc(1, sizeof(regex_t));
7900 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007901 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007902 return -1;
7903 }
7904
7905 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7906 }
7907 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7908 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007909 if (curproxy == &defproxy) {
7910 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7911 return -1;
7912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007913
7914 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007915 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007916 return -1;
7917 }
7918
7919 preg = calloc(1, sizeof(regex_t));
7920 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007921 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007922 return -1;
7923 }
7924
7925 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7926 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007927 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7928 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007929 if (curproxy == &defproxy) {
7930 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7931 return -1;
7932 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007933
7934 if (*(args[1]) == 0) {
7935 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7936 return -1;
7937 }
7938
7939 preg = calloc(1, sizeof(regex_t));
7940 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7941 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7942 return -1;
7943 }
7944
7945 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7946 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007947 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7948 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007949 if (curproxy == &defproxy) {
7950 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7951 return -1;
7952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007953
7954 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007955 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007956 return -1;
7957 }
7958
7959 preg = calloc(1, sizeof(regex_t));
7960 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007961 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007962 return -1;
7963 }
7964
7965 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7966 }
7967 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007968 if (curproxy == &defproxy) {
7969 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7970 return -1;
7971 }
7972
willy tarreau9fe663a2005-12-17 13:02:59 +01007973 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007974 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007975 return 0;
7976 }
7977
7978 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007979 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007980 return -1;
7981 }
7982
willy tarreau4302f492005-12-18 01:00:37 +01007983 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7984 }
7985 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7986 regex_t *preg;
7987
7988 if (*(args[1]) == 0 || *(args[2]) == 0) {
7989 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7990 file, linenum, args[0]);
7991 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007992 }
willy tarreau4302f492005-12-18 01:00:37 +01007993
7994 preg = calloc(1, sizeof(regex_t));
7995 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7996 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7997 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007998 }
willy tarreau4302f492005-12-18 01:00:37 +01007999
willy tarreauc1f47532005-12-18 01:08:26 +01008000 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8001 if (err) {
8002 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8003 file, linenum, *err);
8004 return -1;
8005 }
willy tarreau4302f492005-12-18 01:00:37 +01008006 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008007 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
8008 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008009 if (curproxy == &defproxy) {
8010 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8011 return -1;
8012 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008013
8014 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008015 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008016 return -1;
8017 }
willy tarreaue39cd132005-12-17 13:00:18 +01008018
willy tarreau9fe663a2005-12-17 13:02:59 +01008019 preg = calloc(1, sizeof(regex_t));
8020 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008021 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008022 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008023 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008024
willy tarreauc1f47532005-12-18 01:08:26 +01008025 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8026 if (err) {
8027 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8028 file, linenum, *err);
8029 return -1;
8030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008031 }
willy tarreau982249e2005-12-18 00:57:06 +01008032 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
8033 regex_t *preg;
8034 if (curproxy == &defproxy) {
8035 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8036 return -1;
8037 }
8038
8039 if (*(args[1]) == 0) {
8040 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8041 return -1;
8042 }
8043
8044 preg = calloc(1, sizeof(regex_t));
8045 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
8046 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8047 return -1;
8048 }
8049
willy tarreauc1f47532005-12-18 01:08:26 +01008050 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8051 if (err) {
8052 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8053 file, linenum, *err);
8054 return -1;
8055 }
willy tarreau982249e2005-12-18 00:57:06 +01008056 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008057 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01008058 regex_t *preg;
8059 if (curproxy == &defproxy) {
8060 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8061 return -1;
8062 }
willy tarreaue39cd132005-12-17 13:00:18 +01008063
willy tarreaua41a8b42005-12-17 14:02:24 +01008064 if (*(args[1]) == 0 || *(args[2]) == 0) {
8065 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
8066 file, linenum, args[0]);
8067 return -1;
8068 }
willy tarreaue39cd132005-12-17 13:00:18 +01008069
willy tarreaua41a8b42005-12-17 14:02:24 +01008070 preg = calloc(1, sizeof(regex_t));
8071 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8072 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8073 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01008074 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008075
willy tarreauc1f47532005-12-18 01:08:26 +01008076 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
8077 if (err) {
8078 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8079 file, linenum, *err);
8080 return -1;
8081 }
willy tarreaua41a8b42005-12-17 14:02:24 +01008082 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008083 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
8084 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01008085 if (curproxy == &defproxy) {
8086 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8087 return -1;
8088 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008089
8090 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008091 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008092 return -1;
8093 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008094
willy tarreau9fe663a2005-12-17 13:02:59 +01008095 preg = calloc(1, sizeof(regex_t));
8096 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008097 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008098 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008099 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008100
willy tarreauc1f47532005-12-18 01:08:26 +01008101 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
8102 if (err) {
8103 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8104 file, linenum, *err);
8105 return -1;
8106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008107 }
willy tarreau982249e2005-12-18 00:57:06 +01008108 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
8109 regex_t *preg;
8110 if (curproxy == &defproxy) {
8111 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8112 return -1;
8113 }
8114
8115 if (*(args[1]) == 0) {
8116 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
8117 return -1;
8118 }
8119
8120 preg = calloc(1, sizeof(regex_t));
8121 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
8122 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
8123 return -1;
8124 }
8125
willy tarreauc1f47532005-12-18 01:08:26 +01008126 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
8127 if (err) {
8128 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
8129 file, linenum, *err);
8130 return -1;
8131 }
willy tarreau982249e2005-12-18 00:57:06 +01008132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008133 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01008134 if (curproxy == &defproxy) {
8135 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8136 return -1;
8137 }
8138
willy tarreau9fe663a2005-12-17 13:02:59 +01008139 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008140 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008141 return 0;
8142 }
8143
8144 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01008145 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008146 return -1;
8147 }
8148
8149 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
8150 }
willy tarreauc1f47532005-12-18 01:08:26 +01008151 else if (!strcmp(args[0], "errorloc") ||
8152 !strcmp(args[0], "errorloc302") ||
8153 !strcmp(args[0], "errorloc303")) { /* error location */
8154 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008155 char *err;
8156
willy tarreaueedaa9f2005-12-17 14:08:03 +01008157 // if (curproxy == &defproxy) {
8158 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
8159 // return -1;
8160 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01008161
willy tarreau8337c6b2005-12-17 13:41:01 +01008162 if (*(args[2]) == 0) {
8163 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
8164 return -1;
8165 }
8166
8167 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01008168 if (!strcmp(args[0], "errorloc303")) {
8169 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
8170 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
8171 } else {
8172 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
8173 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
8174 }
willy tarreau8337c6b2005-12-17 13:41:01 +01008175
8176 if (errnum == 400) {
8177 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008178 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008179 free(curproxy->errmsg.msg400);
8180 }
8181 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008182 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008183 }
8184 else if (errnum == 403) {
8185 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008186 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008187 free(curproxy->errmsg.msg403);
8188 }
8189 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008190 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008191 }
8192 else if (errnum == 408) {
8193 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008194 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008195 free(curproxy->errmsg.msg408);
8196 }
8197 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008198 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008199 }
8200 else if (errnum == 500) {
8201 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008202 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008203 free(curproxy->errmsg.msg500);
8204 }
8205 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008206 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008207 }
8208 else if (errnum == 502) {
8209 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008210 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008211 free(curproxy->errmsg.msg502);
8212 }
8213 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008214 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008215 }
8216 else if (errnum == 503) {
8217 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008218 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008219 free(curproxy->errmsg.msg503);
8220 }
8221 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008222 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008223 }
8224 else if (errnum == 504) {
8225 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01008226 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01008227 free(curproxy->errmsg.msg504);
8228 }
8229 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01008230 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01008231 }
8232 else {
8233 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
8234 free(err);
8235 }
8236 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008237 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01008238 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01008239 return -1;
8240 }
8241 return 0;
8242}
willy tarreaue39cd132005-12-17 13:00:18 +01008243
willy tarreau5cbea6f2005-12-17 12:48:26 +01008244
willy tarreau9fe663a2005-12-17 13:02:59 +01008245/*
8246 * This function reads and parses the configuration file given in the argument.
8247 * returns 0 if OK, -1 if error.
8248 */
8249int readcfgfile(char *file) {
8250 char thisline[256];
8251 char *line;
8252 FILE *f;
8253 int linenum = 0;
8254 char *end;
8255 char *args[MAX_LINE_ARGS];
8256 int arg;
8257 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01008258 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01008259 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01008260
willy tarreau9fe663a2005-12-17 13:02:59 +01008261 struct proxy *curproxy = NULL;
8262 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01008263
willy tarreau9fe663a2005-12-17 13:02:59 +01008264 if ((f=fopen(file,"r")) == NULL)
8265 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01008266
willy tarreaueedaa9f2005-12-17 14:08:03 +01008267 init_default_instance();
8268
willy tarreau9fe663a2005-12-17 13:02:59 +01008269 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
8270 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008271
willy tarreau9fe663a2005-12-17 13:02:59 +01008272 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01008273
willy tarreau9fe663a2005-12-17 13:02:59 +01008274 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01008275 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01008276 line++;
8277
8278 arg = 0;
8279 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01008280
willy tarreau9fe663a2005-12-17 13:02:59 +01008281 while (*line && arg < MAX_LINE_ARGS) {
8282 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
8283 * C equivalent value. Other combinations left unchanged (eg: \1).
8284 */
8285 if (*line == '\\') {
8286 int skip = 0;
8287 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
8288 *line = line[1];
8289 skip = 1;
8290 }
8291 else if (line[1] == 'r') {
8292 *line = '\r';
8293 skip = 1;
8294 }
8295 else if (line[1] == 'n') {
8296 *line = '\n';
8297 skip = 1;
8298 }
8299 else if (line[1] == 't') {
8300 *line = '\t';
8301 skip = 1;
8302 }
willy tarreauc1f47532005-12-18 01:08:26 +01008303 else if (line[1] == 'x') {
8304 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
8305 unsigned char hex1, hex2;
8306 hex1 = toupper(line[2]) - '0';
8307 hex2 = toupper(line[3]) - '0';
8308 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
8309 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
8310 *line = (hex1<<4) + hex2;
8311 skip = 3;
8312 }
8313 else {
8314 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
8315 return -1;
8316 }
8317 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008318 if (skip) {
8319 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
8320 end -= skip;
8321 }
8322 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008323 }
willy tarreaua1598082005-12-17 13:08:06 +01008324 else if (*line == '#' || *line == '\n' || *line == '\r') {
8325 /* end of string, end of loop */
8326 *line = 0;
8327 break;
8328 }
willy tarreauc29948c2005-12-17 13:10:27 +01008329 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008330 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01008331 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01008332 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01008333 line++;
8334 args[++arg] = line;
8335 }
8336 else {
8337 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01008338 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008339 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008340
willy tarreau9fe663a2005-12-17 13:02:59 +01008341 /* empty line */
8342 if (!**args)
8343 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01008344
willy tarreau9fe663a2005-12-17 13:02:59 +01008345 /* zero out remaining args */
8346 while (++arg < MAX_LINE_ARGS) {
8347 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008348 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008349
willy tarreaua41a8b42005-12-17 14:02:24 +01008350 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01008351 confsect = CFG_LISTEN;
8352 else if (!strcmp(args[0], "global")) /* global config */
8353 confsect = CFG_GLOBAL;
8354 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01008355
willy tarreau9fe663a2005-12-17 13:02:59 +01008356 switch (confsect) {
8357 case CFG_LISTEN:
8358 if (cfg_parse_listen(file, linenum, args) < 0)
8359 return -1;
8360 break;
8361 case CFG_GLOBAL:
8362 if (cfg_parse_global(file, linenum, args) < 0)
8363 return -1;
8364 break;
8365 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01008366 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01008367 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01008368 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008369
8370
willy tarreau0f7af912005-12-17 12:21:26 +01008371 }
8372 fclose(f);
8373
8374 /*
8375 * Now, check for the integrity of all that we have collected.
8376 */
8377
Willy TARREAU3759f982006-03-01 22:44:17 +01008378 /* will be needed further to delay some tasks */
8379 tv_now(&now);
8380
willy tarreau0f7af912005-12-17 12:21:26 +01008381 if ((curproxy = proxy) == NULL) {
8382 Alert("parsing %s : no <listen> line. Nothing to do !\n",
8383 file);
8384 return -1;
8385 }
8386
8387 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01008388 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01008389 curproxy = curproxy->next;
8390 continue;
8391 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008392
8393 if (curproxy->listen == NULL) {
8394 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);
8395 cfgerr++;
8396 }
8397 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01008398 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01008399 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008400 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
8401 file, curproxy->id);
8402 cfgerr++;
8403 }
8404 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
8405 if (curproxy->options & PR_O_TRANSP) {
8406 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
8407 file, curproxy->id);
8408 cfgerr++;
8409 }
8410 else if (curproxy->srv == NULL) {
8411 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
8412 file, curproxy->id);
8413 cfgerr++;
8414 }
willy tarreaua1598082005-12-17 13:08:06 +01008415 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008416 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8417 file, curproxy->id);
8418 }
8419 }
8420 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008421 if (curproxy->cookie_name != NULL) {
8422 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8423 file, curproxy->id);
8424 }
8425 if ((newsrv = curproxy->srv) != NULL) {
8426 Warning("parsing %s : servers will be ignored for listener %s.\n",
8427 file, curproxy->id);
8428 }
willy tarreaue39cd132005-12-17 13:00:18 +01008429 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008430 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8431 file, curproxy->id);
8432 }
willy tarreaue39cd132005-12-17 13:00:18 +01008433 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008434 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8435 file, curproxy->id);
8436 }
8437 }
8438 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8439 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8440 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8441 file, curproxy->id);
8442 cfgerr++;
8443 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008444 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008445
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008446 /* first, we will invert the servers list order */
8447 newsrv = NULL;
8448 while (curproxy->srv) {
8449 struct server *next;
8450
8451 next = curproxy->srv->next;
8452 curproxy->srv->next = newsrv;
8453 newsrv = curproxy->srv;
8454 if (!next)
8455 break;
8456 curproxy->srv = next;
8457 }
8458
8459 /* now, newsrv == curproxy->srv */
8460 if (newsrv) {
8461 struct server *srv;
8462 int pgcd;
8463 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008464
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008465 /* We will factor the weights to reduce the table,
8466 * using Euclide's largest common divisor algorithm
8467 */
8468 pgcd = newsrv->uweight + 1;
8469 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8470 int t, w;
8471
8472 w = srv->uweight + 1;
8473 while (w) {
8474 t = pgcd % w;
8475 pgcd = w;
8476 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008477 }
willy tarreau0f7af912005-12-17 12:21:26 +01008478 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008479
8480 act = bck = 0;
8481 for (srv = newsrv; srv; srv = srv->next) {
8482 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8483 if (srv->state & SRV_BACKUP)
8484 bck += srv->eweight + 1;
8485 else
8486 act += srv->eweight + 1;
8487 }
8488
8489 /* this is the largest map we will ever need for this servers list */
8490 if (act < bck)
8491 act = bck;
8492
8493 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8494 /* recounts servers and their weights */
8495 recount_servers(curproxy);
8496 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008497 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008498
8499 if (curproxy->options & PR_O_LOGASAP)
8500 curproxy->to_log &= ~LW_BYTES;
8501
willy tarreau8337c6b2005-12-17 13:41:01 +01008502 if (curproxy->errmsg.msg400 == NULL) {
8503 curproxy->errmsg.msg400 = (char *)HTTP_400;
8504 curproxy->errmsg.len400 = strlen(HTTP_400);
8505 }
8506 if (curproxy->errmsg.msg403 == NULL) {
8507 curproxy->errmsg.msg403 = (char *)HTTP_403;
8508 curproxy->errmsg.len403 = strlen(HTTP_403);
8509 }
8510 if (curproxy->errmsg.msg408 == NULL) {
8511 curproxy->errmsg.msg408 = (char *)HTTP_408;
8512 curproxy->errmsg.len408 = strlen(HTTP_408);
8513 }
8514 if (curproxy->errmsg.msg500 == NULL) {
8515 curproxy->errmsg.msg500 = (char *)HTTP_500;
8516 curproxy->errmsg.len500 = strlen(HTTP_500);
8517 }
8518 if (curproxy->errmsg.msg502 == NULL) {
8519 curproxy->errmsg.msg502 = (char *)HTTP_502;
8520 curproxy->errmsg.len502 = strlen(HTTP_502);
8521 }
8522 if (curproxy->errmsg.msg503 == NULL) {
8523 curproxy->errmsg.msg503 = (char *)HTTP_503;
8524 curproxy->errmsg.len503 = strlen(HTTP_503);
8525 }
8526 if (curproxy->errmsg.msg504 == NULL) {
8527 curproxy->errmsg.msg504 = (char *)HTTP_504;
8528 curproxy->errmsg.len504 = strlen(HTTP_504);
8529 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008530
8531 /* now we'll start this proxy's health checks if any */
8532 /* 1- count the checkers to run simultaneously */
8533 nbchk = 0;
8534 mininter = 0;
8535 newsrv = curproxy->srv;
8536 while (newsrv != NULL) {
8537 if (newsrv->state & SRV_CHECKED) {
8538 if (!mininter || mininter > newsrv->inter)
8539 mininter = newsrv->inter;
8540 nbchk++;
8541 }
8542 newsrv = newsrv->next;
8543 }
8544
8545 /* 2- start them as far as possible from each others while respecting
8546 * their own intervals. For this, we will start them after their own
8547 * interval added to the min interval divided by the number of servers,
8548 * weighted by the server's position in the list.
8549 */
8550 if (nbchk > 0) {
8551 struct task *t;
8552 int srvpos;
8553
8554 newsrv = curproxy->srv;
8555 srvpos = 0;
8556 while (newsrv != NULL) {
8557 /* should this server be checked ? */
8558 if (newsrv->state & SRV_CHECKED) {
8559 if ((t = pool_alloc(task)) == NULL) {
8560 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8561 return -1;
8562 }
8563
8564 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
willy tarreau5e698ef2006-05-02 14:51:00 +02008565 t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */
Willy TARREAU3759f982006-03-01 22:44:17 +01008566 t->state = TASK_IDLE;
8567 t->process = process_chk;
8568 t->context = newsrv;
8569
8570 /* check this every ms */
8571 tv_delayfrom(&t->expire, &now,
8572 newsrv->inter + mininter * srvpos / nbchk);
8573 task_queue(t);
8574 //task_wakeup(&rq, t);
8575 srvpos++;
8576 }
8577 newsrv = newsrv->next;
8578 }
8579 }
8580
willy tarreau0f7af912005-12-17 12:21:26 +01008581 curproxy = curproxy->next;
8582 }
8583 if (cfgerr > 0) {
8584 Alert("Errors found in configuration file, aborting.\n");
8585 return -1;
8586 }
8587 else
8588 return 0;
8589}
8590
8591
8592/*
8593 * This function initializes all the necessary variables. It only returns
8594 * if everything is OK. If something fails, it exits.
8595 */
8596void init(int argc, char **argv) {
8597 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008598 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008599 char *old_argv = *argv;
8600 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008601 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008602
8603 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008604 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008605 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008606 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008607 exit(1);
8608 }
8609
willy tarreau746e26b2006-03-25 11:14:35 +01008610#ifdef HAPROXY_MEMMAX
8611 global.rlimit_memmax = HAPROXY_MEMMAX;
8612#endif
8613
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008614 /* initialize the libc's localtime structures once for all so that we
8615 * won't be missing memory if we want to send alerts under OOM conditions.
8616 */
8617 tv_now(&now);
8618 localtime(&now.tv_sec);
8619
willy tarreau4302f492005-12-18 01:00:37 +01008620 /* initialize the log header encoding map : '{|}"#' should be encoded with
8621 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8622 * URL encoding only requires '"', '#' to be encoded as well as non-
8623 * printable characters above.
8624 */
8625 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8626 memset(url_encode_map, 0, sizeof(url_encode_map));
8627 for (i = 0; i < 32; i++) {
8628 FD_SET(i, hdr_encode_map);
8629 FD_SET(i, url_encode_map);
8630 }
8631 for (i = 127; i < 256; i++) {
8632 FD_SET(i, hdr_encode_map);
8633 FD_SET(i, url_encode_map);
8634 }
8635
8636 tmp = "\"#{|}";
8637 while (*tmp) {
8638 FD_SET(*tmp, hdr_encode_map);
8639 tmp++;
8640 }
8641
8642 tmp = "\"#";
8643 while (*tmp) {
8644 FD_SET(*tmp, url_encode_map);
8645 tmp++;
8646 }
8647
willy tarreau64a3cc32005-12-18 01:13:11 +01008648 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8649#if defined(ENABLE_POLL)
8650 cfg_polling_mechanism |= POLL_USE_POLL;
8651#endif
8652#if defined(ENABLE_EPOLL)
8653 cfg_polling_mechanism |= POLL_USE_EPOLL;
8654#endif
8655
willy tarreau0f7af912005-12-17 12:21:26 +01008656 pid = getpid();
8657 progname = *argv;
8658 while ((tmp = strchr(progname, '/')) != NULL)
8659 progname = tmp + 1;
8660
8661 argc--; argv++;
8662 while (argc > 0) {
8663 char *flag;
8664
8665 if (**argv == '-') {
8666 flag = *argv+1;
8667
8668 /* 1 arg */
8669 if (*flag == 'v') {
8670 display_version();
8671 exit(0);
8672 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008673#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008674 else if (*flag == 'd' && flag[1] == 'e')
8675 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008676#endif
8677#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008678 else if (*flag == 'd' && flag[1] == 'p')
8679 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008680#endif
willy tarreau982249e2005-12-18 00:57:06 +01008681 else if (*flag == 'V')
8682 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008683 else if (*flag == 'd' && flag[1] == 'b')
8684 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008685 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008686 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008687 else if (*flag == 'c')
8688 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008689 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008690 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008691 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008692 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008693 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8694 /* list of pids to finish ('f') or terminate ('t') */
8695
8696 if (flag[1] == 'f')
8697 oldpids_sig = SIGUSR1; /* finish then exit */
8698 else
8699 oldpids_sig = SIGTERM; /* terminate immediately */
8700 argv++; argc--;
8701
8702 if (argc > 0) {
8703 oldpids = calloc(argc, sizeof(int));
8704 while (argc > 0) {
8705 oldpids[nb_oldpids] = atol(*argv);
8706 if (oldpids[nb_oldpids] <= 0)
8707 usage(old_argv);
8708 argc--; argv++;
8709 nb_oldpids++;
8710 }
8711 }
8712 }
willy tarreau2c513732006-04-15 19:25:16 +02008713#if STATTIME > 0
8714 else if (*flag == 's')
8715 arg_mode |= MODE_STATS;
8716 else if (*flag == 'l')
8717 arg_mode |= MODE_LOG;
8718#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008719 else { /* >=2 args */
8720 argv++; argc--;
8721 if (argc == 0)
8722 usage(old_argv);
8723
8724 switch (*flag) {
8725 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008726 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008727 case 'N' : cfg_maxpconn = atol(*argv); break;
8728 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008729 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008730 default: usage(old_argv);
8731 }
8732 }
8733 }
8734 else
8735 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008736 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008737 }
8738
willy tarreaud0fb4652005-12-18 01:32:04 +01008739 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008740 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8741 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008742
willy tarreau0f7af912005-12-17 12:21:26 +01008743 if (!cfg_cfgfile)
8744 usage(old_argv);
8745
8746 gethostname(hostname, MAX_HOSTNAME_LEN);
8747
willy tarreau12350152005-12-18 01:03:27 +01008748 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008749 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008750 if (readcfgfile(cfg_cfgfile) < 0) {
8751 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8752 exit(1);
8753 }
willy tarreau12350152005-12-18 01:03:27 +01008754 if (have_appsession)
8755 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008756
willy tarreau982249e2005-12-18 00:57:06 +01008757 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008758 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8759 exit(0);
8760 }
8761
willy tarreau9fe663a2005-12-17 13:02:59 +01008762 if (cfg_maxconn > 0)
8763 global.maxconn = cfg_maxconn;
8764
willy tarreaufe2c5c12005-12-17 14:14:34 +01008765 if (cfg_pidfile) {
8766 if (global.pidfile)
8767 free(global.pidfile);
8768 global.pidfile = strdup(cfg_pidfile);
8769 }
8770
willy tarreau9fe663a2005-12-17 13:02:59 +01008771 if (global.maxconn == 0)
8772 global.maxconn = DEFAULT_MAXCONN;
8773
Willy TARREAU203b0b62006-03-12 18:00:28 +01008774 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008775
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008776 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008777 /* command line debug mode inhibits configuration mode */
8778 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8779 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008780 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8781 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008782
8783 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8784 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8785 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8786 }
8787
8788 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008789 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8790 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008791 global.nbproc = 1;
8792 }
8793
8794 if (global.nbproc < 1)
8795 global.nbproc = 1;
8796
willy tarreau0f7af912005-12-17 12:21:26 +01008797 StaticReadEvent = (fd_set *)calloc(1,
8798 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008799 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008800 StaticWriteEvent = (fd_set *)calloc(1,
8801 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008802 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008803
8804 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008805 sizeof(struct fdtab) * (global.maxsock));
8806 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008807 fdtab[i].state = FD_STCLOSE;
8808 }
8809}
8810
8811/*
willy tarreau41310e72006-03-25 18:17:56 +01008812 * this function starts all the proxies. Its return value is composed from
8813 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8814 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008815 */
willy tarreau41310e72006-03-25 18:17:56 +01008816int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008817 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008818 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008819 int err = ERR_NONE;
8820 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008821
8822 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008823 if (curproxy->state != PR_STNEW)
8824 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008825
willy tarreau41310e72006-03-25 18:17:56 +01008826 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008827 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008828 if (listener->fd != -1)
8829 continue; /* already initialized */
8830
8831 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8832 if (verbose)
8833 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8834 curproxy->id);
8835 err |= ERR_RETRYABLE;
8836 pxerr |= 1;
8837 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008838 }
willy tarreau0f7af912005-12-17 12:21:26 +01008839
willy tarreaua41a8b42005-12-17 14:02:24 +01008840 if (fd >= global.maxsock) {
8841 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8842 curproxy->id);
8843 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008844 err |= ERR_FATAL;
8845 pxerr |= 1;
8846 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008847 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008848
willy tarreaua41a8b42005-12-17 14:02:24 +01008849 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8850 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8851 (char *) &one, sizeof(one)) == -1)) {
8852 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8853 curproxy->id);
8854 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008855 err |= ERR_FATAL;
8856 pxerr |= 1;
8857 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008858 }
willy tarreau0f7af912005-12-17 12:21:26 +01008859
willy tarreaua41a8b42005-12-17 14:02:24 +01008860 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8861 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8862 curproxy->id);
8863 }
willy tarreau0f7af912005-12-17 12:21:26 +01008864
willy tarreaua41a8b42005-12-17 14:02:24 +01008865 if (bind(fd,
8866 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008867 listener->addr.ss_family == AF_INET6 ?
8868 sizeof(struct sockaddr_in6) :
8869 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008870 if (verbose)
8871 Alert("cannot bind socket for proxy %s. Aborting.\n",
8872 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008873 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008874 err |= ERR_RETRYABLE;
8875 pxerr |= 1;
8876 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008877 }
willy tarreau0f7af912005-12-17 12:21:26 +01008878
willy tarreaua41a8b42005-12-17 14:02:24 +01008879 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008880 if (verbose)
8881 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8882 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008883 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008884 err |= ERR_RETRYABLE;
8885 pxerr |= 1;
8886 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008887 }
willy tarreau0f7af912005-12-17 12:21:26 +01008888
willy tarreau41310e72006-03-25 18:17:56 +01008889 /* the socket is ready */
8890 listener->fd = fd;
8891
willy tarreaua41a8b42005-12-17 14:02:24 +01008892 /* the function for the accept() event */
8893 fdtab[fd].read = &event_accept;
8894 fdtab[fd].write = NULL; /* never called */
8895 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008896 fdtab[fd].state = FD_STLISTEN;
8897 FD_SET(fd, StaticReadEvent);
8898 fd_insert(fd);
8899 listeners++;
8900 }
willy tarreau41310e72006-03-25 18:17:56 +01008901
8902 if (!pxerr) {
8903 curproxy->state = PR_STRUN;
8904 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8905 }
willy tarreau0f7af912005-12-17 12:21:26 +01008906 }
willy tarreau41310e72006-03-25 18:17:56 +01008907
8908 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008909}
8910
willy tarreaub952e1d2005-12-18 01:31:20 +01008911int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008912
8913 appsess *temp1,*temp2;
8914 temp1 = (appsess *)key1;
8915 temp2 = (appsess *)key2;
8916
8917 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8918 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8919
8920 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8921}/* end match_str */
8922
willy tarreaub952e1d2005-12-18 01:31:20 +01008923void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008924 appsess *temp1;
8925
8926 //printf("destroy called\n");
8927 temp1 = (appsess *)data;
8928
8929 if (temp1->sessid)
8930 pool_free_to(apools.sessid, temp1->sessid);
8931
8932 if (temp1->serverid)
8933 pool_free_to(apools.serverid, temp1->serverid);
8934
8935 pool_free(appsess, temp1);
8936} /* end destroy */
8937
8938void appsession_cleanup( void )
8939{
8940 struct proxy *p = proxy;
8941
8942 while(p) {
8943 chtbl_destroy(&(p->htbl_proxy));
8944 p = p->next;
8945 }
8946}/* end appsession_cleanup() */
8947
8948void pool_destroy(void **pool)
8949{
8950 void *temp, *next;
8951 next = pool;
8952 while (next) {
8953 temp = next;
8954 next = *(void **)temp;
8955 free(temp);
8956 }
8957}/* end pool_destroy() */
8958
willy tarreaub952e1d2005-12-18 01:31:20 +01008959void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008960 struct proxy *p = proxy;
8961 struct cap_hdr *h,*h_next;
8962 struct server *s,*s_next;
8963 struct listener *l,*l_next;
8964
8965 while (p) {
8966 if (p->id)
8967 free(p->id);
8968
8969 if (p->check_req)
8970 free(p->check_req);
8971
8972 if (p->cookie_name)
8973 free(p->cookie_name);
8974
8975 if (p->capture_name)
8976 free(p->capture_name);
8977
8978 /* only strup if the user have set in config.
8979 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008980 if (p->errmsg.msg400) free(p->errmsg.msg400);
8981 if (p->errmsg.msg403) free(p->errmsg.msg403);
8982 if (p->errmsg.msg408) free(p->errmsg.msg408);
8983 if (p->errmsg.msg500) free(p->errmsg.msg500);
8984 if (p->errmsg.msg502) free(p->errmsg.msg502);
8985 if (p->errmsg.msg503) free(p->errmsg.msg503);
8986 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008987 */
8988 if (p->appsession_name)
8989 free(p->appsession_name);
8990
8991 h = p->req_cap;
8992 while (h) {
8993 h_next = h->next;
8994 if (h->name)
8995 free(h->name);
8996 pool_destroy(h->pool);
8997 free(h);
8998 h = h_next;
8999 }/* end while(h) */
9000
9001 h = p->rsp_cap;
9002 while (h) {
9003 h_next = h->next;
9004 if (h->name)
9005 free(h->name);
9006
9007 pool_destroy(h->pool);
9008 free(h);
9009 h = h_next;
9010 }/* end while(h) */
9011
9012 s = p->srv;
9013 while (s) {
9014 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01009015 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01009016 free(s->id);
9017
willy tarreaub952e1d2005-12-18 01:31:20 +01009018 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01009019 free(s->cookie);
9020
9021 free(s);
9022 s = s_next;
9023 }/* end while(s) */
9024
9025 l = p->listen;
9026 while (l) {
9027 l_next = l->next;
9028 free(l);
9029 l = l_next;
9030 }/* end while(l) */
9031
9032 pool_destroy((void **) p->req_cap_pool);
9033 pool_destroy((void **) p->rsp_cap_pool);
9034 p = p->next;
9035 }/* end while(p) */
9036
9037 if (global.chroot) free(global.chroot);
9038 if (global.pidfile) free(global.pidfile);
9039
willy tarreau12350152005-12-18 01:03:27 +01009040 if (StaticReadEvent) free(StaticReadEvent);
9041 if (StaticWriteEvent) free(StaticWriteEvent);
9042 if (fdtab) free(fdtab);
9043
9044 pool_destroy(pool_session);
9045 pool_destroy(pool_buffer);
9046 pool_destroy(pool_fdtab);
9047 pool_destroy(pool_requri);
9048 pool_destroy(pool_task);
9049 pool_destroy(pool_capture);
9050 pool_destroy(pool_appsess);
9051
9052 if (have_appsession) {
9053 pool_destroy(apools.serverid);
9054 pool_destroy(apools.sessid);
9055 }
9056} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01009057
willy tarreau41310e72006-03-25 18:17:56 +01009058/* sends the signal <sig> to all pids found in <oldpids> */
9059static void tell_old_pids(int sig) {
9060 int p;
9061 for (p = 0; p < nb_oldpids; p++)
9062 kill(oldpids[p], sig);
9063}
9064
willy tarreau0f7af912005-12-17 12:21:26 +01009065int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01009066 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01009067 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009068 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01009069 init(argc, argv);
9070
willy tarreau0f7af912005-12-17 12:21:26 +01009071 signal(SIGQUIT, dump);
9072 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01009073 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01009074#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01009075 signal(SIGINT, sig_int);
9076 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01009077#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009078
9079 /* on very high loads, a sigpipe sometimes happen just between the
9080 * getsockopt() which tells "it's OK to write", and the following write :-(
9081 */
willy tarreau3242e862005-12-17 12:27:53 +01009082#ifndef MSG_NOSIGNAL
9083 signal(SIGPIPE, SIG_IGN);
9084#endif
willy tarreau0f7af912005-12-17 12:21:26 +01009085
willy tarreau41310e72006-03-25 18:17:56 +01009086 /* We will loop at most 100 times with 10 ms delay each time.
9087 * That's at most 1 second. We only send a signal to old pids
9088 * if we cannot grab at least one port.
9089 */
9090 retry = MAX_START_RETRIES;
9091 err = ERR_NONE;
9092 while (retry >= 0) {
9093 struct timeval w;
9094 err = start_proxies(retry == 0 || nb_oldpids == 0);
9095 if (err != ERR_RETRYABLE)
9096 break;
9097 if (nb_oldpids == 0)
9098 break;
9099
9100 tell_old_pids(SIGTTOU);
9101 /* give some time to old processes to stop listening */
9102 w.tv_sec = 0;
9103 w.tv_usec = 10*1000;
9104 select(0, NULL, NULL, NULL, &w);
9105 retry--;
9106 }
9107
9108 /* Note: start_proxies() sends an alert when it fails. */
9109 if (err != ERR_NONE) {
9110 if (retry != MAX_START_RETRIES && nb_oldpids)
9111 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01009112 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01009113 }
willy tarreaud0fb4652005-12-18 01:32:04 +01009114
9115 if (listeners == 0) {
9116 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009117 /* Note: we don't have to send anything to the old pids because we
9118 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01009119 exit(1);
9120 }
9121
willy tarreaudbd3bef2006-01-20 19:35:18 +01009122 /* prepare pause/play signals */
9123 signal(SIGTTOU, sig_pause);
9124 signal(SIGTTIN, sig_listen);
9125
Willy TARREAUe3283d12006-03-01 22:15:29 +01009126 if (global.mode & MODE_DAEMON) {
9127 global.mode &= ~MODE_VERBOSE;
9128 global.mode |= MODE_QUIET;
9129 }
9130
willy tarreaud0fb4652005-12-18 01:32:04 +01009131 /* MODE_QUIET can inhibit alerts and warnings below this line */
9132
9133 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01009134 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01009135 /* detach from the tty */
9136 fclose(stdin); fclose(stdout); fclose(stderr);
9137 close(0); close(1); close(2);
9138 }
willy tarreau0f7af912005-12-17 12:21:26 +01009139
willy tarreaufe2c5c12005-12-17 14:14:34 +01009140 /* open log & pid files before the chroot */
9141 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
9142 int pidfd;
9143 unlink(global.pidfile);
9144 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
9145 if (pidfd < 0) {
9146 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01009147 if (nb_oldpids)
9148 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01009149 exit(1);
9150 }
9151 pidfile = fdopen(pidfd, "w");
9152 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009153
9154 /* chroot if needed */
9155 if (global.chroot != NULL) {
9156 if (chroot(global.chroot) == -1) {
9157 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01009158 if (nb_oldpids)
9159 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01009160 }
9161 chdir("/");
9162 }
9163
willy tarreaub1285d52005-12-18 01:20:14 +01009164 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01009165 if (!global.rlimit_nofile)
9166 global.rlimit_nofile = global.maxsock;
9167
willy tarreaub1285d52005-12-18 01:20:14 +01009168 if (global.rlimit_nofile) {
9169 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
9170 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
9171 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
9172 }
willy tarreau746e26b2006-03-25 11:14:35 +01009173 }
9174
9175 if (global.rlimit_memmax) {
9176 limit.rlim_cur = limit.rlim_max =
9177 global.rlimit_memmax * 1048576 / global.nbproc;
9178#ifdef RLIMIT_AS
9179 if (setrlimit(RLIMIT_AS, &limit) == -1) {
9180 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9181 argv[0], global.rlimit_memmax);
9182 }
9183#else
9184 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
9185 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
9186 argv[0], global.rlimit_memmax);
9187 }
9188#endif
willy tarreaub1285d52005-12-18 01:20:14 +01009189 }
9190
willy tarreau41310e72006-03-25 18:17:56 +01009191 if (nb_oldpids)
9192 tell_old_pids(oldpids_sig);
9193
9194 /* Note that any error at this stage will be fatal because we will not
9195 * be able to restart the old pids.
9196 */
9197
willy tarreau9fe663a2005-12-17 13:02:59 +01009198 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01009199 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009200 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
9201 exit(1);
9202 }
9203
willy tarreau036e1ce2005-12-17 13:46:33 +01009204 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01009205 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
9206 exit(1);
9207 }
9208
willy tarreaub1285d52005-12-18 01:20:14 +01009209 /* check ulimits */
9210 limit.rlim_cur = limit.rlim_max = 0;
9211 getrlimit(RLIMIT_NOFILE, &limit);
9212 if (limit.rlim_cur < global.maxsock) {
9213 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",
9214 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
9215 }
9216
willy tarreau9fe663a2005-12-17 13:02:59 +01009217 if (global.mode & MODE_DAEMON) {
9218 int ret = 0;
9219 int proc;
9220
9221 /* the father launches the required number of processes */
9222 for (proc = 0; proc < global.nbproc; proc++) {
9223 ret = fork();
9224 if (ret < 0) {
9225 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01009226 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01009227 exit(1); /* there has been an error */
9228 }
9229 else if (ret == 0) /* child breaks here */
9230 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01009231 if (pidfile != NULL) {
9232 fprintf(pidfile, "%d\n", ret);
9233 fflush(pidfile);
9234 }
willy tarreau9fe663a2005-12-17 13:02:59 +01009235 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01009236 /* close the pidfile both in children and father */
9237 if (pidfile != NULL)
9238 fclose(pidfile);
9239 free(global.pidfile);
9240
willy tarreau9fe663a2005-12-17 13:02:59 +01009241 if (proc == global.nbproc)
9242 exit(0); /* parent must leave */
9243
willy tarreau750a4722005-12-17 13:21:24 +01009244 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
9245 * that we can detach from the TTY. We MUST NOT do it in other cases since
9246 * it would have already be done, and 0-2 would have been affected to listening
9247 * sockets
9248 */
9249 if (!(global.mode & MODE_QUIET)) {
9250 /* detach from the tty */
9251 fclose(stdin); fclose(stdout); fclose(stderr);
9252 close(0); close(1); close(2); /* close all fd's */
9253 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
9254 }
willy tarreaua1598082005-12-17 13:08:06 +01009255 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01009256 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01009257 }
9258
willy tarreau1c2ad212005-12-18 01:11:29 +01009259#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009260 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009261 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
9262 epoll_loop(POLL_LOOP_ACTION_RUN);
9263 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009264 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009265 }
9266 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01009267 Warning("epoll() is not available. Using poll()/select() instead.\n");
9268 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009269 }
9270 }
9271#endif
9272
9273#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01009274 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009275 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
9276 poll_loop(POLL_LOOP_ACTION_RUN);
9277 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009278 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009279 }
9280 else {
9281 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01009282 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01009283 }
9284 }
9285#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01009286 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01009287 if (select_loop(POLL_LOOP_ACTION_INIT)) {
9288 select_loop(POLL_LOOP_ACTION_RUN);
9289 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01009290 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01009291 }
9292 }
9293
willy tarreau0f7af912005-12-17 12:21:26 +01009294
willy tarreau12350152005-12-18 01:03:27 +01009295 /* Free all Hash Keys and all Hash elements */
9296 appsession_cleanup();
9297 /* Do some cleanup */
9298 deinit();
9299
willy tarreau0f7af912005-12-17 12:21:26 +01009300 exit(0);
9301}
willy tarreau12350152005-12-18 01:03:27 +01009302
9303#if defined(DEBUG_HASH)
9304static void print_table(const CHTbl *htbl) {
9305
9306 ListElmt *element;
9307 int i;
9308 appsess *asession;
9309
9310 /*****************************************************************************
9311 * *
9312 * Display the chained hash table. *
9313 * *
9314 *****************************************************************************/
9315
9316 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
9317
9318 for (i = 0; i < TBLSIZ; i++) {
9319 fprintf(stdout, "Bucket[%03d]\n", i);
9320
9321 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9322 //fprintf(stdout, "%c", *(char *)list_data(element));
9323 asession = (appsess *)list_data(element);
9324 fprintf(stdout, "ELEM :%s:", asession->sessid);
9325 fprintf(stdout, " Server :%s: \n", asession->serverid);
9326 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
9327 }
9328
9329 fprintf(stdout, "\n");
9330 }
9331 return;
9332} /* end print_table */
9333#endif
9334
9335static int appsession_init(void)
9336{
9337 static int initialized = 0;
9338 int idlen;
9339 struct server *s;
9340 struct proxy *p = proxy;
9341
9342 if (!initialized) {
9343 if (!appsession_task_init()) {
9344 apools.sessid = NULL;
9345 apools.serverid = NULL;
9346 apools.ser_waste = 0;
9347 apools.ser_use = 0;
9348 apools.ser_msize = sizeof(void *);
9349 apools.ses_waste = 0;
9350 apools.ses_use = 0;
9351 apools.ses_msize = sizeof(void *);
9352 while (p) {
9353 s = p->srv;
9354 if (apools.ses_msize < p->appsession_len)
9355 apools.ses_msize = p->appsession_len;
9356 while (s) {
9357 idlen = strlen(s->id);
9358 if (apools.ser_msize < idlen)
9359 apools.ser_msize = idlen;
9360 s = s->next;
9361 }
9362 p = p->next;
9363 }
9364 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
9365 apools.ses_msize ++;
9366 }
9367 else {
9368 fprintf(stderr, "appsession_task_init failed\n");
9369 return -1;
9370 }
9371 initialized ++;
9372 }
9373 return 0;
9374}
9375
9376static int appsession_task_init(void)
9377{
9378 static int initialized = 0;
9379 struct task *t;
9380 if (!initialized) {
9381 if ((t = pool_alloc(task)) == NULL)
9382 return -1;
9383 t->next = t->prev = t->rqnext = NULL;
willy tarreau5e698ef2006-05-02 14:51:00 +02009384 t->wq = LIST_HEAD(wait_queue[0]);
willy tarreau12350152005-12-18 01:03:27 +01009385 t->state = TASK_IDLE;
9386 t->context = NULL;
9387 tv_delayfrom(&t->expire, &now, TBLCHKINT);
9388 task_queue(t);
9389 t->process = appsession_refresh;
9390 initialized ++;
9391 }
9392 return 0;
9393}
9394
9395static int appsession_refresh(struct task *t) {
9396 struct proxy *p = proxy;
9397 CHTbl *htbl;
9398 ListElmt *element, *last;
9399 int i;
9400 appsess *asession;
9401 void *data;
9402
9403 while (p) {
9404 if (p->appsession_name != NULL) {
9405 htbl = &p->htbl_proxy;
9406 /* if we ever give up the use of TBLSIZ, we need to change this */
9407 for (i = 0; i < TBLSIZ; i++) {
9408 last = NULL;
9409 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
9410 asession = (appsess *)list_data(element);
9411 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
9412 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
9413 int len;
9414 /*
9415 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9416 */
9417 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9418 asession->sessid, asession->serverid?asession->serverid:"(null)");
9419 write(1, trash, len);
9420 }
9421 /* delete the expired element from within the hash table */
9422 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9423 && (htbl->table[i].destroy != NULL)) {
9424 htbl->table[i].destroy(data);
9425 }
9426 if (last == NULL) {/* patient lost his head, get a new one */
9427 element = list_head(&htbl->table[i]);
9428 if (element == NULL) break; /* no heads left, go to next patient */
9429 }
9430 else
9431 element = last;
9432 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9433 else
9434 last = element;
9435 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9436 }
9437 }
9438 p = p->next;
9439 }
9440 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9441 return TBLCHKINT;
9442} /* end appsession_refresh */
9443
willy tarreau18a957c2006-04-12 19:26:23 +02009444
9445/*
9446 * Local variables:
9447 * c-indent-level: 4
9448 * c-basic-offset: 4
9449 * End:
9450 */