blob: 696b80dc795404bd3fa7f7c76122037464495d66 [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 tarreaue39cd132005-12-17 13:00:18 +0100355/* various session flags */
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 */
willy tarreaub1285d52005-12-18 01:20:14 +0100362#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100363
364#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 tarreaub1285d52005-12-18 01:20:14 +0100371#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100372#define SN_ERR_CLITO 0x00000100 /* client time-out */
373#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
374#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
375#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
376#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100377#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
378#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100379#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
380#define SN_ERR_SHIFT 8 /* bit shift */
381
382#define SN_FINST_R 0x00001000 /* session ended during client request */
383#define SN_FINST_C 0x00002000 /* session ended during server connect */
384#define SN_FINST_H 0x00003000 /* session ended during server headers */
385#define SN_FINST_D 0x00004000 /* session ended during data phase */
386#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
387#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
388#define SN_FINST_SHIFT 12 /* bit shift */
389
390#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
391#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
392#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
393#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
394#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100395#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100396#define SN_SCK_SHIFT 16 /* bit shift */
397
willy tarreau97f58572005-12-18 00:53:44 +0100398#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
399#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
400#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401
402/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100403#define CL_STHEADERS 0
404#define CL_STDATA 1
405#define CL_STSHUTR 2
406#define CL_STSHUTW 3
407#define CL_STCLOSE 4
408
willy tarreau5cbea6f2005-12-17 12:48:26 +0100409/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100410#define SV_STIDLE 0
willy tarreau18a957c2006-04-12 19:26:23 +0200411#define SV_STCPEND 1
412#define SV_STCONN 2
413#define SV_STHEADERS 3
414#define SV_STDATA 4
415#define SV_STSHUTR 5
416#define SV_STSHUTW 6
417#define SV_STCLOSE 7
willy tarreau0f7af912005-12-17 12:21:26 +0100418
419/* result of an I/O event */
420#define RES_SILENT 0 /* didn't happen */
421#define RES_DATA 1 /* data were sent or received */
422#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
423#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
424
willy tarreau9fe663a2005-12-17 13:02:59 +0100425/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100426#define MODE_DEBUG 1
427#define MODE_STATS 2
428#define MODE_LOG 4
429#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100430#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100431#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100432#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100433#define MODE_STARTING 128
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100434#define MODE_FOREGROUND 256
willy tarreau5cbea6f2005-12-17 12:48:26 +0100435
436/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100437#define SRV_RUNNING 1 /* the server is UP */
438#define SRV_BACKUP 2 /* this server is a backup server */
439#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100440#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100441#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100442
willy tarreaue39cd132005-12-17 13:00:18 +0100443/* what to do when a header matches a regex */
444#define ACT_ALLOW 0 /* allow the request */
445#define ACT_REPLACE 1 /* replace the matching header */
446#define ACT_REMOVE 2 /* remove the matching header */
447#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100448#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100449
willy tarreau9fe663a2005-12-17 13:02:59 +0100450/* configuration sections */
451#define CFG_NONE 0
452#define CFG_GLOBAL 1
453#define CFG_LISTEN 2
454
willy tarreaua1598082005-12-17 13:08:06 +0100455/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100456#define LW_DATE 1 /* date */
457#define LW_CLIP 2 /* CLient IP */
458#define LW_SVIP 4 /* SerVer IP */
459#define LW_SVID 8 /* server ID */
460#define LW_REQ 16 /* http REQuest */
461#define LW_RESP 32 /* http RESPonse */
462#define LW_PXIP 64 /* proxy IP */
463#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100464#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100465#define LW_COOKIE 512 /* captured cookie */
466#define LW_REQHDR 1024 /* request header(s) */
467#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100468
willy tarreau41310e72006-03-25 18:17:56 +0100469#define ERR_NONE 0 /* no error */
470#define ERR_RETRYABLE 1 /* retryable error, may be cumulated */
471#define ERR_FATAL 2 /* fatal error, may be cumulated */
472
willy tarreau0f7af912005-12-17 12:21:26 +0100473/*********************************************************************/
474
475#define LIST_HEAD(a) ((void *)(&(a)))
476
477/*********************************************************************/
478
willy tarreau4302f492005-12-18 01:00:37 +0100479struct cap_hdr {
480 struct cap_hdr *next;
481 char *name; /* header name, case insensitive */
482 int namelen; /* length of the header name, to speed-up lookups */
483 int len; /* capture length, not including terminal zero */
484 int index; /* index in the output array */
485 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
486};
487
willy tarreau0f7af912005-12-17 12:21:26 +0100488struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100489 struct hdr_exp *next;
490 regex_t *preg; /* expression to look for */
491 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
492 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100493};
494
495struct buffer {
496 unsigned int l; /* data length */
497 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100498 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100499 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100500 char data[BUFSIZE];
501};
502
willy tarreau18a957c2006-04-12 19:26:23 +0200503struct pendconn {
504 struct list list; /* chaining ... */
505 struct session *sess; /* the session waiting for a connection */
506 struct server *srv; /* the server we are waiting for */
507};
508
willy tarreau0f7af912005-12-17 12:21:26 +0100509struct server {
510 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100511 int state; /* server state (SRV_*) */
512 int cklen; /* the len of the cookie, to speed up checks */
513 char *cookie; /* the id set in the cookie */
514 char *id; /* just for identification */
willy tarreau18a957c2006-04-12 19:26:23 +0200515 struct list pendconns; /* pending connections */
516 int nbpend; /* number of pending connections */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100518 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100519 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100520 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100521 int rise, fall; /* time in iterations */
522 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100523 int result; /* 0 = connect OK, -1 = connect KO */
524 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreaue3f023f2006-04-08 21:52:24 +0200525 unsigned char uweight, eweight; /* user-specified weight-1, and effective weight-1 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200526 unsigned int wscore; /* weight score, used during srv map computation */
willy tarreaua647c702006-04-15 22:45:52 +0200527 int cur_sess; /* number of currently active sessions (including syn_sent) */
528 unsigned int cum_sess; /* cumulated number of sessions really sent to this server */
willy tarreau18a957c2006-04-12 19:26:23 +0200529 unsigned int maxconn; /* max # of active sessions. 0 = unlimited. */
willy tarreau535ae7a2005-12-17 12:58:00 +0100530 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100531};
532
willy tarreau5cbea6f2005-12-17 12:48:26 +0100533/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100534struct task {
535 struct task *next, *prev; /* chaining ... */
536 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100537 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100538 int state; /* task state : IDLE or RUNNING */
539 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100540 int (*process)(struct task *t); /* the function which processes the task */
541 void *context; /* the task's context */
542};
543
544/* WARNING: if new fields are added, they must be initialized in event_accept() */
545struct session {
546 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100547 /* application specific below */
548 struct timeval crexpire; /* expiration date for a client read */
549 struct timeval cwexpire; /* expiration date for a client write */
550 struct timeval srexpire; /* expiration date for a server read */
551 struct timeval swexpire; /* expiration date for a server write */
552 struct timeval cnexpire; /* expiration date for a connect */
553 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
554 struct proxy *proxy; /* the proxy this socket belongs to */
555 int cli_fd; /* the client side fd */
556 int srv_fd; /* the server side fd */
557 int cli_state; /* state of the client side */
558 int srv_state; /* state of the server side */
559 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100560 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100561 struct buffer *req; /* request buffer */
562 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100563 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100565 struct server *srv; /* the server being used */
willy tarreau18a957c2006-04-12 19:26:23 +0200566 struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */
willy tarreau4302f492005-12-18 01:00:37 +0100567 char **req_cap; /* array of captured request headers (may be NULL) */
568 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100569 struct {
570 int logwait; /* log fields waiting to be collected : LW_* */
571 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
572 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
573 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
574 long t_data; /* delay before the first data byte from the server ... */
575 unsigned long t_close; /* total session duration */
576 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100577 char *cli_cookie; /* cookie presented by the client, in capture mode */
578 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100579 int status; /* HTTP status from the server, negative if from proxy */
580 long long bytes; /* number of bytes transferred from the server */
581 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100582 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100583};
584
willy tarreaua41a8b42005-12-17 14:02:24 +0100585struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100586 int fd; /* the listen socket */
587 struct sockaddr_storage addr; /* the address we listen to */
588 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100589};
590
591
willy tarreau0f7af912005-12-17 12:21:26 +0100592struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100593 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100594 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 +0100595 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100596 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreaucc1e2bd2006-04-10 20:32:43 +0200597 struct server *srv; /* known servers */
598 int srv_act, srv_bck; /* # of running servers */
599 int tot_wact, tot_wbck; /* total weights of active and backup servers */
600 struct server **srv_map; /* the server map used to apply weights */
601 int srv_map_sz; /* the size of the effective server map */
602 int srv_rr_idx; /* next server to be elected in round robin mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100603 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100604 int cookie_len; /* strlen(cookie_name), computed only once */
605 char *appsession_name; /* name of the cookie to look for */
606 int appsession_name_len; /* strlen(appsession_name), computed only once */
607 int appsession_len; /* length of the appsession cookie value to be used */
608 int appsession_timeout;
609 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100610 char *capture_name; /* beginning of the name of the cookie to capture */
611 int capture_namelen; /* length of the cookie name to match */
612 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100613 int clitimeout; /* client I/O timeout (in milliseconds) */
614 int srvtimeout; /* server I/O timeout (in milliseconds) */
615 int contimeout; /* connect timeout (in milliseconds) */
616 char *id; /* proxy id */
617 int nbconn; /* # of active sessions */
willy tarreau14b4d432006-04-07 18:23:29 +0200618 unsigned int cum_conn; /* cumulated number of processed sessions */
willy tarreau0f7af912005-12-17 12:21:26 +0100619 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100620 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100621 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100622 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100623 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100624 struct proxy *next;
625 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100626 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100627 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100628 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100629 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100630 int nb_reqadd, nb_rspadd;
631 struct hdr_exp *req_exp; /* regular expressions for request headers */
632 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100633 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
634 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
635 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
636 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100637 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100638 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100639 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
640 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100641 struct {
642 char *msg400; /* message for error 400 */
643 int len400; /* message length for error 400 */
644 char *msg403; /* message for error 403 */
645 int len403; /* message length for error 403 */
646 char *msg408; /* message for error 408 */
647 int len408; /* message length for error 408 */
648 char *msg500; /* message for error 500 */
649 int len500; /* message length for error 500 */
650 char *msg502; /* message for error 502 */
651 int len502; /* message length for error 502 */
652 char *msg503; /* message for error 503 */
653 int len503; /* message length for error 503 */
654 char *msg504; /* message for error 504 */
655 int len504; /* message length for error 504 */
656 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100657};
658
659/* info about one given fd */
660struct fdtab {
661 int (*read)(int fd); /* read function */
662 int (*write)(int fd); /* write function */
663 struct task *owner; /* the session (or proxy) associated with this fd */
664 int state; /* the state of this fd */
665};
666
667/*********************************************************************/
668
willy tarreaub952e1d2005-12-18 01:31:20 +0100669int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
Willy TARREAU13032e72006-03-12 17:31:45 +0100670int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +0100671char *cfg_cfgfile = NULL; /* configuration file */
672char *progname = NULL; /* program name */
673int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100674
675/* global options */
676static struct {
677 int uid;
678 int gid;
679 int nbproc;
680 int maxconn;
681 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100682 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau746e26b2006-03-25 11:14:35 +0100683 int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100684 int mode;
685 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100686 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100687 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100688 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100689 struct sockaddr_in logsrv1, logsrv2;
690} global = {
691 logfac1 : -1,
692 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100693 loglev1 : 7, /* max syslog level : debug */
694 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100695 /* others NULL OK */
696};
697
willy tarreau0f7af912005-12-17 12:21:26 +0100698/*********************************************************************/
699
willy tarreau1c2ad212005-12-18 01:11:29 +0100700fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100701 *StaticWriteEvent;
702
willy tarreau64a3cc32005-12-18 01:13:11 +0100703int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100704
willy tarreau0f7af912005-12-17 12:21:26 +0100705void **pool_session = NULL,
willy tarreau18a957c2006-04-12 19:26:23 +0200706 **pool_pendconn = NULL,
willy tarreau0f7af912005-12-17 12:21:26 +0100707 **pool_buffer = NULL,
708 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100709 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100710 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100711 **pool_capture = NULL,
712 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100713
714struct proxy *proxy = NULL; /* list of all existing proxies */
715struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100716struct task *rq = NULL; /* global run queue */
717struct task wait_queue = { /* global wait queue */
718 prev:LIST_HEAD(wait_queue),
719 next:LIST_HEAD(wait_queue)
720};
willy tarreau0f7af912005-12-17 12:21:26 +0100721
willy tarreau0f7af912005-12-17 12:21:26 +0100722static int totalconn = 0; /* total # of terminated sessions */
723static int actconn = 0; /* # of active sessions */
724static int maxfd = 0; /* # of the highest fd + 1 */
725static int listeners = 0; /* # of listeners */
726static int stopping = 0; /* non zero means stopping in progress */
727static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100728static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100729
willy tarreau53e99702006-03-25 18:53:50 +0100730/* Here we store informations about the pids of the processes we may pause
731 * or kill. We will send them a signal every 10 ms until we can bind to all
732 * our ports. With 200 retries, that's about 2 seconds.
willy tarreau41310e72006-03-25 18:17:56 +0100733 */
willy tarreau53e99702006-03-25 18:53:50 +0100734#define MAX_START_RETRIES 200
willy tarreau41310e72006-03-25 18:17:56 +0100735static int nb_oldpids = 0;
736static int *oldpids = NULL;
737static int oldpids_sig; /* use USR1 or TERM */
738
willy tarreau08dedbe2005-12-18 01:13:48 +0100739#if defined(ENABLE_EPOLL)
740/* FIXME: this is dirty, but at the moment, there's no other solution to remove
741 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
742 * structure with pointers to functions such as init_fd() and close_fd(), plus
743 * a private structure with several pointers to places such as below.
744 */
745
746static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
747#endif
748
willy tarreau0f7af912005-12-17 12:21:26 +0100749static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100750/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100751static char trash[BUFSIZE];
752
willy tarreaudd07e972005-12-18 00:48:48 +0100753const int zero = 0;
754const int one = 1;
755
willy tarreau0f7af912005-12-17 12:21:26 +0100756/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100757 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100758 */
759
760#define MAX_SYSLOG_LEN 1024
761#define NB_LOG_FACILITIES 24
762const char *log_facilities[NB_LOG_FACILITIES] = {
763 "kern", "user", "mail", "daemon",
764 "auth", "syslog", "lpr", "news",
765 "uucp", "cron", "auth2", "ftp",
766 "ntp", "audit", "alert", "cron2",
767 "local0", "local1", "local2", "local3",
768 "local4", "local5", "local6", "local7"
769};
770
771
772#define NB_LOG_LEVELS 8
773const char *log_levels[NB_LOG_LEVELS] = {
774 "emerg", "alert", "crit", "err",
775 "warning", "notice", "info", "debug"
776};
777
778#define SYSLOG_PORT 514
779
780const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
781 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100782
willy tarreaub1285d52005-12-18 01:20:14 +0100783const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100784const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
785const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
786const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
787 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
788 unknown, Set-cookie Rewritten */
789
willy tarreau0f7af912005-12-17 12:21:26 +0100790#define MAX_HOSTNAME_LEN 32
791static char hostname[MAX_HOSTNAME_LEN] = "";
792
willy tarreau8337c6b2005-12-17 13:41:01 +0100793const char *HTTP_302 =
794 "HTTP/1.0 302 Found\r\n"
795 "Cache-Control: no-cache\r\n"
796 "Connection: close\r\n"
797 "Location: "; /* not terminated since it will be concatenated with the URL */
798
willy tarreauc1f47532005-12-18 01:08:26 +0100799/* same as 302 except that the browser MUST retry with the GET method */
800const char *HTTP_303 =
801 "HTTP/1.0 303 See Other\r\n"
802 "Cache-Control: no-cache\r\n"
803 "Connection: close\r\n"
804 "Location: "; /* not terminated since it will be concatenated with the URL */
805
willy tarreaua1598082005-12-17 13:08:06 +0100806const char *HTTP_400 =
807 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100808 "Cache-Control: no-cache\r\n"
809 "Connection: close\r\n"
810 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100811 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100812
willy tarreaua1598082005-12-17 13:08:06 +0100813const char *HTTP_403 =
814 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100815 "Cache-Control: no-cache\r\n"
816 "Connection: close\r\n"
817 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100818 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
819
willy tarreau8337c6b2005-12-17 13:41:01 +0100820const char *HTTP_408 =
821 "HTTP/1.0 408 Request Time-out\r\n"
822 "Cache-Control: no-cache\r\n"
823 "Connection: close\r\n"
824 "\r\n"
825 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
826
willy tarreau750a4722005-12-17 13:21:24 +0100827const char *HTTP_500 =
828 "HTTP/1.0 500 Server Error\r\n"
829 "Cache-Control: no-cache\r\n"
830 "Connection: close\r\n"
831 "\r\n"
832 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100833
834const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100835 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100836 "Cache-Control: no-cache\r\n"
837 "Connection: close\r\n"
838 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100839 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
840
841const char *HTTP_503 =
842 "HTTP/1.0 503 Service Unavailable\r\n"
843 "Cache-Control: no-cache\r\n"
844 "Connection: close\r\n"
845 "\r\n"
846 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
847
848const char *HTTP_504 =
849 "HTTP/1.0 504 Gateway Time-out\r\n"
850 "Cache-Control: no-cache\r\n"
851 "Connection: close\r\n"
852 "\r\n"
853 "<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 +0100854
willy tarreau0f7af912005-12-17 12:21:26 +0100855/*********************************************************************/
856/* statistics ******************************************************/
857/*********************************************************************/
858
willy tarreau750a4722005-12-17 13:21:24 +0100859#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100860static int stats_tsk_lsrch, stats_tsk_rsrch,
861 stats_tsk_good, stats_tsk_right, stats_tsk_left,
862 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100863#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100864
865
866/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100867/* debugging *******************************************************/
868/*********************************************************************/
869#ifdef DEBUG_FULL
870static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau18a957c2006-04-12 19:26:23 +0200871static char *srv_stnames[8] = {"IDL", "PND", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
willy tarreau750a4722005-12-17 13:21:24 +0100872#endif
873
874/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100875/* function prototypes *********************************************/
876/*********************************************************************/
877
878int event_accept(int fd);
879int event_cli_read(int fd);
880int event_cli_write(int fd);
881int event_srv_read(int fd);
882int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100883int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100884
willy tarreau12350152005-12-18 01:03:27 +0100885static int appsession_task_init(void);
886static int appsession_init(void);
887static int appsession_refresh(struct task *t);
888
willy tarreau0f7af912005-12-17 12:21:26 +0100889/*********************************************************************/
890/* general purpose functions ***************************************/
891/*********************************************************************/
892
893void display_version() {
894 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100895 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100896}
897
898/*
899 * This function prints the command line usage and exits
900 */
901void usage(char *name) {
902 display_version();
903 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100904 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100905#if STATTIME > 0
906 "sl"
907#endif
willy tarreau746e26b2006-03-25 11:14:35 +0100908 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
909 " [ -p <pidfile> ] [ -m <max megs> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100910 " -v displays version\n"
willy tarreaubf8ff3d2006-03-25 19:47:03 +0100911 " -d enters debug mode ; -db only disables background mode.\n"
willy tarreau982249e2005-12-18 00:57:06 +0100912 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100913#if STATTIME > 0
914 " -s enables statistics output\n"
915 " -l enables long statistics format\n"
916#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100917 " -D goes daemon ; implies -q\n"
918 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100919 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100920 " -n sets the maximum total # of connections (%d)\n"
willy tarreau746e26b2006-03-25 11:14:35 +0100921 " -m limits the usable amount of memory (in MB)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100922 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100923 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100924#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100925 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100926#endif
927#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100928 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100929#endif
willy tarreau53e99702006-03-25 18:53:50 +0100930 " -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100931 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100932 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100933 exit(1);
934}
935
936
937/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100938 * Displays the message on stderr with the date and pid. Overrides the quiet
939 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100940 */
941void Alert(char *fmt, ...) {
942 va_list argp;
943 struct timeval tv;
944 struct tm *tm;
945
willy tarreaud0fb4652005-12-18 01:32:04 +0100946 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100947 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100948
willy tarreau5cbea6f2005-12-17 12:48:26 +0100949 gettimeofday(&tv, NULL);
950 tm=localtime(&tv.tv_sec);
951 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100952 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100953 vfprintf(stderr, fmt, argp);
954 fflush(stderr);
955 va_end(argp);
956 }
willy tarreau0f7af912005-12-17 12:21:26 +0100957}
958
959
960/*
961 * Displays the message on stderr with the date and pid.
962 */
963void Warning(char *fmt, ...) {
964 va_list argp;
965 struct timeval tv;
966 struct tm *tm;
967
willy tarreau982249e2005-12-18 00:57:06 +0100968 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100969 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100970
willy tarreau5cbea6f2005-12-17 12:48:26 +0100971 gettimeofday(&tv, NULL);
972 tm=localtime(&tv.tv_sec);
973 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100974 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100975 vfprintf(stderr, fmt, argp);
976 fflush(stderr);
977 va_end(argp);
978 }
979}
980
981/*
982 * Displays the message on <out> only if quiet mode is not set.
983 */
984void qfprintf(FILE *out, char *fmt, ...) {
985 va_list argp;
986
willy tarreau982249e2005-12-18 00:57:06 +0100987 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100988 va_start(argp, fmt);
989 vfprintf(out, fmt, argp);
990 fflush(out);
991 va_end(argp);
992 }
willy tarreau0f7af912005-12-17 12:21:26 +0100993}
994
995
996/*
997 * converts <str> to a struct sockaddr_in* which is locally allocated.
998 * The format is "addr:port", where "addr" can be empty or "*" to indicate
999 * INADDR_ANY.
1000 */
1001struct sockaddr_in *str2sa(char *str) {
1002 static struct sockaddr_in sa;
1003 char *c;
1004 int port;
1005
willy tarreaua1598082005-12-17 13:08:06 +01001006 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +01001007 str=strdup(str);
1008
1009 if ((c=strrchr(str,':')) != NULL) {
1010 *c++=0;
1011 port=atol(c);
1012 }
1013 else
1014 port=0;
1015
1016 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1017 sa.sin_addr.s_addr = INADDR_ANY;
1018 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01001019 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +01001020 struct hostent *he;
1021
1022 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01001023 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +01001024 }
1025 else
1026 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
1027 }
1028 sa.sin_port=htons(port);
1029 sa.sin_family=AF_INET;
1030
1031 free(str);
1032 return &sa;
1033}
1034
willy tarreaub1285d52005-12-18 01:20:14 +01001035/*
1036 * converts <str> to a two struct in_addr* which are locally allocated.
1037 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
1038 * is optionnal and either in the dotted or CIDR notation.
1039 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
1040 */
1041int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
1042 char *c;
1043 unsigned long len;
1044
1045 memset(mask, 0, sizeof(*mask));
1046 memset(addr, 0, sizeof(*addr));
1047 str=strdup(str);
1048
1049 if ((c = strrchr(str, '/')) != NULL) {
1050 *c++ = 0;
1051 /* c points to the mask */
1052 if (strchr(c, '.') != NULL) { /* dotted notation */
1053 if (!inet_pton(AF_INET, c, mask))
1054 return 0;
1055 }
1056 else { /* mask length */
1057 char *err;
1058 len = strtol(c, &err, 10);
1059 if (!*c || (err && *err) || (unsigned)len > 32)
1060 return 0;
1061 if (len)
1062 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
1063 else
1064 mask->s_addr = 0;
1065 }
1066 }
1067 else {
1068 mask->s_addr = 0xFFFFFFFF;
1069 }
1070 if (!inet_pton(AF_INET, str, addr)) {
1071 struct hostent *he;
1072
1073 if ((he = gethostbyname(str)) == NULL) {
1074 return 0;
1075 }
1076 else
1077 *addr = *(struct in_addr *) *(he->h_addr_list);
1078 }
1079 free(str);
1080 return 1;
1081}
1082
willy tarreau9fe663a2005-12-17 13:02:59 +01001083
1084/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001085 * converts <str> to a list of listeners which are dynamically allocated.
1086 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1087 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1088 * - <port> is a numerical port from 1 to 65535 ;
1089 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1090 * This can be repeated as many times as necessary, separated by a coma.
1091 * The <tail> argument is a pointer to a current list which should be appended
1092 * to the tail of the new list. The pointer to the new list is returned.
1093 */
1094struct listener *str2listener(char *str, struct listener *tail) {
1095 struct listener *l;
1096 char *c, *next, *range, *dupstr;
1097 int port, end;
1098
1099 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001100
willy tarreaua41a8b42005-12-17 14:02:24 +01001101 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001102 struct sockaddr_storage ss;
1103
willy tarreaua41a8b42005-12-17 14:02:24 +01001104 str = next;
1105 /* 1) look for the end of the first address */
1106 if ((next = strrchr(str, ',')) != NULL) {
1107 *next++ = 0;
1108 }
1109
willy tarreau8a86dbf2005-12-18 00:45:59 +01001110 /* 2) look for the addr/port delimiter, it's the last colon. */
1111 if ((range = strrchr(str, ':')) == NULL) {
1112 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001113 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001114 }
1115
1116 *range++ = 0;
1117
1118 if (strrchr(str, ':') != NULL) {
1119 /* IPv6 address contains ':' */
1120 memset(&ss, 0, sizeof(ss));
1121 ss.ss_family = AF_INET6;
1122
1123 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1124 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001125 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001126 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001127 }
1128 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001129 memset(&ss, 0, sizeof(ss));
1130 ss.ss_family = AF_INET;
1131
1132 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1133 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1134 }
1135 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1136 struct hostent *he;
1137
1138 if ((he = gethostbyname(str)) == NULL) {
1139 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001140 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001141 }
1142 else
1143 ((struct sockaddr_in *)&ss)->sin_addr =
1144 *(struct in_addr *) *(he->h_addr_list);
1145 }
1146 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001147
1148 /* 3) look for the port-end delimiter */
1149 if ((c = strchr(range, '-')) != NULL) {
1150 *c++ = 0;
1151 end = atol(c);
1152 }
1153 else {
1154 end = atol(range);
1155 }
1156
willy tarreaud0fb4652005-12-18 01:32:04 +01001157 port = atol(range);
1158
1159 if (port < 1 || port > 65535) {
1160 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1161 goto fail;
1162 }
1163
1164 if (end < 1 || end > 65535) {
1165 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1166 goto fail;
1167 }
1168
1169 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001170 l = (struct listener *)calloc(1, sizeof(struct listener));
1171 l->next = tail;
1172 tail = l;
1173
willy tarreau41310e72006-03-25 18:17:56 +01001174 l->fd = -1;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001175 l->addr = ss;
1176 if (ss.ss_family == AF_INET6)
1177 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1178 else
1179 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1180
willy tarreaua41a8b42005-12-17 14:02:24 +01001181 } /* end for(port) */
1182 } /* end while(next) */
1183 free(dupstr);
1184 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001185 fail:
1186 free(dupstr);
1187 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001188}
1189
willy tarreau4302f492005-12-18 01:00:37 +01001190
1191#define FD_SETS_ARE_BITFIELDS
1192#ifdef FD_SETS_ARE_BITFIELDS
1193/*
1194 * This map is used with all the FD_* macros to check whether a particular bit
1195 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1196 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1197 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1198 * exclusively to the macros.
1199 */
1200fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1201fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1202
1203#else
1204#error "Check if your OS uses bitfields for fd_sets"
1205#endif
1206
1207/* will try to encode the string <string> replacing all characters tagged in
1208 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1209 * prefixed by <escape>, and will store the result between <start> (included
1210 *) and <stop> (excluded), and will always terminate the string with a '\0'
1211 * before <stop>. The position of the '\0' is returned if the conversion
1212 * completes. If bytes are missing between <start> and <stop>, then the
1213 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1214 * cannot even be stored so we return <start> without writing the 0.
1215 * The input string must also be zero-terminated.
1216 */
1217char hextab[16] = "0123456789ABCDEF";
1218char *encode_string(char *start, char *stop,
1219 const char escape, const fd_set *map,
1220 const char *string)
1221{
1222 if (start < stop) {
1223 stop--; /* reserve one byte for the final '\0' */
1224 while (start < stop && *string != 0) {
1225 if (!FD_ISSET((unsigned char)(*string), map))
1226 *start++ = *string;
1227 else {
1228 if (start + 3 >= stop)
1229 break;
1230 *start++ = escape;
1231 *start++ = hextab[(*string >> 4) & 15];
1232 *start++ = hextab[*string & 15];
1233 }
1234 string++;
1235 }
1236 *start = '\0';
1237 }
1238 return start;
1239}
willy tarreaua41a8b42005-12-17 14:02:24 +01001240
1241/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001242 * This function sends a syslog message to both log servers of a proxy,
1243 * or to global log servers if the proxy is NULL.
1244 * It also tries not to waste too much time computing the message header.
1245 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001246 */
1247void send_log(struct proxy *p, int level, char *message, ...) {
1248 static int logfd = -1; /* syslog UDP socket */
1249 static long tvsec = -1; /* to force the string to be initialized */
1250 struct timeval tv;
1251 va_list argp;
1252 static char logmsg[MAX_SYSLOG_LEN];
1253 static char *dataptr = NULL;
1254 int fac_level;
1255 int hdr_len, data_len;
1256 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001257 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001258 int nbloggers = 0;
1259 char *log_ptr;
1260
1261 if (logfd < 0) {
1262 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1263 return;
1264 }
1265
1266 if (level < 0 || progname == NULL || message == NULL)
1267 return;
1268
1269 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001270 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001271 /* this string is rebuild only once a second */
1272 struct tm *tm = localtime(&tv.tv_sec);
1273 tvsec = tv.tv_sec;
1274
willy tarreauc29948c2005-12-17 13:10:27 +01001275 hdr_len = snprintf(logmsg, sizeof(logmsg),
1276 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1277 monthname[tm->tm_mon],
1278 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1279 progname, pid);
1280 /* WARNING: depending upon implementations, snprintf may return
1281 * either -1 or the number of bytes that would be needed to store
1282 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001283 */
willy tarreauc29948c2005-12-17 13:10:27 +01001284 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1285 hdr_len = sizeof(logmsg);
1286
1287 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001288 }
1289
1290 va_start(argp, message);
1291 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001292 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1293 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001294 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001295 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001296
1297 if (p == NULL) {
1298 if (global.logfac1 >= 0) {
1299 sa[nbloggers] = &global.logsrv1;
1300 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001301 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001302 nbloggers++;
1303 }
1304 if (global.logfac2 >= 0) {
1305 sa[nbloggers] = &global.logsrv2;
1306 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001307 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001308 nbloggers++;
1309 }
1310 } else {
1311 if (p->logfac1 >= 0) {
1312 sa[nbloggers] = &p->logsrv1;
1313 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001314 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001315 nbloggers++;
1316 }
1317 if (p->logfac2 >= 0) {
1318 sa[nbloggers] = &p->logsrv2;
1319 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001320 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001321 nbloggers++;
1322 }
1323 }
1324
1325 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001326 /* we can filter the level of the messages that are sent to each logger */
1327 if (level > loglevel[nbloggers])
1328 continue;
1329
willy tarreauc29948c2005-12-17 13:10:27 +01001330 /* For each target, we may have a different facility.
1331 * We can also have a different log level for each message.
1332 * This induces variations in the message header length.
1333 * Since we don't want to recompute it each time, nor copy it every
1334 * time, we only change the facility in the pre-computed header,
1335 * and we change the pointer to the header accordingly.
1336 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001337 fac_level = (facilities[nbloggers] << 3) + level;
1338 log_ptr = logmsg + 3; /* last digit of the log level */
1339 do {
1340 *log_ptr = '0' + fac_level % 10;
1341 fac_level /= 10;
1342 log_ptr--;
1343 } while (fac_level && log_ptr > logmsg);
1344 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001345
willy tarreauc29948c2005-12-17 13:10:27 +01001346 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001347
1348#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001349 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001350 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1351#else
willy tarreauc29948c2005-12-17 13:10:27 +01001352 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001353 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1354#endif
1355 }
willy tarreau0f7af912005-12-17 12:21:26 +01001356}
1357
1358
1359/* sets <tv> to the current time */
1360static inline struct timeval *tv_now(struct timeval *tv) {
1361 if (tv)
1362 gettimeofday(tv, NULL);
1363 return tv;
1364}
1365
1366/*
1367 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1368 */
1369static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1370 if (!tv || !from)
1371 return NULL;
1372 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1373 tv->tv_sec = from->tv_sec + (ms/1000);
1374 while (tv->tv_usec >= 1000000) {
1375 tv->tv_usec -= 1000000;
1376 tv->tv_sec++;
1377 }
1378 return tv;
1379}
1380
1381/*
1382 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001383 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001384 */
1385static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001386 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001387 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001388 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001389 return 1;
1390 else if (tv1->tv_usec < tv2->tv_usec)
1391 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001392 else if (tv1->tv_usec > tv2->tv_usec)
1393 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001394 else
1395 return 0;
1396}
1397
1398/*
1399 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001400 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001401 */
1402unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1403 int cmp;
1404 unsigned long ret;
1405
1406
willy tarreauef900ab2005-12-17 12:52:52 +01001407 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001408 if (!cmp)
1409 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001410 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001411 struct timeval *tmp = tv1;
1412 tv1 = tv2;
1413 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001414 }
willy tarreauef900ab2005-12-17 12:52:52 +01001415 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001416 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001417 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001418 else
willy tarreauef900ab2005-12-17 12:52:52 +01001419 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001420 return (unsigned long) ret;
1421}
1422
1423/*
willy tarreau750a4722005-12-17 13:21:24 +01001424 * returns the 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 tarreau750a4722005-12-17 13:21:24 +01001426 */
1427static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1428 unsigned long ret;
1429
willy tarreau6e682ce2005-12-17 13:26:49 +01001430 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1431 if (tv2->tv_usec > tv1->tv_usec)
1432 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001433 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001434 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001435 return (unsigned long) ret;
1436}
1437
1438/*
willy tarreau0f7af912005-12-17 12:21:26 +01001439 * 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 +01001440 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001441 */
1442static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001443 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001444 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001445 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001446 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001447 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001448 else
1449 return 0;
1450 }
willy tarreau0f7af912005-12-17 12:21:26 +01001451 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001452 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001453 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001454 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001455 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001456 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001457 else
1458 return 0;
1459}
1460
1461/*
1462 * returns the remaining time between tv1=now and event=tv2
1463 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001464 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001465 */
1466static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1467 unsigned long ret;
1468
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (tv_cmp_ms(tv1, tv2) >= 0)
1470 return 0; /* event elapsed */
1471
willy tarreauef900ab2005-12-17 12:52:52 +01001472 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001473 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001474 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001475 else
willy tarreauef900ab2005-12-17 12:52:52 +01001476 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001477 return (unsigned long) ret;
1478}
1479
1480
1481/*
1482 * zeroes a struct timeval
1483 */
1484
1485static inline struct timeval *tv_eternity(struct timeval *tv) {
1486 tv->tv_sec = tv->tv_usec = 0;
1487 return tv;
1488}
1489
1490/*
1491 * returns 1 if tv is null, else 0
1492 */
1493static inline int tv_iseternity(struct timeval *tv) {
1494 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1495 return 1;
1496 else
1497 return 0;
1498}
1499
1500/*
1501 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1502 * considering that 0 is the eternity.
1503 */
1504static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1505 if (tv_iseternity(tv1))
1506 if (tv_iseternity(tv2))
1507 return 0; /* same */
1508 else
1509 return 1; /* tv1 later than tv2 */
1510 else if (tv_iseternity(tv2))
1511 return -1; /* tv2 later than tv1 */
1512
1513 if (tv1->tv_sec > tv2->tv_sec)
1514 return 1;
1515 else if (tv1->tv_sec < tv2->tv_sec)
1516 return -1;
1517 else if (tv1->tv_usec > tv2->tv_usec)
1518 return 1;
1519 else if (tv1->tv_usec < tv2->tv_usec)
1520 return -1;
1521 else
1522 return 0;
1523}
1524
1525/*
1526 * compares <tv1> and <tv2> modulo 1 ms: 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_ms(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
willy tarreauefae1842005-12-17 12:51:03 +01001538 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001539 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001540 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001541 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001542 return -1;
1543 else
1544 return 0;
1545 }
1546 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001547 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001548 return 1;
1549 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001550 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001551 return -1;
1552 else
1553 return 0;
1554}
1555
1556/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001557 * returns the remaining time between tv1=now and event=tv2
1558 * if tv2 is passed, 0 is returned.
1559 * Returns TIME_ETERNITY if tv2 is eternity.
1560 */
1561static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1562 unsigned long ret;
1563
1564 if (tv_iseternity(tv2))
1565 return TIME_ETERNITY;
1566
1567 if (tv_cmp_ms(tv1, tv2) >= 0)
1568 return 0; /* event elapsed */
1569
1570 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1571 if (tv2->tv_usec > tv1->tv_usec)
1572 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1573 else
1574 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1575 return (unsigned long) ret;
1576}
1577
1578/*
willy tarreau0f7af912005-12-17 12:21:26 +01001579 * returns the first event between tv1 and tv2 into tvmin.
1580 * a zero tv is ignored. tvmin is returned.
1581 */
1582static inline struct timeval *tv_min(struct timeval *tvmin,
1583 struct timeval *tv1, struct timeval *tv2) {
1584
1585 if (tv_cmp2(tv1, tv2) <= 0)
1586 *tvmin = *tv1;
1587 else
1588 *tvmin = *tv2;
1589
1590 return tvmin;
1591}
1592
1593
1594
1595/***********************************************************/
1596/* fd management ***************************************/
1597/***********************************************************/
1598
1599
1600
willy tarreau5cbea6f2005-12-17 12:48:26 +01001601/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1602 * The file descriptor is also closed.
1603 */
willy tarreau0f7af912005-12-17 12:21:26 +01001604static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001605 FD_CLR(fd, StaticReadEvent);
1606 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001607#if defined(ENABLE_EPOLL)
1608 if (PrevReadEvent) {
1609 FD_CLR(fd, PrevReadEvent);
1610 FD_CLR(fd, PrevWriteEvent);
1611 }
1612#endif
1613
willy tarreau5cbea6f2005-12-17 12:48:26 +01001614 close(fd);
1615 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001616
1617 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1618 maxfd--;
1619}
1620
1621/* recomputes the maxfd limit from the fd */
1622static inline void fd_insert(int fd) {
1623 if (fd+1 > maxfd)
1624 maxfd = fd+1;
1625}
1626
1627/*************************************************************/
1628/* task management ***************************************/
1629/*************************************************************/
1630
willy tarreau5cbea6f2005-12-17 12:48:26 +01001631/* puts the task <t> in run queue <q>, and returns <t> */
1632static inline struct task *task_wakeup(struct task **q, struct task *t) {
1633 if (t->state == TASK_RUNNING)
1634 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001635 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 t->rqnext = *q;
1637 t->state = TASK_RUNNING;
1638 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001639 }
1640}
1641
willy tarreau5cbea6f2005-12-17 12:48:26 +01001642/* removes the task <t> from the queue <q>
1643 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001644 * set the run queue to point to the next one, and return it
1645 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001646static inline struct task *task_sleep(struct task **q, struct task *t) {
1647 if (t->state == TASK_RUNNING) {
1648 *q = t->rqnext;
1649 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001650 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001651 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001652}
1653
1654/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001655 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001656 * from the run queue. A pointer to the task itself is returned.
1657 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658static inline struct task *task_delete(struct task *t) {
1659 t->prev->next = t->next;
1660 t->next->prev = t->prev;
1661 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001662}
1663
1664/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001665 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001666 */
1667static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001668 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001669}
1670
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001672 * may be only moved or left where it was, depending on its timing requirements.
1673 * <task> is returned.
1674 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001675struct task *task_queue(struct task *task) {
1676 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001677 struct task *start_from;
1678
1679 /* first, test if the task was already in a list */
1680 if (task->prev == NULL) {
1681 // start_from = list;
1682 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001683#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001684 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001685#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001686 /* insert the unlinked <task> into the list, searching back from the last entry */
1687 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1688 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001689#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001690 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001691#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001692 }
1693
1694 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1695 // start_from = start_from->next;
1696 // stats_tsk_nsrch++;
1697 // }
1698 }
1699 else if (task->prev == list ||
1700 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1701 start_from = task->next;
1702 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001703#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001704 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001705#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001706 return task; /* it's already in the right place */
1707 }
1708
willy tarreau750a4722005-12-17 13:21:24 +01001709#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001710 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001711#endif
1712
1713 /* if the task is not at the right place, there's little chance that
1714 * it has only shifted a bit, and it will nearly always be queued
1715 * at the end of the list because of constant timeouts
1716 * (observed in real case).
1717 */
1718#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1719 start_from = list->prev; /* assume we'll queue to the end of the list */
1720 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1721 start_from = start_from->prev;
1722#if STATTIME > 0
1723 stats_tsk_lsrch++;
1724#endif
1725 }
1726#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001727 /* insert the unlinked <task> into the list, searching after position <start_from> */
1728 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1729 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001730#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001731 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001732#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001733 }
willy tarreau750a4722005-12-17 13:21:24 +01001734#endif /* WE_REALLY_... */
1735
willy tarreau0f7af912005-12-17 12:21:26 +01001736 /* we need to unlink it now */
1737 task_delete(task);
1738 }
1739 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001740#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001741 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001742#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001743#ifdef LEFT_TO_TOP /* not very good */
1744 start_from = list;
1745 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1746 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001747#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001748 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001749#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001750 }
1751#else
1752 start_from = task->prev->prev; /* valid because of the previous test above */
1753 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1754 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001755#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001756 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001757#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001758 }
1759#endif
1760 /* we need to unlink it now */
1761 task_delete(task);
1762 }
1763 task->prev = start_from;
1764 task->next = start_from->next;
1765 task->next->prev = task;
1766 start_from->next = task;
1767 return task;
1768}
1769
1770
1771/*********************************************************************/
willy tarreau18a957c2006-04-12 19:26:23 +02001772/* pending connections queues **************************************/
1773/*********************************************************************/
1774
1775/*
1776 * returns the first pending connection of server <s> or NULL if none.
1777 */
1778static inline struct pendconn *pendconn_peek(struct server *s) {
1779 if (!s->nbpend)
1780 return NULL;
1781
1782 return LIST_ELEM(s->pendconns.n, struct pendconn *, list);
1783}
1784
1785/*
1786 * Detaches pending connection <p>, decreases the pending count, and frees
1787 * the pending connection.
1788 */
1789static inline void pendconn_free(struct pendconn *p) {
1790 LIST_DEL(&p->list);
1791 p->sess->pend_pos = NULL;
1792 p->srv->nbpend--;
1793 pool_free(pendconn, p);
1794}
1795
1796/* detaches the first pending connection for server <s> and returns its
1797 * associated session. If no pending connection is found, NULL is returned.
1798 */
1799static inline struct session *pendconn_get(struct server *s) {
1800 struct pendconn *p;
1801 struct session *sess;
1802
1803 p = pendconn_peek(s);
1804 if (!p)
1805 return NULL;
1806 sess = p->sess;
1807 pendconn_free(p);
1808 return sess;
1809}
1810
1811/* adds the session <sess> to the pending connection list of server <srv>.
1812 * All counters and back pointers are updated accordingly. Returns NULL if
1813 * no memory is available, otherwise the pendconn itself.
1814 */
1815static struct pendconn *pendconn_add(struct server *srv, struct session *sess) {
1816 struct pendconn *p;
1817
1818 p = pool_alloc(pendconn);
1819 if (!p)
1820 return NULL;
1821
1822 LIST_ADDQ(&srv->pendconns, &p->list);
1823 p->sess = sess;
1824 p->srv = srv;
1825 sess->pend_pos = p;
1826 srv->nbpend++;
1827 return p;
1828}
1829
1830/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +01001831/* more specific functions ***************************************/
1832/*********************************************************************/
1833
1834/* some prototypes */
1835static int maintain_proxies(void);
1836
willy tarreaub952e1d2005-12-18 01:31:20 +01001837/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001838 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1839 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001840static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001841#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1843#else
willy tarreaua1598082005-12-17 13:08:06 +01001844#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001845 return getsockname(fd, (struct sockaddr *)sa, salen);
1846#else
1847 return -1;
1848#endif
1849#endif
1850}
1851
1852/*
1853 * frees the context associated to a session. It must have been removed first.
1854 */
1855static inline void session_free(struct session *s) {
willy tarreau18a957c2006-04-12 19:26:23 +02001856 if (s->pend_pos)
1857 pendconn_free(s->pend_pos);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 if (s->req)
1859 pool_free(buffer, s->req);
1860 if (s->rep)
1861 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001862
1863 if (s->rsp_cap != NULL) {
1864 struct cap_hdr *h;
1865 for (h = s->proxy->rsp_cap; h; h = h->next) {
1866 if (s->rsp_cap[h->index] != NULL)
1867 pool_free_to(h->pool, s->rsp_cap[h->index]);
1868 }
1869 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1870 }
1871 if (s->req_cap != NULL) {
1872 struct cap_hdr *h;
1873 for (h = s->proxy->req_cap; h; h = h->next) {
1874 if (s->req_cap[h->index] != NULL)
1875 pool_free_to(h->pool, s->req_cap[h->index]);
1876 }
1877 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1878 }
1879
willy tarreaua1598082005-12-17 13:08:06 +01001880 if (s->logs.uri)
1881 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001882 if (s->logs.cli_cookie)
1883 pool_free(capture, s->logs.cli_cookie);
1884 if (s->logs.srv_cookie)
1885 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001886
willy tarreau5cbea6f2005-12-17 12:48:26 +01001887 pool_free(session, s);
1888}
1889
willy tarreau0f7af912005-12-17 12:21:26 +01001890
1891/*
willy tarreau4c8c2b52006-03-24 19:36:41 +01001892 * This function recounts the number of usable active and backup servers for
1893 * proxy <p>. These numbers are returned into the p->srv_act and p->srv_bck.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001894 * This function also recomputes the total active and backup weights.
willy tarreau4c8c2b52006-03-24 19:36:41 +01001895 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001896static void recount_servers(struct proxy *px) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001897 struct server *srv;
1898
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001899 px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001900 for (srv = px->srv; srv != NULL; srv = srv->next) {
1901 if (srv->state & SRV_RUNNING) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001902 if (srv->state & SRV_BACKUP) {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001903 px->srv_bck++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001904 px->tot_wbck += srv->eweight + 1;
1905 } else {
willy tarreau4c8c2b52006-03-24 19:36:41 +01001906 px->srv_act++;
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001907 px->tot_wact += srv->eweight + 1;
1908 }
willy tarreau4c8c2b52006-03-24 19:36:41 +01001909 }
1910 }
1911}
1912
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001913/* This function recomputes the server map for proxy px. It
1914 * relies on px->tot_wact and px->tot_wbck, so it must be
1915 * called after recount_servers(). It also expects px->srv_map
1916 * to be initialized to the largest value needed.
willy tarreau8337c6b2005-12-17 13:41:01 +01001917 */
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001918static void recalc_server_map(struct proxy *px) {
1919 int o, tot, flag;
1920 struct server *cur, *best;
willy tarreau8337c6b2005-12-17 13:41:01 +01001921
willy tarreau4c8c2b52006-03-24 19:36:41 +01001922 if (px->srv_act) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001923 flag = SRV_RUNNING;
1924 tot = px->tot_wact;
1925 } else if (px->srv_bck) {
1926 flag = SRV_RUNNING | SRV_BACKUP;
1927 if (px->options & PR_O_USE_ALL_BK)
1928 tot = px->tot_wbck;
1929 else
1930 tot = 1; /* the first server is enough */
1931 } else {
1932 px->srv_map_sz = 0;
1933 return;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001934 }
Willy TARREAU3481c462006-03-01 22:37:57 +01001935
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001936 /* this algorithm gives priority to the first server, which means that
1937 * it will respect the declaration order for equivalent weights, and
1938 * that whatever the weights, the first server called will always be
1939 * the first declard. This is an important asumption for the backup
1940 * case, where we want the first server only.
1941 */
1942 for (cur = px->srv; cur; cur = cur->next)
1943 cur->wscore = 0;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001944
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001945 for (o = 0; o < tot; o++) {
1946 int max = 0;
1947 best = NULL;
1948 for (cur = px->srv; cur; cur = cur->next) {
1949 if ((cur->state & (SRV_RUNNING | SRV_BACKUP)) == flag) {
1950 int v;
1951
1952 /* If we are forced to return only one server, we don't want to
1953 * go further, because we would return the wrong one due to
1954 * divide overflow.
1955 */
1956 if (tot == 1) {
1957 best = cur;
1958 break;
1959 }
1960
1961 cur->wscore += cur->eweight + 1;
1962 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
1963 if (best == NULL || v > max) {
1964 max = v;
1965 best = cur;
1966 }
1967 }
1968 }
1969 px->srv_map[o] = best;
1970 best->wscore -= tot;
willy tarreau4c8c2b52006-03-24 19:36:41 +01001971 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001972 px->srv_map_sz = tot;
1973}
Willy TARREAU3481c462006-03-01 22:37:57 +01001974
willy tarreaucc1e2bd2006-04-10 20:32:43 +02001975/*
willy tarreau898db9d2006-04-12 20:29:08 +02001976 * This function tries to find a running server with free connection slots for
1977 * the proxy <px> following the round-robin method.
1978 * If any server is found, it will be returned and px->srv_rr_idx will be updated
1979 * to point to the next server. If no valid server is found, NULL is returned.
1980 */
1981static inline struct server *get_server_rr_with_conns(struct proxy *px) {
1982 int newidx;
1983 struct server *srv;
1984
1985 if (px->srv_map_sz == 0)
1986 return NULL;
1987
1988 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
1989 px->srv_rr_idx = 0;
1990 newidx = px->srv_rr_idx;
1991
1992 do {
1993 srv = px->srv_map[newidx++];
1994 if (!srv->maxconn || srv->cur_sess < srv->maxconn) {
1995 px->srv_rr_idx = newidx;
1996 return srv;
1997 }
1998 if (newidx == px->srv_map_sz)
1999 newidx = 0;
2000 } while (newidx != px->srv_rr_idx);
2001
2002 return NULL;
2003}
2004
2005
2006/*
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002007 * This function tries to find a running server for the proxy <px> following
willy tarreau898db9d2006-04-12 20:29:08 +02002008 * the round-robin method.
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002009 * If any server is found, it will be returned and px->srv_rr_idx will be updated
2010 * to point to the next server. If no valid server is found, NULL is returned.
2011 */
2012static inline struct server *get_server_rr(struct proxy *px) {
2013 if (px->srv_map_sz == 0)
2014 return NULL;
2015
2016 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
2017 px->srv_rr_idx = 0;
2018 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01002019}
2020
willy tarreau62084d42006-03-24 18:57:41 +01002021
2022/*
willy tarreau1a3442d2006-03-24 21:03:20 +01002023 * This function tries to find a running server for the proxy <px> following
2024 * the source hash method. Depending on the number of active/backup servers,
2025 * it will either look for active servers, or for backup servers.
2026 * If any server is found, it will be returned. If no valid server is found,
2027 * NULL is returned.
2028 */
2029static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002030 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002031
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002032 if (px->srv_map_sz == 0)
2033 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002034
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002035 l = h = 0;
2036 if (px->srv_act > 1) {
2037 while ((l + sizeof (int)) <= len) {
2038 h ^= ntohl(*(unsigned int *)(&addr[l]));
2039 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002040 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002041 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002042 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002043 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002044}
2045
2046
2047/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01002049 * is set, or to the dispatch server if (s->direct) is 0.
2050 * It can return one of :
2051 * - SN_ERR_NONE if everything's OK
2052 * - SN_ERR_SRVTO if there are no more servers
2053 * - SN_ERR_SRVCL if the connection was refused by the server
2054 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2055 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2056 * - SN_ERR_INTERNAL for any other purely internal errors
2057 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01002058 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002059int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01002060 int fd;
2061
willy tarreau12350152005-12-18 01:03:27 +01002062#ifdef DEBUG_FULL
2063 fprintf(stderr,"connect_server : s=%p\n",s);
2064#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002065
willy tarreaue39cd132005-12-17 13:00:18 +01002066 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002067 s->srv_addr = s->srv->addr;
2068 }
2069 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01002070 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01002071 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2072 return SN_ERR_SRVTO;
2073
willy tarreau5cbea6f2005-12-17 12:48:26 +01002074 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002075 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002076
willy tarreau898db9d2006-04-12 20:29:08 +02002077 srv = get_server_rr_with_conns(s->proxy);
2078 if (!srv)
2079 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01002080 s->srv_addr = srv->addr;
2081 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01002082 }
willy tarreau1a3442d2006-03-24 21:03:20 +01002083 else if (s->proxy->options & PR_O_BALANCE_SH) {
2084 struct server *srv;
2085 int len;
2086
2087 if (s->cli_addr.ss_family == AF_INET)
2088 len = 4;
2089 else if (s->cli_addr.ss_family == AF_INET6)
2090 len = 16;
2091 else /* unknown IP family */
2092 return SN_ERR_INTERNAL;
2093
2094 srv = get_server_sh(s->proxy,
2095 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2096 len);
2097 s->srv_addr = srv->addr;
2098 s->srv = srv;
2099 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01002101 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002102 }
willy tarreaua1598082005-12-17 13:08:06 +01002103 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002104 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002105 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002106 }
2107 else if (s->proxy->options & PR_O_TRANSP) {
2108 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002109 socklen_t salen = sizeof(s->srv_addr);
2110
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2112 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002113 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002114 }
2115 }
willy tarreau0f7af912005-12-17 12:21:26 +01002116
willy tarreaua41a8b42005-12-17 14:02:24 +01002117 /* if this server remaps proxied ports, we'll use
2118 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002119 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002120 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002121 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002122
willy tarreaub952e1d2005-12-18 01:31:20 +01002123 if (!(s->proxy->options & PR_O_TRANSP) ||
2124 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002125 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2126 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2127 }
2128
willy tarreau0f7af912005-12-17 12:21:26 +01002129 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002130 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002131
2132 if (errno == ENFILE)
2133 send_log(s->proxy, LOG_EMERG,
2134 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2135 s->proxy->id, maxfd);
2136 else if (errno == EMFILE)
2137 send_log(s->proxy, LOG_EMERG,
2138 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2139 s->proxy->id, maxfd);
2140 else if (errno == ENOBUFS || errno == ENOMEM)
2141 send_log(s->proxy, LOG_EMERG,
2142 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2143 s->proxy->id, maxfd);
2144 /* this is a resource error */
2145 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002146 }
2147
willy tarreau9fe663a2005-12-17 13:02:59 +01002148 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002149 /* do not log anything there, it's a normal condition when this option
2150 * is used to serialize connections to a server !
2151 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002152 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2153 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002154 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 }
2156
willy tarreau0f7af912005-12-17 12:21:26 +01002157 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2158 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002160 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002161 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002162 }
2163
willy tarreaub952e1d2005-12-18 01:31:20 +01002164 if (s->proxy->options & PR_O_TCP_SRV_KA)
2165 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2166
willy tarreau0174f312005-12-18 01:02:42 +01002167 /* allow specific binding :
2168 * - server-specific at first
2169 * - proxy-specific next
2170 */
2171 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2172 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2173 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2174 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2175 s->proxy->id, s->srv->id);
2176 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002177 send_log(s->proxy, LOG_EMERG,
2178 "Cannot bind to source address before connect() for server %s/%s.\n",
2179 s->proxy->id, s->srv->id);
2180 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002181 }
2182 }
2183 else if (s->proxy->options & PR_O_BIND_SRC) {
2184 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2185 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2186 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2187 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002188 send_log(s->proxy, LOG_EMERG,
2189 "Cannot bind to source address before connect() for server %s/%s.\n",
2190 s->proxy->id, s->srv->id);
2191 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002192 }
willy tarreaua1598082005-12-17 13:08:06 +01002193 }
2194
willy tarreaub1285d52005-12-18 01:20:14 +01002195 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2196 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2197
2198 if (errno == EAGAIN || errno == EADDRINUSE) {
2199 char *msg;
2200 if (errno == EAGAIN) /* no free ports left, try again later */
2201 msg = "no free ports";
2202 else
2203 msg = "local address already in use";
2204
2205 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002206 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002207 send_log(s->proxy, LOG_EMERG,
2208 "Connect() failed for server %s/%s: %s.\n",
2209 s->proxy->id, s->srv->id, msg);
2210 return SN_ERR_RESOURCE;
2211 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002212 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002213 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002214 return SN_ERR_SRVTO;
2215 } else {
2216 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002217 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002218 close(fd);
2219 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002220 }
2221 }
2222
willy tarreau5cbea6f2005-12-17 12:48:26 +01002223 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002224 fdtab[fd].read = &event_srv_read;
2225 fdtab[fd].write = &event_srv_write;
2226 fdtab[fd].state = FD_STCONN; /* connection in progress */
2227
2228 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002229#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2230 if (PrevReadEvent) {
2231 assert(!(FD_ISSET(fd, PrevReadEvent)));
2232 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2233 }
2234#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002235
2236 fd_insert(fd);
willy tarreaua647c702006-04-15 22:45:52 +02002237 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002238
2239 if (s->proxy->contimeout)
2240 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2241 else
2242 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002243 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002244}
2245
2246/*
2247 * this function is called on a read event from a client socket.
2248 * It returns 0.
2249 */
2250int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002251 struct task *t = fdtab[fd].owner;
2252 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002253 struct buffer *b = s->req;
2254 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002255
willy tarreau12350152005-12-18 01:03:27 +01002256#ifdef DEBUG_FULL
2257 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2258#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002259
willy tarreau0f7af912005-12-17 12:21:26 +01002260 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002261#ifdef FILL_BUFFERS
2262 while (1)
2263#else
2264 do
2265#endif
2266 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002267 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2268 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002269 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002270 }
2271 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002272 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002273 }
2274 else {
2275 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002276 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2277 * since it means that the rewrite protection has been removed. This
2278 * implies that the if statement can be removed.
2279 */
2280 if (max > b->rlim - b->data)
2281 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002282 }
2283
2284 if (max == 0) { /* not anymore room to store data */
2285 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002286 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287 }
2288
willy tarreau3242e862005-12-17 12:27:53 +01002289#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002290 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002291 int skerr;
2292 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002293
willy tarreau5cbea6f2005-12-17 12:48:26 +01002294 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2295 if (skerr)
2296 ret = -1;
2297 else
2298 ret = recv(fd, b->r, max, 0);
2299 }
willy tarreau3242e862005-12-17 12:27:53 +01002300#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002301 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002302#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002303 if (ret > 0) {
2304 b->r += ret;
2305 b->l += ret;
2306 s->res_cr = RES_DATA;
2307
2308 if (b->r == b->data + BUFSIZE) {
2309 b->r = b->data; /* wrap around the buffer */
2310 }
willy tarreaua1598082005-12-17 13:08:06 +01002311
2312 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002313 /* we hope to read more data or to get a close on next round */
2314 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002315 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002316 else if (ret == 0) {
2317 s->res_cr = RES_NULL;
2318 break;
2319 }
2320 else if (errno == EAGAIN) {/* ignore EAGAIN */
2321 break;
2322 }
2323 else {
2324 s->res_cr = RES_ERROR;
2325 fdtab[fd].state = FD_STERROR;
2326 break;
2327 }
2328 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002329#ifndef FILL_BUFFERS
2330 while (0);
2331#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002332 }
2333 else {
2334 s->res_cr = RES_ERROR;
2335 fdtab[fd].state = FD_STERROR;
2336 }
2337
willy tarreau5cbea6f2005-12-17 12:48:26 +01002338 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002339 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2341 else
2342 tv_eternity(&s->crexpire);
2343
2344 task_wakeup(&rq, t);
2345 }
willy tarreau0f7af912005-12-17 12:21:26 +01002346
willy tarreau0f7af912005-12-17 12:21:26 +01002347 return 0;
2348}
2349
2350
2351/*
2352 * this function is called on a read event from a server socket.
2353 * It returns 0.
2354 */
2355int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002356 struct task *t = fdtab[fd].owner;
2357 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002358 struct buffer *b = s->rep;
2359 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002360
willy tarreau12350152005-12-18 01:03:27 +01002361#ifdef DEBUG_FULL
2362 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2363#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002364
willy tarreau0f7af912005-12-17 12:21:26 +01002365 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002366#ifdef FILL_BUFFERS
2367 while (1)
2368#else
2369 do
2370#endif
2371 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002372 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2373 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002374 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002375 }
2376 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002377 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002378 }
2379 else {
2380 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002381 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2382 * since it means that the rewrite protection has been removed. This
2383 * implies that the if statement can be removed.
2384 */
2385 if (max > b->rlim - b->data)
2386 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002387 }
2388
2389 if (max == 0) { /* not anymore room to store data */
2390 FD_CLR(fd, StaticReadEvent);
2391 break;
2392 }
2393
willy tarreau3242e862005-12-17 12:27:53 +01002394#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002395 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002396 int skerr;
2397 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002398
willy tarreau5cbea6f2005-12-17 12:48:26 +01002399 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2400 if (skerr)
2401 ret = -1;
2402 else
2403 ret = recv(fd, b->r, max, 0);
2404 }
willy tarreau3242e862005-12-17 12:27:53 +01002405#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002406 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002407#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002408 if (ret > 0) {
2409 b->r += ret;
2410 b->l += ret;
2411 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002412
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 if (b->r == b->data + BUFSIZE) {
2414 b->r = b->data; /* wrap around the buffer */
2415 }
willy tarreaua1598082005-12-17 13:08:06 +01002416
2417 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002418 /* we hope to read more data or to get a close on next round */
2419 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002420 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002421 else if (ret == 0) {
2422 s->res_sr = RES_NULL;
2423 break;
2424 }
2425 else if (errno == EAGAIN) {/* ignore EAGAIN */
2426 break;
2427 }
2428 else {
2429 s->res_sr = RES_ERROR;
2430 fdtab[fd].state = FD_STERROR;
2431 break;
2432 }
2433 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002434#ifndef FILL_BUFFERS
2435 while (0);
2436#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002437 }
2438 else {
2439 s->res_sr = RES_ERROR;
2440 fdtab[fd].state = FD_STERROR;
2441 }
2442
willy tarreau5cbea6f2005-12-17 12:48:26 +01002443 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002444 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2446 else
2447 tv_eternity(&s->srexpire);
2448
2449 task_wakeup(&rq, t);
2450 }
willy tarreau0f7af912005-12-17 12:21:26 +01002451
willy tarreau0f7af912005-12-17 12:21:26 +01002452 return 0;
2453}
2454
2455/*
2456 * this function is called on a write event from a client socket.
2457 * It returns 0.
2458 */
2459int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002460 struct task *t = fdtab[fd].owner;
2461 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002462 struct buffer *b = s->rep;
2463 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002464
willy tarreau12350152005-12-18 01:03:27 +01002465#ifdef DEBUG_FULL
2466 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2467#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002468
2469 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002470 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002471 // max = BUFSIZE; BUG !!!!
2472 max = 0;
2473 }
2474 else if (b->r > b->w) {
2475 max = b->r - b->w;
2476 }
2477 else
2478 max = b->data + BUFSIZE - b->w;
2479
willy tarreau0f7af912005-12-17 12:21:26 +01002480 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002481 if (max == 0) {
2482 s->res_cw = RES_NULL;
2483 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002484 tv_eternity(&s->cwexpire);
2485 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002486 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002487 }
2488
willy tarreau3242e862005-12-17 12:27:53 +01002489#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002490 {
2491 int skerr;
2492 socklen_t lskerr = sizeof(skerr);
2493
2494 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2495 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002496 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002497 else
willy tarreau3242e862005-12-17 12:27:53 +01002498 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002499 }
willy tarreau3242e862005-12-17 12:27:53 +01002500#else
willy tarreau0f7af912005-12-17 12:21:26 +01002501 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002502#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002503
2504 if (ret > 0) {
2505 b->l -= ret;
2506 b->w += ret;
2507
2508 s->res_cw = RES_DATA;
2509
2510 if (b->w == b->data + BUFSIZE) {
2511 b->w = b->data; /* wrap around the buffer */
2512 }
2513 }
2514 else if (ret == 0) {
2515 /* nothing written, just make as if we were never called */
2516// s->res_cw = RES_NULL;
2517 return 0;
2518 }
2519 else if (errno == EAGAIN) /* ignore EAGAIN */
2520 return 0;
2521 else {
2522 s->res_cw = RES_ERROR;
2523 fdtab[fd].state = FD_STERROR;
2524 }
2525 }
2526 else {
2527 s->res_cw = RES_ERROR;
2528 fdtab[fd].state = FD_STERROR;
2529 }
2530
willy tarreaub1ff9db2005-12-17 13:51:03 +01002531 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002532 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002533 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2534 s->crexpire = s->cwexpire;
2535 }
willy tarreau0f7af912005-12-17 12:21:26 +01002536 else
2537 tv_eternity(&s->cwexpire);
2538
willy tarreau5cbea6f2005-12-17 12:48:26 +01002539 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002540 return 0;
2541}
2542
2543
2544/*
2545 * this function is called on a write event from a server socket.
2546 * It returns 0.
2547 */
2548int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002549 struct task *t = fdtab[fd].owner;
2550 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002551 struct buffer *b = s->req;
2552 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002553
willy tarreau12350152005-12-18 01:03:27 +01002554#ifdef DEBUG_FULL
2555 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2556#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002557
2558 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002559 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002560 // max = BUFSIZE; BUG !!!!
2561 max = 0;
2562 }
2563 else if (b->r > b->w) {
2564 max = b->r - b->w;
2565 }
2566 else
2567 max = b->data + BUFSIZE - b->w;
2568
willy tarreau0f7af912005-12-17 12:21:26 +01002569 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002570 if (max == 0) {
2571 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002572 if (s->srv_state == SV_STCONN) {
2573 int skerr;
2574 socklen_t lskerr = sizeof(skerr);
2575 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2576 if (skerr) {
2577 s->res_sw = RES_ERROR;
2578 fdtab[fd].state = FD_STERROR;
2579 task_wakeup(&rq, t);
2580 tv_eternity(&s->swexpire);
2581 FD_CLR(fd, StaticWriteEvent);
2582 return 0;
2583 }
2584 }
2585
willy tarreau0f7af912005-12-17 12:21:26 +01002586 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002587 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002588 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002589 tv_eternity(&s->swexpire);
2590 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002591 return 0;
2592 }
2593
willy tarreau3242e862005-12-17 12:27:53 +01002594#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002595 {
2596 int skerr;
2597 socklen_t lskerr = sizeof(skerr);
2598 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2599 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002600 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002601 else
willy tarreau3242e862005-12-17 12:27:53 +01002602 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002603 }
willy tarreau3242e862005-12-17 12:27:53 +01002604#else
willy tarreau0f7af912005-12-17 12:21:26 +01002605 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002606#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002607 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002608 if (ret > 0) {
2609 b->l -= ret;
2610 b->w += ret;
2611
2612 s->res_sw = RES_DATA;
2613
2614 if (b->w == b->data + BUFSIZE) {
2615 b->w = b->data; /* wrap around the buffer */
2616 }
2617 }
2618 else if (ret == 0) {
2619 /* nothing written, just make as if we were never called */
2620 // s->res_sw = RES_NULL;
2621 return 0;
2622 }
2623 else if (errno == EAGAIN) /* ignore EAGAIN */
2624 return 0;
2625 else {
2626 s->res_sw = RES_ERROR;
2627 fdtab[fd].state = FD_STERROR;
2628 }
2629 }
2630 else {
2631 s->res_sw = RES_ERROR;
2632 fdtab[fd].state = FD_STERROR;
2633 }
2634
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002635 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2636 * otherwise it could loop indefinitely !
2637 */
2638 if (s->srv_state != SV_STCONN) {
2639 if (s->proxy->srvtimeout) {
2640 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2641 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2642 s->srexpire = s->swexpire;
2643 }
2644 else
2645 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002646 }
willy tarreau0f7af912005-12-17 12:21:26 +01002647
willy tarreau5cbea6f2005-12-17 12:48:26 +01002648 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002649 return 0;
2650}
2651
2652
2653/*
willy tarreaue39cd132005-12-17 13:00:18 +01002654 * returns a message to the client ; the connection is shut down for read,
2655 * and the request is cleared so that no server connection can be initiated.
2656 * The client must be in a valid state for this (HEADER, DATA ...).
2657 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002658 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002659 */
2660void client_retnclose(struct session *s, int len, const char *msg) {
2661 FD_CLR(s->cli_fd, StaticReadEvent);
2662 FD_SET(s->cli_fd, StaticWriteEvent);
2663 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002664 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002665 shutdown(s->cli_fd, SHUT_RD);
2666 s->cli_state = CL_STSHUTR;
2667 strcpy(s->rep->data, msg);
2668 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002669 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002670 s->rep->r += len;
2671 s->req->l = 0;
2672}
2673
2674
2675/*
2676 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002677 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002678 */
2679void client_return(struct session *s, int len, const char *msg) {
2680 strcpy(s->rep->data, msg);
2681 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002682 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002683 s->rep->r += len;
2684 s->req->l = 0;
2685}
2686
willy tarreau9fe663a2005-12-17 13:02:59 +01002687/*
2688 * send a log for the session when we have enough info about it
2689 */
2690void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002691 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002692 struct proxy *p = s->proxy;
2693 int log;
2694 char *uri;
2695 char *pxid;
2696 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002697 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002698
2699 /* This is a first attempt at a better logging system.
2700 * For now, we rely on send_log() to provide the date, although it obviously
2701 * is the date of the log and not of the request, and most fields are not
2702 * computed.
2703 */
2704
willy tarreaua1598082005-12-17 13:08:06 +01002705 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002706
willy tarreau8a86dbf2005-12-18 00:45:59 +01002707 if (s->cli_addr.ss_family == AF_INET)
2708 inet_ntop(AF_INET,
2709 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2710 pn, sizeof(pn));
2711 else
2712 inet_ntop(AF_INET6,
2713 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2714 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002715
willy tarreauc1cae632005-12-17 14:12:23 +01002716 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002717 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002718 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002719
willy tarreauc1cae632005-12-17 14:12:23 +01002720 tm = localtime(&s->logs.tv_accept.tv_sec);
2721 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002722 char tmpline[MAX_SYSLOG_LEN], *h;
2723 int hdr;
2724
2725 h = tmpline;
2726 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2727 *(h++) = ' ';
2728 *(h++) = '{';
2729 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2730 if (hdr)
2731 *(h++) = '|';
2732 if (s->req_cap[hdr] != NULL)
2733 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2734 }
2735 *(h++) = '}';
2736 }
2737
2738 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2739 *(h++) = ' ';
2740 *(h++) = '{';
2741 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2742 if (hdr)
2743 *(h++) = '|';
2744 if (s->rsp_cap[hdr] != NULL)
2745 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2746 }
2747 *(h++) = '}';
2748 }
2749
2750 if (h < tmpline + sizeof(tmpline) - 4) {
2751 *(h++) = ' ';
2752 *(h++) = '"';
2753 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2754 *(h++) = '"';
2755 }
2756 *h = '\0';
2757
willy tarreaua647c702006-04-15 22:45:52 +02002758 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 +01002759 pn,
2760 (s->cli_addr.ss_family == AF_INET) ?
2761 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2762 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002763 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2764 tm->tm_hour, tm->tm_min, tm->tm_sec,
2765 pxid, srv,
2766 s->logs.t_request,
2767 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2768 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002769 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2770 s->logs.status,
2771 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002772 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2773 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002774 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2775 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2776 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2777 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua647c702006-04-15 22:45:52 +02002778 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002779 }
2780 else {
willy tarreaua647c702006-04-15 22:45:52 +02002781 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 +01002782 pn,
2783 (s->cli_addr.ss_family == AF_INET) ?
2784 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2785 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002786 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2787 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002788 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002789 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002790 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2791 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002792 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002793 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreaua647c702006-04-15 22:45:52 +02002794 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002795 }
2796
2797 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002798}
2799
willy tarreaue39cd132005-12-17 13:00:18 +01002800
2801/*
willy tarreau0f7af912005-12-17 12:21:26 +01002802 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 * to an accept. It tries to accept as many connections as possible.
2804 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002805 */
2806int event_accept(int fd) {
2807 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 struct session *s;
2809 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002810 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002811 int max_accept;
2812
2813 if (global.nbproc > 1)
2814 max_accept = 8; /* let other processes catch some connections too */
2815 else
2816 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002817
willy tarreauc2becdc2006-03-19 19:36:48 +01002818 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002819 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002820 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002821
willy tarreaub1285d52005-12-18 01:20:14 +01002822 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2823 switch (errno) {
2824 case EAGAIN:
2825 case EINTR:
2826 case ECONNABORTED:
2827 return 0; /* nothing more to accept */
2828 case ENFILE:
2829 send_log(p, LOG_EMERG,
2830 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2831 p->id, maxfd);
2832 return 0;
2833 case EMFILE:
2834 send_log(p, LOG_EMERG,
2835 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2836 p->id, maxfd);
2837 return 0;
2838 case ENOBUFS:
2839 case ENOMEM:
2840 send_log(p, LOG_EMERG,
2841 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2842 p->id, maxfd);
2843 return 0;
2844 default:
2845 return 0;
2846 }
2847 }
willy tarreau0f7af912005-12-17 12:21:26 +01002848
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2850 Alert("out of memory in event_accept().\n");
2851 FD_CLR(fd, StaticReadEvent);
2852 p->state = PR_STIDLE;
2853 close(cfd);
2854 return 0;
2855 }
willy tarreau0f7af912005-12-17 12:21:26 +01002856
willy tarreaub1285d52005-12-18 01:20:14 +01002857 /* if this session comes from a known monitoring system, we want to ignore
2858 * it as soon as possible, which means closing it immediately for TCP.
2859 */
2860 s->flags = 0;
2861 if (addr.ss_family == AF_INET &&
2862 p->mon_mask.s_addr &&
2863 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2864 if (p->mode == PR_MODE_TCP) {
2865 close(cfd);
2866 pool_free(session, s);
2867 continue;
2868 }
2869 s->flags |= SN_MONITOR;
2870 }
2871
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2873 Alert("out of memory in event_accept().\n");
2874 FD_CLR(fd, StaticReadEvent);
2875 p->state = PR_STIDLE;
2876 close(cfd);
2877 pool_free(session, s);
2878 return 0;
2879 }
willy tarreau0f7af912005-12-17 12:21:26 +01002880
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002882 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2884 close(cfd);
2885 pool_free(task, t);
2886 pool_free(session, s);
2887 return 0;
2888 }
willy tarreau0f7af912005-12-17 12:21:26 +01002889
willy tarreau5cbea6f2005-12-17 12:48:26 +01002890 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2891 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2892 (char *) &one, sizeof(one)) == -1)) {
2893 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2894 close(cfd);
2895 pool_free(task, t);
2896 pool_free(session, s);
2897 return 0;
2898 }
willy tarreau0f7af912005-12-17 12:21:26 +01002899
willy tarreaub952e1d2005-12-18 01:31:20 +01002900 if (p->options & PR_O_TCP_CLI_KA)
2901 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2902
willy tarreau9fe663a2005-12-17 13:02:59 +01002903 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2904 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2905 t->state = TASK_IDLE;
2906 t->process = process_session;
2907 t->context = s;
2908
2909 s->task = t;
2910 s->proxy = p;
2911 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2912 s->srv_state = SV_STIDLE;
2913 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002914
willy tarreau9fe663a2005-12-17 13:02:59 +01002915 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2916 s->cli_fd = cfd;
2917 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002918 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002919 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002920
willy tarreaub1285d52005-12-18 01:20:14 +01002921 if (s->flags & SN_MONITOR)
2922 s->logs.logwait = 0;
2923 else
2924 s->logs.logwait = p->to_log;
2925
willy tarreaua1598082005-12-17 13:08:06 +01002926 s->logs.tv_accept = now;
2927 s->logs.t_request = -1;
2928 s->logs.t_connect = -1;
2929 s->logs.t_data = -1;
2930 s->logs.t_close = 0;
2931 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002932 s->logs.cli_cookie = NULL;
2933 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002934 s->logs.status = -1;
2935 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002936
willy tarreau2f6ba652005-12-17 13:57:42 +01002937 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02002938 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01002939
willy tarreau4302f492005-12-18 01:00:37 +01002940 if (p->nb_req_cap > 0) {
2941 if ((s->req_cap =
2942 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2943 == NULL) { /* no memory */
2944 close(cfd); /* nothing can be done for this fd without memory */
2945 pool_free(task, t);
2946 pool_free(session, s);
2947 return 0;
2948 }
2949 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2950 }
2951 else
2952 s->req_cap = NULL;
2953
2954 if (p->nb_rsp_cap > 0) {
2955 if ((s->rsp_cap =
2956 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2957 == NULL) { /* no memory */
2958 if (s->req_cap != NULL)
2959 pool_free_to(p->req_cap_pool, s->req_cap);
2960 close(cfd); /* nothing can be done for this fd without memory */
2961 pool_free(task, t);
2962 pool_free(session, s);
2963 return 0;
2964 }
2965 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2966 }
2967 else
2968 s->rsp_cap = NULL;
2969
willy tarreau5cbea6f2005-12-17 12:48:26 +01002970 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2971 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002972 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002973 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002974
willy tarreau8a86dbf2005-12-18 00:45:59 +01002975 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002976 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002977 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002979
willy tarreau9fe663a2005-12-17 13:02:59 +01002980 if (p->to_log) {
2981 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002982 if (s->logs.logwait & LW_CLIP)
2983 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002984 sess_log(s);
2985 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002986 else if (s->cli_addr.ss_family == AF_INET) {
2987 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2988 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2989 sn, sizeof(sn)) &&
2990 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2991 pn, sizeof(pn))) {
2992 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2993 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2994 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2995 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2996 }
2997 }
2998 else {
2999 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
3000 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
3001 sn, sizeof(sn)) &&
3002 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
3003 pn, sizeof(pn))) {
3004 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
3005 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
3006 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
3007 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
3008 }
3009 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010 }
willy tarreau0f7af912005-12-17 12:21:26 +01003011
willy tarreau982249e2005-12-18 00:57:06 +01003012 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01003013 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01003014 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01003015 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01003016 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01003017 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01003018 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01003019 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01003020
willy tarreau8a86dbf2005-12-18 00:45:59 +01003021 if (s->cli_addr.ss_family == AF_INET) {
3022 char pn[INET_ADDRSTRLEN];
3023 inet_ntop(AF_INET,
3024 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
3025 pn, sizeof(pn));
3026
3027 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3028 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3029 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
3030 }
3031 else {
3032 char pn[INET6_ADDRSTRLEN];
3033 inet_ntop(AF_INET6,
3034 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3035 pn, sizeof(pn));
3036
3037 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3038 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3039 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3040 }
3041
willy tarreauef900ab2005-12-17 12:52:52 +01003042 write(1, trash, len);
3043 }
willy tarreau0f7af912005-12-17 12:21:26 +01003044
willy tarreau5cbea6f2005-12-17 12:48:26 +01003045 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003046 if (s->rsp_cap != NULL)
3047 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3048 if (s->req_cap != NULL)
3049 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003050 close(cfd); /* nothing can be done for this fd without memory */
3051 pool_free(task, t);
3052 pool_free(session, s);
3053 return 0;
3054 }
willy tarreau4302f492005-12-18 01:00:37 +01003055
willy tarreau5cbea6f2005-12-17 12:48:26 +01003056 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003057 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003058 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3059 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003060 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003061 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003062
willy tarreau5cbea6f2005-12-17 12:48:26 +01003063 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3064 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003065 if (s->rsp_cap != NULL)
3066 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3067 if (s->req_cap != NULL)
3068 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003069 close(cfd); /* nothing can be done for this fd without memory */
3070 pool_free(task, t);
3071 pool_free(session, s);
3072 return 0;
3073 }
3074 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003075 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003076 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 +01003077
willy tarreau5cbea6f2005-12-17 12:48:26 +01003078 fdtab[cfd].read = &event_cli_read;
3079 fdtab[cfd].write = &event_cli_write;
3080 fdtab[cfd].owner = t;
3081 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003082
willy tarreaub1285d52005-12-18 01:20:14 +01003083 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3084 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3085 /* Either we got a request from a monitoring system on an HTTP instance,
3086 * or we're in health check mode with the 'httpchk' option enabled. In
3087 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3088 */
3089 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3090 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3091 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003092 }
3093 else {
3094 FD_SET(cfd, StaticReadEvent);
3095 }
3096
willy tarreaub952e1d2005-12-18 01:31:20 +01003097#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3098 if (PrevReadEvent) {
3099 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3100 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3101 }
3102#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 fd_insert(cfd);
3104
3105 tv_eternity(&s->cnexpire);
3106 tv_eternity(&s->srexpire);
3107 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003108 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 tv_eternity(&s->cwexpire);
3110
willy tarreaub1285d52005-12-18 01:20:14 +01003111 if (s->proxy->clitimeout) {
3112 if (FD_ISSET(cfd, StaticReadEvent))
3113 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3114 if (FD_ISSET(cfd, StaticWriteEvent))
3115 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3116 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003117
willy tarreaub1285d52005-12-18 01:20:14 +01003118 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003119
3120 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003121
3122 if (p->mode != PR_MODE_HEALTH)
3123 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124
3125 p->nbconn++;
3126 actconn++;
3127 totalconn++;
3128
willy tarreaub952e1d2005-12-18 01:31:20 +01003129 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003130 } /* end of while (p->nbconn < p->maxconn) */
3131 return 0;
3132}
willy tarreau0f7af912005-12-17 12:21:26 +01003133
willy tarreau0f7af912005-12-17 12:21:26 +01003134
willy tarreau5cbea6f2005-12-17 12:48:26 +01003135/*
3136 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003137 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3138 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003139 * or -1 if an error occured.
3140 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003141int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003142 struct task *t = fdtab[fd].owner;
3143 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003144 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003145 socklen_t lskerr = sizeof(skerr);
3146
willy tarreau05be12b2006-03-19 19:35:00 +01003147 skerr = 1;
3148 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3149 || (skerr != 0)) {
3150 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003151 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003152 fdtab[fd].state = FD_STERROR;
3153 FD_CLR(fd, StaticWriteEvent);
3154 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003155 else if (s->result != -1) {
3156 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003157 if (s->proxy->options & PR_O_HTTP_CHK) {
3158 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003159 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003160 * so we'll send the request, and won't wake the checker up now.
3161 */
3162#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003163 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003164#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003165 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003166#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003167 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003168 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3169 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3170 return 0;
3171 }
willy tarreau05be12b2006-03-19 19:35:00 +01003172 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003173 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003174 FD_CLR(fd, StaticWriteEvent);
3175 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003176 }
3177 else {
3178 /* good TCP connection is enough */
3179 s->result = 1;
3180 }
3181 }
3182
3183 task_wakeup(&rq, t);
3184 return 0;
3185}
3186
willy tarreau0f7af912005-12-17 12:21:26 +01003187
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003188/*
3189 * This function is used only for server health-checks. It handles
3190 * the server's reply to an HTTP request. It returns 1 if the server replies
3191 * 2xx or 3xx (valid responses), or -1 in other cases.
3192 */
3193int event_srv_chk_r(int fd) {
3194 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003195 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003196 struct task *t = fdtab[fd].owner;
3197 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003198 int skerr;
3199 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003200
willy tarreaua4a583a2005-12-18 01:39:19 +01003201 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003202
willy tarreau05be12b2006-03-19 19:35:00 +01003203 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3204 if (!skerr) {
3205#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003206 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003207#else
willy tarreau05be12b2006-03-19 19:35:00 +01003208 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3209 * but the connection was closed on the remote end. Fortunately, recv still
3210 * works correctly and we don't need to do the getsockopt() on linux.
3211 */
3212 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003213#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003214
3215 if ((len >= sizeof("HTTP/1.0 000")) &&
3216 !memcmp(reply, "HTTP/1.", 7) &&
3217 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3218 result = 1;
3219 }
3220
3221 if (result == -1)
3222 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003223
3224 if (s->result != -1)
3225 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003226
3227 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003228 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003229 return 0;
3230}
3231
3232
3233/*
3234 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3235 * and moves <end> just after the end of <str>.
3236 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3237 * the shift value (positive or negative) is returned.
3238 * If there's no space left, the move is not done.
3239 *
3240 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003241int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003242 int delta;
3243 int len;
3244
3245 len = strlen(str);
3246 delta = len - (end - pos);
3247
3248 if (delta + b->r >= b->data + BUFSIZE)
3249 return 0; /* no space left */
3250
3251 /* first, protect the end of the buffer */
3252 memmove(end + delta, end, b->data + b->l - end);
3253
3254 /* now, copy str over pos */
3255 memcpy(pos, str,len);
3256
willy tarreau5cbea6f2005-12-17 12:48:26 +01003257 /* we only move data after the displaced zone */
3258 if (b->r > pos) b->r += delta;
3259 if (b->w > pos) b->w += delta;
3260 if (b->h > pos) b->h += delta;
3261 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003262 b->l += delta;
3263
3264 return delta;
3265}
3266
willy tarreau8337c6b2005-12-17 13:41:01 +01003267/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003268 * len is 0.
3269 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003271 int delta;
3272
3273 delta = len - (end - pos);
3274
3275 if (delta + b->r >= b->data + BUFSIZE)
3276 return 0; /* no space left */
3277
Willy TARREAUe78ae262006-01-08 01:24:12 +01003278 if (b->data + b->l < end)
3279 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3280 return 0;
3281
willy tarreau0f7af912005-12-17 12:21:26 +01003282 /* first, protect the end of the buffer */
3283 memmove(end + delta, end, b->data + b->l - end);
3284
3285 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003286 if (len)
3287 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003288
willy tarreau5cbea6f2005-12-17 12:48:26 +01003289 /* we only move data after the displaced zone */
3290 if (b->r > pos) b->r += delta;
3291 if (b->w > pos) b->w += delta;
3292 if (b->h > pos) b->h += delta;
3293 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003294 b->l += delta;
3295
3296 return delta;
3297}
3298
3299
3300int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3301 char *old_dst = dst;
3302
3303 while (*str) {
3304 if (*str == '\\') {
3305 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003306 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003307 int len, num;
3308
3309 num = *str - '0';
3310 str++;
3311
willy tarreau8a86dbf2005-12-18 00:45:59 +01003312 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003313 len = matches[num].rm_eo - matches[num].rm_so;
3314 memcpy(dst, src + matches[num].rm_so, len);
3315 dst += len;
3316 }
3317
3318 }
3319 else if (*str == 'x') {
3320 unsigned char hex1, hex2;
3321 str++;
3322
willy tarreauc1f47532005-12-18 01:08:26 +01003323 hex1 = toupper(*str++) - '0';
3324 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003325
3326 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3327 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3328 *dst++ = (hex1<<4) + hex2;
3329 }
3330 else
3331 *dst++ = *str++;
3332 }
3333 else
3334 *dst++ = *str++;
3335 }
3336 *dst = 0;
3337 return dst - old_dst;
3338}
3339
willy tarreauc1f47532005-12-18 01:08:26 +01003340static int ishex(char s)
3341{
3342 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3343}
3344
3345/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3346char *check_replace_string(char *str)
3347{
3348 char *err = NULL;
3349 while (*str) {
3350 if (*str == '\\') {
3351 err = str; /* in case of a backslash, we return the pointer to it */
3352 str++;
3353 if (!*str)
3354 return err;
3355 else if (isdigit((int)*str))
3356 err = NULL;
3357 else if (*str == 'x') {
3358 str++;
3359 if (!ishex(*str))
3360 return err;
3361 str++;
3362 if (!ishex(*str))
3363 return err;
3364 err = NULL;
3365 }
3366 else {
3367 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3368 err = NULL;
3369 }
3370 }
3371 str++;
3372 }
3373 return err;
3374}
3375
3376
willy tarreau9fe663a2005-12-17 13:02:59 +01003377
willy tarreau0f7af912005-12-17 12:21:26 +01003378/*
3379 * manages the client FSM and its socket. BTW, it also tries to handle the
3380 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3381 * 0 else.
3382 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003383int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003384 int s = t->srv_state;
3385 int c = t->cli_state;
3386 struct buffer *req = t->req;
3387 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003388 int method_checked = 0;
3389 appsess *asession_temp = NULL;
3390 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003391
willy tarreau750a4722005-12-17 13:21:24 +01003392#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003393 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3394 cli_stnames[c], srv_stnames[s],
3395 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3396 t->crexpire.tv_sec, t->crexpire.tv_usec,
3397 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003398#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003399 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3400 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3401 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3402 //);
3403 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003404 /* now parse the partial (or complete) headers */
3405 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3406 char *ptr;
3407 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003408 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003409
willy tarreau5cbea6f2005-12-17 12:48:26 +01003410 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003411
willy tarreau0f7af912005-12-17 12:21:26 +01003412 /* look for the end of the current header */
3413 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3414 ptr++;
3415
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003417 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003418
3419 /*
3420 * first, let's check that it's not a leading empty line, in
3421 * which case we'll ignore and remove it (according to RFC2616).
3422 */
3423 if (req->h == req->data) {
3424 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3425 if (ptr > req->r - 2) {
3426 /* this is a partial header, let's wait for more to come */
3427 req->lr = ptr;
3428 break;
3429 }
3430
3431 /* now we know that *ptr is either \r or \n,
3432 * and that there are at least 1 char after it.
3433 */
3434 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3435 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3436 else
3437 req->lr = ptr + 2; /* \r\n or \n\r */
3438 /* ignore empty leading lines */
3439 buffer_replace2(req, req->h, req->lr, NULL, 0);
3440 req->h = req->lr;
3441 continue;
3442 }
3443
willy tarreau5cbea6f2005-12-17 12:48:26 +01003444 /* we can only get here after an end of headers */
3445 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003446
willy tarreaue39cd132005-12-17 13:00:18 +01003447 if (t->flags & SN_CLDENY) {
3448 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003449 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003450 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003451 if (!(t->flags & SN_ERR_MASK))
3452 t->flags |= SN_ERR_PRXCOND;
3453 if (!(t->flags & SN_FINST_MASK))
3454 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003455 return 1;
3456 }
3457
willy tarreau5cbea6f2005-12-17 12:48:26 +01003458 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003459 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3460 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003461 }
willy tarreau0f7af912005-12-17 12:21:26 +01003462
willy tarreau9fe663a2005-12-17 13:02:59 +01003463 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003464 if (t->cli_addr.ss_family == AF_INET) {
3465 unsigned char *pn;
3466 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3467 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3468 pn[0], pn[1], pn[2], pn[3]);
3469 buffer_replace2(req, req->h, req->h, trash, len);
3470 }
3471 else if (t->cli_addr.ss_family == AF_INET6) {
3472 char pn[INET6_ADDRSTRLEN];
3473 inet_ntop(AF_INET6,
3474 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3475 pn, sizeof(pn));
3476 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3477 buffer_replace2(req, req->h, req->h, trash, len);
3478 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003479 }
3480
willy tarreau25c4ea52005-12-18 00:49:49 +01003481 /* add a "connection: close" line if needed */
3482 if (t->proxy->options & PR_O_HTTP_CLOSE)
3483 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3484
willy tarreau982249e2005-12-18 00:57:06 +01003485 if (!memcmp(req->data, "POST ", 5)) {
3486 /* this is a POST request, which is not cacheable by default */
3487 t->flags |= SN_POST;
3488 }
willy tarreaucd878942005-12-17 13:27:43 +01003489
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003491 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003492
willy tarreau750a4722005-12-17 13:21:24 +01003493 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003494 /* FIXME: we'll set the client in a wait state while we try to
3495 * connect to the server. Is this really needed ? wouldn't it be
3496 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003497 //FD_CLR(t->cli_fd, StaticReadEvent);
3498 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003499
3500 /* FIXME: if we break here (as up to 1.1.23), having the client
3501 * shutdown its connection can lead to an abort further.
3502 * it's better to either return 1 or even jump directly to the
3503 * data state which will save one schedule.
3504 */
3505 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003506
3507 if (!t->proxy->clitimeout ||
3508 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3509 /* If the client has no timeout, or if the server is not ready yet,
3510 * and we know for sure that it can expire, then it's cleaner to
3511 * disable the timeout on the client side so that too low values
3512 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003513 *
3514 * FIXME-20050705: the server needs a way to re-enable this time-out
3515 * when it switches its state, otherwise a client can stay connected
3516 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003517 */
3518 tv_eternity(&t->crexpire);
3519
willy tarreau197e8ec2005-12-17 14:10:59 +01003520 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003521 }
willy tarreau0f7af912005-12-17 12:21:26 +01003522
Willy TARREAU13032e72006-03-12 17:31:45 +01003523 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3524 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003525 /* this is a partial header, let's wait for more to come */
3526 req->lr = ptr;
3527 break;
3528 }
willy tarreau0f7af912005-12-17 12:21:26 +01003529
willy tarreau5cbea6f2005-12-17 12:48:26 +01003530 /* now we know that *ptr is either \r or \n,
3531 * and that there are at least 1 char after it.
3532 */
3533 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3534 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3535 else
3536 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003537
willy tarreau5cbea6f2005-12-17 12:48:26 +01003538 /*
3539 * now we know that we have a full header ; we can do whatever
3540 * we want with these pointers :
3541 * req->h = beginning of header
3542 * ptr = end of header (first \r or \n)
3543 * req->lr = beginning of next line (next rep->h)
3544 * req->r = end of data (not used at this stage)
3545 */
willy tarreau0f7af912005-12-17 12:21:26 +01003546
willy tarreau12350152005-12-18 01:03:27 +01003547 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3548 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3549 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3550
3551 /* skip ; */
3552 request_line++;
3553
3554 /* look if we have a jsessionid */
3555
3556 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3557
3558 /* skip jsessionid= */
3559 request_line += t->proxy->appsession_name_len + 1;
3560
3561 /* First try if we allready have an appsession */
3562 asession_temp = &local_asession;
3563
3564 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3565 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3566 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3567 return 0;
3568 }
3569
3570 /* Copy the sessionid */
3571 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3572 asession_temp->sessid[t->proxy->appsession_len] = 0;
3573 asession_temp->serverid = NULL;
3574
3575 /* only do insert, if lookup fails */
3576 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3577 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3578 Alert("Not enough memory process_cli():asession:calloc().\n");
3579 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3580 return 0;
3581 }
3582 asession_temp->sessid = local_asession.sessid;
3583 asession_temp->serverid = local_asession.serverid;
3584 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003585 } /* end if (chtbl_lookup()) */
3586 else {
willy tarreau12350152005-12-18 01:03:27 +01003587 /*free wasted memory;*/
3588 pool_free_to(apools.sessid, local_asession.sessid);
3589 }
3590
3591 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3592 asession_temp->request_count++;
3593
3594#if defined(DEBUG_HASH)
3595 print_table(&(t->proxy->htbl_proxy));
3596#endif
3597
3598 if (asession_temp->serverid == NULL) {
3599 Alert("Found Application Session without matching server.\n");
3600 } else {
3601 struct server *srv = t->proxy->srv;
3602 while (srv) {
3603 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3604 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3605 /* we found the server and it's usable */
3606 t->flags &= ~SN_CK_MASK;
3607 t->flags |= SN_CK_VALID | SN_DIRECT;
3608 t->srv = srv;
3609 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003610 } else {
willy tarreau12350152005-12-18 01:03:27 +01003611 t->flags &= ~SN_CK_MASK;
3612 t->flags |= SN_CK_DOWN;
3613 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003614 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003615 srv = srv->next;
3616 }/* end while(srv) */
3617 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003618 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003619 else {
3620 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3621 }
willy tarreau598da412005-12-18 01:07:29 +01003622 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003623 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003624 else{
3625 //printf("No Methode-Header with Session-String\n");
3626 }
3627
willy tarreau8337c6b2005-12-17 13:41:01 +01003628 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003629 /* we have a complete HTTP request that we must log */
3630 int urilen;
3631
willy tarreaua1598082005-12-17 13:08:06 +01003632 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003633 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003634 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003635 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003636 if (!(t->flags & SN_ERR_MASK))
3637 t->flags |= SN_ERR_PRXCOND;
3638 if (!(t->flags & SN_FINST_MASK))
3639 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003640 return 1;
3641 }
3642
3643 urilen = ptr - req->h;
3644 if (urilen >= REQURI_LEN)
3645 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003646 memcpy(t->logs.uri, req->h, urilen);
3647 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003648
willy tarreaua1598082005-12-17 13:08:06 +01003649 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003650 sess_log(t);
3651 }
willy tarreau4302f492005-12-18 01:00:37 +01003652 else if (t->logs.logwait & LW_REQHDR) {
3653 struct cap_hdr *h;
3654 int len;
3655 for (h = t->proxy->req_cap; h; h = h->next) {
3656 if ((h->namelen + 2 <= ptr - req->h) &&
3657 (req->h[h->namelen] == ':') &&
3658 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3659
3660 if (t->req_cap[h->index] == NULL)
3661 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3662
3663 len = ptr - (req->h + h->namelen + 2);
3664 if (len > h->len)
3665 len = h->len;
3666
3667 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3668 t->req_cap[h->index][len]=0;
3669 }
3670 }
3671
3672 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003673
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003675
willy tarreau982249e2005-12-18 00:57:06 +01003676 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003677 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003678 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 +01003679 max = ptr - req->h;
3680 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003681 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003682 trash[len++] = '\n';
3683 write(1, trash, len);
3684 }
willy tarreau0f7af912005-12-17 12:21:26 +01003685
willy tarreau25c4ea52005-12-18 00:49:49 +01003686
3687 /* remove "connection: " if needed */
3688 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3689 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3690 delete_header = 1;
3691 }
3692
willy tarreau5cbea6f2005-12-17 12:48:26 +01003693 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003694 if (!delete_header && t->proxy->req_exp != NULL
3695 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003696 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003697 char term;
3698
3699 term = *ptr;
3700 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003701 exp = t->proxy->req_exp;
3702 do {
3703 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3704 switch (exp->action) {
3705 case ACT_ALLOW:
3706 if (!(t->flags & SN_CLDENY))
3707 t->flags |= SN_CLALLOW;
3708 break;
3709 case ACT_REPLACE:
3710 if (!(t->flags & SN_CLDENY)) {
3711 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3712 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3713 }
3714 break;
3715 case ACT_REMOVE:
3716 if (!(t->flags & SN_CLDENY))
3717 delete_header = 1;
3718 break;
3719 case ACT_DENY:
3720 if (!(t->flags & SN_CLALLOW))
3721 t->flags |= SN_CLDENY;
3722 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003723 case ACT_PASS: /* we simply don't deny this one */
3724 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003725 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003727 }
willy tarreaue39cd132005-12-17 13:00:18 +01003728 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003730 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731
willy tarreau240afa62005-12-17 13:14:35 +01003732 /* Now look for cookies. Conforming to RFC2109, we have to support
3733 * attributes whose name begin with a '$', and associate them with
3734 * the right cookie, if we want to delete this cookie.
3735 * So there are 3 cases for each cookie read :
3736 * 1) it's a special attribute, beginning with a '$' : ignore it.
3737 * 2) it's a server id cookie that we *MAY* want to delete : save
3738 * some pointers on it (last semi-colon, beginning of cookie...)
3739 * 3) it's an application cookie : we *MAY* have to delete a previous
3740 * "special" cookie.
3741 * At the end of loop, if a "special" cookie remains, we may have to
3742 * remove it. If no application cookie persists in the header, we
3743 * *MUST* delete it
3744 */
willy tarreau12350152005-12-18 01:03:27 +01003745 if (!delete_header &&
3746 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003747 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003748 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003749 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003750 char *del_colon, *del_cookie, *colon;
3751 int app_cookies;
3752
willy tarreau5cbea6f2005-12-17 12:48:26 +01003753 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003754 colon = p1;
3755 /* del_cookie == NULL => nothing to be deleted */
3756 del_colon = del_cookie = NULL;
3757 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003758
3759 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003760 /* skip spaces and colons, but keep an eye on these ones */
3761 while (p1 < ptr) {
3762 if (*p1 == ';' || *p1 == ',')
3763 colon = p1;
3764 else if (!isspace((int)*p1))
3765 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003766 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003767 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003768
3769 if (p1 == ptr)
3770 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003771
3772 /* p1 is at the beginning of the cookie name */
3773 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003774 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003775 p2++;
3776
3777 if (p2 == ptr)
3778 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003779
3780 p3 = p2 + 1; /* skips the '=' sign */
3781 if (p3 == ptr)
3782 break;
3783
willy tarreau240afa62005-12-17 13:14:35 +01003784 p4 = p3;
3785 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003786 p4++;
3787
3788 /* here, we have the cookie name between p1 and p2,
3789 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003790 * we can process it :
3791 *
3792 * Cookie: NAME=VALUE;
3793 * | || || |
3794 * | || || +--> p4
3795 * | || |+-------> p3
3796 * | || +--------> p2
3797 * | |+------------> p1
3798 * | +-------------> colon
3799 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003800 */
3801
willy tarreau240afa62005-12-17 13:14:35 +01003802 if (*p1 == '$') {
3803 /* skip this one */
3804 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003805 else {
3806 /* first, let's see if we want to capture it */
3807 if (t->proxy->capture_name != NULL &&
3808 t->logs.cli_cookie == NULL &&
3809 (p4 - p1 >= t->proxy->capture_namelen) &&
3810 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3811 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003812
willy tarreau8337c6b2005-12-17 13:41:01 +01003813 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3814 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003815 } else {
3816 if (log_len > t->proxy->capture_len)
3817 log_len = t->proxy->capture_len;
3818 memcpy(t->logs.cli_cookie, p1, log_len);
3819 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003820 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003821 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003822
3823 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3824 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3825 /* Cool... it's the right one */
3826 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003827 char *delim;
3828
3829 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3830 * have the server ID betweek p3 and delim, and the original cookie between
3831 * delim+1 and p4. Otherwise, delim==p4 :
3832 *
3833 * Cookie: NAME=SRV~VALUE;
3834 * | || || | |
3835 * | || || | +--> p4
3836 * | || || +--------> delim
3837 * | || |+-----------> p3
3838 * | || +------------> p2
3839 * | |+----------------> p1
3840 * | +-----------------> colon
3841 * +------------------------> req->h
3842 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003843
willy tarreau0174f312005-12-18 01:02:42 +01003844 if (t->proxy->options & PR_O_COOK_PFX) {
3845 for (delim = p3; delim < p4; delim++)
3846 if (*delim == COOKIE_DELIM)
3847 break;
3848 }
3849 else
3850 delim = p4;
3851
3852
3853 /* Here, we'll look for the first running server which supports the cookie.
3854 * This allows to share a same cookie between several servers, for example
3855 * to dedicate backup servers to specific servers only.
3856 */
3857 while (srv) {
3858 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3859 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3860 /* we found the server and it's usable */
3861 t->flags &= ~SN_CK_MASK;
3862 t->flags |= SN_CK_VALID | SN_DIRECT;
3863 t->srv = srv;
3864 break;
willy tarreau12350152005-12-18 01:03:27 +01003865 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003866 /* we found a server, but it's down */
3867 t->flags &= ~SN_CK_MASK;
3868 t->flags |= SN_CK_DOWN;
3869 }
3870 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003871 srv = srv->next;
3872 }
3873
willy tarreau0174f312005-12-18 01:02:42 +01003874 if (!srv && !(t->flags & SN_CK_DOWN)) {
3875 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003876 t->flags &= ~SN_CK_MASK;
3877 t->flags |= SN_CK_INVALID;
3878 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003879
willy tarreau0174f312005-12-18 01:02:42 +01003880 /* depending on the cookie mode, we may have to either :
3881 * - delete the complete cookie if we're in insert+indirect mode, so that
3882 * the server never sees it ;
3883 * - remove the server id from the cookie value, and tag the cookie as an
3884 * application cookie so that it does not get accidentely removed later,
3885 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003886 */
willy tarreau0174f312005-12-18 01:02:42 +01003887 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3888 buffer_replace2(req, p3, delim + 1, NULL, 0);
3889 p4 -= (delim + 1 - p3);
3890 ptr -= (delim + 1 - p3);
3891 del_cookie = del_colon = NULL;
3892 app_cookies++; /* protect the header from deletion */
3893 }
3894 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003895 (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 +01003896 del_cookie = p1;
3897 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003898 }
willy tarreau12350152005-12-18 01:03:27 +01003899 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003900 /* now we know that we must keep this cookie since it's
3901 * not ours. But if we wanted to delete our cookie
3902 * earlier, we cannot remove the complete header, but we
3903 * can remove the previous block itself.
3904 */
3905 app_cookies++;
3906
3907 if (del_cookie != NULL) {
3908 buffer_replace2(req, del_cookie, p1, NULL, 0);
3909 p4 -= (p1 - del_cookie);
3910 ptr -= (p1 - del_cookie);
3911 del_cookie = del_colon = NULL;
3912 }
willy tarreau240afa62005-12-17 13:14:35 +01003913 }
willy tarreau12350152005-12-18 01:03:27 +01003914
3915 if ((t->proxy->appsession_name != NULL) &&
3916 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3917 /* first, let's see if the cookie is our appcookie*/
3918
3919 /* Cool... it's the right one */
3920
3921 asession_temp = &local_asession;
3922
3923 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3924 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3925 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3926 return 0;
3927 }
3928
3929 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3930 asession_temp->sessid[t->proxy->appsession_len] = 0;
3931 asession_temp->serverid = NULL;
3932
3933 /* only do insert, if lookup fails */
3934 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3935 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3936 Alert("Not enough memory process_cli():asession:calloc().\n");
3937 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3938 return 0;
3939 }
3940
3941 asession_temp->sessid = local_asession.sessid;
3942 asession_temp->serverid = local_asession.serverid;
3943 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3944 }
3945 else{
3946 /* free wasted memory */
3947 pool_free_to(apools.sessid, local_asession.sessid);
3948 }
3949
3950 if (asession_temp->serverid == NULL) {
3951 Alert("Found Application Session without matching server.\n");
3952 } else {
3953 struct server *srv = t->proxy->srv;
3954 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003955 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003956 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3957 /* we found the server and it's usable */
3958 t->flags &= ~SN_CK_MASK;
3959 t->flags |= SN_CK_VALID | SN_DIRECT;
3960 t->srv = srv;
3961 break;
3962 } else {
3963 t->flags &= ~SN_CK_MASK;
3964 t->flags |= SN_CK_DOWN;
3965 }
3966 }
3967 srv = srv->next;
3968 }/* end while(srv) */
3969 }/* end else if server == NULL */
3970
3971 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003972 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003973 }
willy tarreau240afa62005-12-17 13:14:35 +01003974
willy tarreau5cbea6f2005-12-17 12:48:26 +01003975 /* we'll have to look for another cookie ... */
3976 p1 = p4;
3977 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003978
3979 /* There's no more cookie on this line.
3980 * We may have marked the last one(s) for deletion.
3981 * We must do this now in two ways :
3982 * - if there is no app cookie, we simply delete the header ;
3983 * - if there are app cookies, we must delete the end of the
3984 * string properly, including the colon/semi-colon before
3985 * the cookie name.
3986 */
3987 if (del_cookie != NULL) {
3988 if (app_cookies) {
3989 buffer_replace2(req, del_colon, ptr, NULL, 0);
3990 /* WARNING! <ptr> becomes invalid for now. If some code
3991 * below needs to rely on it before the end of the global
3992 * header loop, we need to correct it with this code :
3993 * ptr = del_colon;
3994 */
3995 }
3996 else
3997 delete_header = 1;
3998 }
3999 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000
4001 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004002 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01004003 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01004004 }
willy tarreau240afa62005-12-17 13:14:35 +01004005 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
4006
willy tarreau5cbea6f2005-12-17 12:48:26 +01004007 req->h = req->lr;
4008 } /* while (req->lr < req->r) */
4009
4010 /* end of header processing (even if incomplete) */
4011
willy tarreauef900ab2005-12-17 12:52:52 +01004012 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4013 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4014 * full. We cannot loop here since event_cli_read will disable it only if
4015 * req->l == rlim-data
4016 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004017 FD_SET(t->cli_fd, StaticReadEvent);
4018 if (t->proxy->clitimeout)
4019 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4020 else
4021 tv_eternity(&t->crexpire);
4022 }
4023
willy tarreaue39cd132005-12-17 13:00:18 +01004024 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01004025 * won't be able to free more later, so the session will never terminate.
4026 */
willy tarreaue39cd132005-12-17 13:00:18 +01004027 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01004028 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01004029 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01004030 if (!(t->flags & SN_ERR_MASK))
4031 t->flags |= SN_ERR_PRXCOND;
4032 if (!(t->flags & SN_FINST_MASK))
4033 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004034 return 1;
4035 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004036 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004037 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004038 tv_eternity(&t->crexpire);
4039 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004041 if (!(t->flags & SN_ERR_MASK))
4042 t->flags |= SN_ERR_CLICL;
4043 if (!(t->flags & SN_FINST_MASK))
4044 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004046 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004047 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4048
4049 /* read timeout : give up with an error message.
4050 */
4051 t->logs.status = 408;
4052 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004053 if (!(t->flags & SN_ERR_MASK))
4054 t->flags |= SN_ERR_CLITO;
4055 if (!(t->flags & SN_FINST_MASK))
4056 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004057 return 1;
4058 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059
4060 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004061 }
4062 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004063 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004064 /* FIXME: this error handling is partly buggy because we always report
4065 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4066 * or HEADER phase. BTW, it's not logical to expire the client while
4067 * we're waiting for the server to connect.
4068 */
willy tarreau0f7af912005-12-17 12:21:26 +01004069 /* read or write error */
4070 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004071 tv_eternity(&t->crexpire);
4072 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004073 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004074 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004075 if (!(t->flags & SN_ERR_MASK))
4076 t->flags |= SN_ERR_CLICL;
4077 if (!(t->flags & SN_FINST_MASK))
4078 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004079 return 1;
4080 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004081 /* last read, or end of server write */
4082 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004083 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004084 tv_eternity(&t->crexpire);
4085 shutdown(t->cli_fd, SHUT_RD);
4086 t->cli_state = CL_STSHUTR;
4087 return 1;
4088 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004089 /* last server read and buffer empty */
4090 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004091 FD_CLR(t->cli_fd, StaticWriteEvent);
4092 tv_eternity(&t->cwexpire);
4093 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004094 /* We must ensure that the read part is still alive when switching
4095 * to shutw */
4096 FD_SET(t->cli_fd, StaticReadEvent);
4097 if (t->proxy->clitimeout)
4098 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004099 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004100 //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 +01004101 return 1;
4102 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004103 /* read timeout */
4104 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4105 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004106 tv_eternity(&t->crexpire);
4107 shutdown(t->cli_fd, SHUT_RD);
4108 t->cli_state = CL_STSHUTR;
4109 if (!(t->flags & SN_ERR_MASK))
4110 t->flags |= SN_ERR_CLITO;
4111 if (!(t->flags & SN_FINST_MASK))
4112 t->flags |= SN_FINST_D;
4113 return 1;
4114 }
4115 /* write timeout */
4116 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4117 FD_CLR(t->cli_fd, StaticWriteEvent);
4118 tv_eternity(&t->cwexpire);
4119 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004120 /* We must ensure that the read part is still alive when switching
4121 * to shutw */
4122 FD_SET(t->cli_fd, StaticReadEvent);
4123 if (t->proxy->clitimeout)
4124 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4125
willy tarreau036e1ce2005-12-17 13:46:33 +01004126 t->cli_state = CL_STSHUTW;
4127 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004128 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004129 if (!(t->flags & SN_FINST_MASK))
4130 t->flags |= SN_FINST_D;
4131 return 1;
4132 }
willy tarreau0f7af912005-12-17 12:21:26 +01004133
willy tarreauc58fc692005-12-17 14:13:08 +01004134 if (req->l >= req->rlim - req->data) {
4135 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004136 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004137 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004138 FD_CLR(t->cli_fd, StaticReadEvent);
4139 tv_eternity(&t->crexpire);
4140 }
4141 }
4142 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004143 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004144 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4145 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004146 if (!t->proxy->clitimeout ||
4147 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4148 /* If the client has no timeout, or if the server not ready yet, and we
4149 * know for sure that it can expire, then it's cleaner to disable the
4150 * timeout on the client side so that too low values cannot make the
4151 * sessions abort too early.
4152 */
willy tarreau0f7af912005-12-17 12:21:26 +01004153 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004154 else
4155 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004156 }
4157 }
4158
4159 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004160 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004161 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4162 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4163 tv_eternity(&t->cwexpire);
4164 }
4165 }
4166 else { /* buffer not empty */
4167 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4168 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004169 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004170 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004171 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4172 t->crexpire = t->cwexpire;
4173 }
willy tarreau0f7af912005-12-17 12:21:26 +01004174 else
4175 tv_eternity(&t->cwexpire);
4176 }
4177 }
4178 return 0; /* other cases change nothing */
4179 }
4180 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004181 if (t->res_cw == RES_ERROR) {
4182 tv_eternity(&t->cwexpire);
4183 fd_delete(t->cli_fd);
4184 t->cli_state = CL_STCLOSE;
4185 if (!(t->flags & SN_ERR_MASK))
4186 t->flags |= SN_ERR_CLICL;
4187 if (!(t->flags & SN_FINST_MASK))
4188 t->flags |= SN_FINST_D;
4189 return 1;
4190 }
4191 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004192 tv_eternity(&t->cwexpire);
4193 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004194 t->cli_state = CL_STCLOSE;
4195 return 1;
4196 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004197 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4198 tv_eternity(&t->cwexpire);
4199 fd_delete(t->cli_fd);
4200 t->cli_state = CL_STCLOSE;
4201 if (!(t->flags & SN_ERR_MASK))
4202 t->flags |= SN_ERR_CLITO;
4203 if (!(t->flags & SN_FINST_MASK))
4204 t->flags |= SN_FINST_D;
4205 return 1;
4206 }
willy tarreau0f7af912005-12-17 12:21:26 +01004207 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004208 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004209 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4210 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4211 tv_eternity(&t->cwexpire);
4212 }
4213 }
4214 else { /* buffer not empty */
4215 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4216 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004217 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004218 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004219 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4220 t->crexpire = t->cwexpire;
4221 }
willy tarreau0f7af912005-12-17 12:21:26 +01004222 else
4223 tv_eternity(&t->cwexpire);
4224 }
4225 }
4226 return 0;
4227 }
4228 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004229 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004230 tv_eternity(&t->crexpire);
4231 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004232 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004233 if (!(t->flags & SN_ERR_MASK))
4234 t->flags |= SN_ERR_CLICL;
4235 if (!(t->flags & SN_FINST_MASK))
4236 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004237 return 1;
4238 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004239 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4240 tv_eternity(&t->crexpire);
4241 fd_delete(t->cli_fd);
4242 t->cli_state = CL_STCLOSE;
4243 return 1;
4244 }
4245 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4246 tv_eternity(&t->crexpire);
4247 fd_delete(t->cli_fd);
4248 t->cli_state = CL_STCLOSE;
4249 if (!(t->flags & SN_ERR_MASK))
4250 t->flags |= SN_ERR_CLITO;
4251 if (!(t->flags & SN_FINST_MASK))
4252 t->flags |= SN_FINST_D;
4253 return 1;
4254 }
willy tarreauef900ab2005-12-17 12:52:52 +01004255 else if (req->l >= req->rlim - req->data) {
4256 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004257
4258 /* FIXME-20050705: is it possible for a client to maintain a session
4259 * after the timeout by sending more data after it receives a close ?
4260 */
4261
willy tarreau0f7af912005-12-17 12:21:26 +01004262 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004263 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004264 FD_CLR(t->cli_fd, StaticReadEvent);
4265 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004266 //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 +01004267 }
4268 }
4269 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004270 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004271 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4272 FD_SET(t->cli_fd, StaticReadEvent);
4273 if (t->proxy->clitimeout)
4274 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4275 else
4276 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004277 //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 +01004278 }
4279 }
4280 return 0;
4281 }
4282 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004283 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004284 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004285 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 +01004286 write(1, trash, len);
4287 }
4288 return 0;
4289 }
4290 return 0;
4291}
4292
4293
4294/*
4295 * manages the server FSM and its socket. It returns 1 if a state has changed
4296 * (and a resync may be needed), 0 else.
4297 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004298int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004299 int s = t->srv_state;
4300 int c = t->cli_state;
4301 struct buffer *req = t->req;
4302 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004303 appsess *asession_temp = NULL;
4304 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004305 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004306
willy tarreau750a4722005-12-17 13:21:24 +01004307#ifdef DEBUG_FULL
4308 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4309#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004310 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4311 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4312 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4313 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004314 if (s == SV_STIDLE) {
4315 if (c == CL_STHEADERS)
4316 return 0; /* stay in idle, waiting for data to reach the client side */
4317 else if (c == CL_STCLOSE ||
4318 c == CL_STSHUTW ||
4319 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4320 tv_eternity(&t->cnexpire);
4321 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004322 if (!(t->flags & SN_ERR_MASK))
4323 t->flags |= SN_ERR_CLICL;
4324 if (!(t->flags & SN_FINST_MASK))
4325 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004326 return 1;
4327 }
4328 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004329 /* initiate a connection to the server */
4330 conn_err = connect_server(t);
4331 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004332 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4333 t->srv_state = SV_STCONN;
4334 }
4335 else { /* try again */
4336 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004337 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004338 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004339 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004340 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4341 t->flags &= ~SN_CK_MASK;
4342 t->flags |= SN_CK_DOWN;
4343 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004344 }
4345
willy tarreaub1285d52005-12-18 01:20:14 +01004346 conn_err = connect_server(t);
4347 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004348 t->srv_state = SV_STCONN;
4349 break;
4350 }
4351 }
4352 if (t->conn_retries < 0) {
4353 /* if conn_retries < 0 or other error, let's abort */
4354 tv_eternity(&t->cnexpire);
4355 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004356 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004357 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004358 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004359 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004360 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004361 if (!(t->flags & SN_FINST_MASK))
4362 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004363 }
4364 }
4365 return 1;
4366 }
4367 }
4368 else if (s == SV_STCONN) { /* connection in progress */
4369 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004370 //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 +01004371 return 0; /* nothing changed */
4372 }
4373 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4374 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4375 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004376 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004377 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004378 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004380 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004381 if (t->conn_retries >= 0) {
4382 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004383 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004384 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004385 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4386 t->flags &= ~SN_CK_MASK;
4387 t->flags |= SN_CK_DOWN;
4388 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004389 }
willy tarreaub1285d52005-12-18 01:20:14 +01004390 conn_err = connect_server(t);
4391 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004392 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004393 }
willy tarreaub1285d52005-12-18 01:20:14 +01004394 else if (t->res_sw == RES_SILENT)
4395 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4396 else
4397 conn_err = SN_ERR_SRVCL; // it was a connect error.
4398
willy tarreau0f7af912005-12-17 12:21:26 +01004399 /* if conn_retries < 0 or other error, let's abort */
4400 tv_eternity(&t->cnexpire);
4401 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004402 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004403 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004404 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004405 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004406 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004407 if (!(t->flags & SN_FINST_MASK))
4408 t->flags |= SN_FINST_C;
willy tarreaucfbb2182006-04-07 17:37:55 +02004409 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004410 return 1;
4411 }
4412 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004413 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004414
willy tarreau0f7af912005-12-17 12:21:26 +01004415 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004416 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004417 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004418 tv_eternity(&t->swexpire);
4419 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004420 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004421 if (t->proxy->srvtimeout) {
4422 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4423 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4424 t->srexpire = t->swexpire;
4425 }
4426 else
4427 tv_eternity(&t->swexpire);
4428 }
willy tarreau0f7af912005-12-17 12:21:26 +01004429
4430 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4431 FD_SET(t->srv_fd, StaticReadEvent);
4432 if (t->proxy->srvtimeout)
4433 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4434 else
4435 tv_eternity(&t->srexpire);
4436
4437 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004438 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004439 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004440
4441 /* if the user wants to log as soon as possible, without counting
4442 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004443 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004444 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4445 sess_log(t);
4446 }
willy tarreau0f7af912005-12-17 12:21:26 +01004447 }
willy tarreauef900ab2005-12-17 12:52:52 +01004448 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004449 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004450 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004451 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004453 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004454 return 1;
4455 }
4456 }
4457 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004458 /* now parse the partial (or complete) headers */
4459 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4460 char *ptr;
4461 int delete_header;
4462
4463 ptr = rep->lr;
4464
4465 /* look for the end of the current header */
4466 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4467 ptr++;
4468
4469 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004470 int line, len;
4471
4472 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004473
4474 /* first, we'll block if security checks have caught nasty things */
4475 if (t->flags & SN_CACHEABLE) {
4476 if ((t->flags & SN_CACHE_COOK) &&
4477 (t->flags & SN_SCK_ANY) &&
4478 (t->proxy->options & PR_O_CHK_CACHE)) {
4479
4480 /* we're in presence of a cacheable response containing
4481 * a set-cookie header. We'll block it as requested by
4482 * the 'checkcache' option, and send an alert.
4483 */
4484 tv_eternity(&t->srexpire);
4485 tv_eternity(&t->swexpire);
4486 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004487 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004488 t->srv_state = SV_STCLOSE;
4489 t->logs.status = 502;
4490 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4491 if (!(t->flags & SN_ERR_MASK))
4492 t->flags |= SN_ERR_PRXCOND;
4493 if (!(t->flags & SN_FINST_MASK))
4494 t->flags |= SN_FINST_H;
4495
4496 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4497 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4498
willy tarreaucfbb2182006-04-07 17:37:55 +02004499 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004500 return 1;
4501 }
4502 }
4503
willy tarreau982249e2005-12-18 00:57:06 +01004504 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4505 if (t->flags & SN_SVDENY) {
4506 tv_eternity(&t->srexpire);
4507 tv_eternity(&t->swexpire);
4508 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004509 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004510 t->srv_state = SV_STCLOSE;
4511 t->logs.status = 502;
4512 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4513 if (!(t->flags & SN_ERR_MASK))
4514 t->flags |= SN_ERR_PRXCOND;
4515 if (!(t->flags & SN_FINST_MASK))
4516 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004517 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004518 return 1;
4519 }
4520
willy tarreau5cbea6f2005-12-17 12:48:26 +01004521 /* we'll have something else to do here : add new headers ... */
4522
willy tarreaucd878942005-12-17 13:27:43 +01004523 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4524 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004525 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004526 * insert a set-cookie here, except if we want to insert only on POST
4527 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 */
willy tarreau750a4722005-12-17 13:21:24 +01004529 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004530 t->proxy->cookie_name,
4531 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004532
willy tarreau036e1ce2005-12-17 13:46:33 +01004533 t->flags |= SN_SCK_INSERTED;
4534
willy tarreau750a4722005-12-17 13:21:24 +01004535 /* Here, we will tell an eventual cache on the client side that we don't
4536 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4537 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4538 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4539 */
willy tarreau240afa62005-12-17 13:14:35 +01004540 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004541 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4542 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004543
4544 if (rep->data + rep->l < rep->h)
4545 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4546 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004547 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004548 }
4549
4550 /* headers to be added */
4551 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004552 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4553 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004554 }
4555
willy tarreau25c4ea52005-12-18 00:49:49 +01004556 /* add a "connection: close" line if needed */
4557 if (t->proxy->options & PR_O_HTTP_CLOSE)
4558 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4559
willy tarreau5cbea6f2005-12-17 12:48:26 +01004560 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004561 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004562 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004563
Willy TARREAU767ba712006-03-01 22:40:50 +01004564 /* client connection already closed or option 'httpclose' required :
4565 * we close the server's outgoing connection right now.
4566 */
4567 if ((req->l == 0) &&
4568 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4569 FD_CLR(t->srv_fd, StaticWriteEvent);
4570 tv_eternity(&t->swexpire);
4571
4572 /* We must ensure that the read part is still alive when switching
4573 * to shutw */
4574 FD_SET(t->srv_fd, StaticReadEvent);
4575 if (t->proxy->srvtimeout)
4576 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4577
4578 shutdown(t->srv_fd, SHUT_WR);
4579 t->srv_state = SV_STSHUTW;
4580 }
4581
willy tarreau25c4ea52005-12-18 00:49:49 +01004582 /* if the user wants to log as soon as possible, without counting
4583 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004584 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004585 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4586 t->logs.bytes = rep->h - rep->data;
4587 sess_log(t);
4588 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004589 break;
4590 }
4591
4592 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4593 if (ptr > rep->r - 2) {
4594 /* this is a partial header, let's wait for more to come */
4595 rep->lr = ptr;
4596 break;
4597 }
4598
4599 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4600 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4601
4602 /* now we know that *ptr is either \r or \n,
4603 * and that there are at least 1 char after it.
4604 */
4605 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4606 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4607 else
4608 rep->lr = ptr + 2; /* \r\n or \n\r */
4609
4610 /*
4611 * now we know that we have a full header ; we can do whatever
4612 * we want with these pointers :
4613 * rep->h = beginning of header
4614 * ptr = end of header (first \r or \n)
4615 * rep->lr = beginning of next line (next rep->h)
4616 * rep->r = end of data (not used at this stage)
4617 */
4618
willy tarreaua1598082005-12-17 13:08:06 +01004619
willy tarreau982249e2005-12-18 00:57:06 +01004620 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004621 t->logs.logwait &= ~LW_RESP;
4622 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004623 switch (t->logs.status) {
4624 case 200:
4625 case 203:
4626 case 206:
4627 case 300:
4628 case 301:
4629 case 410:
4630 /* RFC2616 @13.4:
4631 * "A response received with a status code of
4632 * 200, 203, 206, 300, 301 or 410 MAY be stored
4633 * by a cache (...) unless a cache-control
4634 * directive prohibits caching."
4635 *
4636 * RFC2616 @9.5: POST method :
4637 * "Responses to this method are not cacheable,
4638 * unless the response includes appropriate
4639 * Cache-Control or Expires header fields."
4640 */
4641 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4642 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4643 break;
4644 default:
4645 break;
4646 }
willy tarreau4302f492005-12-18 01:00:37 +01004647 }
4648 else if (t->logs.logwait & LW_RSPHDR) {
4649 struct cap_hdr *h;
4650 int len;
4651 for (h = t->proxy->rsp_cap; h; h = h->next) {
4652 if ((h->namelen + 2 <= ptr - rep->h) &&
4653 (rep->h[h->namelen] == ':') &&
4654 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4655
4656 if (t->rsp_cap[h->index] == NULL)
4657 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4658
4659 len = ptr - (rep->h + h->namelen + 2);
4660 if (len > h->len)
4661 len = h->len;
4662
4663 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4664 t->rsp_cap[h->index][len]=0;
4665 }
4666 }
4667
willy tarreaua1598082005-12-17 13:08:06 +01004668 }
4669
willy tarreau5cbea6f2005-12-17 12:48:26 +01004670 delete_header = 0;
4671
willy tarreau982249e2005-12-18 00:57:06 +01004672 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004673 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004674 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 +01004675 max = ptr - rep->h;
4676 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004677 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004678 trash[len++] = '\n';
4679 write(1, trash, len);
4680 }
4681
willy tarreau25c4ea52005-12-18 00:49:49 +01004682 /* remove "connection: " if needed */
4683 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4684 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4685 delete_header = 1;
4686 }
4687
willy tarreau5cbea6f2005-12-17 12:48:26 +01004688 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004689 if (!delete_header && t->proxy->rsp_exp != NULL
4690 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004691 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004692 char term;
4693
4694 term = *ptr;
4695 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004696 exp = t->proxy->rsp_exp;
4697 do {
4698 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4699 switch (exp->action) {
4700 case ACT_ALLOW:
4701 if (!(t->flags & SN_SVDENY))
4702 t->flags |= SN_SVALLOW;
4703 break;
4704 case ACT_REPLACE:
4705 if (!(t->flags & SN_SVDENY)) {
4706 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4707 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4708 }
4709 break;
4710 case ACT_REMOVE:
4711 if (!(t->flags & SN_SVDENY))
4712 delete_header = 1;
4713 break;
4714 case ACT_DENY:
4715 if (!(t->flags & SN_SVALLOW))
4716 t->flags |= SN_SVDENY;
4717 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004718 case ACT_PASS: /* we simply don't deny this one */
4719 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004720 }
4721 break;
4722 }
willy tarreaue39cd132005-12-17 13:00:18 +01004723 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004724 *ptr = term; /* restore the string terminator */
4725 }
4726
willy tarreau97f58572005-12-18 00:53:44 +01004727 /* check for cache-control: or pragma: headers */
4728 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4729 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4730 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4731 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4732 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004733 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004734 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4735 else {
4736 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004737 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004738 t->flags &= ~SN_CACHE_COOK;
4739 }
4740 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004741 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004742 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004743 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004744 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4745 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004746 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004747 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004748 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4749 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4750 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4751 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4752 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4753 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004754 }
4755 }
4756 }
4757
willy tarreau5cbea6f2005-12-17 12:48:26 +01004758 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004759 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004760 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004761 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004762 char *p1, *p2, *p3, *p4;
4763
willy tarreau97f58572005-12-18 00:53:44 +01004764 t->flags |= SN_SCK_ANY;
4765
willy tarreau5cbea6f2005-12-17 12:48:26 +01004766 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4767
4768 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004769 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004770 p1++;
4771
4772 if (p1 == ptr || *p1 == ';') /* end of cookie */
4773 break;
4774
4775 /* p1 is at the beginning of the cookie name */
4776 p2 = p1;
4777
4778 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4779 p2++;
4780
4781 if (p2 == ptr || *p2 == ';') /* next cookie */
4782 break;
4783
4784 p3 = p2 + 1; /* skips the '=' sign */
4785 if (p3 == ptr)
4786 break;
4787
4788 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004789 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004790 p4++;
4791
4792 /* here, we have the cookie name between p1 and p2,
4793 * and its value between p3 and p4.
4794 * we can process it.
4795 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004796
4797 /* first, let's see if we want to capture it */
4798 if (t->proxy->capture_name != NULL &&
4799 t->logs.srv_cookie == NULL &&
4800 (p4 - p1 >= t->proxy->capture_namelen) &&
4801 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4802 int log_len = p4 - p1;
4803
4804 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4805 Alert("HTTP logging : out of memory.\n");
4806 }
4807
4808 if (log_len > t->proxy->capture_len)
4809 log_len = t->proxy->capture_len;
4810 memcpy(t->logs.srv_cookie, p1, log_len);
4811 t->logs.srv_cookie[log_len] = 0;
4812 }
4813
4814 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4815 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004817 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004818
4819 /* If the cookie is in insert mode on a known server, we'll delete
4820 * this occurrence because we'll insert another one later.
4821 * We'll delete it too if the "indirect" option is set and we're in
4822 * a direct access. */
4823 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004824 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004825 /* this header must be deleted */
4826 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004827 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004828 }
4829 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4830 /* replace bytes p3->p4 with the cookie name associated
4831 * with this server since we know it.
4832 */
4833 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004834 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004835 }
willy tarreau0174f312005-12-18 01:02:42 +01004836 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4837 /* insert the cookie name associated with this server
4838 * before existing cookie, and insert a delimitor between them..
4839 */
4840 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4841 p3[t->srv->cklen] = COOKIE_DELIM;
4842 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4843 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004844 break;
4845 }
willy tarreau12350152005-12-18 01:03:27 +01004846
4847 /* first, let's see if the cookie is our appcookie*/
4848 if ((t->proxy->appsession_name != NULL) &&
4849 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4850
4851 /* Cool... it's the right one */
4852
willy tarreaub952e1d2005-12-18 01:31:20 +01004853 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004854 asession_temp = &local_asession;
4855
willy tarreaub952e1d2005-12-18 01:31:20 +01004856 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004857 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4858 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4859 }
4860 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4861 asession_temp->sessid[t->proxy->appsession_len] = 0;
4862 asession_temp->serverid = NULL;
4863
4864 /* only do insert, if lookup fails */
4865 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4866 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4867 Alert("Not enought Memory process_srv():asession:calloc().\n");
4868 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4869 return 0;
4870 }
4871 asession_temp->sessid = local_asession.sessid;
4872 asession_temp->serverid = local_asession.serverid;
4873 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004874 }/* end if (chtbl_lookup()) */
4875 else {
willy tarreau12350152005-12-18 01:03:27 +01004876 /* free wasted memory */
4877 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004878 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004879
willy tarreaub952e1d2005-12-18 01:31:20 +01004880 if (asession_temp->serverid == NULL) {
4881 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004882 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4883 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4884 }
4885 asession_temp->serverid[0] = '\0';
4886 }
4887
willy tarreaub952e1d2005-12-18 01:31:20 +01004888 if (asession_temp->serverid[0] == '\0')
4889 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004890
4891 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4892
4893#if defined(DEBUG_HASH)
4894 print_table(&(t->proxy->htbl_proxy));
4895#endif
4896 break;
4897 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004898 else {
4899 // fprintf(stderr,"Ignoring unknown cookie : ");
4900 // write(2, p1, p2-p1);
4901 // fprintf(stderr," = ");
4902 // write(2, p3, p4-p3);
4903 // fprintf(stderr,"\n");
4904 }
4905 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4906 } /* we're now at the end of the cookie value */
4907 } /* end of cookie processing */
4908
willy tarreau97f58572005-12-18 00:53:44 +01004909 /* check for any set-cookie in case we check for cacheability */
4910 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4911 (t->proxy->options & PR_O_CHK_CACHE) &&
4912 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4913 t->flags |= SN_SCK_ANY;
4914 }
4915
willy tarreau5cbea6f2005-12-17 12:48:26 +01004916 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004917 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004918 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004919
willy tarreau5cbea6f2005-12-17 12:48:26 +01004920 rep->h = rep->lr;
4921 } /* while (rep->lr < rep->r) */
4922
4923 /* end of header processing (even if incomplete) */
4924
willy tarreauef900ab2005-12-17 12:52:52 +01004925 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4926 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4927 * full. We cannot loop here since event_srv_read will disable it only if
4928 * rep->l == rlim-data
4929 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004930 FD_SET(t->srv_fd, StaticReadEvent);
4931 if (t->proxy->srvtimeout)
4932 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4933 else
4934 tv_eternity(&t->srexpire);
4935 }
willy tarreau0f7af912005-12-17 12:21:26 +01004936
willy tarreau8337c6b2005-12-17 13:41:01 +01004937 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004938 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004939 tv_eternity(&t->srexpire);
4940 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004942 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004943 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004944 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004945 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004946 if (!(t->flags & SN_ERR_MASK))
4947 t->flags |= SN_ERR_SRVCL;
4948 if (!(t->flags & SN_FINST_MASK))
4949 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004950 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004951 return 1;
4952 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004953 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004954 * since we are in header mode, if there's no space left for headers, we
4955 * won't be able to free more later, so the session will never terminate.
4956 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004957 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 +01004958 FD_CLR(t->srv_fd, StaticReadEvent);
4959 tv_eternity(&t->srexpire);
4960 shutdown(t->srv_fd, SHUT_RD);
4961 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004962 //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 +01004963 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004964 }
4965 /* read timeout : return a 504 to the client.
4966 */
4967 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4968 tv_eternity(&t->srexpire);
4969 tv_eternity(&t->swexpire);
4970 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004971 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004972 t->srv_state = SV_STCLOSE;
4973 t->logs.status = 504;
4974 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004975 if (!(t->flags & SN_ERR_MASK))
4976 t->flags |= SN_ERR_SRVTO;
4977 if (!(t->flags & SN_FINST_MASK))
4978 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004979 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004980 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004981 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004982 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004983 /* FIXME!!! here, we don't want to switch to SHUTW if the
4984 * client shuts read too early, because we may still have
4985 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004986 * The side-effect is that if the client completely closes its
4987 * connection during SV_STHEADER, the connection to the server
4988 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004989 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004990 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004991 FD_CLR(t->srv_fd, StaticWriteEvent);
4992 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004993
4994 /* We must ensure that the read part is still alive when switching
4995 * to shutw */
4996 FD_SET(t->srv_fd, StaticReadEvent);
4997 if (t->proxy->srvtimeout)
4998 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4999
willy tarreau0f7af912005-12-17 12:21:26 +01005000 shutdown(t->srv_fd, SHUT_WR);
5001 t->srv_state = SV_STSHUTW;
5002 return 1;
5003 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005004 /* write timeout */
5005 /* FIXME!!! here, we don't want to switch to SHUTW if the
5006 * client shuts read too early, because we may still have
5007 * some work to do on the headers.
5008 */
5009 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5010 FD_CLR(t->srv_fd, StaticWriteEvent);
5011 tv_eternity(&t->swexpire);
5012 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005013 /* We must ensure that the read part is still alive when switching
5014 * to shutw */
5015 FD_SET(t->srv_fd, StaticReadEvent);
5016 if (t->proxy->srvtimeout)
5017 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5018
5019 /* We must ensure that the read part is still alive when switching
5020 * to shutw */
5021 FD_SET(t->srv_fd, StaticReadEvent);
5022 if (t->proxy->srvtimeout)
5023 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5024
willy tarreau036e1ce2005-12-17 13:46:33 +01005025 t->srv_state = SV_STSHUTW;
5026 if (!(t->flags & SN_ERR_MASK))
5027 t->flags |= SN_ERR_SRVTO;
5028 if (!(t->flags & SN_FINST_MASK))
5029 t->flags |= SN_FINST_H;
5030 return 1;
5031 }
willy tarreau0f7af912005-12-17 12:21:26 +01005032
5033 if (req->l == 0) {
5034 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5035 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5036 tv_eternity(&t->swexpire);
5037 }
5038 }
5039 else { /* client buffer not empty */
5040 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5041 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005042 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005043 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005044 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5045 t->srexpire = t->swexpire;
5046 }
willy tarreau0f7af912005-12-17 12:21:26 +01005047 else
5048 tv_eternity(&t->swexpire);
5049 }
5050 }
5051
willy tarreau5cbea6f2005-12-17 12:48:26 +01005052 /* be nice with the client side which would like to send a complete header
5053 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5054 * would read all remaining data at once ! The client should not write past rep->lr
5055 * when the server is in header state.
5056 */
5057 //return header_processed;
5058 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005059 }
5060 else if (s == SV_STDATA) {
5061 /* read or write error */
5062 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005063 tv_eternity(&t->srexpire);
5064 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005065 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005066 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005067 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005068 if (!(t->flags & SN_ERR_MASK))
5069 t->flags |= SN_ERR_SRVCL;
5070 if (!(t->flags & SN_FINST_MASK))
5071 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005072 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005073 return 1;
5074 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005075 /* last read, or end of client write */
5076 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005077 FD_CLR(t->srv_fd, StaticReadEvent);
5078 tv_eternity(&t->srexpire);
5079 shutdown(t->srv_fd, SHUT_RD);
5080 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005081 //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 +01005082 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005083 }
5084 /* end of client read and no more data to send */
5085 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5086 FD_CLR(t->srv_fd, StaticWriteEvent);
5087 tv_eternity(&t->swexpire);
5088 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005089 /* We must ensure that the read part is still alive when switching
5090 * to shutw */
5091 FD_SET(t->srv_fd, StaticReadEvent);
5092 if (t->proxy->srvtimeout)
5093 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5094
willy tarreaua41a8b42005-12-17 14:02:24 +01005095 t->srv_state = SV_STSHUTW;
5096 return 1;
5097 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005098 /* read timeout */
5099 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5100 FD_CLR(t->srv_fd, StaticReadEvent);
5101 tv_eternity(&t->srexpire);
5102 shutdown(t->srv_fd, SHUT_RD);
5103 t->srv_state = SV_STSHUTR;
5104 if (!(t->flags & SN_ERR_MASK))
5105 t->flags |= SN_ERR_SRVTO;
5106 if (!(t->flags & SN_FINST_MASK))
5107 t->flags |= SN_FINST_D;
5108 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005109 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005110 /* write timeout */
5111 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005112 FD_CLR(t->srv_fd, StaticWriteEvent);
5113 tv_eternity(&t->swexpire);
5114 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005115 /* We must ensure that the read part is still alive when switching
5116 * to shutw */
5117 FD_SET(t->srv_fd, StaticReadEvent);
5118 if (t->proxy->srvtimeout)
5119 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005120 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005121 if (!(t->flags & SN_ERR_MASK))
5122 t->flags |= SN_ERR_SRVTO;
5123 if (!(t->flags & SN_FINST_MASK))
5124 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005125 return 1;
5126 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005127
5128 /* recompute request time-outs */
5129 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005130 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5131 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5132 tv_eternity(&t->swexpire);
5133 }
5134 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005135 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005136 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5137 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005138 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005139 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005140 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5141 t->srexpire = t->swexpire;
5142 }
willy tarreau0f7af912005-12-17 12:21:26 +01005143 else
5144 tv_eternity(&t->swexpire);
5145 }
5146 }
5147
willy tarreaub1ff9db2005-12-17 13:51:03 +01005148 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005149 if (rep->l == BUFSIZE) { /* no room to read more data */
5150 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5151 FD_CLR(t->srv_fd, StaticReadEvent);
5152 tv_eternity(&t->srexpire);
5153 }
5154 }
5155 else {
5156 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5157 FD_SET(t->srv_fd, StaticReadEvent);
5158 if (t->proxy->srvtimeout)
5159 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5160 else
5161 tv_eternity(&t->srexpire);
5162 }
5163 }
5164
5165 return 0; /* other cases change nothing */
5166 }
5167 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005168 if (t->res_sw == RES_ERROR) {
5169 //FD_CLR(t->srv_fd, StaticWriteEvent);
5170 tv_eternity(&t->swexpire);
5171 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005172 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005173 //close(t->srv_fd);
5174 t->srv_state = SV_STCLOSE;
5175 if (!(t->flags & SN_ERR_MASK))
5176 t->flags |= SN_ERR_SRVCL;
5177 if (!(t->flags & SN_FINST_MASK))
5178 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005179 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005180 return 1;
5181 }
5182 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005183 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005184 tv_eternity(&t->swexpire);
5185 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005186 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005187 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005188 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005189 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005190 return 1;
5191 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005192 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5193 //FD_CLR(t->srv_fd, StaticWriteEvent);
5194 tv_eternity(&t->swexpire);
5195 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005196 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005197 //close(t->srv_fd);
5198 t->srv_state = SV_STCLOSE;
5199 if (!(t->flags & SN_ERR_MASK))
5200 t->flags |= SN_ERR_SRVTO;
5201 if (!(t->flags & SN_FINST_MASK))
5202 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005203 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005204 return 1;
5205 }
willy tarreau0f7af912005-12-17 12:21:26 +01005206 else if (req->l == 0) {
5207 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5208 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5209 tv_eternity(&t->swexpire);
5210 }
5211 }
5212 else { /* buffer not empty */
5213 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5214 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005215 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005216 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005217 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5218 t->srexpire = t->swexpire;
5219 }
willy tarreau0f7af912005-12-17 12:21:26 +01005220 else
5221 tv_eternity(&t->swexpire);
5222 }
5223 }
5224 return 0;
5225 }
5226 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005227 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005229 tv_eternity(&t->srexpire);
5230 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005231 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005232 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005233 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005234 if (!(t->flags & SN_ERR_MASK))
5235 t->flags |= SN_ERR_SRVCL;
5236 if (!(t->flags & SN_FINST_MASK))
5237 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005238 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005239 return 1;
5240 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005241 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5242 //FD_CLR(t->srv_fd, StaticReadEvent);
5243 tv_eternity(&t->srexpire);
5244 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005245 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005246 //close(t->srv_fd);
5247 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005248 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005249 return 1;
5250 }
5251 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5252 //FD_CLR(t->srv_fd, StaticReadEvent);
5253 tv_eternity(&t->srexpire);
5254 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005255 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005256 //close(t->srv_fd);
5257 t->srv_state = SV_STCLOSE;
5258 if (!(t->flags & SN_ERR_MASK))
5259 t->flags |= SN_ERR_SRVTO;
5260 if (!(t->flags & SN_FINST_MASK))
5261 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005262 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005263 return 1;
5264 }
willy tarreau0f7af912005-12-17 12:21:26 +01005265 else if (rep->l == BUFSIZE) { /* no room to read more data */
5266 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5267 FD_CLR(t->srv_fd, StaticReadEvent);
5268 tv_eternity(&t->srexpire);
5269 }
5270 }
5271 else {
5272 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5273 FD_SET(t->srv_fd, StaticReadEvent);
5274 if (t->proxy->srvtimeout)
5275 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5276 else
5277 tv_eternity(&t->srexpire);
5278 }
5279 }
5280 return 0;
5281 }
5282 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005283 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005284 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005285 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 +01005286 write(1, trash, len);
5287 }
5288 return 0;
5289 }
5290 return 0;
5291}
5292
5293
willy tarreau5cbea6f2005-12-17 12:48:26 +01005294/* Processes the client and server jobs of a session task, then
5295 * puts it back to the wait queue in a clean state, or
5296 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005297 * the time the task accepts to wait, or TIME_ETERNITY for
5298 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005299 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005300int process_session(struct task *t) {
5301 struct session *s = t->context;
5302 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005303
willy tarreau5cbea6f2005-12-17 12:48:26 +01005304 do {
5305 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005306 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005307 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005308 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005309 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005310 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005311 } while (fsm_resync);
5312
5313 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005314 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005315 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005316
willy tarreau5cbea6f2005-12-17 12:48:26 +01005317 tv_min(&min1, &s->crexpire, &s->cwexpire);
5318 tv_min(&min2, &s->srexpire, &s->swexpire);
5319 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005320 tv_min(&t->expire, &min1, &min2);
5321
5322 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005323 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005324
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005325#ifdef DEBUG_FULL
5326 /* DEBUG code : this should never ever happen, otherwise it indicates
5327 * that a task still has something to do and will provoke a quick loop.
5328 */
5329 if (tv_remain2(&now, &t->expire) <= 0)
5330 exit(100);
5331#endif
5332
willy tarreaub952e1d2005-12-18 01:31:20 +01005333 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005334 }
5335
willy tarreau5cbea6f2005-12-17 12:48:26 +01005336 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005337 actconn--;
5338
willy tarreau982249e2005-12-18 00:57:06 +01005339 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005340 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005341 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 +01005342 write(1, trash, len);
5343 }
5344
willy tarreau750a4722005-12-17 13:21:24 +01005345 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005346 if (s->rep != NULL)
5347 s->logs.bytes = s->rep->total;
5348
willy tarreau9fe663a2005-12-17 13:02:59 +01005349 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005350 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005351 sess_log(s);
5352
willy tarreau0f7af912005-12-17 12:21:26 +01005353 /* the task MUST not be in the run queue anymore */
5354 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005355 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005356 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005357 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005358}
5359
5360
5361
5362/*
5363 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005364 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005365 */
5366int process_chk(struct task *t) {
5367 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005368 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005369 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005370
willy tarreauef900ab2005-12-17 12:52:52 +01005371 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005372
willy tarreau25424f82006-03-19 19:37:48 +01005373 new_chk:
5374 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005375 if (fd < 0) { /* no check currently running */
5376 //fprintf(stderr, "process_chk: 2\n");
5377 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5378 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005379 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005380 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005381
5382 /* we don't send any health-checks when the proxy is stopped or when
5383 * the server should not be checked.
5384 */
5385 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005386 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5387 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005388 task_queue(t); /* restore t to its place in the task list */
5389 return tv_remain2(&now, &t->expire);
5390 }
5391
willy tarreau5cbea6f2005-12-17 12:48:26 +01005392 /* we'll initiate a new check */
5393 s->result = 0; /* no result yet */
5394 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005395 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005396 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5397 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5398 //fprintf(stderr, "process_chk: 3\n");
5399
willy tarreaua41a8b42005-12-17 14:02:24 +01005400 /* we'll connect to the check port on the server */
5401 sa = s->addr;
5402 sa.sin_port = htons(s->check_port);
5403
willy tarreau0174f312005-12-18 01:02:42 +01005404 /* allow specific binding :
5405 * - server-specific at first
5406 * - proxy-specific next
5407 */
5408 if (s->state & SRV_BIND_SRC) {
5409 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5410 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5411 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5412 s->proxy->id, s->id);
5413 s->result = -1;
5414 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005415 }
willy tarreau0174f312005-12-18 01:02:42 +01005416 else if (s->proxy->options & PR_O_BIND_SRC) {
5417 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5418 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5419 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5420 s->proxy->id);
5421 s->result = -1;
5422 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005423 }
willy tarreau0174f312005-12-18 01:02:42 +01005424
5425 if (!s->result) {
5426 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5427 /* OK, connection in progress or established */
5428
5429 //fprintf(stderr, "process_chk: 4\n");
5430
5431 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5432 fdtab[fd].owner = t;
5433 fdtab[fd].read = &event_srv_chk_r;
5434 fdtab[fd].write = &event_srv_chk_w;
5435 fdtab[fd].state = FD_STCONN; /* connection in progress */
5436 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005437#ifdef DEBUG_FULL
5438 assert (!FD_ISSET(fd, StaticReadEvent));
5439#endif
willy tarreau0174f312005-12-18 01:02:42 +01005440 fd_insert(fd);
5441 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5442 tv_delayfrom(&t->expire, &now, s->inter);
5443 task_queue(t); /* restore t to its place in the task list */
5444 return tv_remain(&now, &t->expire);
5445 }
5446 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5447 s->result = -1; /* a real error */
5448 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005449 }
5450 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005451 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005452 }
5453
5454 if (!s->result) { /* nothing done */
5455 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005456 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5457 tv_delayfrom(&t->expire, &t->expire, s->inter);
5458 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005459 }
5460
5461 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005462 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005463 s->health--; /* still good */
5464 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005465 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005466 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005467 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005468 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005469 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5470 s->state & SRV_BACKUP ? "Backup " : "",
5471 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5472 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5473 send_log(s->proxy, LOG_ALERT,
5474 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5475 s->state & SRV_BACKUP ? "Backup " : "",
5476 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5477 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005478
willy tarreau62084d42006-03-24 18:57:41 +01005479 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005480 Alert("Proxy %s has no server available !\n", s->proxy->id);
5481 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5482 }
5483 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005484 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005485 }
5486
5487 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005488 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005489 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5490 tv_delayfrom(&t->expire, &t->expire, s->inter);
5491 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005492 }
5493 else {
5494 //fprintf(stderr, "process_chk: 8\n");
5495 /* there was a test running */
5496 if (s->result > 0) { /* good server detected */
5497 //fprintf(stderr, "process_chk: 9\n");
5498 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005499 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005500 s->state |= SRV_RUNNING;
5501
willy tarreau535ae7a2005-12-17 12:58:00 +01005502 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005503 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005504 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005505 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5506 s->state & SRV_BACKUP ? "Backup " : "",
5507 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5508 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5509 send_log(s->proxy, LOG_NOTICE,
5510 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5511 s->state & SRV_BACKUP ? "Backup " : "",
5512 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5513 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005514 }
willy tarreauef900ab2005-12-17 12:52:52 +01005515
willy tarreaue47c8d72005-12-17 12:55:52 +01005516 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005517 }
willy tarreauef900ab2005-12-17 12:52:52 +01005518 s->curfd = -1; /* no check running anymore */
5519 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005520 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005521 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5522 tv_delayfrom(&t->expire, &t->expire, s->inter);
5523 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005524 }
5525 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5526 //fprintf(stderr, "process_chk: 10\n");
5527 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005528 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005529 s->health--; /* still good */
5530 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005531 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005532
willy tarreau62084d42006-03-24 18:57:41 +01005533 if (s->health == s->rise) {
5534 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005535 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005536 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5537 s->state & SRV_BACKUP ? "Backup " : "",
5538 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5539 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5540 send_log(s->proxy, LOG_ALERT,
5541 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5542 s->state & SRV_BACKUP ? "Backup " : "",
5543 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5544 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5545
5546 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5547 Alert("Proxy %s has no server available !\n", s->proxy->id);
5548 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5549 }
5550 }
willy tarreauef900ab2005-12-17 12:52:52 +01005551
willy tarreau5cbea6f2005-12-17 12:48:26 +01005552 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005553 }
5554 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005555 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005556 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005557 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5558 tv_delayfrom(&t->expire, &t->expire, s->inter);
5559 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005560 }
5561 /* if result is 0 and there's no timeout, we have to wait again */
5562 }
5563 //fprintf(stderr, "process_chk: 11\n");
5564 s->result = 0;
5565 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005566 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005567}
5568
5569
willy tarreau5cbea6f2005-12-17 12:48:26 +01005570
willy tarreau0f7af912005-12-17 12:21:26 +01005571#if STATTIME > 0
5572int stats(void);
5573#endif
5574
5575/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005576 * This does 4 things :
5577 * - wake up all expired tasks
5578 * - call all runnable tasks
5579 * - call maintain_proxies() to enable/disable the listeners
5580 * - return the delay till next event in ms, -1 = wait indefinitely
5581 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5582 *
willy tarreau0f7af912005-12-17 12:21:26 +01005583 */
5584
willy tarreau1c2ad212005-12-18 01:11:29 +01005585int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005586 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005587 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005588 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005589
willy tarreaub952e1d2005-12-18 01:31:20 +01005590 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005591
willy tarreau1c2ad212005-12-18 01:11:29 +01005592 /* look for expired tasks and add them to the run queue.
5593 */
5594 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5595 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5596 tnext = t->next;
5597 if (t->state & TASK_RUNNING)
5598 continue;
5599
willy tarreaub952e1d2005-12-18 01:31:20 +01005600 if (tv_iseternity(&t->expire))
5601 continue;
5602
willy tarreau1c2ad212005-12-18 01:11:29 +01005603 /* wakeup expired entries. It doesn't matter if they are
5604 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005605 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005606 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005607 task_wakeup(&rq, t);
5608 }
5609 else {
5610 /* first non-runnable task. Use its expiration date as an upper bound */
5611 int temp_time = tv_remain(&now, &t->expire);
5612 if (temp_time)
5613 next_time = temp_time;
5614 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005615 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005616 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005617
willy tarreau1c2ad212005-12-18 01:11:29 +01005618 /* process each task in the run queue now. Each task may be deleted
willy tarreau7feab592006-04-22 15:13:16 +02005619 * since we only use the run queue's head. Note that any task can be
5620 * woken up by any other task and it will be processed immediately
5621 * after as it will be queued on the run queue's head.
willy tarreau1c2ad212005-12-18 01:11:29 +01005622 */
willy tarreau7feab592006-04-22 15:13:16 +02005623 while ((t = rq) != NULL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005624 int temp_time;
willy tarreau7feab592006-04-22 15:13:16 +02005625
willy tarreau1c2ad212005-12-18 01:11:29 +01005626 task_sleep(&rq, t);
5627 temp_time = t->process(t);
5628 next_time = MINTIME(temp_time, next_time);
5629 }
5630
5631 /* maintain all proxies in a consistent state. This should quickly become a task */
5632 time2 = maintain_proxies();
5633 return MINTIME(time2, next_time);
5634}
5635
5636
5637#if defined(ENABLE_EPOLL)
5638
5639/*
5640 * Main epoll() loop.
5641 */
5642
5643/* does 3 actions :
5644 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5645 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5646 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5647 *
5648 * returns 0 if initialization failed, !0 otherwise.
5649 */
5650
5651int epoll_loop(int action) {
5652 int next_time;
5653 int status;
5654 int fd;
5655
5656 int fds, count;
5657 int pr, pw, sr, sw;
5658 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5659 struct epoll_event ev;
5660
5661 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005662 static struct epoll_event *epoll_events = NULL;
5663 static int epoll_fd;
5664
5665 if (action == POLL_LOOP_ACTION_INIT) {
5666 epoll_fd = epoll_create(global.maxsock + 1);
5667 if (epoll_fd < 0)
5668 return 0;
5669 else {
5670 epoll_events = (struct epoll_event*)
5671 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5672 PrevReadEvent = (fd_set *)
5673 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5674 PrevWriteEvent = (fd_set *)
5675 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005676 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005677 return 1;
5678 }
5679 else if (action == POLL_LOOP_ACTION_CLEAN) {
5680 if (PrevWriteEvent) free(PrevWriteEvent);
5681 if (PrevReadEvent) free(PrevReadEvent);
5682 if (epoll_events) free(epoll_events);
5683 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005684 epoll_fd = 0;
5685 return 1;
5686 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005687
willy tarreau1c2ad212005-12-18 01:11:29 +01005688 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005689
willy tarreau1c2ad212005-12-18 01:11:29 +01005690 tv_now(&now);
5691
5692 while (1) {
5693 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005694
5695 /* stop when there's no connection left and we don't allow them anymore */
5696 if (!actconn && listeners == 0)
5697 break;
5698
willy tarreau0f7af912005-12-17 12:21:26 +01005699#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005700 {
5701 int time2;
5702 time2 = stats();
5703 next_time = MINTIME(time2, next_time);
5704 }
willy tarreau0f7af912005-12-17 12:21:26 +01005705#endif
5706
willy tarreau1c2ad212005-12-18 01:11:29 +01005707 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5708
5709 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5710 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5711
5712 if ((ro^rn) | (wo^wn)) {
5713 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5714#define FDSETS_ARE_INT_ALIGNED
5715#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005716
willy tarreauad90a0c2005-12-18 01:09:15 +01005717#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5718#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005719 pr = (ro >> count) & 1;
5720 pw = (wo >> count) & 1;
5721 sr = (rn >> count) & 1;
5722 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005723#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005724 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5725 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5726 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5727 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005728#endif
5729#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005730 pr = FD_ISSET(fd, PrevReadEvent);
5731 pw = FD_ISSET(fd, PrevWriteEvent);
5732 sr = FD_ISSET(fd, StaticReadEvent);
5733 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005734#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005735 if (!((sr^pr) | (sw^pw)))
5736 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005737
willy tarreau1c2ad212005-12-18 01:11:29 +01005738 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5739 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005740
willy tarreaub952e1d2005-12-18 01:31:20 +01005741#ifdef EPOLL_CTL_MOD_WORKAROUND
5742 /* I encountered a rarely reproducible problem with
5743 * EPOLL_CTL_MOD where a modified FD (systematically
5744 * the one in epoll_events[0], fd#7) would sometimes
5745 * be set EPOLL_OUT while asked for a read ! This is
5746 * with the 2.4 epoll patch. The workaround is to
5747 * delete then recreate in case of modification.
5748 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5749 * nor RHEL kernels.
5750 */
5751
5752 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5753 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5754
5755 if ((sr | sw))
5756 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5757#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005758 if ((pr | pw)) {
5759 /* the file-descriptor already exists... */
5760 if ((sr | sw)) {
5761 /* ...and it will still exist */
5762 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5763 // perror("epoll_ctl(MOD)");
5764 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005765 }
5766 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005767 /* ...and it will be removed */
5768 if (fdtab[fd].state != FD_STCLOSE &&
5769 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5770 // perror("epoll_ctl(DEL)");
5771 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005772 }
5773 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005774 } else {
5775 /* the file-descriptor did not exist, let's add it */
5776 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5777 // perror("epoll_ctl(ADD)");
5778 // exit(1);
5779 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005780 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005781#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005782 }
5783 ((int*)PrevReadEvent)[fds] = rn;
5784 ((int*)PrevWriteEvent)[fds] = wn;
5785 }
5786 }
5787
5788 /* now let's wait for events */
5789 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5790 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005791
willy tarreau1c2ad212005-12-18 01:11:29 +01005792 for (count = 0; count < status; count++) {
5793 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005794
5795 if (FD_ISSET(fd, StaticReadEvent)) {
5796 if (fdtab[fd].state == FD_STCLOSE)
5797 continue;
5798 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5799 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005800 }
willy tarreau05be12b2006-03-19 19:35:00 +01005801
5802 if (FD_ISSET(fd, StaticWriteEvent)) {
5803 if (fdtab[fd].state == FD_STCLOSE)
5804 continue;
5805 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5806 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005807 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005808 }
5809 }
5810 return 1;
5811}
5812#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005813
willy tarreauad90a0c2005-12-18 01:09:15 +01005814
willy tarreau5cbea6f2005-12-17 12:48:26 +01005815
willy tarreau1c2ad212005-12-18 01:11:29 +01005816#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005817
willy tarreau1c2ad212005-12-18 01:11:29 +01005818/*
5819 * Main poll() loop.
5820 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005821
willy tarreau1c2ad212005-12-18 01:11:29 +01005822/* does 3 actions :
5823 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5824 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5825 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5826 *
5827 * returns 0 if initialization failed, !0 otherwise.
5828 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005829
willy tarreau1c2ad212005-12-18 01:11:29 +01005830int poll_loop(int action) {
5831 int next_time;
5832 int status;
5833 int fd, nbfd;
5834
5835 int fds, count;
5836 int sr, sw;
5837 unsigned rn, wn; /* read new, write new */
5838
5839 /* private data */
5840 static struct pollfd *poll_events = NULL;
5841
5842 if (action == POLL_LOOP_ACTION_INIT) {
5843 poll_events = (struct pollfd*)
5844 calloc(1, sizeof(struct pollfd) * global.maxsock);
5845 return 1;
5846 }
5847 else if (action == POLL_LOOP_ACTION_CLEAN) {
5848 if (poll_events)
5849 free(poll_events);
5850 return 1;
5851 }
5852
5853 /* OK, it's POLL_LOOP_ACTION_RUN */
5854
5855 tv_now(&now);
5856
5857 while (1) {
5858 next_time = process_runnable_tasks();
5859
5860 /* stop when there's no connection left and we don't allow them anymore */
5861 if (!actconn && listeners == 0)
5862 break;
5863
5864#if STATTIME > 0
5865 {
5866 int time2;
5867 time2 = stats();
5868 next_time = MINTIME(time2, next_time);
5869 }
5870#endif
5871
5872
5873 nbfd = 0;
5874 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5875
5876 rn = ((int*)StaticReadEvent)[fds];
5877 wn = ((int*)StaticWriteEvent)[fds];
5878
5879 if ((rn|wn)) {
5880 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5881#define FDSETS_ARE_INT_ALIGNED
5882#ifdef FDSETS_ARE_INT_ALIGNED
5883
5884#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5885#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5886 sr = (rn >> count) & 1;
5887 sw = (wn >> count) & 1;
5888#else
5889 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5890 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5891#endif
5892#else
5893 sr = FD_ISSET(fd, StaticReadEvent);
5894 sw = FD_ISSET(fd, StaticWriteEvent);
5895#endif
5896 if ((sr|sw)) {
5897 poll_events[nbfd].fd = fd;
5898 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5899 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005900 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005901 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005902 }
5903 }
5904
5905 /* now let's wait for events */
5906 status = poll(poll_events, nbfd, next_time);
5907 tv_now(&now);
5908
5909 for (count = 0; status > 0 && count < nbfd; count++) {
5910 fd = poll_events[count].fd;
5911
5912 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5913 continue;
5914
5915 /* ok, we found one active fd */
5916 status--;
5917
willy tarreau05be12b2006-03-19 19:35:00 +01005918 if (FD_ISSET(fd, StaticReadEvent)) {
5919 if (fdtab[fd].state == FD_STCLOSE)
5920 continue;
5921 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5922 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005923 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005924
willy tarreau05be12b2006-03-19 19:35:00 +01005925 if (FD_ISSET(fd, StaticWriteEvent)) {
5926 if (fdtab[fd].state == FD_STCLOSE)
5927 continue;
5928 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5929 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005930 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005931 }
5932 }
5933 return 1;
5934}
willy tarreauad90a0c2005-12-18 01:09:15 +01005935#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005936
willy tarreauad90a0c2005-12-18 01:09:15 +01005937
willy tarreauad90a0c2005-12-18 01:09:15 +01005938
willy tarreau1c2ad212005-12-18 01:11:29 +01005939/*
5940 * Main select() loop.
5941 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005942
willy tarreau1c2ad212005-12-18 01:11:29 +01005943/* does 3 actions :
5944 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5945 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5946 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5947 *
5948 * returns 0 if initialization failed, !0 otherwise.
5949 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005950
willy tarreauad90a0c2005-12-18 01:09:15 +01005951
willy tarreau1c2ad212005-12-18 01:11:29 +01005952int select_loop(int action) {
5953 int next_time;
5954 int status;
5955 int fd,i;
5956 struct timeval delta;
5957 int readnotnull, writenotnull;
5958 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005959
willy tarreau1c2ad212005-12-18 01:11:29 +01005960 if (action == POLL_LOOP_ACTION_INIT) {
5961 ReadEvent = (fd_set *)
5962 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5963 WriteEvent = (fd_set *)
5964 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5965 return 1;
5966 }
5967 else if (action == POLL_LOOP_ACTION_CLEAN) {
5968 if (WriteEvent) free(WriteEvent);
5969 if (ReadEvent) free(ReadEvent);
5970 return 1;
5971 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005972
willy tarreau1c2ad212005-12-18 01:11:29 +01005973 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005974
willy tarreau1c2ad212005-12-18 01:11:29 +01005975 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005976
willy tarreau1c2ad212005-12-18 01:11:29 +01005977 while (1) {
5978 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005979
willy tarreau1c2ad212005-12-18 01:11:29 +01005980 /* stop when there's no connection left and we don't allow them anymore */
5981 if (!actconn && listeners == 0)
5982 break;
5983
5984#if STATTIME > 0
5985 {
5986 int time2;
5987 time2 = stats();
5988 next_time = MINTIME(time2, next_time);
5989 }
5990#endif
5991
willy tarreau1c2ad212005-12-18 01:11:29 +01005992 if (next_time > 0) { /* FIXME */
5993 /* Convert to timeval */
5994 /* to avoid eventual select loops due to timer precision */
5995 next_time += SCHEDULER_RESOLUTION;
5996 delta.tv_sec = next_time / 1000;
5997 delta.tv_usec = (next_time % 1000) * 1000;
5998 }
5999 else if (next_time == 0) { /* allow select to return immediately when needed */
6000 delta.tv_sec = delta.tv_usec = 0;
6001 }
6002
6003
6004 /* let's restore fdset state */
6005
6006 readnotnull = 0; writenotnull = 0;
6007 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
6008 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
6009 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
6010 }
6011
6012 // /* just a verification code, needs to be removed for performance */
6013 // for (i=0; i<maxfd; i++) {
6014 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
6015 // abort();
6016 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
6017 // abort();
6018 //
6019 // }
6020
6021 status = select(maxfd,
6022 readnotnull ? ReadEvent : NULL,
6023 writenotnull ? WriteEvent : NULL,
6024 NULL,
6025 (next_time >= 0) ? &delta : NULL);
6026
6027 /* this is an experiment on the separation of the select work */
6028 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6029 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
6030
6031 tv_now(&now);
6032
6033 if (status > 0) { /* must proceed with events */
6034
6035 int fds;
6036 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006037
willy tarreau1c2ad212005-12-18 01:11:29 +01006038 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6039 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6040 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6041
6042 /* if we specify read first, the accepts and zero reads will be
6043 * seen first. Moreover, system buffers will be flushed faster.
6044 */
willy tarreau05be12b2006-03-19 19:35:00 +01006045 if (FD_ISSET(fd, ReadEvent)) {
6046 if (fdtab[fd].state == FD_STCLOSE)
6047 continue;
6048 fdtab[fd].read(fd);
6049 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006050
willy tarreau05be12b2006-03-19 19:35:00 +01006051 if (FD_ISSET(fd, WriteEvent)) {
6052 if (fdtab[fd].state == FD_STCLOSE)
6053 continue;
6054 fdtab[fd].write(fd);
6055 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006056 }
6057 }
6058 else {
6059 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006060 }
willy tarreau0f7af912005-12-17 12:21:26 +01006061 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006062 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006063}
6064
6065
6066#if STATTIME > 0
6067/*
6068 * Display proxy statistics regularly. It is designed to be called from the
6069 * select_loop().
6070 */
6071int stats(void) {
6072 static int lines;
6073 static struct timeval nextevt;
6074 static struct timeval lastevt;
6075 static struct timeval starttime = {0,0};
6076 unsigned long totaltime, deltatime;
6077 int ret;
6078
willy tarreau750a4722005-12-17 13:21:24 +01006079 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006080 deltatime = (tv_diff(&lastevt, &now)?:1);
6081 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006082
willy tarreau9fe663a2005-12-17 13:02:59 +01006083 if (global.mode & MODE_STATS) {
6084 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006085 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006086 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6087 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006088 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006089 actconn, totalconn,
6090 stats_tsk_new, stats_tsk_good,
6091 stats_tsk_left, stats_tsk_right,
6092 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6093 }
6094 }
6095
6096 tv_delayfrom(&nextevt, &now, STATTIME);
6097
6098 lastevt=now;
6099 }
6100 ret = tv_remain(&now, &nextevt);
6101 return ret;
6102}
6103#endif
6104
6105
6106/*
6107 * this function enables proxies when there are enough free sessions,
6108 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006109 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006110 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006111 */
6112static int maintain_proxies(void) {
6113 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006114 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006115 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006116
6117 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006118 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006119
6120 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006121 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006122 while (p) {
6123 if (p->nbconn < p->maxconn) {
6124 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006125 for (l = p->listen; l != NULL; l = l->next) {
6126 FD_SET(l->fd, StaticReadEvent);
6127 }
willy tarreau0f7af912005-12-17 12:21:26 +01006128 p->state = PR_STRUN;
6129 }
6130 }
6131 else {
6132 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006133 for (l = p->listen; l != NULL; l = l->next) {
6134 FD_CLR(l->fd, StaticReadEvent);
6135 }
willy tarreau0f7af912005-12-17 12:21:26 +01006136 p->state = PR_STIDLE;
6137 }
6138 }
6139 p = p->next;
6140 }
6141 }
6142 else { /* block all proxies */
6143 while (p) {
6144 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006145 for (l = p->listen; l != NULL; l = l->next) {
6146 FD_CLR(l->fd, StaticReadEvent);
6147 }
willy tarreau0f7af912005-12-17 12:21:26 +01006148 p->state = PR_STIDLE;
6149 }
6150 p = p->next;
6151 }
6152 }
6153
willy tarreau5cbea6f2005-12-17 12:48:26 +01006154 if (stopping) {
6155 p = proxy;
6156 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006157 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006158 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006159 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006160 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006161 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006162 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006163
willy tarreaua41a8b42005-12-17 14:02:24 +01006164 for (l = p->listen; l != NULL; l = l->next) {
6165 fd_delete(l->fd);
6166 listeners--;
6167 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006168 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006169 }
6170 else {
6171 tleft = MINTIME(t, tleft);
6172 }
6173 }
6174 p = p->next;
6175 }
6176 }
6177 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006178}
6179
6180/*
6181 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006182 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6183 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006184 */
6185static void soft_stop(void) {
6186 struct proxy *p;
6187
6188 stopping = 1;
6189 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006190 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006191 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006192 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006193 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006194 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006195 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006196 }
willy tarreau0f7af912005-12-17 12:21:26 +01006197 p = p->next;
6198 }
6199}
6200
willy tarreaudbd3bef2006-01-20 19:35:18 +01006201static void pause_proxy(struct proxy *p) {
6202 struct listener *l;
6203 for (l = p->listen; l != NULL; l = l->next) {
6204 shutdown(l->fd, SHUT_RD);
6205 FD_CLR(l->fd, StaticReadEvent);
6206 p->state = PR_STPAUSED;
6207 }
6208}
6209
6210/*
6211 * This function temporarily disables listening so that another new instance
6212 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006213 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006214 * the proxy, or a SIGTTIN can be sent to listen again.
6215 */
6216static void pause_proxies(void) {
6217 struct proxy *p;
6218
6219 p = proxy;
6220 tv_now(&now); /* else, the old time before select will be used */
6221 while (p) {
6222 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6223 Warning("Pausing proxy %s.\n", p->id);
6224 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6225 pause_proxy(p);
6226 }
6227 p = p->next;
6228 }
6229}
6230
6231
6232/*
6233 * This function reactivates listening. This can be used after a call to
6234 * sig_pause(), for example when a new instance has failed starting up.
6235 * It is designed to be called upon reception of a SIGTTIN.
6236 */
6237static void listen_proxies(void) {
6238 struct proxy *p;
6239 struct listener *l;
6240
6241 p = proxy;
6242 tv_now(&now); /* else, the old time before select will be used */
6243 while (p) {
6244 if (p->state == PR_STPAUSED) {
6245 Warning("Enabling proxy %s.\n", p->id);
6246 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6247
6248 for (l = p->listen; l != NULL; l = l->next) {
6249 if (listen(l->fd, p->maxconn) == 0) {
6250 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6251 FD_SET(l->fd, StaticReadEvent);
6252 p->state = PR_STRUN;
6253 }
6254 else
6255 p->state = PR_STIDLE;
6256 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006257 int port;
6258
6259 if (l->addr.ss_family == AF_INET6)
6260 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6261 else
6262 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6263
willy tarreaudbd3bef2006-01-20 19:35:18 +01006264 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006265 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006266 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006267 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006268 /* Another port might have been enabled. Let's stop everything. */
6269 pause_proxy(p);
6270 break;
6271 }
6272 }
6273 }
6274 p = p->next;
6275 }
6276}
6277
6278
willy tarreau0f7af912005-12-17 12:21:26 +01006279/*
6280 * upon SIGUSR1, let's have a soft stop.
6281 */
6282void sig_soft_stop(int sig) {
6283 soft_stop();
6284 signal(sig, SIG_IGN);
6285}
6286
willy tarreaudbd3bef2006-01-20 19:35:18 +01006287/*
6288 * upon SIGTTOU, we pause everything
6289 */
6290void sig_pause(int sig) {
6291 pause_proxies();
6292 signal(sig, sig_pause);
6293}
willy tarreau0f7af912005-12-17 12:21:26 +01006294
willy tarreau8337c6b2005-12-17 13:41:01 +01006295/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006296 * upon SIGTTIN, let's have a soft stop.
6297 */
6298void sig_listen(int sig) {
6299 listen_proxies();
6300 signal(sig, sig_listen);
6301}
6302
6303/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006304 * this function dumps every server's state when the process receives SIGHUP.
6305 */
6306void sig_dump_state(int sig) {
6307 struct proxy *p = proxy;
6308
6309 Warning("SIGHUP received, dumping servers states.\n");
6310 while (p) {
6311 struct server *s = p->srv;
6312
6313 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6314 while (s) {
6315 if (s->state & SRV_RUNNING) {
willy tarreau14b4d432006-04-07 18:23:29 +02006316 snprintf(trash, sizeof(trash),
6317 "SIGHUP: Server %s/%s is UP. Conn: %d act, %d tot.",
6318 p->id, s->id, s->cur_sess, s->cum_sess);
6319 } else {
6320 snprintf(trash, sizeof(trash),
6321 "SIGHUP: Server %s/%s is DOWN. Conn: %d act, %d tot.",
6322 p->id, s->id, s->cur_sess, s->cum_sess);
willy tarreau8337c6b2005-12-17 13:41:01 +01006323 }
willy tarreau14b4d432006-04-07 18:23:29 +02006324 Warning("%s\n", trash);
6325 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006326 s = s->next;
6327 }
willy tarreaudd07e972005-12-18 00:48:48 +01006328
willy tarreau62084d42006-03-24 18:57:41 +01006329 if (p->srv_act == 0) {
6330 if (p->srv_bck) {
willy tarreau14b4d432006-04-07 18:23:29 +02006331 snprintf(trash, sizeof(trash),
6332 "SIGHUP: Proxy %s is running on backup servers ! Conn: %d act, %d tot.",
6333 p->id, p->nbconn, p->cum_conn);
6334 } else {
6335 snprintf(trash, sizeof(trash),
6336 "SIGHUP: Proxy %s has no server availble ! Conn: %d act, %d tot.",
6337 p->id, p->nbconn, p->cum_conn);
6338 }
6339 } else {
6340 snprintf(trash, sizeof(trash),
6341 "SIGHUP: Proxy %s has %d active servers and %d backup servers availble. Conn: %d act, %d tot.",
6342 p->id, p->srv_act, p->srv_bck, p->nbconn, p->cum_conn);
6343 }
6344 Warning("%s\n", trash);
6345 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006346
willy tarreau8337c6b2005-12-17 13:41:01 +01006347 p = p->next;
6348 }
6349 signal(sig, sig_dump_state);
6350}
6351
willy tarreau0f7af912005-12-17 12:21:26 +01006352void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006353 struct task *t, *tnext;
6354 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006355
willy tarreau5cbea6f2005-12-17 12:48:26 +01006356 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6357 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6358 tnext = t->next;
6359 s = t->context;
6360 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6361 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6362 "req=%d, rep=%d, clifd=%d\n",
6363 s, tv_remain(&now, &t->expire),
6364 s->cli_state,
6365 s->srv_state,
6366 FD_ISSET(s->cli_fd, StaticReadEvent),
6367 FD_ISSET(s->cli_fd, StaticWriteEvent),
6368 FD_ISSET(s->srv_fd, StaticReadEvent),
6369 FD_ISSET(s->srv_fd, StaticWriteEvent),
6370 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6371 );
willy tarreau0f7af912005-12-17 12:21:26 +01006372 }
willy tarreau12350152005-12-18 01:03:27 +01006373}
6374
willy tarreau64a3cc32005-12-18 01:13:11 +01006375#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006376static void fast_stop(void)
6377{
6378 struct proxy *p;
6379 p = proxy;
6380 while (p) {
6381 p->grace = 0;
6382 p = p->next;
6383 }
6384 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006385}
6386
willy tarreau12350152005-12-18 01:03:27 +01006387void sig_int(int sig) {
6388 /* This would normally be a hard stop,
6389 but we want to be sure about deallocation,
6390 and so on, so we do a soft stop with
6391 0 GRACE time
6392 */
6393 fast_stop();
6394 /* If we are killed twice, we decide to die*/
6395 signal(sig, SIG_DFL);
6396}
6397
6398void sig_term(int sig) {
6399 /* This would normally be a hard stop,
6400 but we want to be sure about deallocation,
6401 and so on, so we do a soft stop with
6402 0 GRACE time
6403 */
6404 fast_stop();
6405 /* If we are killed twice, we decide to die*/
6406 signal(sig, SIG_DFL);
6407}
willy tarreau64a3cc32005-12-18 01:13:11 +01006408#endif
willy tarreau12350152005-12-18 01:03:27 +01006409
willy tarreauc1f47532005-12-18 01:08:26 +01006410/* returns the pointer to an error in the replacement string, or NULL if OK */
6411char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006412 struct hdr_exp *exp;
6413
willy tarreauc1f47532005-12-18 01:08:26 +01006414 if (replace != NULL) {
6415 char *err;
6416 err = check_replace_string(replace);
6417 if (err)
6418 return err;
6419 }
6420
willy tarreaue39cd132005-12-17 13:00:18 +01006421 while (*head != NULL)
6422 head = &(*head)->next;
6423
6424 exp = calloc(1, sizeof(struct hdr_exp));
6425
6426 exp->preg = preg;
6427 exp->replace = replace;
6428 exp->action = action;
6429 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006430
6431 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006432}
6433
willy tarreau9fe663a2005-12-17 13:02:59 +01006434
willy tarreau0f7af912005-12-17 12:21:26 +01006435/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006436 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006437 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006438int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006439
willy tarreau9fe663a2005-12-17 13:02:59 +01006440 if (!strcmp(args[0], "global")) { /* new section */
6441 /* no option, nothing special to do */
6442 return 0;
6443 }
6444 else if (!strcmp(args[0], "daemon")) {
6445 global.mode |= MODE_DAEMON;
6446 }
6447 else if (!strcmp(args[0], "debug")) {
6448 global.mode |= MODE_DEBUG;
6449 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006450 else if (!strcmp(args[0], "noepoll")) {
6451 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6452 }
6453 else if (!strcmp(args[0], "nopoll")) {
6454 cfg_polling_mechanism &= ~POLL_USE_POLL;
6455 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006456 else if (!strcmp(args[0], "quiet")) {
6457 global.mode |= MODE_QUIET;
6458 }
6459 else if (!strcmp(args[0], "stats")) {
6460 global.mode |= MODE_STATS;
6461 }
6462 else if (!strcmp(args[0], "uid")) {
6463 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006464 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006465 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006467 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006468 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006469 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006470 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006471 global.uid = atol(args[1]);
6472 }
6473 else if (!strcmp(args[0], "gid")) {
6474 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006475 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006476 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006477 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006478 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006479 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006480 return -1;
6481 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006482 global.gid = atol(args[1]);
6483 }
6484 else if (!strcmp(args[0], "nbproc")) {
6485 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006486 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006487 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006489 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006490 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006491 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006492 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006493 global.nbproc = atol(args[1]);
6494 }
6495 else if (!strcmp(args[0], "maxconn")) {
6496 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006497 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006498 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006499 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006500 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006501 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006502 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006503 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006504 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006505#ifdef SYSTEM_MAXCONN
6506 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6507 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);
6508 global.maxconn = DEFAULT_MAXCONN;
6509 }
6510#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006511 }
willy tarreaub1285d52005-12-18 01:20:14 +01006512 else if (!strcmp(args[0], "ulimit-n")) {
6513 if (global.rlimit_nofile != 0) {
6514 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6515 return 0;
6516 }
6517 if (*(args[1]) == 0) {
6518 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6519 return -1;
6520 }
6521 global.rlimit_nofile = atol(args[1]);
6522 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006523 else if (!strcmp(args[0], "chroot")) {
6524 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006525 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006526 return 0;
6527 }
6528 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006529 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006530 return -1;
6531 }
6532 global.chroot = strdup(args[1]);
6533 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006534 else if (!strcmp(args[0], "pidfile")) {
6535 if (global.pidfile != NULL) {
6536 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6537 return 0;
6538 }
6539 if (*(args[1]) == 0) {
6540 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6541 return -1;
6542 }
6543 global.pidfile = strdup(args[1]);
6544 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006545 else if (!strcmp(args[0], "log")) { /* syslog server address */
6546 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006547 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006548
6549 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006550 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006551 return -1;
6552 }
6553
6554 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6555 if (!strcmp(log_facilities[facility], args[2]))
6556 break;
6557
6558 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006559 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006560 exit(1);
6561 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006562
6563 level = 7; /* max syslog level = debug */
6564 if (*(args[3])) {
6565 while (level >= 0 && strcmp(log_levels[level], args[3]))
6566 level--;
6567 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006568 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006569 exit(1);
6570 }
6571 }
6572
willy tarreau9fe663a2005-12-17 13:02:59 +01006573 sa = str2sa(args[1]);
6574 if (!sa->sin_port)
6575 sa->sin_port = htons(SYSLOG_PORT);
6576
6577 if (global.logfac1 == -1) {
6578 global.logsrv1 = *sa;
6579 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006580 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006581 }
6582 else if (global.logfac2 == -1) {
6583 global.logsrv2 = *sa;
6584 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006585 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006586 }
6587 else {
6588 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6589 return -1;
6590 }
6591
6592 }
6593 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006594 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006595 return -1;
6596 }
6597 return 0;
6598}
6599
6600
willy tarreaua41a8b42005-12-17 14:02:24 +01006601void init_default_instance() {
6602 memset(&defproxy, 0, sizeof(defproxy));
6603 defproxy.mode = PR_MODE_TCP;
6604 defproxy.state = PR_STNEW;
6605 defproxy.maxconn = cfg_maxpconn;
6606 defproxy.conn_retries = CONN_RETRIES;
6607 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6608}
6609
willy tarreau9fe663a2005-12-17 13:02:59 +01006610/*
6611 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6612 */
6613int cfg_parse_listen(char *file, int linenum, char **args) {
6614 static struct proxy *curproxy = NULL;
6615 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006616 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006617 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006618
6619 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006620 if (!*args[1]) {
6621 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6622 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006623 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 return -1;
6625 }
6626
6627 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006628 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 return -1;
6630 }
6631 curproxy->next = proxy;
6632 proxy = curproxy;
6633 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006634
6635 /* parse the listener address if any */
6636 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006637 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006638 if (!curproxy->listen)
6639 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006640 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006641 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006642
willy tarreau9fe663a2005-12-17 13:02:59 +01006643 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006644 curproxy->state = defproxy.state;
6645 curproxy->maxconn = defproxy.maxconn;
6646 curproxy->conn_retries = defproxy.conn_retries;
6647 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006648
6649 if (defproxy.check_req)
6650 curproxy->check_req = strdup(defproxy.check_req);
6651 curproxy->check_len = defproxy.check_len;
6652
6653 if (defproxy.cookie_name)
6654 curproxy->cookie_name = strdup(defproxy.cookie_name);
6655 curproxy->cookie_len = defproxy.cookie_len;
6656
6657 if (defproxy.capture_name)
6658 curproxy->capture_name = strdup(defproxy.capture_name);
6659 curproxy->capture_namelen = defproxy.capture_namelen;
6660 curproxy->capture_len = defproxy.capture_len;
6661
6662 if (defproxy.errmsg.msg400)
6663 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6664 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6665
6666 if (defproxy.errmsg.msg403)
6667 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6668 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6669
6670 if (defproxy.errmsg.msg408)
6671 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6672 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6673
6674 if (defproxy.errmsg.msg500)
6675 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6676 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6677
6678 if (defproxy.errmsg.msg502)
6679 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6680 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6681
6682 if (defproxy.errmsg.msg503)
6683 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6684 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6685
6686 if (defproxy.errmsg.msg504)
6687 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6688 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6689
willy tarreaua41a8b42005-12-17 14:02:24 +01006690 curproxy->clitimeout = defproxy.clitimeout;
6691 curproxy->contimeout = defproxy.contimeout;
6692 curproxy->srvtimeout = defproxy.srvtimeout;
6693 curproxy->mode = defproxy.mode;
6694 curproxy->logfac1 = defproxy.logfac1;
6695 curproxy->logsrv1 = defproxy.logsrv1;
6696 curproxy->loglev1 = defproxy.loglev1;
6697 curproxy->logfac2 = defproxy.logfac2;
6698 curproxy->logsrv2 = defproxy.logsrv2;
6699 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006700 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006701 curproxy->grace = defproxy.grace;
6702 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006703 curproxy->mon_net = defproxy.mon_net;
6704 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006705 return 0;
6706 }
6707 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006708 /* some variables may have already been initialized earlier */
6709 if (defproxy.check_req) free(defproxy.check_req);
6710 if (defproxy.cookie_name) free(defproxy.cookie_name);
6711 if (defproxy.capture_name) free(defproxy.capture_name);
6712 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6713 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6714 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6715 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6716 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6717 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6718 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6719
6720 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006721 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006722 return 0;
6723 }
6724 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006725 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006726 return -1;
6727 }
6728
willy tarreaua41a8b42005-12-17 14:02:24 +01006729 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6730 if (curproxy == &defproxy) {
6731 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6732 return -1;
6733 }
6734
6735 if (strchr(args[1], ':') == NULL) {
6736 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6737 file, linenum, args[0]);
6738 return -1;
6739 }
6740 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006741 if (!curproxy->listen)
6742 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006743 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006744 return 0;
6745 }
willy tarreaub1285d52005-12-18 01:20:14 +01006746 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6747 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6748 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6749 file, linenum, args[0]);
6750 return -1;
6751 }
6752 /* flush useless bits */
6753 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6754 return 0;
6755 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006756 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006757 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6758 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6759 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6760 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006761 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006762 return -1;
6763 }
6764 }
6765 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006766 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006767 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006768 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6769 curproxy->state = PR_STNEW;
6770 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006771 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6772 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006773// if (curproxy == &defproxy) {
6774// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6775// return -1;
6776// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006777
willy tarreau9fe663a2005-12-17 13:02:59 +01006778 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006779// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6780// file, linenum);
6781// return 0;
6782 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006783 }
6784
6785 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006786 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6787 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006788 return -1;
6789 }
6790 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006791 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006792
6793 cur_arg = 2;
6794 while (*(args[cur_arg])) {
6795 if (!strcmp(args[cur_arg], "rewrite")) {
6796 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006798 else if (!strcmp(args[cur_arg], "indirect")) {
6799 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006801 else if (!strcmp(args[cur_arg], "insert")) {
6802 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006803 }
willy tarreau240afa62005-12-17 13:14:35 +01006804 else if (!strcmp(args[cur_arg], "nocache")) {
6805 curproxy->options |= PR_O_COOK_NOC;
6806 }
willy tarreaucd878942005-12-17 13:27:43 +01006807 else if (!strcmp(args[cur_arg], "postonly")) {
6808 curproxy->options |= PR_O_COOK_POST;
6809 }
willy tarreau0174f312005-12-18 01:02:42 +01006810 else if (!strcmp(args[cur_arg], "prefix")) {
6811 curproxy->options |= PR_O_COOK_PFX;
6812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813 else {
willy tarreau0174f312005-12-18 01:02:42 +01006814 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006815 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006816 return -1;
6817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006818 cur_arg++;
6819 }
willy tarreau0174f312005-12-18 01:02:42 +01006820 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6821 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6822 file, linenum);
6823 return -1;
6824 }
6825
6826 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6827 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006828 file, linenum);
6829 return -1;
6830 }
willy tarreau12350152005-12-18 01:03:27 +01006831 }/* end else if (!strcmp(args[0], "cookie")) */
6832 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6833// if (curproxy == &defproxy) {
6834// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6835// return -1;
6836// }
6837
6838 if (curproxy->appsession_name != NULL) {
6839// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6840// file, linenum);
6841// return 0;
6842 free(curproxy->appsession_name);
6843 }
6844
6845 if (*(args[5]) == 0) {
6846 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6847 file, linenum, args[0]);
6848 return -1;
6849 }
6850 have_appsession = 1;
6851 curproxy->appsession_name = strdup(args[1]);
6852 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6853 curproxy->appsession_len = atoi(args[3]);
6854 curproxy->appsession_timeout = atoi(args[5]);
6855 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6856 if (rc) {
6857 Alert("Error Init Appsession Hashtable.\n");
6858 return -1;
6859 }
6860 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006861 else if (!strcmp(args[0], "capture")) {
6862 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6863 // if (curproxy == &defproxy) {
6864 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6865 // return -1;
6866 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006867
willy tarreau4302f492005-12-18 01:00:37 +01006868 if (curproxy->capture_name != NULL) {
6869 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6870 // file, linenum, args[0]);
6871 // return 0;
6872 free(curproxy->capture_name);
6873 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006874
willy tarreau4302f492005-12-18 01:00:37 +01006875 if (*(args[4]) == 0) {
6876 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6877 file, linenum, args[0]);
6878 return -1;
6879 }
6880 curproxy->capture_name = strdup(args[2]);
6881 curproxy->capture_namelen = strlen(curproxy->capture_name);
6882 curproxy->capture_len = atol(args[4]);
6883 if (curproxy->capture_len >= CAPTURE_LEN) {
6884 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6885 file, linenum, CAPTURE_LEN - 1);
6886 curproxy->capture_len = CAPTURE_LEN - 1;
6887 }
6888 curproxy->to_log |= LW_COOKIE;
6889 }
6890 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6891 struct cap_hdr *hdr;
6892
6893 if (curproxy == &defproxy) {
6894 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6895 return -1;
6896 }
6897
6898 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6899 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6900 file, linenum, args[0], args[1]);
6901 return -1;
6902 }
6903
6904 hdr = calloc(sizeof(struct cap_hdr), 1);
6905 hdr->next = curproxy->req_cap;
6906 hdr->name = strdup(args[3]);
6907 hdr->namelen = strlen(args[3]);
6908 hdr->len = atol(args[5]);
6909 hdr->index = curproxy->nb_req_cap++;
6910 curproxy->req_cap = hdr;
6911 curproxy->to_log |= LW_REQHDR;
6912 }
6913 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6914 struct cap_hdr *hdr;
6915
6916 if (curproxy == &defproxy) {
6917 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6918 return -1;
6919 }
6920
6921 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6922 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6923 file, linenum, args[0], args[1]);
6924 return -1;
6925 }
6926 hdr = calloc(sizeof(struct cap_hdr), 1);
6927 hdr->next = curproxy->rsp_cap;
6928 hdr->name = strdup(args[3]);
6929 hdr->namelen = strlen(args[3]);
6930 hdr->len = atol(args[5]);
6931 hdr->index = curproxy->nb_rsp_cap++;
6932 curproxy->rsp_cap = hdr;
6933 curproxy->to_log |= LW_RSPHDR;
6934 }
6935 else {
6936 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006937 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006938 return -1;
6939 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006942 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006943 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006944 return 0;
6945 }
6946 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006947 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6948 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006950 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 curproxy->contimeout = atol(args[1]);
6952 }
6953 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006954 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006955 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6956 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 return 0;
6958 }
6959 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006960 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6961 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006962 return -1;
6963 }
6964 curproxy->clitimeout = atol(args[1]);
6965 }
6966 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006967 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006968 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006969 return 0;
6970 }
6971 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006972 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6973 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006974 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006975 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006976 curproxy->srvtimeout = atol(args[1]);
6977 }
6978 else if (!strcmp(args[0], "retries")) { /* connection retries */
6979 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006980 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6981 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 return -1;
6983 }
6984 curproxy->conn_retries = atol(args[1]);
6985 }
6986 else if (!strcmp(args[0], "option")) {
6987 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006988 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006989 return -1;
6990 }
6991 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006992 /* enable reconnections to dispatch */
6993 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006994#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006995 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006996 /* enable transparent proxy connections */
6997 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006998#endif
6999 else if (!strcmp(args[1], "keepalive"))
7000 /* enable keep-alive */
7001 curproxy->options |= PR_O_KEEPALIVE;
7002 else if (!strcmp(args[1], "forwardfor"))
7003 /* insert x-forwarded-for field */
7004 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01007005 else if (!strcmp(args[1], "logasap"))
7006 /* log as soon as possible, without waiting for the session to complete */
7007 curproxy->options |= PR_O_LOGASAP;
7008 else if (!strcmp(args[1], "httpclose"))
7009 /* force connection: close in both directions in HTTP mode */
7010 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01007011 else if (!strcmp(args[1], "forceclose"))
7012 /* force connection: close in both directions in HTTP mode and enforce end of session */
7013 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01007014 else if (!strcmp(args[1], "checkcache"))
7015 /* require examination of cacheability of the 'set-cookie' field */
7016 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01007017 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01007018 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007019 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01007020 else if (!strcmp(args[1], "tcplog"))
7021 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01007022 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01007023 else if (!strcmp(args[1], "dontlognull")) {
7024 /* don't log empty requests */
7025 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007026 }
willy tarreaub952e1d2005-12-18 01:31:20 +01007027 else if (!strcmp(args[1], "tcpka")) {
7028 /* enable TCP keep-alives on client and server sessions */
7029 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
7030 }
7031 else if (!strcmp(args[1], "clitcpka")) {
7032 /* enable TCP keep-alives on client sessions */
7033 curproxy->options |= PR_O_TCP_CLI_KA;
7034 }
7035 else if (!strcmp(args[1], "srvtcpka")) {
7036 /* enable TCP keep-alives on server sessions */
7037 curproxy->options |= PR_O_TCP_SRV_KA;
7038 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007039 else if (!strcmp(args[1], "allbackups")) {
7040 /* Use all backup servers simultaneously */
7041 curproxy->options |= PR_O_USE_ALL_BK;
7042 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007043 else if (!strcmp(args[1], "httpchk")) {
7044 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007045 if (curproxy->check_req != NULL) {
7046 free(curproxy->check_req);
7047 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007048 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007049 if (!*args[2]) { /* no argument */
7050 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7051 curproxy->check_len = strlen(DEF_CHECK_REQ);
7052 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007053 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7054 curproxy->check_req = (char *)malloc(reqlen);
7055 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7056 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007057 } else { /* more arguments : METHOD URI [HTTP_VER] */
7058 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7059 if (*args[4])
7060 reqlen += strlen(args[4]);
7061 else
7062 reqlen += strlen("HTTP/1.0");
7063
7064 curproxy->check_req = (char *)malloc(reqlen);
7065 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7066 "%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 +01007067 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007068 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007069 else if (!strcmp(args[1], "persist")) {
7070 /* persist on using the server specified by the cookie, even when it's down */
7071 curproxy->options |= PR_O_PERSIST;
7072 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007073 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007074 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007075 return -1;
7076 }
7077 return 0;
7078 }
7079 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7080 /* enable reconnections to dispatch */
7081 curproxy->options |= PR_O_REDISP;
7082 }
willy tarreaua1598082005-12-17 13:08:06 +01007083#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007084 else if (!strcmp(args[0], "transparent")) {
7085 /* enable transparent proxy connections */
7086 curproxy->options |= PR_O_TRANSP;
7087 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007088#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007089 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7090 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007091 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007092 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 curproxy->maxconn = atol(args[1]);
7095 }
7096 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7097 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007098 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007100 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007101 curproxy->grace = atol(args[1]);
7102 }
7103 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007104 if (curproxy == &defproxy) {
7105 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7106 return -1;
7107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007108 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007109 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007110 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007111 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007112 curproxy->dispatch_addr = *str2sa(args[1]);
7113 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007114 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007115 if (*(args[1])) {
7116 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007117 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007119 else if (!strcmp(args[1], "source")) {
7120 curproxy->options |= PR_O_BALANCE_SH;
7121 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007122 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007123 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 return -1;
7125 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007126 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007127 else /* if no option is set, use round-robin by default */
7128 curproxy->options |= PR_O_BALANCE_RR;
7129 }
7130 else if (!strcmp(args[0], "server")) { /* server address */
7131 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007132 char *rport;
7133 char *raddr;
7134 short realport;
7135 int do_check;
7136
7137 if (curproxy == &defproxy) {
7138 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7139 return -1;
7140 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007141
willy tarreaua41a8b42005-12-17 14:02:24 +01007142 if (!*args[2]) {
7143 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007144 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007145 return -1;
7146 }
7147 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7148 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7149 return -1;
7150 }
willy tarreau0174f312005-12-18 01:02:42 +01007151
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007152 /* the servers are linked backwards first */
7153 newsrv->next = curproxy->srv;
7154 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007155 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007156
willy tarreau18a957c2006-04-12 19:26:23 +02007157 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007158 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007159 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007160 newsrv->id = strdup(args[1]);
7161
7162 /* several ways to check the port component :
7163 * - IP => port=+0, relative
7164 * - IP: => port=+0, relative
7165 * - IP:N => port=N, absolute
7166 * - IP:+N => port=+N, relative
7167 * - IP:-N => port=-N, relative
7168 */
7169 raddr = strdup(args[2]);
7170 rport = strchr(raddr, ':');
7171 if (rport) {
7172 *rport++ = 0;
7173 realport = atol(rport);
7174 if (!isdigit((int)*rport))
7175 newsrv->state |= SRV_MAPPORTS;
7176 } else {
7177 realport = 0;
7178 newsrv->state |= SRV_MAPPORTS;
7179 }
7180
7181 newsrv->addr = *str2sa(raddr);
7182 newsrv->addr.sin_port = htons(realport);
7183 free(raddr);
7184
willy tarreau9fe663a2005-12-17 13:02:59 +01007185 newsrv->curfd = -1; /* no health-check in progress */
7186 newsrv->inter = DEF_CHKINTR;
7187 newsrv->rise = DEF_RISETIME;
7188 newsrv->fall = DEF_FALLTIME;
7189 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7190 cur_arg = 3;
7191 while (*args[cur_arg]) {
7192 if (!strcmp(args[cur_arg], "cookie")) {
7193 newsrv->cookie = strdup(args[cur_arg + 1]);
7194 newsrv->cklen = strlen(args[cur_arg + 1]);
7195 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007196 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007197 else if (!strcmp(args[cur_arg], "rise")) {
7198 newsrv->rise = atol(args[cur_arg + 1]);
7199 newsrv->health = newsrv->rise;
7200 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007201 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007202 else if (!strcmp(args[cur_arg], "fall")) {
7203 newsrv->fall = atol(args[cur_arg + 1]);
7204 cur_arg += 2;
7205 }
7206 else if (!strcmp(args[cur_arg], "inter")) {
7207 newsrv->inter = atol(args[cur_arg + 1]);
7208 cur_arg += 2;
7209 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007210 else if (!strcmp(args[cur_arg], "port")) {
7211 newsrv->check_port = atol(args[cur_arg + 1]);
7212 cur_arg += 2;
7213 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007214 else if (!strcmp(args[cur_arg], "backup")) {
7215 newsrv->state |= SRV_BACKUP;
7216 cur_arg ++;
7217 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007218 else if (!strcmp(args[cur_arg], "weight")) {
7219 int w;
7220 w = atol(args[cur_arg + 1]);
7221 if (w < 1 || w > 256) {
7222 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7223 file, linenum, newsrv->id, w);
7224 return -1;
7225 }
7226 newsrv->uweight = w - 1;
7227 cur_arg += 2;
7228 }
willy tarreau18a957c2006-04-12 19:26:23 +02007229 else if (!strcmp(args[cur_arg], "maxconn")) {
7230 newsrv->maxconn = atol(args[cur_arg + 1]);
7231 cur_arg += 2;
7232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007233 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007234 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007235 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007236 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007237 }
willy tarreau0174f312005-12-18 01:02:42 +01007238 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7239 if (!*args[cur_arg + 1]) {
7240 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7241 file, linenum, "source");
7242 return -1;
7243 }
7244 newsrv->state |= SRV_BIND_SRC;
7245 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7246 cur_arg += 2;
7247 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007249 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 +01007250 file, linenum, newsrv->id);
7251 return -1;
7252 }
7253 }
7254
7255 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007256 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7257 newsrv->check_port = realport; /* by default */
7258 if (!newsrv->check_port) {
7259 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 +01007260 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007261 return -1;
7262 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007263 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007264 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007265
willy tarreau62084d42006-03-24 18:57:41 +01007266 if (newsrv->state & SRV_BACKUP)
7267 curproxy->srv_bck++;
7268 else
7269 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007270 }
7271 else if (!strcmp(args[0], "log")) { /* syslog server address */
7272 struct sockaddr_in *sa;
7273 int facility;
7274
7275 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7276 curproxy->logfac1 = global.logfac1;
7277 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007278 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007279 curproxy->logfac2 = global.logfac2;
7280 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007281 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007282 }
7283 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007284 int level;
7285
willy tarreau0f7af912005-12-17 12:21:26 +01007286 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7287 if (!strcmp(log_facilities[facility], args[2]))
7288 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007289
willy tarreau0f7af912005-12-17 12:21:26 +01007290 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007291 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007292 exit(1);
7293 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007294
willy tarreau8337c6b2005-12-17 13:41:01 +01007295 level = 7; /* max syslog level = debug */
7296 if (*(args[3])) {
7297 while (level >= 0 && strcmp(log_levels[level], args[3]))
7298 level--;
7299 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007300 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007301 exit(1);
7302 }
7303 }
7304
willy tarreau0f7af912005-12-17 12:21:26 +01007305 sa = str2sa(args[1]);
7306 if (!sa->sin_port)
7307 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007308
willy tarreau0f7af912005-12-17 12:21:26 +01007309 if (curproxy->logfac1 == -1) {
7310 curproxy->logsrv1 = *sa;
7311 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007312 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007313 }
7314 else if (curproxy->logfac2 == -1) {
7315 curproxy->logsrv2 = *sa;
7316 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007317 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007318 }
7319 else {
7320 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007321 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007322 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007323 }
7324 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007325 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007326 file, linenum);
7327 return -1;
7328 }
7329 }
willy tarreaua1598082005-12-17 13:08:06 +01007330 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007331 if (!*args[1]) {
7332 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007333 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007334 return -1;
7335 }
7336
7337 curproxy->source_addr = *str2sa(args[1]);
7338 curproxy->options |= PR_O_BIND_SRC;
7339 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007340 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7341 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007342 if (curproxy == &defproxy) {
7343 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7344 return -1;
7345 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007346
7347 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007348 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7349 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007350 return -1;
7351 }
7352
7353 preg = calloc(1, sizeof(regex_t));
7354 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007355 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007356 return -1;
7357 }
7358
willy tarreauc1f47532005-12-18 01:08:26 +01007359 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7360 if (err) {
7361 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7362 file, linenum, *err);
7363 return -1;
7364 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007365 }
7366 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7367 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007368 if (curproxy == &defproxy) {
7369 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7370 return -1;
7371 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007372
7373 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007374 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007375 return -1;
7376 }
7377
7378 preg = calloc(1, sizeof(regex_t));
7379 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007380 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007381 return -1;
7382 }
7383
7384 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7385 }
7386 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7387 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007388 if (curproxy == &defproxy) {
7389 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7390 return -1;
7391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007392
7393 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007394 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007395 return -1;
7396 }
7397
7398 preg = calloc(1, sizeof(regex_t));
7399 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007400 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007401 return -1;
7402 }
7403
7404 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7405 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007406 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7407 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007408 if (curproxy == &defproxy) {
7409 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7410 return -1;
7411 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007412
7413 if (*(args[1]) == 0) {
7414 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7415 return -1;
7416 }
7417
7418 preg = calloc(1, sizeof(regex_t));
7419 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7420 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7421 return -1;
7422 }
7423
7424 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7425 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007426 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7427 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007428 if (curproxy == &defproxy) {
7429 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7430 return -1;
7431 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007432
7433 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007434 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007435 return -1;
7436 }
7437
7438 preg = calloc(1, sizeof(regex_t));
7439 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007440 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007441 return -1;
7442 }
7443
7444 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7445 }
7446 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7447 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007448 if (curproxy == &defproxy) {
7449 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7450 return -1;
7451 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007452
7453 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007454 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7455 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007456 return -1;
7457 }
7458
7459 preg = calloc(1, sizeof(regex_t));
7460 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007461 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007462 return -1;
7463 }
7464
willy tarreauc1f47532005-12-18 01:08:26 +01007465 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7466 if (err) {
7467 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7468 file, linenum, *err);
7469 return -1;
7470 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007471 }
7472 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7473 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007474 if (curproxy == &defproxy) {
7475 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7476 return -1;
7477 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007478
7479 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007480 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007481 return -1;
7482 }
7483
7484 preg = calloc(1, sizeof(regex_t));
7485 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007486 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 return -1;
7488 }
7489
7490 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7491 }
7492 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7493 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007494 if (curproxy == &defproxy) {
7495 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7496 return -1;
7497 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007498
7499 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007500 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007501 return -1;
7502 }
7503
7504 preg = calloc(1, sizeof(regex_t));
7505 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007506 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007507 return -1;
7508 }
7509
7510 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7511 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007512 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7513 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007514 if (curproxy == &defproxy) {
7515 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7516 return -1;
7517 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007518
7519 if (*(args[1]) == 0) {
7520 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7521 return -1;
7522 }
7523
7524 preg = calloc(1, sizeof(regex_t));
7525 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7526 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7527 return -1;
7528 }
7529
7530 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7531 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007532 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7533 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007534 if (curproxy == &defproxy) {
7535 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7536 return -1;
7537 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007538
7539 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007540 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007541 return -1;
7542 }
7543
7544 preg = calloc(1, sizeof(regex_t));
7545 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007546 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007547 return -1;
7548 }
7549
7550 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7551 }
7552 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007553 if (curproxy == &defproxy) {
7554 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7555 return -1;
7556 }
7557
willy tarreau9fe663a2005-12-17 13:02:59 +01007558 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007559 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007560 return 0;
7561 }
7562
7563 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007564 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007565 return -1;
7566 }
7567
willy tarreau4302f492005-12-18 01:00:37 +01007568 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7569 }
7570 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7571 regex_t *preg;
7572
7573 if (*(args[1]) == 0 || *(args[2]) == 0) {
7574 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7575 file, linenum, args[0]);
7576 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007577 }
willy tarreau4302f492005-12-18 01:00:37 +01007578
7579 preg = calloc(1, sizeof(regex_t));
7580 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7581 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7582 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007583 }
willy tarreau4302f492005-12-18 01:00:37 +01007584
willy tarreauc1f47532005-12-18 01:08:26 +01007585 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7586 if (err) {
7587 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7588 file, linenum, *err);
7589 return -1;
7590 }
willy tarreau4302f492005-12-18 01:00:37 +01007591 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007592 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7593 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007594 if (curproxy == &defproxy) {
7595 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7596 return -1;
7597 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007598
7599 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007600 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007601 return -1;
7602 }
willy tarreaue39cd132005-12-17 13:00:18 +01007603
willy tarreau9fe663a2005-12-17 13:02:59 +01007604 preg = calloc(1, sizeof(regex_t));
7605 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007606 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007607 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007609
willy tarreauc1f47532005-12-18 01:08:26 +01007610 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7611 if (err) {
7612 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7613 file, linenum, *err);
7614 return -1;
7615 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007616 }
willy tarreau982249e2005-12-18 00:57:06 +01007617 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7618 regex_t *preg;
7619 if (curproxy == &defproxy) {
7620 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7621 return -1;
7622 }
7623
7624 if (*(args[1]) == 0) {
7625 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7626 return -1;
7627 }
7628
7629 preg = calloc(1, sizeof(regex_t));
7630 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7631 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7632 return -1;
7633 }
7634
willy tarreauc1f47532005-12-18 01:08:26 +01007635 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7636 if (err) {
7637 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7638 file, linenum, *err);
7639 return -1;
7640 }
willy tarreau982249e2005-12-18 00:57:06 +01007641 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007642 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007643 regex_t *preg;
7644 if (curproxy == &defproxy) {
7645 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7646 return -1;
7647 }
willy tarreaue39cd132005-12-17 13:00:18 +01007648
willy tarreaua41a8b42005-12-17 14:02:24 +01007649 if (*(args[1]) == 0 || *(args[2]) == 0) {
7650 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7651 file, linenum, args[0]);
7652 return -1;
7653 }
willy tarreaue39cd132005-12-17 13:00:18 +01007654
willy tarreaua41a8b42005-12-17 14:02:24 +01007655 preg = calloc(1, sizeof(regex_t));
7656 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7657 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7658 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007659 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007660
willy tarreauc1f47532005-12-18 01:08:26 +01007661 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7662 if (err) {
7663 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7664 file, linenum, *err);
7665 return -1;
7666 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007667 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007668 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7669 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007670 if (curproxy == &defproxy) {
7671 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7672 return -1;
7673 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007674
7675 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007676 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007677 return -1;
7678 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007679
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 preg = calloc(1, sizeof(regex_t));
7681 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007682 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007683 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007684 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007685
willy tarreauc1f47532005-12-18 01:08:26 +01007686 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7687 if (err) {
7688 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7689 file, linenum, *err);
7690 return -1;
7691 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007692 }
willy tarreau982249e2005-12-18 00:57:06 +01007693 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7694 regex_t *preg;
7695 if (curproxy == &defproxy) {
7696 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7697 return -1;
7698 }
7699
7700 if (*(args[1]) == 0) {
7701 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7702 return -1;
7703 }
7704
7705 preg = calloc(1, sizeof(regex_t));
7706 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7707 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7708 return -1;
7709 }
7710
willy tarreauc1f47532005-12-18 01:08:26 +01007711 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7712 if (err) {
7713 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7714 file, linenum, *err);
7715 return -1;
7716 }
willy tarreau982249e2005-12-18 00:57:06 +01007717 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007718 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007719 if (curproxy == &defproxy) {
7720 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7721 return -1;
7722 }
7723
willy tarreau9fe663a2005-12-17 13:02:59 +01007724 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007725 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007726 return 0;
7727 }
7728
7729 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007730 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007731 return -1;
7732 }
7733
7734 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7735 }
willy tarreauc1f47532005-12-18 01:08:26 +01007736 else if (!strcmp(args[0], "errorloc") ||
7737 !strcmp(args[0], "errorloc302") ||
7738 !strcmp(args[0], "errorloc303")) { /* error location */
7739 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007740 char *err;
7741
willy tarreaueedaa9f2005-12-17 14:08:03 +01007742 // if (curproxy == &defproxy) {
7743 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7744 // return -1;
7745 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007746
willy tarreau8337c6b2005-12-17 13:41:01 +01007747 if (*(args[2]) == 0) {
7748 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7749 return -1;
7750 }
7751
7752 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007753 if (!strcmp(args[0], "errorloc303")) {
7754 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7755 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7756 } else {
7757 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7758 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7759 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007760
7761 if (errnum == 400) {
7762 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007763 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007764 free(curproxy->errmsg.msg400);
7765 }
7766 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007767 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007768 }
7769 else if (errnum == 403) {
7770 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007771 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007772 free(curproxy->errmsg.msg403);
7773 }
7774 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007775 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007776 }
7777 else if (errnum == 408) {
7778 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007779 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007780 free(curproxy->errmsg.msg408);
7781 }
7782 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007783 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007784 }
7785 else if (errnum == 500) {
7786 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007787 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007788 free(curproxy->errmsg.msg500);
7789 }
7790 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007791 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007792 }
7793 else if (errnum == 502) {
7794 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007795 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007796 free(curproxy->errmsg.msg502);
7797 }
7798 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007799 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007800 }
7801 else if (errnum == 503) {
7802 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007803 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007804 free(curproxy->errmsg.msg503);
7805 }
7806 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007807 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007808 }
7809 else if (errnum == 504) {
7810 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007811 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007812 free(curproxy->errmsg.msg504);
7813 }
7814 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007815 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007816 }
7817 else {
7818 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7819 free(err);
7820 }
7821 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007822 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007823 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007824 return -1;
7825 }
7826 return 0;
7827}
willy tarreaue39cd132005-12-17 13:00:18 +01007828
willy tarreau5cbea6f2005-12-17 12:48:26 +01007829
willy tarreau9fe663a2005-12-17 13:02:59 +01007830/*
7831 * This function reads and parses the configuration file given in the argument.
7832 * returns 0 if OK, -1 if error.
7833 */
7834int readcfgfile(char *file) {
7835 char thisline[256];
7836 char *line;
7837 FILE *f;
7838 int linenum = 0;
7839 char *end;
7840 char *args[MAX_LINE_ARGS];
7841 int arg;
7842 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007843 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007844 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007845
willy tarreau9fe663a2005-12-17 13:02:59 +01007846 struct proxy *curproxy = NULL;
7847 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007848
willy tarreau9fe663a2005-12-17 13:02:59 +01007849 if ((f=fopen(file,"r")) == NULL)
7850 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007851
willy tarreaueedaa9f2005-12-17 14:08:03 +01007852 init_default_instance();
7853
willy tarreau9fe663a2005-12-17 13:02:59 +01007854 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7855 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007856
willy tarreau9fe663a2005-12-17 13:02:59 +01007857 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007858
willy tarreau9fe663a2005-12-17 13:02:59 +01007859 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007860 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 line++;
7862
7863 arg = 0;
7864 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007865
willy tarreau9fe663a2005-12-17 13:02:59 +01007866 while (*line && arg < MAX_LINE_ARGS) {
7867 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7868 * C equivalent value. Other combinations left unchanged (eg: \1).
7869 */
7870 if (*line == '\\') {
7871 int skip = 0;
7872 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7873 *line = line[1];
7874 skip = 1;
7875 }
7876 else if (line[1] == 'r') {
7877 *line = '\r';
7878 skip = 1;
7879 }
7880 else if (line[1] == 'n') {
7881 *line = '\n';
7882 skip = 1;
7883 }
7884 else if (line[1] == 't') {
7885 *line = '\t';
7886 skip = 1;
7887 }
willy tarreauc1f47532005-12-18 01:08:26 +01007888 else if (line[1] == 'x') {
7889 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7890 unsigned char hex1, hex2;
7891 hex1 = toupper(line[2]) - '0';
7892 hex2 = toupper(line[3]) - '0';
7893 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7894 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7895 *line = (hex1<<4) + hex2;
7896 skip = 3;
7897 }
7898 else {
7899 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7900 return -1;
7901 }
7902 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007903 if (skip) {
7904 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7905 end -= skip;
7906 }
7907 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007908 }
willy tarreaua1598082005-12-17 13:08:06 +01007909 else if (*line == '#' || *line == '\n' || *line == '\r') {
7910 /* end of string, end of loop */
7911 *line = 0;
7912 break;
7913 }
willy tarreauc29948c2005-12-17 13:10:27 +01007914 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007915 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007916 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007917 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007918 line++;
7919 args[++arg] = line;
7920 }
7921 else {
7922 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007923 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007924 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007925
willy tarreau9fe663a2005-12-17 13:02:59 +01007926 /* empty line */
7927 if (!**args)
7928 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007929
willy tarreau9fe663a2005-12-17 13:02:59 +01007930 /* zero out remaining args */
7931 while (++arg < MAX_LINE_ARGS) {
7932 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007933 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007934
willy tarreaua41a8b42005-12-17 14:02:24 +01007935 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007936 confsect = CFG_LISTEN;
7937 else if (!strcmp(args[0], "global")) /* global config */
7938 confsect = CFG_GLOBAL;
7939 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007940
willy tarreau9fe663a2005-12-17 13:02:59 +01007941 switch (confsect) {
7942 case CFG_LISTEN:
7943 if (cfg_parse_listen(file, linenum, args) < 0)
7944 return -1;
7945 break;
7946 case CFG_GLOBAL:
7947 if (cfg_parse_global(file, linenum, args) < 0)
7948 return -1;
7949 break;
7950 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007951 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007952 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007954
7955
willy tarreau0f7af912005-12-17 12:21:26 +01007956 }
7957 fclose(f);
7958
7959 /*
7960 * Now, check for the integrity of all that we have collected.
7961 */
7962
Willy TARREAU3759f982006-03-01 22:44:17 +01007963 /* will be needed further to delay some tasks */
7964 tv_now(&now);
7965
willy tarreau0f7af912005-12-17 12:21:26 +01007966 if ((curproxy = proxy) == NULL) {
7967 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7968 file);
7969 return -1;
7970 }
7971
7972 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007973 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007974 curproxy = curproxy->next;
7975 continue;
7976 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007977
7978 if (curproxy->listen == NULL) {
7979 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);
7980 cfgerr++;
7981 }
7982 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007983 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007984 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007985 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7986 file, curproxy->id);
7987 cfgerr++;
7988 }
7989 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7990 if (curproxy->options & PR_O_TRANSP) {
7991 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7992 file, curproxy->id);
7993 cfgerr++;
7994 }
7995 else if (curproxy->srv == NULL) {
7996 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7997 file, curproxy->id);
7998 cfgerr++;
7999 }
willy tarreaua1598082005-12-17 13:08:06 +01008000 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01008001 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
8002 file, curproxy->id);
8003 }
8004 }
8005 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01008006 if (curproxy->cookie_name != NULL) {
8007 Warning("parsing %s : cookie will be ignored for listener %s.\n",
8008 file, curproxy->id);
8009 }
8010 if ((newsrv = curproxy->srv) != NULL) {
8011 Warning("parsing %s : servers will be ignored for listener %s.\n",
8012 file, curproxy->id);
8013 }
willy tarreaue39cd132005-12-17 13:00:18 +01008014 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008015 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
8016 file, curproxy->id);
8017 }
willy tarreaue39cd132005-12-17 13:00:18 +01008018 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01008019 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
8020 file, curproxy->id);
8021 }
8022 }
8023 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
8024 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
8025 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
8026 file, curproxy->id);
8027 cfgerr++;
8028 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008029 }
willy tarreaue3f023f2006-04-08 21:52:24 +02008030
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008031 /* first, we will invert the servers list order */
8032 newsrv = NULL;
8033 while (curproxy->srv) {
8034 struct server *next;
8035
8036 next = curproxy->srv->next;
8037 curproxy->srv->next = newsrv;
8038 newsrv = curproxy->srv;
8039 if (!next)
8040 break;
8041 curproxy->srv = next;
8042 }
8043
8044 /* now, newsrv == curproxy->srv */
8045 if (newsrv) {
8046 struct server *srv;
8047 int pgcd;
8048 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008049
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008050 /* We will factor the weights to reduce the table,
8051 * using Euclide's largest common divisor algorithm
8052 */
8053 pgcd = newsrv->uweight + 1;
8054 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8055 int t, w;
8056
8057 w = srv->uweight + 1;
8058 while (w) {
8059 t = pgcd % w;
8060 pgcd = w;
8061 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008062 }
willy tarreau0f7af912005-12-17 12:21:26 +01008063 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008064
8065 act = bck = 0;
8066 for (srv = newsrv; srv; srv = srv->next) {
8067 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8068 if (srv->state & SRV_BACKUP)
8069 bck += srv->eweight + 1;
8070 else
8071 act += srv->eweight + 1;
8072 }
8073
8074 /* this is the largest map we will ever need for this servers list */
8075 if (act < bck)
8076 act = bck;
8077
8078 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8079 /* recounts servers and their weights */
8080 recount_servers(curproxy);
8081 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008082 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008083
8084 if (curproxy->options & PR_O_LOGASAP)
8085 curproxy->to_log &= ~LW_BYTES;
8086
willy tarreau8337c6b2005-12-17 13:41:01 +01008087 if (curproxy->errmsg.msg400 == NULL) {
8088 curproxy->errmsg.msg400 = (char *)HTTP_400;
8089 curproxy->errmsg.len400 = strlen(HTTP_400);
8090 }
8091 if (curproxy->errmsg.msg403 == NULL) {
8092 curproxy->errmsg.msg403 = (char *)HTTP_403;
8093 curproxy->errmsg.len403 = strlen(HTTP_403);
8094 }
8095 if (curproxy->errmsg.msg408 == NULL) {
8096 curproxy->errmsg.msg408 = (char *)HTTP_408;
8097 curproxy->errmsg.len408 = strlen(HTTP_408);
8098 }
8099 if (curproxy->errmsg.msg500 == NULL) {
8100 curproxy->errmsg.msg500 = (char *)HTTP_500;
8101 curproxy->errmsg.len500 = strlen(HTTP_500);
8102 }
8103 if (curproxy->errmsg.msg502 == NULL) {
8104 curproxy->errmsg.msg502 = (char *)HTTP_502;
8105 curproxy->errmsg.len502 = strlen(HTTP_502);
8106 }
8107 if (curproxy->errmsg.msg503 == NULL) {
8108 curproxy->errmsg.msg503 = (char *)HTTP_503;
8109 curproxy->errmsg.len503 = strlen(HTTP_503);
8110 }
8111 if (curproxy->errmsg.msg504 == NULL) {
8112 curproxy->errmsg.msg504 = (char *)HTTP_504;
8113 curproxy->errmsg.len504 = strlen(HTTP_504);
8114 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008115
8116 /* now we'll start this proxy's health checks if any */
8117 /* 1- count the checkers to run simultaneously */
8118 nbchk = 0;
8119 mininter = 0;
8120 newsrv = curproxy->srv;
8121 while (newsrv != NULL) {
8122 if (newsrv->state & SRV_CHECKED) {
8123 if (!mininter || mininter > newsrv->inter)
8124 mininter = newsrv->inter;
8125 nbchk++;
8126 }
8127 newsrv = newsrv->next;
8128 }
8129
8130 /* 2- start them as far as possible from each others while respecting
8131 * their own intervals. For this, we will start them after their own
8132 * interval added to the min interval divided by the number of servers,
8133 * weighted by the server's position in the list.
8134 */
8135 if (nbchk > 0) {
8136 struct task *t;
8137 int srvpos;
8138
8139 newsrv = curproxy->srv;
8140 srvpos = 0;
8141 while (newsrv != NULL) {
8142 /* should this server be checked ? */
8143 if (newsrv->state & SRV_CHECKED) {
8144 if ((t = pool_alloc(task)) == NULL) {
8145 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8146 return -1;
8147 }
8148
8149 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8150 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
8151 t->state = TASK_IDLE;
8152 t->process = process_chk;
8153 t->context = newsrv;
8154
8155 /* check this every ms */
8156 tv_delayfrom(&t->expire, &now,
8157 newsrv->inter + mininter * srvpos / nbchk);
8158 task_queue(t);
8159 //task_wakeup(&rq, t);
8160 srvpos++;
8161 }
8162 newsrv = newsrv->next;
8163 }
8164 }
8165
willy tarreau0f7af912005-12-17 12:21:26 +01008166 curproxy = curproxy->next;
8167 }
8168 if (cfgerr > 0) {
8169 Alert("Errors found in configuration file, aborting.\n");
8170 return -1;
8171 }
8172 else
8173 return 0;
8174}
8175
8176
8177/*
8178 * This function initializes all the necessary variables. It only returns
8179 * if everything is OK. If something fails, it exits.
8180 */
8181void init(int argc, char **argv) {
8182 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008183 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008184 char *old_argv = *argv;
8185 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008186 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008187
8188 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008189 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008190 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008191 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008192 exit(1);
8193 }
8194
willy tarreau746e26b2006-03-25 11:14:35 +01008195#ifdef HAPROXY_MEMMAX
8196 global.rlimit_memmax = HAPROXY_MEMMAX;
8197#endif
8198
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008199 /* initialize the libc's localtime structures once for all so that we
8200 * won't be missing memory if we want to send alerts under OOM conditions.
8201 */
8202 tv_now(&now);
8203 localtime(&now.tv_sec);
8204
willy tarreau4302f492005-12-18 01:00:37 +01008205 /* initialize the log header encoding map : '{|}"#' should be encoded with
8206 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8207 * URL encoding only requires '"', '#' to be encoded as well as non-
8208 * printable characters above.
8209 */
8210 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8211 memset(url_encode_map, 0, sizeof(url_encode_map));
8212 for (i = 0; i < 32; i++) {
8213 FD_SET(i, hdr_encode_map);
8214 FD_SET(i, url_encode_map);
8215 }
8216 for (i = 127; i < 256; i++) {
8217 FD_SET(i, hdr_encode_map);
8218 FD_SET(i, url_encode_map);
8219 }
8220
8221 tmp = "\"#{|}";
8222 while (*tmp) {
8223 FD_SET(*tmp, hdr_encode_map);
8224 tmp++;
8225 }
8226
8227 tmp = "\"#";
8228 while (*tmp) {
8229 FD_SET(*tmp, url_encode_map);
8230 tmp++;
8231 }
8232
willy tarreau64a3cc32005-12-18 01:13:11 +01008233 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8234#if defined(ENABLE_POLL)
8235 cfg_polling_mechanism |= POLL_USE_POLL;
8236#endif
8237#if defined(ENABLE_EPOLL)
8238 cfg_polling_mechanism |= POLL_USE_EPOLL;
8239#endif
8240
willy tarreau0f7af912005-12-17 12:21:26 +01008241 pid = getpid();
8242 progname = *argv;
8243 while ((tmp = strchr(progname, '/')) != NULL)
8244 progname = tmp + 1;
8245
8246 argc--; argv++;
8247 while (argc > 0) {
8248 char *flag;
8249
8250 if (**argv == '-') {
8251 flag = *argv+1;
8252
8253 /* 1 arg */
8254 if (*flag == 'v') {
8255 display_version();
8256 exit(0);
8257 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008258#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008259 else if (*flag == 'd' && flag[1] == 'e')
8260 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008261#endif
8262#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008263 else if (*flag == 'd' && flag[1] == 'p')
8264 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008265#endif
willy tarreau982249e2005-12-18 00:57:06 +01008266 else if (*flag == 'V')
8267 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008268 else if (*flag == 'd' && flag[1] == 'b')
8269 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008270 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008271 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008272 else if (*flag == 'c')
8273 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008274 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008275 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008276 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008277 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008278 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8279 /* list of pids to finish ('f') or terminate ('t') */
8280
8281 if (flag[1] == 'f')
8282 oldpids_sig = SIGUSR1; /* finish then exit */
8283 else
8284 oldpids_sig = SIGTERM; /* terminate immediately */
8285 argv++; argc--;
8286
8287 if (argc > 0) {
8288 oldpids = calloc(argc, sizeof(int));
8289 while (argc > 0) {
8290 oldpids[nb_oldpids] = atol(*argv);
8291 if (oldpids[nb_oldpids] <= 0)
8292 usage(old_argv);
8293 argc--; argv++;
8294 nb_oldpids++;
8295 }
8296 }
8297 }
willy tarreau2c513732006-04-15 19:25:16 +02008298#if STATTIME > 0
8299 else if (*flag == 's')
8300 arg_mode |= MODE_STATS;
8301 else if (*flag == 'l')
8302 arg_mode |= MODE_LOG;
8303#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008304 else { /* >=2 args */
8305 argv++; argc--;
8306 if (argc == 0)
8307 usage(old_argv);
8308
8309 switch (*flag) {
8310 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008311 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008312 case 'N' : cfg_maxpconn = atol(*argv); break;
8313 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008314 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008315 default: usage(old_argv);
8316 }
8317 }
8318 }
8319 else
8320 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008321 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008322 }
8323
willy tarreaud0fb4652005-12-18 01:32:04 +01008324 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008325 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8326 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008327
willy tarreau0f7af912005-12-17 12:21:26 +01008328 if (!cfg_cfgfile)
8329 usage(old_argv);
8330
8331 gethostname(hostname, MAX_HOSTNAME_LEN);
8332
willy tarreau12350152005-12-18 01:03:27 +01008333 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008334 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008335 if (readcfgfile(cfg_cfgfile) < 0) {
8336 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8337 exit(1);
8338 }
willy tarreau12350152005-12-18 01:03:27 +01008339 if (have_appsession)
8340 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008341
willy tarreau982249e2005-12-18 00:57:06 +01008342 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008343 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8344 exit(0);
8345 }
8346
willy tarreau9fe663a2005-12-17 13:02:59 +01008347 if (cfg_maxconn > 0)
8348 global.maxconn = cfg_maxconn;
8349
willy tarreaufe2c5c12005-12-17 14:14:34 +01008350 if (cfg_pidfile) {
8351 if (global.pidfile)
8352 free(global.pidfile);
8353 global.pidfile = strdup(cfg_pidfile);
8354 }
8355
willy tarreau9fe663a2005-12-17 13:02:59 +01008356 if (global.maxconn == 0)
8357 global.maxconn = DEFAULT_MAXCONN;
8358
Willy TARREAU203b0b62006-03-12 18:00:28 +01008359 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008360
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008361 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008362 /* command line debug mode inhibits configuration mode */
8363 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8364 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008365 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8366 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008367
8368 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8369 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8370 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8371 }
8372
8373 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008374 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8375 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008376 global.nbproc = 1;
8377 }
8378
8379 if (global.nbproc < 1)
8380 global.nbproc = 1;
8381
willy tarreau0f7af912005-12-17 12:21:26 +01008382 StaticReadEvent = (fd_set *)calloc(1,
8383 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008384 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008385 StaticWriteEvent = (fd_set *)calloc(1,
8386 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008387 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008388
8389 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008390 sizeof(struct fdtab) * (global.maxsock));
8391 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008392 fdtab[i].state = FD_STCLOSE;
8393 }
8394}
8395
8396/*
willy tarreau41310e72006-03-25 18:17:56 +01008397 * this function starts all the proxies. Its return value is composed from
8398 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8399 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008400 */
willy tarreau41310e72006-03-25 18:17:56 +01008401int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008402 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008403 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008404 int err = ERR_NONE;
8405 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008406
8407 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008408 if (curproxy->state != PR_STNEW)
8409 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008410
willy tarreau41310e72006-03-25 18:17:56 +01008411 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008412 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008413 if (listener->fd != -1)
8414 continue; /* already initialized */
8415
8416 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8417 if (verbose)
8418 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8419 curproxy->id);
8420 err |= ERR_RETRYABLE;
8421 pxerr |= 1;
8422 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008423 }
willy tarreau0f7af912005-12-17 12:21:26 +01008424
willy tarreaua41a8b42005-12-17 14:02:24 +01008425 if (fd >= global.maxsock) {
8426 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8427 curproxy->id);
8428 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008429 err |= ERR_FATAL;
8430 pxerr |= 1;
8431 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008432 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008433
willy tarreaua41a8b42005-12-17 14:02:24 +01008434 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8435 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8436 (char *) &one, sizeof(one)) == -1)) {
8437 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8438 curproxy->id);
8439 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008440 err |= ERR_FATAL;
8441 pxerr |= 1;
8442 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008443 }
willy tarreau0f7af912005-12-17 12:21:26 +01008444
willy tarreaua41a8b42005-12-17 14:02:24 +01008445 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8446 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8447 curproxy->id);
8448 }
willy tarreau0f7af912005-12-17 12:21:26 +01008449
willy tarreaua41a8b42005-12-17 14:02:24 +01008450 if (bind(fd,
8451 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008452 listener->addr.ss_family == AF_INET6 ?
8453 sizeof(struct sockaddr_in6) :
8454 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008455 if (verbose)
8456 Alert("cannot bind socket for proxy %s. Aborting.\n",
8457 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008458 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008459 err |= ERR_RETRYABLE;
8460 pxerr |= 1;
8461 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008462 }
willy tarreau0f7af912005-12-17 12:21:26 +01008463
willy tarreaua41a8b42005-12-17 14:02:24 +01008464 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008465 if (verbose)
8466 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8467 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008468 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008469 err |= ERR_RETRYABLE;
8470 pxerr |= 1;
8471 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008472 }
willy tarreau0f7af912005-12-17 12:21:26 +01008473
willy tarreau41310e72006-03-25 18:17:56 +01008474 /* the socket is ready */
8475 listener->fd = fd;
8476
willy tarreaua41a8b42005-12-17 14:02:24 +01008477 /* the function for the accept() event */
8478 fdtab[fd].read = &event_accept;
8479 fdtab[fd].write = NULL; /* never called */
8480 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008481 fdtab[fd].state = FD_STLISTEN;
8482 FD_SET(fd, StaticReadEvent);
8483 fd_insert(fd);
8484 listeners++;
8485 }
willy tarreau41310e72006-03-25 18:17:56 +01008486
8487 if (!pxerr) {
8488 curproxy->state = PR_STRUN;
8489 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8490 }
willy tarreau0f7af912005-12-17 12:21:26 +01008491 }
willy tarreau41310e72006-03-25 18:17:56 +01008492
8493 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008494}
8495
willy tarreaub952e1d2005-12-18 01:31:20 +01008496int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008497
8498 appsess *temp1,*temp2;
8499 temp1 = (appsess *)key1;
8500 temp2 = (appsess *)key2;
8501
8502 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8503 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8504
8505 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8506}/* end match_str */
8507
willy tarreaub952e1d2005-12-18 01:31:20 +01008508void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008509 appsess *temp1;
8510
8511 //printf("destroy called\n");
8512 temp1 = (appsess *)data;
8513
8514 if (temp1->sessid)
8515 pool_free_to(apools.sessid, temp1->sessid);
8516
8517 if (temp1->serverid)
8518 pool_free_to(apools.serverid, temp1->serverid);
8519
8520 pool_free(appsess, temp1);
8521} /* end destroy */
8522
8523void appsession_cleanup( void )
8524{
8525 struct proxy *p = proxy;
8526
8527 while(p) {
8528 chtbl_destroy(&(p->htbl_proxy));
8529 p = p->next;
8530 }
8531}/* end appsession_cleanup() */
8532
8533void pool_destroy(void **pool)
8534{
8535 void *temp, *next;
8536 next = pool;
8537 while (next) {
8538 temp = next;
8539 next = *(void **)temp;
8540 free(temp);
8541 }
8542}/* end pool_destroy() */
8543
willy tarreaub952e1d2005-12-18 01:31:20 +01008544void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008545 struct proxy *p = proxy;
8546 struct cap_hdr *h,*h_next;
8547 struct server *s,*s_next;
8548 struct listener *l,*l_next;
8549
8550 while (p) {
8551 if (p->id)
8552 free(p->id);
8553
8554 if (p->check_req)
8555 free(p->check_req);
8556
8557 if (p->cookie_name)
8558 free(p->cookie_name);
8559
8560 if (p->capture_name)
8561 free(p->capture_name);
8562
8563 /* only strup if the user have set in config.
8564 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008565 if (p->errmsg.msg400) free(p->errmsg.msg400);
8566 if (p->errmsg.msg403) free(p->errmsg.msg403);
8567 if (p->errmsg.msg408) free(p->errmsg.msg408);
8568 if (p->errmsg.msg500) free(p->errmsg.msg500);
8569 if (p->errmsg.msg502) free(p->errmsg.msg502);
8570 if (p->errmsg.msg503) free(p->errmsg.msg503);
8571 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008572 */
8573 if (p->appsession_name)
8574 free(p->appsession_name);
8575
8576 h = p->req_cap;
8577 while (h) {
8578 h_next = h->next;
8579 if (h->name)
8580 free(h->name);
8581 pool_destroy(h->pool);
8582 free(h);
8583 h = h_next;
8584 }/* end while(h) */
8585
8586 h = p->rsp_cap;
8587 while (h) {
8588 h_next = h->next;
8589 if (h->name)
8590 free(h->name);
8591
8592 pool_destroy(h->pool);
8593 free(h);
8594 h = h_next;
8595 }/* end while(h) */
8596
8597 s = p->srv;
8598 while (s) {
8599 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008600 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008601 free(s->id);
8602
willy tarreaub952e1d2005-12-18 01:31:20 +01008603 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008604 free(s->cookie);
8605
8606 free(s);
8607 s = s_next;
8608 }/* end while(s) */
8609
8610 l = p->listen;
8611 while (l) {
8612 l_next = l->next;
8613 free(l);
8614 l = l_next;
8615 }/* end while(l) */
8616
8617 pool_destroy((void **) p->req_cap_pool);
8618 pool_destroy((void **) p->rsp_cap_pool);
8619 p = p->next;
8620 }/* end while(p) */
8621
8622 if (global.chroot) free(global.chroot);
8623 if (global.pidfile) free(global.pidfile);
8624
willy tarreau12350152005-12-18 01:03:27 +01008625 if (StaticReadEvent) free(StaticReadEvent);
8626 if (StaticWriteEvent) free(StaticWriteEvent);
8627 if (fdtab) free(fdtab);
8628
8629 pool_destroy(pool_session);
8630 pool_destroy(pool_buffer);
8631 pool_destroy(pool_fdtab);
8632 pool_destroy(pool_requri);
8633 pool_destroy(pool_task);
8634 pool_destroy(pool_capture);
8635 pool_destroy(pool_appsess);
8636
8637 if (have_appsession) {
8638 pool_destroy(apools.serverid);
8639 pool_destroy(apools.sessid);
8640 }
8641} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008642
willy tarreau41310e72006-03-25 18:17:56 +01008643/* sends the signal <sig> to all pids found in <oldpids> */
8644static void tell_old_pids(int sig) {
8645 int p;
8646 for (p = 0; p < nb_oldpids; p++)
8647 kill(oldpids[p], sig);
8648}
8649
willy tarreau0f7af912005-12-17 12:21:26 +01008650int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008651 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008652 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008653 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008654 init(argc, argv);
8655
willy tarreau0f7af912005-12-17 12:21:26 +01008656 signal(SIGQUIT, dump);
8657 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008658 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008659#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008660 signal(SIGINT, sig_int);
8661 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008662#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008663
8664 /* on very high loads, a sigpipe sometimes happen just between the
8665 * getsockopt() which tells "it's OK to write", and the following write :-(
8666 */
willy tarreau3242e862005-12-17 12:27:53 +01008667#ifndef MSG_NOSIGNAL
8668 signal(SIGPIPE, SIG_IGN);
8669#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008670
willy tarreau41310e72006-03-25 18:17:56 +01008671 /* We will loop at most 100 times with 10 ms delay each time.
8672 * That's at most 1 second. We only send a signal to old pids
8673 * if we cannot grab at least one port.
8674 */
8675 retry = MAX_START_RETRIES;
8676 err = ERR_NONE;
8677 while (retry >= 0) {
8678 struct timeval w;
8679 err = start_proxies(retry == 0 || nb_oldpids == 0);
8680 if (err != ERR_RETRYABLE)
8681 break;
8682 if (nb_oldpids == 0)
8683 break;
8684
8685 tell_old_pids(SIGTTOU);
8686 /* give some time to old processes to stop listening */
8687 w.tv_sec = 0;
8688 w.tv_usec = 10*1000;
8689 select(0, NULL, NULL, NULL, &w);
8690 retry--;
8691 }
8692
8693 /* Note: start_proxies() sends an alert when it fails. */
8694 if (err != ERR_NONE) {
8695 if (retry != MAX_START_RETRIES && nb_oldpids)
8696 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008697 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008698 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008699
8700 if (listeners == 0) {
8701 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008702 /* Note: we don't have to send anything to the old pids because we
8703 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008704 exit(1);
8705 }
8706
willy tarreaudbd3bef2006-01-20 19:35:18 +01008707 /* prepare pause/play signals */
8708 signal(SIGTTOU, sig_pause);
8709 signal(SIGTTIN, sig_listen);
8710
Willy TARREAUe3283d12006-03-01 22:15:29 +01008711 if (global.mode & MODE_DAEMON) {
8712 global.mode &= ~MODE_VERBOSE;
8713 global.mode |= MODE_QUIET;
8714 }
8715
willy tarreaud0fb4652005-12-18 01:32:04 +01008716 /* MODE_QUIET can inhibit alerts and warnings below this line */
8717
8718 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008719 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008720 /* detach from the tty */
8721 fclose(stdin); fclose(stdout); fclose(stderr);
8722 close(0); close(1); close(2);
8723 }
willy tarreau0f7af912005-12-17 12:21:26 +01008724
willy tarreaufe2c5c12005-12-17 14:14:34 +01008725 /* open log & pid files before the chroot */
8726 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8727 int pidfd;
8728 unlink(global.pidfile);
8729 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8730 if (pidfd < 0) {
8731 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008732 if (nb_oldpids)
8733 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008734 exit(1);
8735 }
8736 pidfile = fdopen(pidfd, "w");
8737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008738
8739 /* chroot if needed */
8740 if (global.chroot != NULL) {
8741 if (chroot(global.chroot) == -1) {
8742 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008743 if (nb_oldpids)
8744 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008745 }
8746 chdir("/");
8747 }
8748
willy tarreaub1285d52005-12-18 01:20:14 +01008749 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008750 if (!global.rlimit_nofile)
8751 global.rlimit_nofile = global.maxsock;
8752
willy tarreaub1285d52005-12-18 01:20:14 +01008753 if (global.rlimit_nofile) {
8754 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8755 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8756 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8757 }
willy tarreau746e26b2006-03-25 11:14:35 +01008758 }
8759
8760 if (global.rlimit_memmax) {
8761 limit.rlim_cur = limit.rlim_max =
8762 global.rlimit_memmax * 1048576 / global.nbproc;
8763#ifdef RLIMIT_AS
8764 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8765 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8766 argv[0], global.rlimit_memmax);
8767 }
8768#else
8769 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8770 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8771 argv[0], global.rlimit_memmax);
8772 }
8773#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008774 }
8775
willy tarreau41310e72006-03-25 18:17:56 +01008776 if (nb_oldpids)
8777 tell_old_pids(oldpids_sig);
8778
8779 /* Note that any error at this stage will be fatal because we will not
8780 * be able to restart the old pids.
8781 */
8782
willy tarreau9fe663a2005-12-17 13:02:59 +01008783 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008784 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008785 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8786 exit(1);
8787 }
8788
willy tarreau036e1ce2005-12-17 13:46:33 +01008789 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008790 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8791 exit(1);
8792 }
8793
willy tarreaub1285d52005-12-18 01:20:14 +01008794 /* check ulimits */
8795 limit.rlim_cur = limit.rlim_max = 0;
8796 getrlimit(RLIMIT_NOFILE, &limit);
8797 if (limit.rlim_cur < global.maxsock) {
8798 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",
8799 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8800 }
8801
willy tarreau9fe663a2005-12-17 13:02:59 +01008802 if (global.mode & MODE_DAEMON) {
8803 int ret = 0;
8804 int proc;
8805
8806 /* the father launches the required number of processes */
8807 for (proc = 0; proc < global.nbproc; proc++) {
8808 ret = fork();
8809 if (ret < 0) {
8810 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008811 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008812 exit(1); /* there has been an error */
8813 }
8814 else if (ret == 0) /* child breaks here */
8815 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008816 if (pidfile != NULL) {
8817 fprintf(pidfile, "%d\n", ret);
8818 fflush(pidfile);
8819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008820 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008821 /* close the pidfile both in children and father */
8822 if (pidfile != NULL)
8823 fclose(pidfile);
8824 free(global.pidfile);
8825
willy tarreau9fe663a2005-12-17 13:02:59 +01008826 if (proc == global.nbproc)
8827 exit(0); /* parent must leave */
8828
willy tarreau750a4722005-12-17 13:21:24 +01008829 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8830 * that we can detach from the TTY. We MUST NOT do it in other cases since
8831 * it would have already be done, and 0-2 would have been affected to listening
8832 * sockets
8833 */
8834 if (!(global.mode & MODE_QUIET)) {
8835 /* detach from the tty */
8836 fclose(stdin); fclose(stdout); fclose(stderr);
8837 close(0); close(1); close(2); /* close all fd's */
8838 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8839 }
willy tarreaua1598082005-12-17 13:08:06 +01008840 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008841 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008842 }
8843
willy tarreau1c2ad212005-12-18 01:11:29 +01008844#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008845 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008846 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8847 epoll_loop(POLL_LOOP_ACTION_RUN);
8848 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008849 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008850 }
8851 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008852 Warning("epoll() is not available. Using poll()/select() instead.\n");
8853 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008854 }
8855 }
8856#endif
8857
8858#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008859 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008860 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8861 poll_loop(POLL_LOOP_ACTION_RUN);
8862 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008863 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008864 }
8865 else {
8866 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008867 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008868 }
8869 }
8870#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008871 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008872 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8873 select_loop(POLL_LOOP_ACTION_RUN);
8874 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008875 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008876 }
8877 }
8878
willy tarreau0f7af912005-12-17 12:21:26 +01008879
willy tarreau12350152005-12-18 01:03:27 +01008880 /* Free all Hash Keys and all Hash elements */
8881 appsession_cleanup();
8882 /* Do some cleanup */
8883 deinit();
8884
willy tarreau0f7af912005-12-17 12:21:26 +01008885 exit(0);
8886}
willy tarreau12350152005-12-18 01:03:27 +01008887
8888#if defined(DEBUG_HASH)
8889static void print_table(const CHTbl *htbl) {
8890
8891 ListElmt *element;
8892 int i;
8893 appsess *asession;
8894
8895 /*****************************************************************************
8896 * *
8897 * Display the chained hash table. *
8898 * *
8899 *****************************************************************************/
8900
8901 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8902
8903 for (i = 0; i < TBLSIZ; i++) {
8904 fprintf(stdout, "Bucket[%03d]\n", i);
8905
8906 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8907 //fprintf(stdout, "%c", *(char *)list_data(element));
8908 asession = (appsess *)list_data(element);
8909 fprintf(stdout, "ELEM :%s:", asession->sessid);
8910 fprintf(stdout, " Server :%s: \n", asession->serverid);
8911 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8912 }
8913
8914 fprintf(stdout, "\n");
8915 }
8916 return;
8917} /* end print_table */
8918#endif
8919
8920static int appsession_init(void)
8921{
8922 static int initialized = 0;
8923 int idlen;
8924 struct server *s;
8925 struct proxy *p = proxy;
8926
8927 if (!initialized) {
8928 if (!appsession_task_init()) {
8929 apools.sessid = NULL;
8930 apools.serverid = NULL;
8931 apools.ser_waste = 0;
8932 apools.ser_use = 0;
8933 apools.ser_msize = sizeof(void *);
8934 apools.ses_waste = 0;
8935 apools.ses_use = 0;
8936 apools.ses_msize = sizeof(void *);
8937 while (p) {
8938 s = p->srv;
8939 if (apools.ses_msize < p->appsession_len)
8940 apools.ses_msize = p->appsession_len;
8941 while (s) {
8942 idlen = strlen(s->id);
8943 if (apools.ser_msize < idlen)
8944 apools.ser_msize = idlen;
8945 s = s->next;
8946 }
8947 p = p->next;
8948 }
8949 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8950 apools.ses_msize ++;
8951 }
8952 else {
8953 fprintf(stderr, "appsession_task_init failed\n");
8954 return -1;
8955 }
8956 initialized ++;
8957 }
8958 return 0;
8959}
8960
8961static int appsession_task_init(void)
8962{
8963 static int initialized = 0;
8964 struct task *t;
8965 if (!initialized) {
8966 if ((t = pool_alloc(task)) == NULL)
8967 return -1;
8968 t->next = t->prev = t->rqnext = NULL;
8969 t->wq = LIST_HEAD(wait_queue);
8970 t->state = TASK_IDLE;
8971 t->context = NULL;
8972 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8973 task_queue(t);
8974 t->process = appsession_refresh;
8975 initialized ++;
8976 }
8977 return 0;
8978}
8979
8980static int appsession_refresh(struct task *t) {
8981 struct proxy *p = proxy;
8982 CHTbl *htbl;
8983 ListElmt *element, *last;
8984 int i;
8985 appsess *asession;
8986 void *data;
8987
8988 while (p) {
8989 if (p->appsession_name != NULL) {
8990 htbl = &p->htbl_proxy;
8991 /* if we ever give up the use of TBLSIZ, we need to change this */
8992 for (i = 0; i < TBLSIZ; i++) {
8993 last = NULL;
8994 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8995 asession = (appsess *)list_data(element);
8996 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8997 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8998 int len;
8999 /*
9000 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
9001 */
9002 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
9003 asession->sessid, asession->serverid?asession->serverid:"(null)");
9004 write(1, trash, len);
9005 }
9006 /* delete the expired element from within the hash table */
9007 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
9008 && (htbl->table[i].destroy != NULL)) {
9009 htbl->table[i].destroy(data);
9010 }
9011 if (last == NULL) {/* patient lost his head, get a new one */
9012 element = list_head(&htbl->table[i]);
9013 if (element == NULL) break; /* no heads left, go to next patient */
9014 }
9015 else
9016 element = last;
9017 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
9018 else
9019 last = element;
9020 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
9021 }
9022 }
9023 p = p->next;
9024 }
9025 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
9026 return TBLCHKINT;
9027} /* end appsession_refresh */
9028
willy tarreau18a957c2006-04-12 19:26:23 +02009029
9030/*
9031 * Local variables:
9032 * c-indent-level: 4
9033 * c-basic-offset: 4
9034 * End:
9035 */