blob: d4953ac4f3480fa61f2ad7a345bc61884e3c6ae5 [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/*
1976 * This function tries to find a running server for the proxy <px> following
1977 * the round-robin method. Depending on the number of active/backup servers,
1978 * it will either look for active servers, or for backup servers.
1979 * If any server is found, it will be returned and px->srv_rr_idx will be updated
1980 * to point to the next server. If no valid server is found, NULL is returned.
1981 */
1982static inline struct server *get_server_rr(struct proxy *px) {
1983 if (px->srv_map_sz == 0)
1984 return NULL;
1985
1986 if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
1987 px->srv_rr_idx = 0;
1988 return px->srv_map[px->srv_rr_idx++];
willy tarreau8337c6b2005-12-17 13:41:01 +01001989}
1990
willy tarreau62084d42006-03-24 18:57:41 +01001991
1992/*
willy tarreau1a3442d2006-03-24 21:03:20 +01001993 * This function tries to find a running server for the proxy <px> following
1994 * the source hash method. Depending on the number of active/backup servers,
1995 * it will either look for active servers, or for backup servers.
1996 * If any server is found, it will be returned. If no valid server is found,
1997 * NULL is returned.
1998 */
1999static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002000 unsigned int h, l;
willy tarreau1a3442d2006-03-24 21:03:20 +01002001
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002002 if (px->srv_map_sz == 0)
2003 return NULL;
willy tarreau1a3442d2006-03-24 21:03:20 +01002004
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002005 l = h = 0;
2006 if (px->srv_act > 1) {
2007 while ((l + sizeof (int)) <= len) {
2008 h ^= ntohl(*(unsigned int *)(&addr[l]));
2009 l += sizeof (int);
willy tarreau1a3442d2006-03-24 21:03:20 +01002010 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002011 h %= px->srv_map_sz;
willy tarreau1a3442d2006-03-24 21:03:20 +01002012 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02002013 return px->srv_map[h];
willy tarreau1a3442d2006-03-24 21:03:20 +01002014}
2015
2016
2017/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01002019 * is set, or to the dispatch server if (s->direct) is 0.
2020 * It can return one of :
2021 * - SN_ERR_NONE if everything's OK
2022 * - SN_ERR_SRVTO if there are no more servers
2023 * - SN_ERR_SRVCL if the connection was refused by the server
2024 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
2025 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
2026 * - SN_ERR_INTERNAL for any other purely internal errors
2027 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01002028 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01002030 int fd;
2031
willy tarreau12350152005-12-18 01:03:27 +01002032#ifdef DEBUG_FULL
2033 fprintf(stderr,"connect_server : s=%p\n",s);
2034#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002035
willy tarreaue39cd132005-12-17 13:00:18 +01002036 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 s->srv_addr = s->srv->addr;
2038 }
2039 else if (s->proxy->options & PR_O_BALANCE) {
willy tarreau1a3442d2006-03-24 21:03:20 +01002040 /* Ensure that srv will not be NULL */
willy tarreau4c8c2b52006-03-24 19:36:41 +01002041 if (!s->proxy->srv_act && !s->proxy->srv_bck)
2042 return SN_ERR_SRVTO;
2043
willy tarreau5cbea6f2005-12-17 12:48:26 +01002044 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01002045 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002046
willy tarreau4c8c2b52006-03-24 19:36:41 +01002047 srv = get_server_rr(s->proxy);
willy tarreau8337c6b2005-12-17 13:41:01 +01002048 s->srv_addr = srv->addr;
2049 s->srv = srv;
willy tarreau0f7af912005-12-17 12:21:26 +01002050 }
willy tarreau1a3442d2006-03-24 21:03:20 +01002051 else if (s->proxy->options & PR_O_BALANCE_SH) {
2052 struct server *srv;
2053 int len;
2054
2055 if (s->cli_addr.ss_family == AF_INET)
2056 len = 4;
2057 else if (s->cli_addr.ss_family == AF_INET6)
2058 len = 16;
2059 else /* unknown IP family */
2060 return SN_ERR_INTERNAL;
2061
2062 srv = get_server_sh(s->proxy,
2063 (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2064 len);
2065 s->srv_addr = srv->addr;
2066 s->srv = srv;
2067 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002068 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01002069 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002070 }
willy tarreaua1598082005-12-17 13:08:06 +01002071 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002072 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01002073 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002074 }
2075 else if (s->proxy->options & PR_O_TRANSP) {
2076 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01002077 socklen_t salen = sizeof(s->srv_addr);
2078
willy tarreau5cbea6f2005-12-17 12:48:26 +01002079 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
2080 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002081 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002082 }
2083 }
willy tarreau0f7af912005-12-17 12:21:26 +01002084
willy tarreaua41a8b42005-12-17 14:02:24 +01002085 /* if this server remaps proxied ports, we'll use
2086 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01002087 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01002088 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002089 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01002090
willy tarreaub952e1d2005-12-18 01:31:20 +01002091 if (!(s->proxy->options & PR_O_TRANSP) ||
2092 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01002093 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
2094 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
2095 }
2096
willy tarreau0f7af912005-12-17 12:21:26 +01002097 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002098 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01002099
2100 if (errno == ENFILE)
2101 send_log(s->proxy, LOG_EMERG,
2102 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2103 s->proxy->id, maxfd);
2104 else if (errno == EMFILE)
2105 send_log(s->proxy, LOG_EMERG,
2106 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2107 s->proxy->id, maxfd);
2108 else if (errno == ENOBUFS || errno == ENOMEM)
2109 send_log(s->proxy, LOG_EMERG,
2110 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2111 s->proxy->id, maxfd);
2112 /* this is a resource error */
2113 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01002114 }
2115
willy tarreau9fe663a2005-12-17 13:02:59 +01002116 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01002117 /* do not log anything there, it's a normal condition when this option
2118 * is used to serialize connections to a server !
2119 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
2121 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002122 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 }
2124
willy tarreau0f7af912005-12-17 12:21:26 +01002125 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
2126 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002127 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01002128 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002129 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01002130 }
2131
willy tarreaub952e1d2005-12-18 01:31:20 +01002132 if (s->proxy->options & PR_O_TCP_SRV_KA)
2133 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2134
willy tarreau0174f312005-12-18 01:02:42 +01002135 /* allow specific binding :
2136 * - server-specific at first
2137 * - proxy-specific next
2138 */
2139 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
2140 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2141 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
2142 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
2143 s->proxy->id, s->srv->id);
2144 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002145 send_log(s->proxy, LOG_EMERG,
2146 "Cannot bind to source address before connect() for server %s/%s.\n",
2147 s->proxy->id, s->srv->id);
2148 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002149 }
2150 }
2151 else if (s->proxy->options & PR_O_BIND_SRC) {
2152 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
2153 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
2154 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
2155 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002156 send_log(s->proxy, LOG_EMERG,
2157 "Cannot bind to source address before connect() for server %s/%s.\n",
2158 s->proxy->id, s->srv->id);
2159 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01002160 }
willy tarreaua1598082005-12-17 13:08:06 +01002161 }
2162
willy tarreaub1285d52005-12-18 01:20:14 +01002163 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
2164 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
2165
2166 if (errno == EAGAIN || errno == EADDRINUSE) {
2167 char *msg;
2168 if (errno == EAGAIN) /* no free ports left, try again later */
2169 msg = "no free ports";
2170 else
2171 msg = "local address already in use";
2172
2173 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01002174 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002175 send_log(s->proxy, LOG_EMERG,
2176 "Connect() failed for server %s/%s: %s.\n",
2177 s->proxy->id, s->srv->id, msg);
2178 return SN_ERR_RESOURCE;
2179 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01002180 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01002181 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01002182 return SN_ERR_SRVTO;
2183 } else {
2184 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01002185 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01002186 close(fd);
2187 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01002188 }
2189 }
2190
willy tarreau5cbea6f2005-12-17 12:48:26 +01002191 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01002192 fdtab[fd].read = &event_srv_read;
2193 fdtab[fd].write = &event_srv_write;
2194 fdtab[fd].state = FD_STCONN; /* connection in progress */
2195
2196 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01002197#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2198 if (PrevReadEvent) {
2199 assert(!(FD_ISSET(fd, PrevReadEvent)));
2200 assert(!(FD_ISSET(fd, PrevWriteEvent)));
2201 }
2202#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002203
2204 fd_insert(fd);
willy tarreaua647c702006-04-15 22:45:52 +02002205 s->srv->cur_sess++;
willy tarreau0f7af912005-12-17 12:21:26 +01002206
2207 if (s->proxy->contimeout)
2208 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
2209 else
2210 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002211 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01002212}
2213
2214/*
2215 * this function is called on a read event from a client socket.
2216 * It returns 0.
2217 */
2218int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002219 struct task *t = fdtab[fd].owner;
2220 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002221 struct buffer *b = s->req;
2222 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002223
willy tarreau12350152005-12-18 01:03:27 +01002224#ifdef DEBUG_FULL
2225 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
2226#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002227
willy tarreau0f7af912005-12-17 12:21:26 +01002228 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002229#ifdef FILL_BUFFERS
2230 while (1)
2231#else
2232 do
2233#endif
2234 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002235 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2236 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002237 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002238 }
2239 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002240 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 }
2242 else {
2243 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002244 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2245 * since it means that the rewrite protection has been removed. This
2246 * implies that the if statement can be removed.
2247 */
2248 if (max > b->rlim - b->data)
2249 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002250 }
2251
2252 if (max == 0) { /* not anymore room to store data */
2253 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002254 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002255 }
2256
willy tarreau3242e862005-12-17 12:27:53 +01002257#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002258 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002259 int skerr;
2260 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002261
willy tarreau5cbea6f2005-12-17 12:48:26 +01002262 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2263 if (skerr)
2264 ret = -1;
2265 else
2266 ret = recv(fd, b->r, max, 0);
2267 }
willy tarreau3242e862005-12-17 12:27:53 +01002268#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002269 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002270#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002271 if (ret > 0) {
2272 b->r += ret;
2273 b->l += ret;
2274 s->res_cr = RES_DATA;
2275
2276 if (b->r == b->data + BUFSIZE) {
2277 b->r = b->data; /* wrap around the buffer */
2278 }
willy tarreaua1598082005-12-17 13:08:06 +01002279
2280 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002281 /* we hope to read more data or to get a close on next round */
2282 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002283 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002284 else if (ret == 0) {
2285 s->res_cr = RES_NULL;
2286 break;
2287 }
2288 else if (errno == EAGAIN) {/* ignore EAGAIN */
2289 break;
2290 }
2291 else {
2292 s->res_cr = RES_ERROR;
2293 fdtab[fd].state = FD_STERROR;
2294 break;
2295 }
2296 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002297#ifndef FILL_BUFFERS
2298 while (0);
2299#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002300 }
2301 else {
2302 s->res_cr = RES_ERROR;
2303 fdtab[fd].state = FD_STERROR;
2304 }
2305
willy tarreau5cbea6f2005-12-17 12:48:26 +01002306 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002307 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002308 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2309 else
2310 tv_eternity(&s->crexpire);
2311
2312 task_wakeup(&rq, t);
2313 }
willy tarreau0f7af912005-12-17 12:21:26 +01002314
willy tarreau0f7af912005-12-17 12:21:26 +01002315 return 0;
2316}
2317
2318
2319/*
2320 * this function is called on a read event from a server socket.
2321 * It returns 0.
2322 */
2323int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002324 struct task *t = fdtab[fd].owner;
2325 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002326 struct buffer *b = s->rep;
2327 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002328
willy tarreau12350152005-12-18 01:03:27 +01002329#ifdef DEBUG_FULL
2330 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2331#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002332
willy tarreau0f7af912005-12-17 12:21:26 +01002333 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002334#ifdef FILL_BUFFERS
2335 while (1)
2336#else
2337 do
2338#endif
2339 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002340 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2341 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002342 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002343 }
2344 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002345 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002346 }
2347 else {
2348 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002349 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2350 * since it means that the rewrite protection has been removed. This
2351 * implies that the if statement can be removed.
2352 */
2353 if (max > b->rlim - b->data)
2354 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002355 }
2356
2357 if (max == 0) { /* not anymore room to store data */
2358 FD_CLR(fd, StaticReadEvent);
2359 break;
2360 }
2361
willy tarreau3242e862005-12-17 12:27:53 +01002362#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002363 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002364 int skerr;
2365 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002366
willy tarreau5cbea6f2005-12-17 12:48:26 +01002367 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2368 if (skerr)
2369 ret = -1;
2370 else
2371 ret = recv(fd, b->r, max, 0);
2372 }
willy tarreau3242e862005-12-17 12:27:53 +01002373#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002374 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002375#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002376 if (ret > 0) {
2377 b->r += ret;
2378 b->l += ret;
2379 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002380
willy tarreau5cbea6f2005-12-17 12:48:26 +01002381 if (b->r == b->data + BUFSIZE) {
2382 b->r = b->data; /* wrap around the buffer */
2383 }
willy tarreaua1598082005-12-17 13:08:06 +01002384
2385 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002386 /* we hope to read more data or to get a close on next round */
2387 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002388 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002389 else if (ret == 0) {
2390 s->res_sr = RES_NULL;
2391 break;
2392 }
2393 else if (errno == EAGAIN) {/* ignore EAGAIN */
2394 break;
2395 }
2396 else {
2397 s->res_sr = RES_ERROR;
2398 fdtab[fd].state = FD_STERROR;
2399 break;
2400 }
2401 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002402#ifndef FILL_BUFFERS
2403 while (0);
2404#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002405 }
2406 else {
2407 s->res_sr = RES_ERROR;
2408 fdtab[fd].state = FD_STERROR;
2409 }
2410
willy tarreau5cbea6f2005-12-17 12:48:26 +01002411 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002412 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2414 else
2415 tv_eternity(&s->srexpire);
2416
2417 task_wakeup(&rq, t);
2418 }
willy tarreau0f7af912005-12-17 12:21:26 +01002419
willy tarreau0f7af912005-12-17 12:21:26 +01002420 return 0;
2421}
2422
2423/*
2424 * this function is called on a write event from a client socket.
2425 * It returns 0.
2426 */
2427int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002428 struct task *t = fdtab[fd].owner;
2429 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002430 struct buffer *b = s->rep;
2431 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002432
willy tarreau12350152005-12-18 01:03:27 +01002433#ifdef DEBUG_FULL
2434 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2435#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002436
2437 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002438 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002439 // max = BUFSIZE; BUG !!!!
2440 max = 0;
2441 }
2442 else if (b->r > b->w) {
2443 max = b->r - b->w;
2444 }
2445 else
2446 max = b->data + BUFSIZE - b->w;
2447
willy tarreau0f7af912005-12-17 12:21:26 +01002448 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002449 if (max == 0) {
2450 s->res_cw = RES_NULL;
2451 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002452 tv_eternity(&s->cwexpire);
2453 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002454 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002455 }
2456
willy tarreau3242e862005-12-17 12:27:53 +01002457#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002458 {
2459 int skerr;
2460 socklen_t lskerr = sizeof(skerr);
2461
2462 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2463 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002464 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002465 else
willy tarreau3242e862005-12-17 12:27:53 +01002466 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002467 }
willy tarreau3242e862005-12-17 12:27:53 +01002468#else
willy tarreau0f7af912005-12-17 12:21:26 +01002469 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002470#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002471
2472 if (ret > 0) {
2473 b->l -= ret;
2474 b->w += ret;
2475
2476 s->res_cw = RES_DATA;
2477
2478 if (b->w == b->data + BUFSIZE) {
2479 b->w = b->data; /* wrap around the buffer */
2480 }
2481 }
2482 else if (ret == 0) {
2483 /* nothing written, just make as if we were never called */
2484// s->res_cw = RES_NULL;
2485 return 0;
2486 }
2487 else if (errno == EAGAIN) /* ignore EAGAIN */
2488 return 0;
2489 else {
2490 s->res_cw = RES_ERROR;
2491 fdtab[fd].state = FD_STERROR;
2492 }
2493 }
2494 else {
2495 s->res_cw = RES_ERROR;
2496 fdtab[fd].state = FD_STERROR;
2497 }
2498
willy tarreaub1ff9db2005-12-17 13:51:03 +01002499 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002500 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002501 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2502 s->crexpire = s->cwexpire;
2503 }
willy tarreau0f7af912005-12-17 12:21:26 +01002504 else
2505 tv_eternity(&s->cwexpire);
2506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002508 return 0;
2509}
2510
2511
2512/*
2513 * this function is called on a write event from a server socket.
2514 * It returns 0.
2515 */
2516int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002517 struct task *t = fdtab[fd].owner;
2518 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002519 struct buffer *b = s->req;
2520 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002521
willy tarreau12350152005-12-18 01:03:27 +01002522#ifdef DEBUG_FULL
2523 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2524#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002525
2526 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002527 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002528 // max = BUFSIZE; BUG !!!!
2529 max = 0;
2530 }
2531 else if (b->r > b->w) {
2532 max = b->r - b->w;
2533 }
2534 else
2535 max = b->data + BUFSIZE - b->w;
2536
willy tarreau0f7af912005-12-17 12:21:26 +01002537 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002538 if (max == 0) {
2539 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002540 if (s->srv_state == SV_STCONN) {
2541 int skerr;
2542 socklen_t lskerr = sizeof(skerr);
2543 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2544 if (skerr) {
2545 s->res_sw = RES_ERROR;
2546 fdtab[fd].state = FD_STERROR;
2547 task_wakeup(&rq, t);
2548 tv_eternity(&s->swexpire);
2549 FD_CLR(fd, StaticWriteEvent);
2550 return 0;
2551 }
2552 }
2553
willy tarreau0f7af912005-12-17 12:21:26 +01002554 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002555 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002556 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002557 tv_eternity(&s->swexpire);
2558 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002559 return 0;
2560 }
2561
willy tarreau3242e862005-12-17 12:27:53 +01002562#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002563 {
2564 int skerr;
2565 socklen_t lskerr = sizeof(skerr);
2566 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2567 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002568 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002569 else
willy tarreau3242e862005-12-17 12:27:53 +01002570 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002571 }
willy tarreau3242e862005-12-17 12:27:53 +01002572#else
willy tarreau0f7af912005-12-17 12:21:26 +01002573 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002574#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002575 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002576 if (ret > 0) {
2577 b->l -= ret;
2578 b->w += ret;
2579
2580 s->res_sw = RES_DATA;
2581
2582 if (b->w == b->data + BUFSIZE) {
2583 b->w = b->data; /* wrap around the buffer */
2584 }
2585 }
2586 else if (ret == 0) {
2587 /* nothing written, just make as if we were never called */
2588 // s->res_sw = RES_NULL;
2589 return 0;
2590 }
2591 else if (errno == EAGAIN) /* ignore EAGAIN */
2592 return 0;
2593 else {
2594 s->res_sw = RES_ERROR;
2595 fdtab[fd].state = FD_STERROR;
2596 }
2597 }
2598 else {
2599 s->res_sw = RES_ERROR;
2600 fdtab[fd].state = FD_STERROR;
2601 }
2602
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002603 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2604 * otherwise it could loop indefinitely !
2605 */
2606 if (s->srv_state != SV_STCONN) {
2607 if (s->proxy->srvtimeout) {
2608 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2609 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2610 s->srexpire = s->swexpire;
2611 }
2612 else
2613 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002614 }
willy tarreau0f7af912005-12-17 12:21:26 +01002615
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002617 return 0;
2618}
2619
2620
2621/*
willy tarreaue39cd132005-12-17 13:00:18 +01002622 * returns a message to the client ; the connection is shut down for read,
2623 * and the request is cleared so that no server connection can be initiated.
2624 * The client must be in a valid state for this (HEADER, DATA ...).
2625 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002626 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002627 */
2628void client_retnclose(struct session *s, int len, const char *msg) {
2629 FD_CLR(s->cli_fd, StaticReadEvent);
2630 FD_SET(s->cli_fd, StaticWriteEvent);
2631 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002632 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002633 shutdown(s->cli_fd, SHUT_RD);
2634 s->cli_state = CL_STSHUTR;
2635 strcpy(s->rep->data, msg);
2636 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002637 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002638 s->rep->r += len;
2639 s->req->l = 0;
2640}
2641
2642
2643/*
2644 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002645 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002646 */
2647void client_return(struct session *s, int len, const char *msg) {
2648 strcpy(s->rep->data, msg);
2649 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002650 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002651 s->rep->r += len;
2652 s->req->l = 0;
2653}
2654
willy tarreau9fe663a2005-12-17 13:02:59 +01002655/*
2656 * send a log for the session when we have enough info about it
2657 */
2658void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002659 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002660 struct proxy *p = s->proxy;
2661 int log;
2662 char *uri;
2663 char *pxid;
2664 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002665 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002666
2667 /* This is a first attempt at a better logging system.
2668 * For now, we rely on send_log() to provide the date, although it obviously
2669 * is the date of the log and not of the request, and most fields are not
2670 * computed.
2671 */
2672
willy tarreaua1598082005-12-17 13:08:06 +01002673 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002674
willy tarreau8a86dbf2005-12-18 00:45:59 +01002675 if (s->cli_addr.ss_family == AF_INET)
2676 inet_ntop(AF_INET,
2677 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2678 pn, sizeof(pn));
2679 else
2680 inet_ntop(AF_INET6,
2681 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2682 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002683
willy tarreauc1cae632005-12-17 14:12:23 +01002684 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002685 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002686 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002687
willy tarreauc1cae632005-12-17 14:12:23 +01002688 tm = localtime(&s->logs.tv_accept.tv_sec);
2689 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002690 char tmpline[MAX_SYSLOG_LEN], *h;
2691 int hdr;
2692
2693 h = tmpline;
2694 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2695 *(h++) = ' ';
2696 *(h++) = '{';
2697 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2698 if (hdr)
2699 *(h++) = '|';
2700 if (s->req_cap[hdr] != NULL)
2701 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2702 }
2703 *(h++) = '}';
2704 }
2705
2706 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2707 *(h++) = ' ';
2708 *(h++) = '{';
2709 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2710 if (hdr)
2711 *(h++) = '|';
2712 if (s->rsp_cap[hdr] != NULL)
2713 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2714 }
2715 *(h++) = '}';
2716 }
2717
2718 if (h < tmpline + sizeof(tmpline) - 4) {
2719 *(h++) = ' ';
2720 *(h++) = '"';
2721 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2722 *(h++) = '"';
2723 }
2724 *h = '\0';
2725
willy tarreaua647c702006-04-15 22:45:52 +02002726 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 +01002727 pn,
2728 (s->cli_addr.ss_family == AF_INET) ?
2729 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2730 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002731 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2732 tm->tm_hour, tm->tm_min, tm->tm_sec,
2733 pxid, srv,
2734 s->logs.t_request,
2735 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2736 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002737 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2738 s->logs.status,
2739 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002740 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2741 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002742 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2743 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2744 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2745 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreaua647c702006-04-15 22:45:52 +02002746 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002747 }
2748 else {
willy tarreaua647c702006-04-15 22:45:52 +02002749 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 +01002750 pn,
2751 (s->cli_addr.ss_family == AF_INET) ?
2752 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2753 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002754 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2755 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002756 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002757 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002758 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2759 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002760 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002761 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
willy tarreaua647c702006-04-15 22:45:52 +02002762 s->srv ? s->srv->cur_sess : 0, p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002763 }
2764
2765 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002766}
2767
willy tarreaue39cd132005-12-17 13:00:18 +01002768
2769/*
willy tarreau0f7af912005-12-17 12:21:26 +01002770 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002771 * to an accept. It tries to accept as many connections as possible.
2772 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002773 */
2774int event_accept(int fd) {
2775 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002776 struct session *s;
2777 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002778 int cfd;
willy tarreauc2becdc2006-03-19 19:36:48 +01002779 int max_accept;
2780
2781 if (global.nbproc > 1)
2782 max_accept = 8; /* let other processes catch some connections too */
2783 else
2784 max_accept = -1;
willy tarreau0f7af912005-12-17 12:21:26 +01002785
willy tarreauc2becdc2006-03-19 19:36:48 +01002786 while (p->nbconn < p->maxconn && max_accept--) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002787 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002788 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002789
willy tarreaub1285d52005-12-18 01:20:14 +01002790 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2791 switch (errno) {
2792 case EAGAIN:
2793 case EINTR:
2794 case ECONNABORTED:
2795 return 0; /* nothing more to accept */
2796 case ENFILE:
2797 send_log(p, LOG_EMERG,
2798 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2799 p->id, maxfd);
2800 return 0;
2801 case EMFILE:
2802 send_log(p, LOG_EMERG,
2803 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2804 p->id, maxfd);
2805 return 0;
2806 case ENOBUFS:
2807 case ENOMEM:
2808 send_log(p, LOG_EMERG,
2809 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2810 p->id, maxfd);
2811 return 0;
2812 default:
2813 return 0;
2814 }
2815 }
willy tarreau0f7af912005-12-17 12:21:26 +01002816
willy tarreau5cbea6f2005-12-17 12:48:26 +01002817 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2818 Alert("out of memory in event_accept().\n");
2819 FD_CLR(fd, StaticReadEvent);
2820 p->state = PR_STIDLE;
2821 close(cfd);
2822 return 0;
2823 }
willy tarreau0f7af912005-12-17 12:21:26 +01002824
willy tarreaub1285d52005-12-18 01:20:14 +01002825 /* if this session comes from a known monitoring system, we want to ignore
2826 * it as soon as possible, which means closing it immediately for TCP.
2827 */
2828 s->flags = 0;
2829 if (addr.ss_family == AF_INET &&
2830 p->mon_mask.s_addr &&
2831 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2832 if (p->mode == PR_MODE_TCP) {
2833 close(cfd);
2834 pool_free(session, s);
2835 continue;
2836 }
2837 s->flags |= SN_MONITOR;
2838 }
2839
willy tarreau5cbea6f2005-12-17 12:48:26 +01002840 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2841 Alert("out of memory in event_accept().\n");
2842 FD_CLR(fd, StaticReadEvent);
2843 p->state = PR_STIDLE;
2844 close(cfd);
2845 pool_free(session, s);
2846 return 0;
2847 }
willy tarreau0f7af912005-12-17 12:21:26 +01002848
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002850 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002851 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2852 close(cfd);
2853 pool_free(task, t);
2854 pool_free(session, s);
2855 return 0;
2856 }
willy tarreau0f7af912005-12-17 12:21:26 +01002857
willy tarreau5cbea6f2005-12-17 12:48:26 +01002858 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2859 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2860 (char *) &one, sizeof(one)) == -1)) {
2861 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2862 close(cfd);
2863 pool_free(task, t);
2864 pool_free(session, s);
2865 return 0;
2866 }
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreaub952e1d2005-12-18 01:31:20 +01002868 if (p->options & PR_O_TCP_CLI_KA)
2869 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2870
willy tarreau9fe663a2005-12-17 13:02:59 +01002871 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2872 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2873 t->state = TASK_IDLE;
2874 t->process = process_session;
2875 t->context = s;
2876
2877 s->task = t;
2878 s->proxy = p;
2879 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2880 s->srv_state = SV_STIDLE;
2881 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002882
willy tarreau9fe663a2005-12-17 13:02:59 +01002883 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2884 s->cli_fd = cfd;
2885 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002886 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002887 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002888
willy tarreaub1285d52005-12-18 01:20:14 +01002889 if (s->flags & SN_MONITOR)
2890 s->logs.logwait = 0;
2891 else
2892 s->logs.logwait = p->to_log;
2893
willy tarreaua1598082005-12-17 13:08:06 +01002894 s->logs.tv_accept = now;
2895 s->logs.t_request = -1;
2896 s->logs.t_connect = -1;
2897 s->logs.t_data = -1;
2898 s->logs.t_close = 0;
2899 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002900 s->logs.cli_cookie = NULL;
2901 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002902 s->logs.status = -1;
2903 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002904
willy tarreau2f6ba652005-12-17 13:57:42 +01002905 s->uniq_id = totalconn;
willy tarreau14b4d432006-04-07 18:23:29 +02002906 p->cum_conn++;
willy tarreau2f6ba652005-12-17 13:57:42 +01002907
willy tarreau4302f492005-12-18 01:00:37 +01002908 if (p->nb_req_cap > 0) {
2909 if ((s->req_cap =
2910 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2911 == NULL) { /* no memory */
2912 close(cfd); /* nothing can be done for this fd without memory */
2913 pool_free(task, t);
2914 pool_free(session, s);
2915 return 0;
2916 }
2917 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2918 }
2919 else
2920 s->req_cap = NULL;
2921
2922 if (p->nb_rsp_cap > 0) {
2923 if ((s->rsp_cap =
2924 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2925 == NULL) { /* no memory */
2926 if (s->req_cap != NULL)
2927 pool_free_to(p->req_cap_pool, s->req_cap);
2928 close(cfd); /* nothing can be done for this fd without memory */
2929 pool_free(task, t);
2930 pool_free(session, s);
2931 return 0;
2932 }
2933 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2934 }
2935 else
2936 s->rsp_cap = NULL;
2937
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2939 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002940 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002941 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002942
willy tarreau8a86dbf2005-12-18 00:45:59 +01002943 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002944 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002945 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002946 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002947
willy tarreau9fe663a2005-12-17 13:02:59 +01002948 if (p->to_log) {
2949 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002950 if (s->logs.logwait & LW_CLIP)
2951 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002952 sess_log(s);
2953 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002954 else if (s->cli_addr.ss_family == AF_INET) {
2955 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2956 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2957 sn, sizeof(sn)) &&
2958 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2959 pn, sizeof(pn))) {
2960 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2961 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2962 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2963 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2964 }
2965 }
2966 else {
2967 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2968 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2969 sn, sizeof(sn)) &&
2970 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2971 pn, sizeof(pn))) {
2972 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2973 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2974 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2975 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2976 }
2977 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002978 }
willy tarreau0f7af912005-12-17 12:21:26 +01002979
willy tarreau982249e2005-12-18 00:57:06 +01002980 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002981 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002982 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002983 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002984 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002985 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002986 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002987 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002988
willy tarreau8a86dbf2005-12-18 00:45:59 +01002989 if (s->cli_addr.ss_family == AF_INET) {
2990 char pn[INET_ADDRSTRLEN];
2991 inet_ntop(AF_INET,
2992 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2993 pn, sizeof(pn));
2994
2995 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2996 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2997 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2998 }
2999 else {
3000 char pn[INET6_ADDRSTRLEN];
3001 inet_ntop(AF_INET6,
3002 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3003 pn, sizeof(pn));
3004
3005 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
3006 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
3007 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
3008 }
3009
willy tarreauef900ab2005-12-17 12:52:52 +01003010 write(1, trash, len);
3011 }
willy tarreau0f7af912005-12-17 12:21:26 +01003012
willy tarreau5cbea6f2005-12-17 12:48:26 +01003013 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01003014 if (s->rsp_cap != NULL)
3015 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3016 if (s->req_cap != NULL)
3017 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003018 close(cfd); /* nothing can be done for this fd without memory */
3019 pool_free(task, t);
3020 pool_free(session, s);
3021 return 0;
3022 }
willy tarreau4302f492005-12-18 01:00:37 +01003023
willy tarreau5cbea6f2005-12-17 12:48:26 +01003024 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003025 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003026 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
3027 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01003028 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01003029 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01003030
willy tarreau5cbea6f2005-12-17 12:48:26 +01003031 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
3032 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01003033 if (s->rsp_cap != NULL)
3034 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
3035 if (s->req_cap != NULL)
3036 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003037 close(cfd); /* nothing can be done for this fd without memory */
3038 pool_free(task, t);
3039 pool_free(session, s);
3040 return 0;
3041 }
3042 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01003043 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01003044 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 +01003045
willy tarreau5cbea6f2005-12-17 12:48:26 +01003046 fdtab[cfd].read = &event_cli_read;
3047 fdtab[cfd].write = &event_cli_write;
3048 fdtab[cfd].owner = t;
3049 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01003050
willy tarreaub1285d52005-12-18 01:20:14 +01003051 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
3052 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
3053 /* Either we got a request from a monitoring system on an HTTP instance,
3054 * or we're in health check mode with the 'httpchk' option enabled. In
3055 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
3056 */
3057 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
3058 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
3059 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003060 }
3061 else {
3062 FD_SET(cfd, StaticReadEvent);
3063 }
3064
willy tarreaub952e1d2005-12-18 01:31:20 +01003065#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
3066 if (PrevReadEvent) {
3067 assert(!(FD_ISSET(cfd, PrevReadEvent)));
3068 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
3069 }
3070#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071 fd_insert(cfd);
3072
3073 tv_eternity(&s->cnexpire);
3074 tv_eternity(&s->srexpire);
3075 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003076 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003077 tv_eternity(&s->cwexpire);
3078
willy tarreaub1285d52005-12-18 01:20:14 +01003079 if (s->proxy->clitimeout) {
3080 if (FD_ISSET(cfd, StaticReadEvent))
3081 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
3082 if (FD_ISSET(cfd, StaticWriteEvent))
3083 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
3084 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003085
willy tarreaub1285d52005-12-18 01:20:14 +01003086 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003087
3088 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01003089
3090 if (p->mode != PR_MODE_HEALTH)
3091 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003092
3093 p->nbconn++;
3094 actconn++;
3095 totalconn++;
3096
willy tarreaub952e1d2005-12-18 01:31:20 +01003097 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003098 } /* end of while (p->nbconn < p->maxconn) */
3099 return 0;
3100}
willy tarreau0f7af912005-12-17 12:21:26 +01003101
willy tarreau0f7af912005-12-17 12:21:26 +01003102
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103/*
3104 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003105 * the connection acknowledgement. If the proxy requires HTTP health-checks,
3106 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003107 * or -1 if an error occured.
3108 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003109int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003110 struct task *t = fdtab[fd].owner;
3111 struct server *s = t->context;
willy tarreauc5f73ed2005-12-18 01:26:38 +01003112 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01003113 socklen_t lskerr = sizeof(skerr);
3114
willy tarreau05be12b2006-03-19 19:35:00 +01003115 skerr = 1;
3116 if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1)
3117 || (skerr != 0)) {
3118 /* in case of TCP only, this tells us if the connection failed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003119 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003120 fdtab[fd].state = FD_STERROR;
3121 FD_CLR(fd, StaticWriteEvent);
3122 }
willy tarreaua4a583a2005-12-18 01:39:19 +01003123 else if (s->result != -1) {
3124 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003125 if (s->proxy->options & PR_O_HTTP_CHK) {
3126 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01003127 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003128 * so we'll send the request, and won't wake the checker up now.
3129 */
3130#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01003131 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003132#else
willy tarreau2f6ba652005-12-17 13:57:42 +01003133 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003134#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01003135 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003136 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
3137 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
3138 return 0;
3139 }
willy tarreau05be12b2006-03-19 19:35:00 +01003140 else {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003141 s->result = -1;
willy tarreau05be12b2006-03-19 19:35:00 +01003142 FD_CLR(fd, StaticWriteEvent);
3143 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003144 }
3145 else {
3146 /* good TCP connection is enough */
3147 s->result = 1;
3148 }
3149 }
3150
3151 task_wakeup(&rq, t);
3152 return 0;
3153}
3154
willy tarreau0f7af912005-12-17 12:21:26 +01003155
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003156/*
3157 * This function is used only for server health-checks. It handles
3158 * the server's reply to an HTTP request. It returns 1 if the server replies
3159 * 2xx or 3xx (valid responses), or -1 in other cases.
3160 */
3161int event_srv_chk_r(int fd) {
3162 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01003163 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003164 struct task *t = fdtab[fd].owner;
3165 struct server *s = t->context;
willy tarreau05be12b2006-03-19 19:35:00 +01003166 int skerr;
3167 socklen_t lskerr = sizeof(skerr);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003168
willy tarreaua4a583a2005-12-18 01:39:19 +01003169 result = len = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003170
willy tarreau05be12b2006-03-19 19:35:00 +01003171 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
3172 if (!skerr) {
3173#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01003174 len = recv(fd, reply, sizeof(reply), 0);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003175#else
willy tarreau05be12b2006-03-19 19:35:00 +01003176 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
3177 * but the connection was closed on the remote end. Fortunately, recv still
3178 * works correctly and we don't need to do the getsockopt() on linux.
3179 */
3180 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003181#endif
willy tarreau05be12b2006-03-19 19:35:00 +01003182
3183 if ((len >= sizeof("HTTP/1.0 000")) &&
3184 !memcmp(reply, "HTTP/1.", 7) &&
3185 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
3186 result = 1;
3187 }
3188
3189 if (result == -1)
3190 fdtab[fd].state = FD_STERROR;
willy tarreaua4a583a2005-12-18 01:39:19 +01003191
3192 if (s->result != -1)
3193 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01003194
3195 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003196 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01003197 return 0;
3198}
3199
3200
3201/*
3202 * this function writes the string <str> at position <pos> which must be in buffer <b>,
3203 * and moves <end> just after the end of <str>.
3204 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
3205 * the shift value (positive or negative) is returned.
3206 * If there's no space left, the move is not done.
3207 *
3208 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003209int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01003210 int delta;
3211 int len;
3212
3213 len = strlen(str);
3214 delta = len - (end - pos);
3215
3216 if (delta + b->r >= b->data + BUFSIZE)
3217 return 0; /* no space left */
3218
3219 /* first, protect the end of the buffer */
3220 memmove(end + delta, end, b->data + b->l - end);
3221
3222 /* now, copy str over pos */
3223 memcpy(pos, str,len);
3224
willy tarreau5cbea6f2005-12-17 12:48:26 +01003225 /* we only move data after the displaced zone */
3226 if (b->r > pos) b->r += delta;
3227 if (b->w > pos) b->w += delta;
3228 if (b->h > pos) b->h += delta;
3229 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003230 b->l += delta;
3231
3232 return delta;
3233}
3234
willy tarreau8337c6b2005-12-17 13:41:01 +01003235/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01003236 * len is 0.
3237 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003238int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01003239 int delta;
3240
3241 delta = len - (end - pos);
3242
3243 if (delta + b->r >= b->data + BUFSIZE)
3244 return 0; /* no space left */
3245
Willy TARREAUe78ae262006-01-08 01:24:12 +01003246 if (b->data + b->l < end)
3247 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
3248 return 0;
3249
willy tarreau0f7af912005-12-17 12:21:26 +01003250 /* first, protect the end of the buffer */
3251 memmove(end + delta, end, b->data + b->l - end);
3252
3253 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01003254 if (len)
3255 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01003256
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
3267
3268int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3269 char *old_dst = dst;
3270
3271 while (*str) {
3272 if (*str == '\\') {
3273 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003274 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003275 int len, num;
3276
3277 num = *str - '0';
3278 str++;
3279
willy tarreau8a86dbf2005-12-18 00:45:59 +01003280 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003281 len = matches[num].rm_eo - matches[num].rm_so;
3282 memcpy(dst, src + matches[num].rm_so, len);
3283 dst += len;
3284 }
3285
3286 }
3287 else if (*str == 'x') {
3288 unsigned char hex1, hex2;
3289 str++;
3290
willy tarreauc1f47532005-12-18 01:08:26 +01003291 hex1 = toupper(*str++) - '0';
3292 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003293
3294 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3295 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3296 *dst++ = (hex1<<4) + hex2;
3297 }
3298 else
3299 *dst++ = *str++;
3300 }
3301 else
3302 *dst++ = *str++;
3303 }
3304 *dst = 0;
3305 return dst - old_dst;
3306}
3307
willy tarreauc1f47532005-12-18 01:08:26 +01003308static int ishex(char s)
3309{
3310 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3311}
3312
3313/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3314char *check_replace_string(char *str)
3315{
3316 char *err = NULL;
3317 while (*str) {
3318 if (*str == '\\') {
3319 err = str; /* in case of a backslash, we return the pointer to it */
3320 str++;
3321 if (!*str)
3322 return err;
3323 else if (isdigit((int)*str))
3324 err = NULL;
3325 else if (*str == 'x') {
3326 str++;
3327 if (!ishex(*str))
3328 return err;
3329 str++;
3330 if (!ishex(*str))
3331 return err;
3332 err = NULL;
3333 }
3334 else {
3335 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3336 err = NULL;
3337 }
3338 }
3339 str++;
3340 }
3341 return err;
3342}
3343
3344
willy tarreau9fe663a2005-12-17 13:02:59 +01003345
willy tarreau0f7af912005-12-17 12:21:26 +01003346/*
3347 * manages the client FSM and its socket. BTW, it also tries to handle the
3348 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3349 * 0 else.
3350 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003351int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003352 int s = t->srv_state;
3353 int c = t->cli_state;
3354 struct buffer *req = t->req;
3355 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003356 int method_checked = 0;
3357 appsess *asession_temp = NULL;
3358 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003359
willy tarreau750a4722005-12-17 13:21:24 +01003360#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003361 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3362 cli_stnames[c], srv_stnames[s],
3363 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3364 t->crexpire.tv_sec, t->crexpire.tv_usec,
3365 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003366#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003367 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3368 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3369 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3370 //);
3371 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003372 /* now parse the partial (or complete) headers */
3373 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3374 char *ptr;
3375 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003376 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003377
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003379
willy tarreau0f7af912005-12-17 12:21:26 +01003380 /* look for the end of the current header */
3381 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3382 ptr++;
3383
willy tarreau5cbea6f2005-12-17 12:48:26 +01003384 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003385 int line, len;
willy tarreau43b15122006-04-10 21:01:39 +02003386
3387 /*
3388 * first, let's check that it's not a leading empty line, in
3389 * which case we'll ignore and remove it (according to RFC2616).
3390 */
3391 if (req->h == req->data) {
3392 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3393 if (ptr > req->r - 2) {
3394 /* this is a partial header, let's wait for more to come */
3395 req->lr = ptr;
3396 break;
3397 }
3398
3399 /* now we know that *ptr is either \r or \n,
3400 * and that there are at least 1 char after it.
3401 */
3402 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3403 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3404 else
3405 req->lr = ptr + 2; /* \r\n or \n\r */
3406 /* ignore empty leading lines */
3407 buffer_replace2(req, req->h, req->lr, NULL, 0);
3408 req->h = req->lr;
3409 continue;
3410 }
3411
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412 /* we can only get here after an end of headers */
3413 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003414
willy tarreaue39cd132005-12-17 13:00:18 +01003415 if (t->flags & SN_CLDENY) {
3416 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003417 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003418 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003419 if (!(t->flags & SN_ERR_MASK))
3420 t->flags |= SN_ERR_PRXCOND;
3421 if (!(t->flags & SN_FINST_MASK))
3422 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003423 return 1;
3424 }
3425
willy tarreau5cbea6f2005-12-17 12:48:26 +01003426 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003427 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3428 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003429 }
willy tarreau0f7af912005-12-17 12:21:26 +01003430
willy tarreau9fe663a2005-12-17 13:02:59 +01003431 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003432 if (t->cli_addr.ss_family == AF_INET) {
3433 unsigned char *pn;
3434 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3435 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3436 pn[0], pn[1], pn[2], pn[3]);
3437 buffer_replace2(req, req->h, req->h, trash, len);
3438 }
3439 else if (t->cli_addr.ss_family == AF_INET6) {
3440 char pn[INET6_ADDRSTRLEN];
3441 inet_ntop(AF_INET6,
3442 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3443 pn, sizeof(pn));
3444 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3445 buffer_replace2(req, req->h, req->h, trash, len);
3446 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003447 }
3448
willy tarreau25c4ea52005-12-18 00:49:49 +01003449 /* add a "connection: close" line if needed */
3450 if (t->proxy->options & PR_O_HTTP_CLOSE)
3451 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3452
willy tarreau982249e2005-12-18 00:57:06 +01003453 if (!memcmp(req->data, "POST ", 5)) {
3454 /* this is a POST request, which is not cacheable by default */
3455 t->flags |= SN_POST;
3456 }
willy tarreaucd878942005-12-17 13:27:43 +01003457
willy tarreau5cbea6f2005-12-17 12:48:26 +01003458 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003459 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003460
willy tarreau750a4722005-12-17 13:21:24 +01003461 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462 /* FIXME: we'll set the client in a wait state while we try to
3463 * connect to the server. Is this really needed ? wouldn't it be
3464 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003465 //FD_CLR(t->cli_fd, StaticReadEvent);
3466 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003467
3468 /* FIXME: if we break here (as up to 1.1.23), having the client
3469 * shutdown its connection can lead to an abort further.
3470 * it's better to either return 1 or even jump directly to the
3471 * data state which will save one schedule.
3472 */
3473 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003474
3475 if (!t->proxy->clitimeout ||
3476 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3477 /* If the client has no timeout, or if the server is not ready yet,
3478 * and we know for sure that it can expire, then it's cleaner to
3479 * disable the timeout on the client side so that too low values
3480 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003481 *
3482 * FIXME-20050705: the server needs a way to re-enable this time-out
3483 * when it switches its state, otherwise a client can stay connected
3484 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003485 */
3486 tv_eternity(&t->crexpire);
3487
willy tarreau197e8ec2005-12-17 14:10:59 +01003488 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003489 }
willy tarreau0f7af912005-12-17 12:21:26 +01003490
Willy TARREAU13032e72006-03-12 17:31:45 +01003491 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3492 if (ptr > req->r - 2) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003493 /* this is a partial header, let's wait for more to come */
3494 req->lr = ptr;
3495 break;
3496 }
willy tarreau0f7af912005-12-17 12:21:26 +01003497
willy tarreau5cbea6f2005-12-17 12:48:26 +01003498 /* now we know that *ptr is either \r or \n,
3499 * and that there are at least 1 char after it.
3500 */
3501 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3502 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3503 else
3504 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003505
willy tarreau5cbea6f2005-12-17 12:48:26 +01003506 /*
3507 * now we know that we have a full header ; we can do whatever
3508 * we want with these pointers :
3509 * req->h = beginning of header
3510 * ptr = end of header (first \r or \n)
3511 * req->lr = beginning of next line (next rep->h)
3512 * req->r = end of data (not used at this stage)
3513 */
willy tarreau0f7af912005-12-17 12:21:26 +01003514
willy tarreau12350152005-12-18 01:03:27 +01003515 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3516 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3517 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3518
3519 /* skip ; */
3520 request_line++;
3521
3522 /* look if we have a jsessionid */
3523
3524 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3525
3526 /* skip jsessionid= */
3527 request_line += t->proxy->appsession_name_len + 1;
3528
3529 /* First try if we allready have an appsession */
3530 asession_temp = &local_asession;
3531
3532 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3533 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3534 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3535 return 0;
3536 }
3537
3538 /* Copy the sessionid */
3539 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3540 asession_temp->sessid[t->proxy->appsession_len] = 0;
3541 asession_temp->serverid = NULL;
3542
3543 /* only do insert, if lookup fails */
3544 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3545 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3546 Alert("Not enough memory process_cli():asession:calloc().\n");
3547 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3548 return 0;
3549 }
3550 asession_temp->sessid = local_asession.sessid;
3551 asession_temp->serverid = local_asession.serverid;
3552 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003553 } /* end if (chtbl_lookup()) */
3554 else {
willy tarreau12350152005-12-18 01:03:27 +01003555 /*free wasted memory;*/
3556 pool_free_to(apools.sessid, local_asession.sessid);
3557 }
3558
3559 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3560 asession_temp->request_count++;
3561
3562#if defined(DEBUG_HASH)
3563 print_table(&(t->proxy->htbl_proxy));
3564#endif
3565
3566 if (asession_temp->serverid == NULL) {
3567 Alert("Found Application Session without matching server.\n");
3568 } else {
3569 struct server *srv = t->proxy->srv;
3570 while (srv) {
3571 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3572 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3573 /* we found the server and it's usable */
3574 t->flags &= ~SN_CK_MASK;
3575 t->flags |= SN_CK_VALID | SN_DIRECT;
3576 t->srv = srv;
3577 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003578 } else {
willy tarreau12350152005-12-18 01:03:27 +01003579 t->flags &= ~SN_CK_MASK;
3580 t->flags |= SN_CK_DOWN;
3581 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003582 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003583 srv = srv->next;
3584 }/* end while(srv) */
3585 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003586 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003587 else {
3588 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3589 }
willy tarreau598da412005-12-18 01:07:29 +01003590 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003591 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003592 else{
3593 //printf("No Methode-Header with Session-String\n");
3594 }
3595
willy tarreau8337c6b2005-12-17 13:41:01 +01003596 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003597 /* we have a complete HTTP request that we must log */
3598 int urilen;
3599
willy tarreaua1598082005-12-17 13:08:06 +01003600 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003601 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003602 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003603 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003604 if (!(t->flags & SN_ERR_MASK))
3605 t->flags |= SN_ERR_PRXCOND;
3606 if (!(t->flags & SN_FINST_MASK))
3607 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003608 return 1;
3609 }
3610
3611 urilen = ptr - req->h;
3612 if (urilen >= REQURI_LEN)
3613 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003614 memcpy(t->logs.uri, req->h, urilen);
3615 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003616
willy tarreaua1598082005-12-17 13:08:06 +01003617 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003618 sess_log(t);
3619 }
willy tarreau4302f492005-12-18 01:00:37 +01003620 else if (t->logs.logwait & LW_REQHDR) {
3621 struct cap_hdr *h;
3622 int len;
3623 for (h = t->proxy->req_cap; h; h = h->next) {
3624 if ((h->namelen + 2 <= ptr - req->h) &&
3625 (req->h[h->namelen] == ':') &&
3626 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3627
3628 if (t->req_cap[h->index] == NULL)
3629 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3630
3631 len = ptr - (req->h + h->namelen + 2);
3632 if (len > h->len)
3633 len = h->len;
3634
3635 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3636 t->req_cap[h->index][len]=0;
3637 }
3638 }
3639
3640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003641
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003643
willy tarreau982249e2005-12-18 00:57:06 +01003644 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003645 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003646 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 +01003647 max = ptr - req->h;
3648 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003649 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003650 trash[len++] = '\n';
3651 write(1, trash, len);
3652 }
willy tarreau0f7af912005-12-17 12:21:26 +01003653
willy tarreau25c4ea52005-12-18 00:49:49 +01003654
3655 /* remove "connection: " if needed */
3656 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3657 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3658 delete_header = 1;
3659 }
3660
willy tarreau5cbea6f2005-12-17 12:48:26 +01003661 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003662 if (!delete_header && t->proxy->req_exp != NULL
3663 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003664 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003665 char term;
3666
3667 term = *ptr;
3668 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003669 exp = t->proxy->req_exp;
3670 do {
3671 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3672 switch (exp->action) {
3673 case ACT_ALLOW:
3674 if (!(t->flags & SN_CLDENY))
3675 t->flags |= SN_CLALLOW;
3676 break;
3677 case ACT_REPLACE:
3678 if (!(t->flags & SN_CLDENY)) {
3679 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3680 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3681 }
3682 break;
3683 case ACT_REMOVE:
3684 if (!(t->flags & SN_CLDENY))
3685 delete_header = 1;
3686 break;
3687 case ACT_DENY:
3688 if (!(t->flags & SN_CLALLOW))
3689 t->flags |= SN_CLDENY;
3690 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003691 case ACT_PASS: /* we simply don't deny this one */
3692 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003693 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003694 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003695 }
willy tarreaue39cd132005-12-17 13:00:18 +01003696 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003697 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003698 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003699
willy tarreau240afa62005-12-17 13:14:35 +01003700 /* Now look for cookies. Conforming to RFC2109, we have to support
3701 * attributes whose name begin with a '$', and associate them with
3702 * the right cookie, if we want to delete this cookie.
3703 * So there are 3 cases for each cookie read :
3704 * 1) it's a special attribute, beginning with a '$' : ignore it.
3705 * 2) it's a server id cookie that we *MAY* want to delete : save
3706 * some pointers on it (last semi-colon, beginning of cookie...)
3707 * 3) it's an application cookie : we *MAY* have to delete a previous
3708 * "special" cookie.
3709 * At the end of loop, if a "special" cookie remains, we may have to
3710 * remove it. If no application cookie persists in the header, we
3711 * *MUST* delete it
3712 */
willy tarreau12350152005-12-18 01:03:27 +01003713 if (!delete_header &&
3714 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003715 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003716 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003717 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003718 char *del_colon, *del_cookie, *colon;
3719 int app_cookies;
3720
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003722 colon = p1;
3723 /* del_cookie == NULL => nothing to be deleted */
3724 del_colon = del_cookie = NULL;
3725 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726
3727 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003728 /* skip spaces and colons, but keep an eye on these ones */
3729 while (p1 < ptr) {
3730 if (*p1 == ';' || *p1 == ',')
3731 colon = p1;
3732 else if (!isspace((int)*p1))
3733 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003734 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003735 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003736
3737 if (p1 == ptr)
3738 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739
3740 /* p1 is at the beginning of the cookie name */
3741 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003742 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003743 p2++;
3744
3745 if (p2 == ptr)
3746 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003747
3748 p3 = p2 + 1; /* skips the '=' sign */
3749 if (p3 == ptr)
3750 break;
3751
willy tarreau240afa62005-12-17 13:14:35 +01003752 p4 = p3;
3753 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 p4++;
3755
3756 /* here, we have the cookie name between p1 and p2,
3757 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003758 * we can process it :
3759 *
3760 * Cookie: NAME=VALUE;
3761 * | || || |
3762 * | || || +--> p4
3763 * | || |+-------> p3
3764 * | || +--------> p2
3765 * | |+------------> p1
3766 * | +-------------> colon
3767 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003768 */
3769
willy tarreau240afa62005-12-17 13:14:35 +01003770 if (*p1 == '$') {
3771 /* skip this one */
3772 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003773 else {
3774 /* first, let's see if we want to capture it */
3775 if (t->proxy->capture_name != NULL &&
3776 t->logs.cli_cookie == NULL &&
3777 (p4 - p1 >= t->proxy->capture_namelen) &&
3778 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3779 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003780
willy tarreau8337c6b2005-12-17 13:41:01 +01003781 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3782 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003783 } else {
3784 if (log_len > t->proxy->capture_len)
3785 log_len = t->proxy->capture_len;
3786 memcpy(t->logs.cli_cookie, p1, log_len);
3787 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003788 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003789 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003790
3791 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3792 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3793 /* Cool... it's the right one */
3794 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003795 char *delim;
3796
3797 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3798 * have the server ID betweek p3 and delim, and the original cookie between
3799 * delim+1 and p4. Otherwise, delim==p4 :
3800 *
3801 * Cookie: NAME=SRV~VALUE;
3802 * | || || | |
3803 * | || || | +--> p4
3804 * | || || +--------> delim
3805 * | || |+-----------> p3
3806 * | || +------------> p2
3807 * | |+----------------> p1
3808 * | +-----------------> colon
3809 * +------------------------> req->h
3810 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003811
willy tarreau0174f312005-12-18 01:02:42 +01003812 if (t->proxy->options & PR_O_COOK_PFX) {
3813 for (delim = p3; delim < p4; delim++)
3814 if (*delim == COOKIE_DELIM)
3815 break;
3816 }
3817 else
3818 delim = p4;
3819
3820
3821 /* Here, we'll look for the first running server which supports the cookie.
3822 * This allows to share a same cookie between several servers, for example
3823 * to dedicate backup servers to specific servers only.
3824 */
3825 while (srv) {
3826 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3827 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3828 /* we found the server and it's usable */
3829 t->flags &= ~SN_CK_MASK;
3830 t->flags |= SN_CK_VALID | SN_DIRECT;
3831 t->srv = srv;
3832 break;
willy tarreau12350152005-12-18 01:03:27 +01003833 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003834 /* we found a server, but it's down */
3835 t->flags &= ~SN_CK_MASK;
3836 t->flags |= SN_CK_DOWN;
3837 }
3838 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003839 srv = srv->next;
3840 }
3841
willy tarreau0174f312005-12-18 01:02:42 +01003842 if (!srv && !(t->flags & SN_CK_DOWN)) {
3843 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003844 t->flags &= ~SN_CK_MASK;
3845 t->flags |= SN_CK_INVALID;
3846 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003847
willy tarreau0174f312005-12-18 01:02:42 +01003848 /* depending on the cookie mode, we may have to either :
3849 * - delete the complete cookie if we're in insert+indirect mode, so that
3850 * the server never sees it ;
3851 * - remove the server id from the cookie value, and tag the cookie as an
3852 * application cookie so that it does not get accidentely removed later,
3853 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003854 */
willy tarreau0174f312005-12-18 01:02:42 +01003855 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3856 buffer_replace2(req, p3, delim + 1, NULL, 0);
3857 p4 -= (delim + 1 - p3);
3858 ptr -= (delim + 1 - p3);
3859 del_cookie = del_colon = NULL;
3860 app_cookies++; /* protect the header from deletion */
3861 }
3862 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003863 (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 +01003864 del_cookie = p1;
3865 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003866 }
willy tarreau12350152005-12-18 01:03:27 +01003867 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003868 /* now we know that we must keep this cookie since it's
3869 * not ours. But if we wanted to delete our cookie
3870 * earlier, we cannot remove the complete header, but we
3871 * can remove the previous block itself.
3872 */
3873 app_cookies++;
3874
3875 if (del_cookie != NULL) {
3876 buffer_replace2(req, del_cookie, p1, NULL, 0);
3877 p4 -= (p1 - del_cookie);
3878 ptr -= (p1 - del_cookie);
3879 del_cookie = del_colon = NULL;
3880 }
willy tarreau240afa62005-12-17 13:14:35 +01003881 }
willy tarreau12350152005-12-18 01:03:27 +01003882
3883 if ((t->proxy->appsession_name != NULL) &&
3884 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3885 /* first, let's see if the cookie is our appcookie*/
3886
3887 /* Cool... it's the right one */
3888
3889 asession_temp = &local_asession;
3890
3891 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3892 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3893 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3894 return 0;
3895 }
3896
3897 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3898 asession_temp->sessid[t->proxy->appsession_len] = 0;
3899 asession_temp->serverid = NULL;
3900
3901 /* only do insert, if lookup fails */
3902 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3903 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3904 Alert("Not enough memory process_cli():asession:calloc().\n");
3905 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3906 return 0;
3907 }
3908
3909 asession_temp->sessid = local_asession.sessid;
3910 asession_temp->serverid = local_asession.serverid;
3911 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3912 }
3913 else{
3914 /* free wasted memory */
3915 pool_free_to(apools.sessid, local_asession.sessid);
3916 }
3917
3918 if (asession_temp->serverid == NULL) {
3919 Alert("Found Application Session without matching server.\n");
3920 } else {
3921 struct server *srv = t->proxy->srv;
3922 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003923 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003924 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3925 /* we found the server and it's usable */
3926 t->flags &= ~SN_CK_MASK;
3927 t->flags |= SN_CK_VALID | SN_DIRECT;
3928 t->srv = srv;
3929 break;
3930 } else {
3931 t->flags &= ~SN_CK_MASK;
3932 t->flags |= SN_CK_DOWN;
3933 }
3934 }
3935 srv = srv->next;
3936 }/* end while(srv) */
3937 }/* end else if server == NULL */
3938
3939 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003940 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003941 }
willy tarreau240afa62005-12-17 13:14:35 +01003942
willy tarreau5cbea6f2005-12-17 12:48:26 +01003943 /* we'll have to look for another cookie ... */
3944 p1 = p4;
3945 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003946
3947 /* There's no more cookie on this line.
3948 * We may have marked the last one(s) for deletion.
3949 * We must do this now in two ways :
3950 * - if there is no app cookie, we simply delete the header ;
3951 * - if there are app cookies, we must delete the end of the
3952 * string properly, including the colon/semi-colon before
3953 * the cookie name.
3954 */
3955 if (del_cookie != NULL) {
3956 if (app_cookies) {
3957 buffer_replace2(req, del_colon, ptr, NULL, 0);
3958 /* WARNING! <ptr> becomes invalid for now. If some code
3959 * below needs to rely on it before the end of the global
3960 * header loop, we need to correct it with this code :
3961 * ptr = del_colon;
3962 */
3963 }
3964 else
3965 delete_header = 1;
3966 }
3967 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003968
3969 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003970 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003971 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003972 }
willy tarreau240afa62005-12-17 13:14:35 +01003973 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3974
willy tarreau5cbea6f2005-12-17 12:48:26 +01003975 req->h = req->lr;
3976 } /* while (req->lr < req->r) */
3977
3978 /* end of header processing (even if incomplete) */
3979
willy tarreauef900ab2005-12-17 12:52:52 +01003980 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3981 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3982 * full. We cannot loop here since event_cli_read will disable it only if
3983 * req->l == rlim-data
3984 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003985 FD_SET(t->cli_fd, StaticReadEvent);
3986 if (t->proxy->clitimeout)
3987 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3988 else
3989 tv_eternity(&t->crexpire);
3990 }
3991
willy tarreaue39cd132005-12-17 13:00:18 +01003992 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003993 * won't be able to free more later, so the session will never terminate.
3994 */
willy tarreaue39cd132005-12-17 13:00:18 +01003995 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003996 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003997 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003998 if (!(t->flags & SN_ERR_MASK))
3999 t->flags |= SN_ERR_PRXCOND;
4000 if (!(t->flags & SN_FINST_MASK))
4001 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01004002 return 1;
4003 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004004 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004005 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 tv_eternity(&t->crexpire);
4007 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004008 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004009 if (!(t->flags & SN_ERR_MASK))
4010 t->flags |= SN_ERR_CLICL;
4011 if (!(t->flags & SN_FINST_MASK))
4012 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004013 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004014 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004015 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4016
4017 /* read timeout : give up with an error message.
4018 */
4019 t->logs.status = 408;
4020 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01004021 if (!(t->flags & SN_ERR_MASK))
4022 t->flags |= SN_ERR_CLITO;
4023 if (!(t->flags & SN_FINST_MASK))
4024 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01004025 return 1;
4026 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027
4028 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004029 }
4030 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01004031 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01004032 /* FIXME: this error handling is partly buggy because we always report
4033 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
4034 * or HEADER phase. BTW, it's not logical to expire the client while
4035 * we're waiting for the server to connect.
4036 */
willy tarreau0f7af912005-12-17 12:21:26 +01004037 /* read or write error */
4038 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004039 tv_eternity(&t->crexpire);
4040 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004041 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004042 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004043 if (!(t->flags & SN_ERR_MASK))
4044 t->flags |= SN_ERR_CLICL;
4045 if (!(t->flags & SN_FINST_MASK))
4046 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004047 return 1;
4048 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004049 /* last read, or end of server write */
4050 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004051 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004052 tv_eternity(&t->crexpire);
4053 shutdown(t->cli_fd, SHUT_RD);
4054 t->cli_state = CL_STSHUTR;
4055 return 1;
4056 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004057 /* last server read and buffer empty */
4058 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004059 FD_CLR(t->cli_fd, StaticWriteEvent);
4060 tv_eternity(&t->cwexpire);
4061 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004062 /* We must ensure that the read part is still alive when switching
4063 * to shutw */
4064 FD_SET(t->cli_fd, StaticReadEvent);
4065 if (t->proxy->clitimeout)
4066 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004067 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01004068 //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 +01004069 return 1;
4070 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004071 /* read timeout */
4072 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4073 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01004074 tv_eternity(&t->crexpire);
4075 shutdown(t->cli_fd, SHUT_RD);
4076 t->cli_state = CL_STSHUTR;
4077 if (!(t->flags & SN_ERR_MASK))
4078 t->flags |= SN_ERR_CLITO;
4079 if (!(t->flags & SN_FINST_MASK))
4080 t->flags |= SN_FINST_D;
4081 return 1;
4082 }
4083 /* write timeout */
4084 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4085 FD_CLR(t->cli_fd, StaticWriteEvent);
4086 tv_eternity(&t->cwexpire);
4087 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004088 /* We must ensure that the read part is still alive when switching
4089 * to shutw */
4090 FD_SET(t->cli_fd, StaticReadEvent);
4091 if (t->proxy->clitimeout)
4092 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4093
willy tarreau036e1ce2005-12-17 13:46:33 +01004094 t->cli_state = CL_STSHUTW;
4095 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01004096 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01004097 if (!(t->flags & SN_FINST_MASK))
4098 t->flags |= SN_FINST_D;
4099 return 1;
4100 }
willy tarreau0f7af912005-12-17 12:21:26 +01004101
willy tarreauc58fc692005-12-17 14:13:08 +01004102 if (req->l >= req->rlim - req->data) {
4103 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01004104 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004105 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004106 FD_CLR(t->cli_fd, StaticReadEvent);
4107 tv_eternity(&t->crexpire);
4108 }
4109 }
4110 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004111 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004112 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4113 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01004114 if (!t->proxy->clitimeout ||
4115 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
4116 /* If the client has no timeout, or if the server not ready yet, and we
4117 * know for sure that it can expire, then it's cleaner to disable the
4118 * timeout on the client side so that too low values cannot make the
4119 * sessions abort too early.
4120 */
willy tarreau0f7af912005-12-17 12:21:26 +01004121 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01004122 else
4123 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004124 }
4125 }
4126
4127 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01004128 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004129 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4130 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4131 tv_eternity(&t->cwexpire);
4132 }
4133 }
4134 else { /* buffer not empty */
4135 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4136 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004137 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004138 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004139 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4140 t->crexpire = t->cwexpire;
4141 }
willy tarreau0f7af912005-12-17 12:21:26 +01004142 else
4143 tv_eternity(&t->cwexpire);
4144 }
4145 }
4146 return 0; /* other cases change nothing */
4147 }
4148 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004149 if (t->res_cw == RES_ERROR) {
4150 tv_eternity(&t->cwexpire);
4151 fd_delete(t->cli_fd);
4152 t->cli_state = CL_STCLOSE;
4153 if (!(t->flags & SN_ERR_MASK))
4154 t->flags |= SN_ERR_CLICL;
4155 if (!(t->flags & SN_FINST_MASK))
4156 t->flags |= SN_FINST_D;
4157 return 1;
4158 }
4159 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004160 tv_eternity(&t->cwexpire);
4161 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004162 t->cli_state = CL_STCLOSE;
4163 return 1;
4164 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004165 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
4166 tv_eternity(&t->cwexpire);
4167 fd_delete(t->cli_fd);
4168 t->cli_state = CL_STCLOSE;
4169 if (!(t->flags & SN_ERR_MASK))
4170 t->flags |= SN_ERR_CLITO;
4171 if (!(t->flags & SN_FINST_MASK))
4172 t->flags |= SN_FINST_D;
4173 return 1;
4174 }
willy tarreau0f7af912005-12-17 12:21:26 +01004175 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01004176 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004177 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4178 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
4179 tv_eternity(&t->cwexpire);
4180 }
4181 }
4182 else { /* buffer not empty */
4183 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
4184 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004185 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004186 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004187 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
4188 t->crexpire = t->cwexpire;
4189 }
willy tarreau0f7af912005-12-17 12:21:26 +01004190 else
4191 tv_eternity(&t->cwexpire);
4192 }
4193 }
4194 return 0;
4195 }
4196 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004197 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004198 tv_eternity(&t->crexpire);
4199 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004200 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004201 if (!(t->flags & SN_ERR_MASK))
4202 t->flags |= SN_ERR_CLICL;
4203 if (!(t->flags & SN_FINST_MASK))
4204 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004205 return 1;
4206 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004207 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
4208 tv_eternity(&t->crexpire);
4209 fd_delete(t->cli_fd);
4210 t->cli_state = CL_STCLOSE;
4211 return 1;
4212 }
4213 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
4214 tv_eternity(&t->crexpire);
4215 fd_delete(t->cli_fd);
4216 t->cli_state = CL_STCLOSE;
4217 if (!(t->flags & SN_ERR_MASK))
4218 t->flags |= SN_ERR_CLITO;
4219 if (!(t->flags & SN_FINST_MASK))
4220 t->flags |= SN_FINST_D;
4221 return 1;
4222 }
willy tarreauef900ab2005-12-17 12:52:52 +01004223 else if (req->l >= req->rlim - req->data) {
4224 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01004225
4226 /* FIXME-20050705: is it possible for a client to maintain a session
4227 * after the timeout by sending more data after it receives a close ?
4228 */
4229
willy tarreau0f7af912005-12-17 12:21:26 +01004230 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01004231 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01004232 FD_CLR(t->cli_fd, StaticReadEvent);
4233 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004234 //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 +01004235 }
4236 }
4237 else {
willy tarreauef900ab2005-12-17 12:52:52 +01004238 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01004239 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
4240 FD_SET(t->cli_fd, StaticReadEvent);
4241 if (t->proxy->clitimeout)
4242 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
4243 else
4244 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01004245 //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 +01004246 }
4247 }
4248 return 0;
4249 }
4250 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004251 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004252 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004253 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 +01004254 write(1, trash, len);
4255 }
4256 return 0;
4257 }
4258 return 0;
4259}
4260
4261
4262/*
4263 * manages the server FSM and its socket. It returns 1 if a state has changed
4264 * (and a resync may be needed), 0 else.
4265 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004266int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01004267 int s = t->srv_state;
4268 int c = t->cli_state;
4269 struct buffer *req = t->req;
4270 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01004271 appsess *asession_temp = NULL;
4272 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01004273 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01004274
willy tarreau750a4722005-12-17 13:21:24 +01004275#ifdef DEBUG_FULL
4276 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
4277#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01004278 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
4279 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
4280 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
4281 //);
willy tarreau0f7af912005-12-17 12:21:26 +01004282 if (s == SV_STIDLE) {
4283 if (c == CL_STHEADERS)
4284 return 0; /* stay in idle, waiting for data to reach the client side */
4285 else if (c == CL_STCLOSE ||
4286 c == CL_STSHUTW ||
4287 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4288 tv_eternity(&t->cnexpire);
4289 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004290 if (!(t->flags & SN_ERR_MASK))
4291 t->flags |= SN_ERR_CLICL;
4292 if (!(t->flags & SN_FINST_MASK))
4293 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004294 return 1;
4295 }
4296 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004297 /* initiate a connection to the server */
4298 conn_err = connect_server(t);
4299 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004300 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4301 t->srv_state = SV_STCONN;
4302 }
4303 else { /* try again */
4304 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004306 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004307 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004308 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4309 t->flags &= ~SN_CK_MASK;
4310 t->flags |= SN_CK_DOWN;
4311 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004312 }
4313
willy tarreaub1285d52005-12-18 01:20:14 +01004314 conn_err = connect_server(t);
4315 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004316 t->srv_state = SV_STCONN;
4317 break;
4318 }
4319 }
4320 if (t->conn_retries < 0) {
4321 /* if conn_retries < 0 or other error, let's abort */
4322 tv_eternity(&t->cnexpire);
4323 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004324 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004325 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004326 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004327 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004328 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004329 if (!(t->flags & SN_FINST_MASK))
4330 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004331 }
4332 }
4333 return 1;
4334 }
4335 }
4336 else if (s == SV_STCONN) { /* connection in progress */
4337 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004338 //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 +01004339 return 0; /* nothing changed */
4340 }
4341 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4342 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4343 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004344 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004345 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004346 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004347 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004348 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004349 if (t->conn_retries >= 0) {
4350 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004351 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004352 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004353 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4354 t->flags &= ~SN_CK_MASK;
4355 t->flags |= SN_CK_DOWN;
4356 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004357 }
willy tarreaub1285d52005-12-18 01:20:14 +01004358 conn_err = connect_server(t);
4359 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004361 }
willy tarreaub1285d52005-12-18 01:20:14 +01004362 else if (t->res_sw == RES_SILENT)
4363 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4364 else
4365 conn_err = SN_ERR_SRVCL; // it was a connect error.
4366
willy tarreau0f7af912005-12-17 12:21:26 +01004367 /* if conn_retries < 0 or other error, let's abort */
4368 tv_eternity(&t->cnexpire);
4369 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004370 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004371 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004372 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004373 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004374 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004375 if (!(t->flags & SN_FINST_MASK))
4376 t->flags |= SN_FINST_C;
willy tarreaucfbb2182006-04-07 17:37:55 +02004377 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004378 return 1;
4379 }
4380 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004381 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004382
willy tarreau0f7af912005-12-17 12:21:26 +01004383 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004384 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004385 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004386 tv_eternity(&t->swexpire);
4387 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004388 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004389 if (t->proxy->srvtimeout) {
4390 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4391 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4392 t->srexpire = t->swexpire;
4393 }
4394 else
4395 tv_eternity(&t->swexpire);
4396 }
willy tarreau0f7af912005-12-17 12:21:26 +01004397
4398 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4399 FD_SET(t->srv_fd, StaticReadEvent);
4400 if (t->proxy->srvtimeout)
4401 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4402 else
4403 tv_eternity(&t->srexpire);
4404
4405 t->srv_state = SV_STDATA;
willy tarreau14b4d432006-04-07 18:23:29 +02004406 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004407 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004408
4409 /* if the user wants to log as soon as possible, without counting
4410 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004411 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004412 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4413 sess_log(t);
4414 }
willy tarreau0f7af912005-12-17 12:21:26 +01004415 }
willy tarreauef900ab2005-12-17 12:52:52 +01004416 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004417 t->srv_state = SV_STHEADERS;
willy tarreau14b4d432006-04-07 18:23:29 +02004418 t->srv->cum_sess++;
willy tarreauef900ab2005-12-17 12:52:52 +01004419 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4420 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004421 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004422 return 1;
4423 }
4424 }
4425 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004426 /* now parse the partial (or complete) headers */
4427 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4428 char *ptr;
4429 int delete_header;
4430
4431 ptr = rep->lr;
4432
4433 /* look for the end of the current header */
4434 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4435 ptr++;
4436
4437 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004438 int line, len;
4439
4440 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004441
4442 /* first, we'll block if security checks have caught nasty things */
4443 if (t->flags & SN_CACHEABLE) {
4444 if ((t->flags & SN_CACHE_COOK) &&
4445 (t->flags & SN_SCK_ANY) &&
4446 (t->proxy->options & PR_O_CHK_CACHE)) {
4447
4448 /* we're in presence of a cacheable response containing
4449 * a set-cookie header. We'll block it as requested by
4450 * the 'checkcache' option, and send an alert.
4451 */
4452 tv_eternity(&t->srexpire);
4453 tv_eternity(&t->swexpire);
4454 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004455 t->srv->cur_sess--;
willy tarreau97f58572005-12-18 00:53:44 +01004456 t->srv_state = SV_STCLOSE;
4457 t->logs.status = 502;
4458 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4459 if (!(t->flags & SN_ERR_MASK))
4460 t->flags |= SN_ERR_PRXCOND;
4461 if (!(t->flags & SN_FINST_MASK))
4462 t->flags |= SN_FINST_H;
4463
4464 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4465 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4466
willy tarreaucfbb2182006-04-07 17:37:55 +02004467 /* TODO : check if there are pending connections on this server */
willy tarreau97f58572005-12-18 00:53:44 +01004468 return 1;
4469 }
4470 }
4471
willy tarreau982249e2005-12-18 00:57:06 +01004472 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4473 if (t->flags & SN_SVDENY) {
4474 tv_eternity(&t->srexpire);
4475 tv_eternity(&t->swexpire);
4476 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004477 t->srv->cur_sess--;
willy tarreau982249e2005-12-18 00:57:06 +01004478 t->srv_state = SV_STCLOSE;
4479 t->logs.status = 502;
4480 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4481 if (!(t->flags & SN_ERR_MASK))
4482 t->flags |= SN_ERR_PRXCOND;
4483 if (!(t->flags & SN_FINST_MASK))
4484 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004485 /* TODO : check if there are pending connections on this server */
willy tarreau982249e2005-12-18 00:57:06 +01004486 return 1;
4487 }
4488
willy tarreau5cbea6f2005-12-17 12:48:26 +01004489 /* we'll have something else to do here : add new headers ... */
4490
willy tarreaucd878942005-12-17 13:27:43 +01004491 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4492 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004493 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004494 * insert a set-cookie here, except if we want to insert only on POST
4495 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004496 */
willy tarreau750a4722005-12-17 13:21:24 +01004497 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004498 t->proxy->cookie_name,
4499 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004500
willy tarreau036e1ce2005-12-17 13:46:33 +01004501 t->flags |= SN_SCK_INSERTED;
4502
willy tarreau750a4722005-12-17 13:21:24 +01004503 /* Here, we will tell an eventual cache on the client side that we don't
4504 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4505 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4506 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4507 */
willy tarreau240afa62005-12-17 13:14:35 +01004508 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004509 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4510 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004511
4512 if (rep->data + rep->l < rep->h)
4513 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4514 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004515 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004516 }
4517
4518 /* headers to be added */
4519 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004520 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4521 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004522 }
4523
willy tarreau25c4ea52005-12-18 00:49:49 +01004524 /* add a "connection: close" line if needed */
4525 if (t->proxy->options & PR_O_HTTP_CLOSE)
4526 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4527
willy tarreau5cbea6f2005-12-17 12:48:26 +01004528 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004529 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004530 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004531
Willy TARREAU767ba712006-03-01 22:40:50 +01004532 /* client connection already closed or option 'httpclose' required :
4533 * we close the server's outgoing connection right now.
4534 */
4535 if ((req->l == 0) &&
4536 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4537 FD_CLR(t->srv_fd, StaticWriteEvent);
4538 tv_eternity(&t->swexpire);
4539
4540 /* We must ensure that the read part is still alive when switching
4541 * to shutw */
4542 FD_SET(t->srv_fd, StaticReadEvent);
4543 if (t->proxy->srvtimeout)
4544 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4545
4546 shutdown(t->srv_fd, SHUT_WR);
4547 t->srv_state = SV_STSHUTW;
4548 }
4549
willy tarreau25c4ea52005-12-18 00:49:49 +01004550 /* if the user wants to log as soon as possible, without counting
4551 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004552 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004553 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4554 t->logs.bytes = rep->h - rep->data;
4555 sess_log(t);
4556 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004557 break;
4558 }
4559
4560 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4561 if (ptr > rep->r - 2) {
4562 /* this is a partial header, let's wait for more to come */
4563 rep->lr = ptr;
4564 break;
4565 }
4566
4567 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4568 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4569
4570 /* now we know that *ptr is either \r or \n,
4571 * and that there are at least 1 char after it.
4572 */
4573 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4574 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4575 else
4576 rep->lr = ptr + 2; /* \r\n or \n\r */
4577
4578 /*
4579 * now we know that we have a full header ; we can do whatever
4580 * we want with these pointers :
4581 * rep->h = beginning of header
4582 * ptr = end of header (first \r or \n)
4583 * rep->lr = beginning of next line (next rep->h)
4584 * rep->r = end of data (not used at this stage)
4585 */
4586
willy tarreaua1598082005-12-17 13:08:06 +01004587
willy tarreau982249e2005-12-18 00:57:06 +01004588 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004589 t->logs.logwait &= ~LW_RESP;
4590 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004591 switch (t->logs.status) {
4592 case 200:
4593 case 203:
4594 case 206:
4595 case 300:
4596 case 301:
4597 case 410:
4598 /* RFC2616 @13.4:
4599 * "A response received with a status code of
4600 * 200, 203, 206, 300, 301 or 410 MAY be stored
4601 * by a cache (...) unless a cache-control
4602 * directive prohibits caching."
4603 *
4604 * RFC2616 @9.5: POST method :
4605 * "Responses to this method are not cacheable,
4606 * unless the response includes appropriate
4607 * Cache-Control or Expires header fields."
4608 */
4609 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4610 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4611 break;
4612 default:
4613 break;
4614 }
willy tarreau4302f492005-12-18 01:00:37 +01004615 }
4616 else if (t->logs.logwait & LW_RSPHDR) {
4617 struct cap_hdr *h;
4618 int len;
4619 for (h = t->proxy->rsp_cap; h; h = h->next) {
4620 if ((h->namelen + 2 <= ptr - rep->h) &&
4621 (rep->h[h->namelen] == ':') &&
4622 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4623
4624 if (t->rsp_cap[h->index] == NULL)
4625 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4626
4627 len = ptr - (rep->h + h->namelen + 2);
4628 if (len > h->len)
4629 len = h->len;
4630
4631 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4632 t->rsp_cap[h->index][len]=0;
4633 }
4634 }
4635
willy tarreaua1598082005-12-17 13:08:06 +01004636 }
4637
willy tarreau5cbea6f2005-12-17 12:48:26 +01004638 delete_header = 0;
4639
willy tarreau982249e2005-12-18 00:57:06 +01004640 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004641 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004642 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 +01004643 max = ptr - rep->h;
4644 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004645 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004646 trash[len++] = '\n';
4647 write(1, trash, len);
4648 }
4649
willy tarreau25c4ea52005-12-18 00:49:49 +01004650 /* remove "connection: " if needed */
4651 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4652 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4653 delete_header = 1;
4654 }
4655
willy tarreau5cbea6f2005-12-17 12:48:26 +01004656 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004657 if (!delete_header && t->proxy->rsp_exp != NULL
4658 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004659 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004660 char term;
4661
4662 term = *ptr;
4663 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004664 exp = t->proxy->rsp_exp;
4665 do {
4666 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4667 switch (exp->action) {
4668 case ACT_ALLOW:
4669 if (!(t->flags & SN_SVDENY))
4670 t->flags |= SN_SVALLOW;
4671 break;
4672 case ACT_REPLACE:
4673 if (!(t->flags & SN_SVDENY)) {
4674 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4675 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4676 }
4677 break;
4678 case ACT_REMOVE:
4679 if (!(t->flags & SN_SVDENY))
4680 delete_header = 1;
4681 break;
4682 case ACT_DENY:
4683 if (!(t->flags & SN_SVALLOW))
4684 t->flags |= SN_SVDENY;
4685 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004686 case ACT_PASS: /* we simply don't deny this one */
4687 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004688 }
4689 break;
4690 }
willy tarreaue39cd132005-12-17 13:00:18 +01004691 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004692 *ptr = term; /* restore the string terminator */
4693 }
4694
willy tarreau97f58572005-12-18 00:53:44 +01004695 /* check for cache-control: or pragma: headers */
4696 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4697 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4698 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4699 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4700 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004701 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004702 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4703 else {
4704 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004705 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004706 t->flags &= ~SN_CACHE_COOK;
4707 }
4708 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004709 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004710 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004711 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004712 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4713 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004714 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004715 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004716 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4717 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4718 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4719 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4720 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4721 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004722 }
4723 }
4724 }
4725
willy tarreau5cbea6f2005-12-17 12:48:26 +01004726 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004727 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004728 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004729 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004730 char *p1, *p2, *p3, *p4;
4731
willy tarreau97f58572005-12-18 00:53:44 +01004732 t->flags |= SN_SCK_ANY;
4733
willy tarreau5cbea6f2005-12-17 12:48:26 +01004734 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4735
4736 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004737 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004738 p1++;
4739
4740 if (p1 == ptr || *p1 == ';') /* end of cookie */
4741 break;
4742
4743 /* p1 is at the beginning of the cookie name */
4744 p2 = p1;
4745
4746 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4747 p2++;
4748
4749 if (p2 == ptr || *p2 == ';') /* next cookie */
4750 break;
4751
4752 p3 = p2 + 1; /* skips the '=' sign */
4753 if (p3 == ptr)
4754 break;
4755
4756 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004757 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004758 p4++;
4759
4760 /* here, we have the cookie name between p1 and p2,
4761 * and its value between p3 and p4.
4762 * we can process it.
4763 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004764
4765 /* first, let's see if we want to capture it */
4766 if (t->proxy->capture_name != NULL &&
4767 t->logs.srv_cookie == NULL &&
4768 (p4 - p1 >= t->proxy->capture_namelen) &&
4769 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4770 int log_len = p4 - p1;
4771
4772 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4773 Alert("HTTP logging : out of memory.\n");
4774 }
4775
4776 if (log_len > t->proxy->capture_len)
4777 log_len = t->proxy->capture_len;
4778 memcpy(t->logs.srv_cookie, p1, log_len);
4779 t->logs.srv_cookie[log_len] = 0;
4780 }
4781
4782 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4783 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004784 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004785 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004786
4787 /* If the cookie is in insert mode on a known server, we'll delete
4788 * this occurrence because we'll insert another one later.
4789 * We'll delete it too if the "indirect" option is set and we're in
4790 * a direct access. */
4791 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004792 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004793 /* this header must be deleted */
4794 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004795 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004796 }
4797 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4798 /* replace bytes p3->p4 with the cookie name associated
4799 * with this server since we know it.
4800 */
4801 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004802 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004803 }
willy tarreau0174f312005-12-18 01:02:42 +01004804 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4805 /* insert the cookie name associated with this server
4806 * before existing cookie, and insert a delimitor between them..
4807 */
4808 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4809 p3[t->srv->cklen] = COOKIE_DELIM;
4810 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4811 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004812 break;
4813 }
willy tarreau12350152005-12-18 01:03:27 +01004814
4815 /* first, let's see if the cookie is our appcookie*/
4816 if ((t->proxy->appsession_name != NULL) &&
4817 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4818
4819 /* Cool... it's the right one */
4820
willy tarreaub952e1d2005-12-18 01:31:20 +01004821 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004822 asession_temp = &local_asession;
4823
willy tarreaub952e1d2005-12-18 01:31:20 +01004824 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004825 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4826 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4827 }
4828 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4829 asession_temp->sessid[t->proxy->appsession_len] = 0;
4830 asession_temp->serverid = NULL;
4831
4832 /* only do insert, if lookup fails */
4833 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4834 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4835 Alert("Not enought Memory process_srv():asession:calloc().\n");
4836 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4837 return 0;
4838 }
4839 asession_temp->sessid = local_asession.sessid;
4840 asession_temp->serverid = local_asession.serverid;
4841 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004842 }/* end if (chtbl_lookup()) */
4843 else {
willy tarreau12350152005-12-18 01:03:27 +01004844 /* free wasted memory */
4845 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004846 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004847
willy tarreaub952e1d2005-12-18 01:31:20 +01004848 if (asession_temp->serverid == NULL) {
4849 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004850 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4851 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4852 }
4853 asession_temp->serverid[0] = '\0';
4854 }
4855
willy tarreaub952e1d2005-12-18 01:31:20 +01004856 if (asession_temp->serverid[0] == '\0')
4857 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004858
4859 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4860
4861#if defined(DEBUG_HASH)
4862 print_table(&(t->proxy->htbl_proxy));
4863#endif
4864 break;
4865 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004866 else {
4867 // fprintf(stderr,"Ignoring unknown cookie : ");
4868 // write(2, p1, p2-p1);
4869 // fprintf(stderr," = ");
4870 // write(2, p3, p4-p3);
4871 // fprintf(stderr,"\n");
4872 }
4873 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4874 } /* we're now at the end of the cookie value */
4875 } /* end of cookie processing */
4876
willy tarreau97f58572005-12-18 00:53:44 +01004877 /* check for any set-cookie in case we check for cacheability */
4878 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4879 (t->proxy->options & PR_O_CHK_CACHE) &&
4880 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4881 t->flags |= SN_SCK_ANY;
4882 }
4883
willy tarreau5cbea6f2005-12-17 12:48:26 +01004884 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004885 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004886 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004887
willy tarreau5cbea6f2005-12-17 12:48:26 +01004888 rep->h = rep->lr;
4889 } /* while (rep->lr < rep->r) */
4890
4891 /* end of header processing (even if incomplete) */
4892
willy tarreauef900ab2005-12-17 12:52:52 +01004893 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4894 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4895 * full. We cannot loop here since event_srv_read will disable it only if
4896 * rep->l == rlim-data
4897 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004898 FD_SET(t->srv_fd, StaticReadEvent);
4899 if (t->proxy->srvtimeout)
4900 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4901 else
4902 tv_eternity(&t->srexpire);
4903 }
willy tarreau0f7af912005-12-17 12:21:26 +01004904
willy tarreau8337c6b2005-12-17 13:41:01 +01004905 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004906 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004907 tv_eternity(&t->srexpire);
4908 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004909 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004910 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01004911 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004912 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004913 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004914 if (!(t->flags & SN_ERR_MASK))
4915 t->flags |= SN_ERR_SRVCL;
4916 if (!(t->flags & SN_FINST_MASK))
4917 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004918 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01004919 return 1;
4920 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004921 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004922 * since we are in header mode, if there's no space left for headers, we
4923 * won't be able to free more later, so the session will never terminate.
4924 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004925 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 +01004926 FD_CLR(t->srv_fd, StaticReadEvent);
4927 tv_eternity(&t->srexpire);
4928 shutdown(t->srv_fd, SHUT_RD);
4929 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004930 //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 +01004931 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004932 }
4933 /* read timeout : return a 504 to the client.
4934 */
4935 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4936 tv_eternity(&t->srexpire);
4937 tv_eternity(&t->swexpire);
4938 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02004939 t->srv->cur_sess--;
willy tarreau8337c6b2005-12-17 13:41:01 +01004940 t->srv_state = SV_STCLOSE;
4941 t->logs.status = 504;
4942 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004943 if (!(t->flags & SN_ERR_MASK))
4944 t->flags |= SN_ERR_SRVTO;
4945 if (!(t->flags & SN_FINST_MASK))
4946 t->flags |= SN_FINST_H;
willy tarreaucfbb2182006-04-07 17:37:55 +02004947 /* TODO : check if there are pending connections on this server */
willy tarreau8337c6b2005-12-17 13:41:01 +01004948 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004949 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004950 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004951 /* FIXME!!! here, we don't want to switch to SHUTW if the
4952 * client shuts read too early, because we may still have
4953 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004954 * The side-effect is that if the client completely closes its
4955 * connection during SV_STHEADER, the connection to the server
4956 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004957 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004958 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004959 FD_CLR(t->srv_fd, StaticWriteEvent);
4960 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004961
4962 /* We must ensure that the read part is still alive when switching
4963 * to shutw */
4964 FD_SET(t->srv_fd, StaticReadEvent);
4965 if (t->proxy->srvtimeout)
4966 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4967
willy tarreau0f7af912005-12-17 12:21:26 +01004968 shutdown(t->srv_fd, SHUT_WR);
4969 t->srv_state = SV_STSHUTW;
4970 return 1;
4971 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004972 /* write timeout */
4973 /* FIXME!!! here, we don't want to switch to SHUTW if the
4974 * client shuts read too early, because we may still have
4975 * some work to do on the headers.
4976 */
4977 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4978 FD_CLR(t->srv_fd, StaticWriteEvent);
4979 tv_eternity(&t->swexpire);
4980 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004981 /* We must ensure that the read part is still alive when switching
4982 * to shutw */
4983 FD_SET(t->srv_fd, StaticReadEvent);
4984 if (t->proxy->srvtimeout)
4985 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4986
4987 /* We must ensure that the read part is still alive when switching
4988 * to shutw */
4989 FD_SET(t->srv_fd, StaticReadEvent);
4990 if (t->proxy->srvtimeout)
4991 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4992
willy tarreau036e1ce2005-12-17 13:46:33 +01004993 t->srv_state = SV_STSHUTW;
4994 if (!(t->flags & SN_ERR_MASK))
4995 t->flags |= SN_ERR_SRVTO;
4996 if (!(t->flags & SN_FINST_MASK))
4997 t->flags |= SN_FINST_H;
4998 return 1;
4999 }
willy tarreau0f7af912005-12-17 12:21:26 +01005000
5001 if (req->l == 0) {
5002 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5003 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5004 tv_eternity(&t->swexpire);
5005 }
5006 }
5007 else { /* client buffer not empty */
5008 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5009 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005010 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005011 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005012 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5013 t->srexpire = t->swexpire;
5014 }
willy tarreau0f7af912005-12-17 12:21:26 +01005015 else
5016 tv_eternity(&t->swexpire);
5017 }
5018 }
5019
willy tarreau5cbea6f2005-12-17 12:48:26 +01005020 /* be nice with the client side which would like to send a complete header
5021 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
5022 * would read all remaining data at once ! The client should not write past rep->lr
5023 * when the server is in header state.
5024 */
5025 //return header_processed;
5026 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01005027 }
5028 else if (s == SV_STDATA) {
5029 /* read or write error */
5030 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01005031 tv_eternity(&t->srexpire);
5032 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005033 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005034 t->srv->cur_sess--;
willy tarreau0f7af912005-12-17 12:21:26 +01005035 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005036 if (!(t->flags & SN_ERR_MASK))
5037 t->flags |= SN_ERR_SRVCL;
5038 if (!(t->flags & SN_FINST_MASK))
5039 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005040 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005041 return 1;
5042 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005043 /* last read, or end of client write */
5044 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005045 FD_CLR(t->srv_fd, StaticReadEvent);
5046 tv_eternity(&t->srexpire);
5047 shutdown(t->srv_fd, SHUT_RD);
5048 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01005049 //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 +01005050 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01005051 }
5052 /* end of client read and no more data to send */
5053 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
5054 FD_CLR(t->srv_fd, StaticWriteEvent);
5055 tv_eternity(&t->swexpire);
5056 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005057 /* We must ensure that the read part is still alive when switching
5058 * to shutw */
5059 FD_SET(t->srv_fd, StaticReadEvent);
5060 if (t->proxy->srvtimeout)
5061 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5062
willy tarreaua41a8b42005-12-17 14:02:24 +01005063 t->srv_state = SV_STSHUTW;
5064 return 1;
5065 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005066 /* read timeout */
5067 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5068 FD_CLR(t->srv_fd, StaticReadEvent);
5069 tv_eternity(&t->srexpire);
5070 shutdown(t->srv_fd, SHUT_RD);
5071 t->srv_state = SV_STSHUTR;
5072 if (!(t->flags & SN_ERR_MASK))
5073 t->flags |= SN_ERR_SRVTO;
5074 if (!(t->flags & SN_FINST_MASK))
5075 t->flags |= SN_FINST_D;
5076 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005077 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005078 /* write timeout */
5079 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005080 FD_CLR(t->srv_fd, StaticWriteEvent);
5081 tv_eternity(&t->swexpire);
5082 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01005083 /* We must ensure that the read part is still alive when switching
5084 * to shutw */
5085 FD_SET(t->srv_fd, StaticReadEvent);
5086 if (t->proxy->srvtimeout)
5087 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01005088 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01005089 if (!(t->flags & SN_ERR_MASK))
5090 t->flags |= SN_ERR_SRVTO;
5091 if (!(t->flags & SN_FINST_MASK))
5092 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01005093 return 1;
5094 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005095
5096 /* recompute request time-outs */
5097 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01005098 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5099 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5100 tv_eternity(&t->swexpire);
5101 }
5102 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01005103 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01005104 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5105 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005106 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005107 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005108 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5109 t->srexpire = t->swexpire;
5110 }
willy tarreau0f7af912005-12-17 12:21:26 +01005111 else
5112 tv_eternity(&t->swexpire);
5113 }
5114 }
5115
willy tarreaub1ff9db2005-12-17 13:51:03 +01005116 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01005117 if (rep->l == BUFSIZE) { /* no room to read more data */
5118 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5119 FD_CLR(t->srv_fd, StaticReadEvent);
5120 tv_eternity(&t->srexpire);
5121 }
5122 }
5123 else {
5124 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5125 FD_SET(t->srv_fd, StaticReadEvent);
5126 if (t->proxy->srvtimeout)
5127 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5128 else
5129 tv_eternity(&t->srexpire);
5130 }
5131 }
5132
5133 return 0; /* other cases change nothing */
5134 }
5135 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005136 if (t->res_sw == RES_ERROR) {
5137 //FD_CLR(t->srv_fd, StaticWriteEvent);
5138 tv_eternity(&t->swexpire);
5139 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005140 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005141 //close(t->srv_fd);
5142 t->srv_state = SV_STCLOSE;
5143 if (!(t->flags & SN_ERR_MASK))
5144 t->flags |= SN_ERR_SRVCL;
5145 if (!(t->flags & SN_FINST_MASK))
5146 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005147 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005148 return 1;
5149 }
5150 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005151 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005152 tv_eternity(&t->swexpire);
5153 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005154 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005155 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005156 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005157 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005158 return 1;
5159 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005160 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
5161 //FD_CLR(t->srv_fd, StaticWriteEvent);
5162 tv_eternity(&t->swexpire);
5163 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005164 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005165 //close(t->srv_fd);
5166 t->srv_state = SV_STCLOSE;
5167 if (!(t->flags & SN_ERR_MASK))
5168 t->flags |= SN_ERR_SRVTO;
5169 if (!(t->flags & SN_FINST_MASK))
5170 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005171 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005172 return 1;
5173 }
willy tarreau0f7af912005-12-17 12:21:26 +01005174 else if (req->l == 0) {
5175 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5176 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
5177 tv_eternity(&t->swexpire);
5178 }
5179 }
5180 else { /* buffer not empty */
5181 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
5182 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01005183 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01005184 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01005185 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
5186 t->srexpire = t->swexpire;
5187 }
willy tarreau0f7af912005-12-17 12:21:26 +01005188 else
5189 tv_eternity(&t->swexpire);
5190 }
5191 }
5192 return 0;
5193 }
5194 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005195 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005196 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01005197 tv_eternity(&t->srexpire);
5198 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005199 t->srv->cur_sess--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005200 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01005201 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01005202 if (!(t->flags & SN_ERR_MASK))
5203 t->flags |= SN_ERR_SRVCL;
5204 if (!(t->flags & SN_FINST_MASK))
5205 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005206 /* TODO : check if there are pending connections on this server */
willy tarreau0f7af912005-12-17 12:21:26 +01005207 return 1;
5208 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005209 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
5210 //FD_CLR(t->srv_fd, StaticReadEvent);
5211 tv_eternity(&t->srexpire);
5212 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005213 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005214 //close(t->srv_fd);
5215 t->srv_state = SV_STCLOSE;
willy tarreaucfbb2182006-04-07 17:37:55 +02005216 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005217 return 1;
5218 }
5219 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
5220 //FD_CLR(t->srv_fd, StaticReadEvent);
5221 tv_eternity(&t->srexpire);
5222 fd_delete(t->srv_fd);
willy tarreaua647c702006-04-15 22:45:52 +02005223 t->srv->cur_sess--;
willy tarreau036e1ce2005-12-17 13:46:33 +01005224 //close(t->srv_fd);
5225 t->srv_state = SV_STCLOSE;
5226 if (!(t->flags & SN_ERR_MASK))
5227 t->flags |= SN_ERR_SRVTO;
5228 if (!(t->flags & SN_FINST_MASK))
5229 t->flags |= SN_FINST_D;
willy tarreaucfbb2182006-04-07 17:37:55 +02005230 /* TODO : check if there are pending connections on this server */
willy tarreau036e1ce2005-12-17 13:46:33 +01005231 return 1;
5232 }
willy tarreau0f7af912005-12-17 12:21:26 +01005233 else if (rep->l == BUFSIZE) { /* no room to read more data */
5234 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
5235 FD_CLR(t->srv_fd, StaticReadEvent);
5236 tv_eternity(&t->srexpire);
5237 }
5238 }
5239 else {
5240 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
5241 FD_SET(t->srv_fd, StaticReadEvent);
5242 if (t->proxy->srvtimeout)
5243 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
5244 else
5245 tv_eternity(&t->srexpire);
5246 }
5247 }
5248 return 0;
5249 }
5250 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01005251 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005252 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005253 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 +01005254 write(1, trash, len);
5255 }
5256 return 0;
5257 }
5258 return 0;
5259}
5260
5261
willy tarreau5cbea6f2005-12-17 12:48:26 +01005262/* Processes the client and server jobs of a session task, then
5263 * puts it back to the wait queue in a clean state, or
5264 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005265 * the time the task accepts to wait, or TIME_ETERNITY for
5266 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01005267 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005268int process_session(struct task *t) {
5269 struct session *s = t->context;
5270 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005271
willy tarreau5cbea6f2005-12-17 12:48:26 +01005272 do {
5273 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01005274 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005275 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005276 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005277 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01005278 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005279 } while (fsm_resync);
5280
5281 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01005282 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005283 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01005284
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 tv_min(&min1, &s->crexpire, &s->cwexpire);
5286 tv_min(&min2, &s->srexpire, &s->swexpire);
5287 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01005288 tv_min(&t->expire, &min1, &min2);
5289
5290 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005291 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01005292
Willy TARREAU1cec83c2006-03-01 22:33:49 +01005293#ifdef DEBUG_FULL
5294 /* DEBUG code : this should never ever happen, otherwise it indicates
5295 * that a task still has something to do and will provoke a quick loop.
5296 */
5297 if (tv_remain2(&now, &t->expire) <= 0)
5298 exit(100);
5299#endif
5300
willy tarreaub952e1d2005-12-18 01:31:20 +01005301 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01005302 }
5303
willy tarreau5cbea6f2005-12-17 12:48:26 +01005304 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01005305 actconn--;
5306
willy tarreau982249e2005-12-18 00:57:06 +01005307 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01005308 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01005309 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 +01005310 write(1, trash, len);
5311 }
5312
willy tarreau750a4722005-12-17 13:21:24 +01005313 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005314 if (s->rep != NULL)
5315 s->logs.bytes = s->rep->total;
5316
willy tarreau9fe663a2005-12-17 13:02:59 +01005317 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005318 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005319 sess_log(s);
5320
willy tarreau0f7af912005-12-17 12:21:26 +01005321 /* the task MUST not be in the run queue anymore */
5322 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005323 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005324 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005325 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005326}
5327
5328
5329
5330/*
5331 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005332 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005333 */
5334int process_chk(struct task *t) {
5335 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005336 struct sockaddr_in sa;
willy tarreau25424f82006-03-19 19:37:48 +01005337 int fd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005338
willy tarreauef900ab2005-12-17 12:52:52 +01005339 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005340
willy tarreau25424f82006-03-19 19:37:48 +01005341 new_chk:
5342 fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005343 if (fd < 0) { /* no check currently running */
5344 //fprintf(stderr, "process_chk: 2\n");
5345 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5346 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005347 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005348 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005349
5350 /* we don't send any health-checks when the proxy is stopped or when
5351 * the server should not be checked.
5352 */
5353 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
willy tarreau25424f82006-03-19 19:37:48 +01005354 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5355 tv_delayfrom(&t->expire, &t->expire, s->inter);
Willy TARREAU3759f982006-03-01 22:44:17 +01005356 task_queue(t); /* restore t to its place in the task list */
5357 return tv_remain2(&now, &t->expire);
5358 }
5359
willy tarreau5cbea6f2005-12-17 12:48:26 +01005360 /* we'll initiate a new check */
5361 s->result = 0; /* no result yet */
5362 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005363 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005364 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5365 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5366 //fprintf(stderr, "process_chk: 3\n");
5367
willy tarreaua41a8b42005-12-17 14:02:24 +01005368 /* we'll connect to the check port on the server */
5369 sa = s->addr;
5370 sa.sin_port = htons(s->check_port);
5371
willy tarreau0174f312005-12-18 01:02:42 +01005372 /* allow specific binding :
5373 * - server-specific at first
5374 * - proxy-specific next
5375 */
5376 if (s->state & SRV_BIND_SRC) {
5377 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5378 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5379 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5380 s->proxy->id, s->id);
5381 s->result = -1;
5382 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005383 }
willy tarreau0174f312005-12-18 01:02:42 +01005384 else if (s->proxy->options & PR_O_BIND_SRC) {
5385 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5386 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5387 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5388 s->proxy->id);
5389 s->result = -1;
5390 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005391 }
willy tarreau0174f312005-12-18 01:02:42 +01005392
5393 if (!s->result) {
5394 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5395 /* OK, connection in progress or established */
5396
5397 //fprintf(stderr, "process_chk: 4\n");
5398
5399 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5400 fdtab[fd].owner = t;
5401 fdtab[fd].read = &event_srv_chk_r;
5402 fdtab[fd].write = &event_srv_chk_w;
5403 fdtab[fd].state = FD_STCONN; /* connection in progress */
5404 FD_SET(fd, StaticWriteEvent); /* for connect status */
willy tarreau05be12b2006-03-19 19:35:00 +01005405#ifdef DEBUG_FULL
5406 assert (!FD_ISSET(fd, StaticReadEvent));
5407#endif
willy tarreau0174f312005-12-18 01:02:42 +01005408 fd_insert(fd);
5409 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5410 tv_delayfrom(&t->expire, &now, s->inter);
5411 task_queue(t); /* restore t to its place in the task list */
5412 return tv_remain(&now, &t->expire);
5413 }
5414 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5415 s->result = -1; /* a real error */
5416 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005417 }
5418 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005419 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005420 }
5421
5422 if (!s->result) { /* nothing done */
5423 //fprintf(stderr, "process_chk: 6\n");
willy tarreau25424f82006-03-19 19:37:48 +01005424 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5425 tv_delayfrom(&t->expire, &t->expire, s->inter);
5426 goto new_chk; /* may be we should initialize a new check */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005427 }
5428
5429 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005430 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005431 s->health--; /* still good */
5432 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005433 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005434 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005435 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005436 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005437 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5438 s->state & SRV_BACKUP ? "Backup " : "",
5439 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5440 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5441 send_log(s->proxy, LOG_ALERT,
5442 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5443 s->state & SRV_BACKUP ? "Backup " : "",
5444 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5445 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreauef900ab2005-12-17 12:52:52 +01005446
willy tarreau62084d42006-03-24 18:57:41 +01005447 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
willy tarreaudd07e972005-12-18 00:48:48 +01005448 Alert("Proxy %s has no server available !\n", s->proxy->id);
5449 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5450 }
5451 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005452 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005453 }
5454
5455 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005456 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
willy tarreau25424f82006-03-19 19:37:48 +01005457 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5458 tv_delayfrom(&t->expire, &t->expire, s->inter);
5459 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005460 }
5461 else {
5462 //fprintf(stderr, "process_chk: 8\n");
5463 /* there was a test running */
5464 if (s->result > 0) { /* good server detected */
5465 //fprintf(stderr, "process_chk: 9\n");
5466 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005467 if (s->health >= s->rise) {
willy tarreau06a12052006-03-30 14:06:51 +02005468 s->state |= SRV_RUNNING;
5469
willy tarreau535ae7a2005-12-17 12:58:00 +01005470 if (s->health == s->rise) {
willy tarreau62084d42006-03-24 18:57:41 +01005471 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005472 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005473 Warning("%sServer %s/%s UP. %d active and %d backup servers online.%s\n",
5474 s->state & SRV_BACKUP ? "Backup " : "",
5475 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5476 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5477 send_log(s->proxy, LOG_NOTICE,
5478 "%sServer %s/%s is UP. %d active and %d backup servers online.%s\n",
5479 s->state & SRV_BACKUP ? "Backup " : "",
5480 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5481 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
willy tarreau535ae7a2005-12-17 12:58:00 +01005482 }
willy tarreauef900ab2005-12-17 12:52:52 +01005483
willy tarreaue47c8d72005-12-17 12:55:52 +01005484 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005485 }
willy tarreauef900ab2005-12-17 12:52:52 +01005486 s->curfd = -1; /* no check running anymore */
5487 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005488 fd_delete(fd);
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 if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5494 //fprintf(stderr, "process_chk: 10\n");
5495 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005496 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005497 s->health--; /* still good */
5498 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005499 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005500
willy tarreau62084d42006-03-24 18:57:41 +01005501 if (s->health == s->rise) {
5502 recount_servers(s->proxy);
willy tarreaucc1e2bd2006-04-10 20:32:43 +02005503 recalc_server_map(s->proxy);
willy tarreau62084d42006-03-24 18:57:41 +01005504 Warning("%sServer %s/%s DOWN. %d active and %d backup servers left.%s\n",
5505 s->state & SRV_BACKUP ? "Backup " : "",
5506 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5507 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5508 send_log(s->proxy, LOG_ALERT,
5509 "%sServer %s/%s is DOWN. %d active and %d backup servers left.%s\n",
5510 s->state & SRV_BACKUP ? "Backup " : "",
5511 s->proxy->id, s->id, s->proxy->srv_act, s->proxy->srv_bck,
5512 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "");
5513
5514 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
5515 Alert("Proxy %s has no server available !\n", s->proxy->id);
5516 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5517 }
5518 }
willy tarreauef900ab2005-12-17 12:52:52 +01005519
willy tarreau5cbea6f2005-12-17 12:48:26 +01005520 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005521 }
5522 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005523 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005524 fd_delete(fd);
willy tarreau25424f82006-03-19 19:37:48 +01005525 while (tv_cmp2_ms(&t->expire, &now) <= 0)
5526 tv_delayfrom(&t->expire, &t->expire, s->inter);
5527 goto new_chk;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005528 }
5529 /* if result is 0 and there's no timeout, we have to wait again */
5530 }
5531 //fprintf(stderr, "process_chk: 11\n");
5532 s->result = 0;
5533 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005534 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005535}
5536
5537
willy tarreau5cbea6f2005-12-17 12:48:26 +01005538
willy tarreau0f7af912005-12-17 12:21:26 +01005539#if STATTIME > 0
5540int stats(void);
5541#endif
5542
5543/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005544 * This does 4 things :
5545 * - wake up all expired tasks
5546 * - call all runnable tasks
5547 * - call maintain_proxies() to enable/disable the listeners
5548 * - return the delay till next event in ms, -1 = wait indefinitely
5549 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5550 *
willy tarreau0f7af912005-12-17 12:21:26 +01005551 */
5552
willy tarreau1c2ad212005-12-18 01:11:29 +01005553int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005554 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005555 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005556 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005557
willy tarreaub952e1d2005-12-18 01:31:20 +01005558 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005559
willy tarreau1c2ad212005-12-18 01:11:29 +01005560 /* look for expired tasks and add them to the run queue.
5561 */
5562 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5563 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5564 tnext = t->next;
5565 if (t->state & TASK_RUNNING)
5566 continue;
5567
willy tarreaub952e1d2005-12-18 01:31:20 +01005568 if (tv_iseternity(&t->expire))
5569 continue;
5570
willy tarreau1c2ad212005-12-18 01:11:29 +01005571 /* wakeup expired entries. It doesn't matter if they are
5572 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005573 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005574 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005575 task_wakeup(&rq, t);
5576 }
5577 else {
5578 /* first non-runnable task. Use its expiration date as an upper bound */
5579 int temp_time = tv_remain(&now, &t->expire);
5580 if (temp_time)
5581 next_time = temp_time;
5582 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005583 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005584 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005585
willy tarreau1c2ad212005-12-18 01:11:29 +01005586 /* process each task in the run queue now. Each task may be deleted
5587 * since we only use tnext.
5588 */
5589 tnext = rq;
5590 while ((t = tnext) != NULL) {
5591 int temp_time;
5592
5593 tnext = t->rqnext;
5594 task_sleep(&rq, t);
5595 temp_time = t->process(t);
5596 next_time = MINTIME(temp_time, next_time);
5597 }
5598
5599 /* maintain all proxies in a consistent state. This should quickly become a task */
5600 time2 = maintain_proxies();
5601 return MINTIME(time2, next_time);
5602}
5603
5604
5605#if defined(ENABLE_EPOLL)
5606
5607/*
5608 * Main epoll() loop.
5609 */
5610
5611/* does 3 actions :
5612 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5613 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5614 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5615 *
5616 * returns 0 if initialization failed, !0 otherwise.
5617 */
5618
5619int epoll_loop(int action) {
5620 int next_time;
5621 int status;
5622 int fd;
5623
5624 int fds, count;
5625 int pr, pw, sr, sw;
5626 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5627 struct epoll_event ev;
5628
5629 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005630 static struct epoll_event *epoll_events = NULL;
5631 static int epoll_fd;
5632
5633 if (action == POLL_LOOP_ACTION_INIT) {
5634 epoll_fd = epoll_create(global.maxsock + 1);
5635 if (epoll_fd < 0)
5636 return 0;
5637 else {
5638 epoll_events = (struct epoll_event*)
5639 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5640 PrevReadEvent = (fd_set *)
5641 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5642 PrevWriteEvent = (fd_set *)
5643 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005644 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005645 return 1;
5646 }
5647 else if (action == POLL_LOOP_ACTION_CLEAN) {
5648 if (PrevWriteEvent) free(PrevWriteEvent);
5649 if (PrevReadEvent) free(PrevReadEvent);
5650 if (epoll_events) free(epoll_events);
5651 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005652 epoll_fd = 0;
5653 return 1;
5654 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005655
willy tarreau1c2ad212005-12-18 01:11:29 +01005656 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005657
willy tarreau1c2ad212005-12-18 01:11:29 +01005658 tv_now(&now);
5659
5660 while (1) {
5661 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005662
5663 /* stop when there's no connection left and we don't allow them anymore */
5664 if (!actconn && listeners == 0)
5665 break;
5666
willy tarreau0f7af912005-12-17 12:21:26 +01005667#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005668 {
5669 int time2;
5670 time2 = stats();
5671 next_time = MINTIME(time2, next_time);
5672 }
willy tarreau0f7af912005-12-17 12:21:26 +01005673#endif
5674
willy tarreau1c2ad212005-12-18 01:11:29 +01005675 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5676
5677 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5678 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5679
5680 if ((ro^rn) | (wo^wn)) {
5681 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5682#define FDSETS_ARE_INT_ALIGNED
5683#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005684
willy tarreauad90a0c2005-12-18 01:09:15 +01005685#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5686#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005687 pr = (ro >> count) & 1;
5688 pw = (wo >> count) & 1;
5689 sr = (rn >> count) & 1;
5690 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005691#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005692 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5693 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5694 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5695 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005696#endif
5697#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005698 pr = FD_ISSET(fd, PrevReadEvent);
5699 pw = FD_ISSET(fd, PrevWriteEvent);
5700 sr = FD_ISSET(fd, StaticReadEvent);
5701 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005702#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005703 if (!((sr^pr) | (sw^pw)))
5704 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005705
willy tarreau1c2ad212005-12-18 01:11:29 +01005706 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5707 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005708
willy tarreaub952e1d2005-12-18 01:31:20 +01005709#ifdef EPOLL_CTL_MOD_WORKAROUND
5710 /* I encountered a rarely reproducible problem with
5711 * EPOLL_CTL_MOD where a modified FD (systematically
5712 * the one in epoll_events[0], fd#7) would sometimes
5713 * be set EPOLL_OUT while asked for a read ! This is
5714 * with the 2.4 epoll patch. The workaround is to
5715 * delete then recreate in case of modification.
5716 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5717 * nor RHEL kernels.
5718 */
5719
5720 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5721 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5722
5723 if ((sr | sw))
5724 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5725#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005726 if ((pr | pw)) {
5727 /* the file-descriptor already exists... */
5728 if ((sr | sw)) {
5729 /* ...and it will still exist */
5730 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5731 // perror("epoll_ctl(MOD)");
5732 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005733 }
5734 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005735 /* ...and it will be removed */
5736 if (fdtab[fd].state != FD_STCLOSE &&
5737 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5738 // perror("epoll_ctl(DEL)");
5739 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005740 }
5741 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005742 } else {
5743 /* the file-descriptor did not exist, let's add it */
5744 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5745 // perror("epoll_ctl(ADD)");
5746 // exit(1);
5747 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005748 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005749#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005750 }
5751 ((int*)PrevReadEvent)[fds] = rn;
5752 ((int*)PrevWriteEvent)[fds] = wn;
5753 }
5754 }
5755
5756 /* now let's wait for events */
5757 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5758 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005759
willy tarreau1c2ad212005-12-18 01:11:29 +01005760 for (count = 0; count < status; count++) {
5761 fd = epoll_events[count].data.fd;
willy tarreau05be12b2006-03-19 19:35:00 +01005762
5763 if (FD_ISSET(fd, StaticReadEvent)) {
5764 if (fdtab[fd].state == FD_STCLOSE)
5765 continue;
5766 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5767 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005768 }
willy tarreau05be12b2006-03-19 19:35:00 +01005769
5770 if (FD_ISSET(fd, StaticWriteEvent)) {
5771 if (fdtab[fd].state == FD_STCLOSE)
5772 continue;
5773 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5774 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005775 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005776 }
5777 }
5778 return 1;
5779}
5780#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005781
willy tarreauad90a0c2005-12-18 01:09:15 +01005782
willy tarreau5cbea6f2005-12-17 12:48:26 +01005783
willy tarreau1c2ad212005-12-18 01:11:29 +01005784#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005785
willy tarreau1c2ad212005-12-18 01:11:29 +01005786/*
5787 * Main poll() loop.
5788 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005789
willy tarreau1c2ad212005-12-18 01:11:29 +01005790/* does 3 actions :
5791 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5792 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5793 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5794 *
5795 * returns 0 if initialization failed, !0 otherwise.
5796 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005797
willy tarreau1c2ad212005-12-18 01:11:29 +01005798int poll_loop(int action) {
5799 int next_time;
5800 int status;
5801 int fd, nbfd;
5802
5803 int fds, count;
5804 int sr, sw;
5805 unsigned rn, wn; /* read new, write new */
5806
5807 /* private data */
5808 static struct pollfd *poll_events = NULL;
5809
5810 if (action == POLL_LOOP_ACTION_INIT) {
5811 poll_events = (struct pollfd*)
5812 calloc(1, sizeof(struct pollfd) * global.maxsock);
5813 return 1;
5814 }
5815 else if (action == POLL_LOOP_ACTION_CLEAN) {
5816 if (poll_events)
5817 free(poll_events);
5818 return 1;
5819 }
5820
5821 /* OK, it's POLL_LOOP_ACTION_RUN */
5822
5823 tv_now(&now);
5824
5825 while (1) {
5826 next_time = process_runnable_tasks();
5827
5828 /* stop when there's no connection left and we don't allow them anymore */
5829 if (!actconn && listeners == 0)
5830 break;
5831
5832#if STATTIME > 0
5833 {
5834 int time2;
5835 time2 = stats();
5836 next_time = MINTIME(time2, next_time);
5837 }
5838#endif
5839
5840
5841 nbfd = 0;
5842 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5843
5844 rn = ((int*)StaticReadEvent)[fds];
5845 wn = ((int*)StaticWriteEvent)[fds];
5846
5847 if ((rn|wn)) {
5848 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5849#define FDSETS_ARE_INT_ALIGNED
5850#ifdef FDSETS_ARE_INT_ALIGNED
5851
5852#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5853#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5854 sr = (rn >> count) & 1;
5855 sw = (wn >> count) & 1;
5856#else
5857 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5858 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5859#endif
5860#else
5861 sr = FD_ISSET(fd, StaticReadEvent);
5862 sw = FD_ISSET(fd, StaticWriteEvent);
5863#endif
5864 if ((sr|sw)) {
5865 poll_events[nbfd].fd = fd;
5866 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5867 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005868 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005869 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005870 }
5871 }
5872
5873 /* now let's wait for events */
5874 status = poll(poll_events, nbfd, next_time);
5875 tv_now(&now);
5876
5877 for (count = 0; status > 0 && count < nbfd; count++) {
5878 fd = poll_events[count].fd;
5879
5880 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5881 continue;
5882
5883 /* ok, we found one active fd */
5884 status--;
5885
willy tarreau05be12b2006-03-19 19:35:00 +01005886 if (FD_ISSET(fd, StaticReadEvent)) {
5887 if (fdtab[fd].state == FD_STCLOSE)
5888 continue;
5889 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5890 fdtab[fd].read(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005891 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005892
willy tarreau05be12b2006-03-19 19:35:00 +01005893 if (FD_ISSET(fd, StaticWriteEvent)) {
5894 if (fdtab[fd].state == FD_STCLOSE)
5895 continue;
5896 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5897 fdtab[fd].write(fd);
Willy TARREAUe78ae262006-01-08 01:24:12 +01005898 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005899 }
5900 }
5901 return 1;
5902}
willy tarreauad90a0c2005-12-18 01:09:15 +01005903#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005904
willy tarreauad90a0c2005-12-18 01:09:15 +01005905
willy tarreauad90a0c2005-12-18 01:09:15 +01005906
willy tarreau1c2ad212005-12-18 01:11:29 +01005907/*
5908 * Main select() loop.
5909 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005910
willy tarreau1c2ad212005-12-18 01:11:29 +01005911/* does 3 actions :
5912 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5913 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5914 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5915 *
5916 * returns 0 if initialization failed, !0 otherwise.
5917 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005918
willy tarreauad90a0c2005-12-18 01:09:15 +01005919
willy tarreau1c2ad212005-12-18 01:11:29 +01005920int select_loop(int action) {
5921 int next_time;
5922 int status;
5923 int fd,i;
5924 struct timeval delta;
5925 int readnotnull, writenotnull;
5926 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005927
willy tarreau1c2ad212005-12-18 01:11:29 +01005928 if (action == POLL_LOOP_ACTION_INIT) {
5929 ReadEvent = (fd_set *)
5930 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5931 WriteEvent = (fd_set *)
5932 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5933 return 1;
5934 }
5935 else if (action == POLL_LOOP_ACTION_CLEAN) {
5936 if (WriteEvent) free(WriteEvent);
5937 if (ReadEvent) free(ReadEvent);
5938 return 1;
5939 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005940
willy tarreau1c2ad212005-12-18 01:11:29 +01005941 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005942
willy tarreau1c2ad212005-12-18 01:11:29 +01005943 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005944
willy tarreau1c2ad212005-12-18 01:11:29 +01005945 while (1) {
5946 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005947
willy tarreau1c2ad212005-12-18 01:11:29 +01005948 /* stop when there's no connection left and we don't allow them anymore */
5949 if (!actconn && listeners == 0)
5950 break;
5951
5952#if STATTIME > 0
5953 {
5954 int time2;
5955 time2 = stats();
5956 next_time = MINTIME(time2, next_time);
5957 }
5958#endif
5959
willy tarreau1c2ad212005-12-18 01:11:29 +01005960 if (next_time > 0) { /* FIXME */
5961 /* Convert to timeval */
5962 /* to avoid eventual select loops due to timer precision */
5963 next_time += SCHEDULER_RESOLUTION;
5964 delta.tv_sec = next_time / 1000;
5965 delta.tv_usec = (next_time % 1000) * 1000;
5966 }
5967 else if (next_time == 0) { /* allow select to return immediately when needed */
5968 delta.tv_sec = delta.tv_usec = 0;
5969 }
5970
5971
5972 /* let's restore fdset state */
5973
5974 readnotnull = 0; writenotnull = 0;
5975 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5976 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5977 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5978 }
5979
5980 // /* just a verification code, needs to be removed for performance */
5981 // for (i=0; i<maxfd; i++) {
5982 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5983 // abort();
5984 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5985 // abort();
5986 //
5987 // }
5988
5989 status = select(maxfd,
5990 readnotnull ? ReadEvent : NULL,
5991 writenotnull ? WriteEvent : NULL,
5992 NULL,
5993 (next_time >= 0) ? &delta : NULL);
5994
5995 /* this is an experiment on the separation of the select work */
5996 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5997 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5998
5999 tv_now(&now);
6000
6001 if (status > 0) { /* must proceed with events */
6002
6003 int fds;
6004 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01006005
willy tarreau1c2ad212005-12-18 01:11:29 +01006006 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
6007 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
6008 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
6009
6010 /* if we specify read first, the accepts and zero reads will be
6011 * seen first. Moreover, system buffers will be flushed faster.
6012 */
willy tarreau05be12b2006-03-19 19:35:00 +01006013 if (FD_ISSET(fd, ReadEvent)) {
6014 if (fdtab[fd].state == FD_STCLOSE)
6015 continue;
6016 fdtab[fd].read(fd);
6017 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006018
willy tarreau05be12b2006-03-19 19:35:00 +01006019 if (FD_ISSET(fd, WriteEvent)) {
6020 if (fdtab[fd].state == FD_STCLOSE)
6021 continue;
6022 fdtab[fd].write(fd);
6023 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006024 }
6025 }
6026 else {
6027 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01006028 }
willy tarreau0f7af912005-12-17 12:21:26 +01006029 }
willy tarreau1c2ad212005-12-18 01:11:29 +01006030 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01006031}
6032
6033
6034#if STATTIME > 0
6035/*
6036 * Display proxy statistics regularly. It is designed to be called from the
6037 * select_loop().
6038 */
6039int stats(void) {
6040 static int lines;
6041 static struct timeval nextevt;
6042 static struct timeval lastevt;
6043 static struct timeval starttime = {0,0};
6044 unsigned long totaltime, deltatime;
6045 int ret;
6046
willy tarreau750a4722005-12-17 13:21:24 +01006047 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01006048 deltatime = (tv_diff(&lastevt, &now)?:1);
6049 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01006050
willy tarreau9fe663a2005-12-17 13:02:59 +01006051 if (global.mode & MODE_STATS) {
6052 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006053 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01006054 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
6055 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006056 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01006057 actconn, totalconn,
6058 stats_tsk_new, stats_tsk_good,
6059 stats_tsk_left, stats_tsk_right,
6060 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
6061 }
6062 }
6063
6064 tv_delayfrom(&nextevt, &now, STATTIME);
6065
6066 lastevt=now;
6067 }
6068 ret = tv_remain(&now, &nextevt);
6069 return ret;
6070}
6071#endif
6072
6073
6074/*
6075 * this function enables proxies when there are enough free sessions,
6076 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01006077 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01006078 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01006079 */
6080static int maintain_proxies(void) {
6081 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01006082 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006083 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01006084
6085 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01006086 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01006087
6088 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01006089 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01006090 while (p) {
6091 if (p->nbconn < p->maxconn) {
6092 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006093 for (l = p->listen; l != NULL; l = l->next) {
6094 FD_SET(l->fd, StaticReadEvent);
6095 }
willy tarreau0f7af912005-12-17 12:21:26 +01006096 p->state = PR_STRUN;
6097 }
6098 }
6099 else {
6100 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006101 for (l = p->listen; l != NULL; l = l->next) {
6102 FD_CLR(l->fd, StaticReadEvent);
6103 }
willy tarreau0f7af912005-12-17 12:21:26 +01006104 p->state = PR_STIDLE;
6105 }
6106 }
6107 p = p->next;
6108 }
6109 }
6110 else { /* block all proxies */
6111 while (p) {
6112 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006113 for (l = p->listen; l != NULL; l = l->next) {
6114 FD_CLR(l->fd, StaticReadEvent);
6115 }
willy tarreau0f7af912005-12-17 12:21:26 +01006116 p->state = PR_STIDLE;
6117 }
6118 p = p->next;
6119 }
6120 }
6121
willy tarreau5cbea6f2005-12-17 12:48:26 +01006122 if (stopping) {
6123 p = proxy;
6124 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01006125 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006126 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01006127 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006128 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006129 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01006130 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01006131
willy tarreaua41a8b42005-12-17 14:02:24 +01006132 for (l = p->listen; l != NULL; l = l->next) {
6133 fd_delete(l->fd);
6134 listeners--;
6135 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01006136 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006137 }
6138 else {
6139 tleft = MINTIME(t, tleft);
6140 }
6141 }
6142 p = p->next;
6143 }
6144 }
6145 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01006146}
6147
6148/*
6149 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01006150 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
6151 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01006152 */
6153static void soft_stop(void) {
6154 struct proxy *p;
6155
6156 stopping = 1;
6157 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006158 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01006159 while (p) {
Willy TARREAU2bfdd8e2006-03-12 18:03:05 +01006160 if (p->state != PR_STSTOPPED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01006161 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01006162 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01006163 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01006164 }
willy tarreau0f7af912005-12-17 12:21:26 +01006165 p = p->next;
6166 }
6167}
6168
willy tarreaudbd3bef2006-01-20 19:35:18 +01006169static void pause_proxy(struct proxy *p) {
6170 struct listener *l;
6171 for (l = p->listen; l != NULL; l = l->next) {
6172 shutdown(l->fd, SHUT_RD);
6173 FD_CLR(l->fd, StaticReadEvent);
6174 p->state = PR_STPAUSED;
6175 }
6176}
6177
6178/*
6179 * This function temporarily disables listening so that another new instance
6180 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01006181 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01006182 * the proxy, or a SIGTTIN can be sent to listen again.
6183 */
6184static void pause_proxies(void) {
6185 struct proxy *p;
6186
6187 p = proxy;
6188 tv_now(&now); /* else, the old time before select will be used */
6189 while (p) {
6190 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
6191 Warning("Pausing proxy %s.\n", p->id);
6192 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
6193 pause_proxy(p);
6194 }
6195 p = p->next;
6196 }
6197}
6198
6199
6200/*
6201 * This function reactivates listening. This can be used after a call to
6202 * sig_pause(), for example when a new instance has failed starting up.
6203 * It is designed to be called upon reception of a SIGTTIN.
6204 */
6205static void listen_proxies(void) {
6206 struct proxy *p;
6207 struct listener *l;
6208
6209 p = proxy;
6210 tv_now(&now); /* else, the old time before select will be used */
6211 while (p) {
6212 if (p->state == PR_STPAUSED) {
6213 Warning("Enabling proxy %s.\n", p->id);
6214 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
6215
6216 for (l = p->listen; l != NULL; l = l->next) {
6217 if (listen(l->fd, p->maxconn) == 0) {
6218 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
6219 FD_SET(l->fd, StaticReadEvent);
6220 p->state = PR_STRUN;
6221 }
6222 else
6223 p->state = PR_STIDLE;
6224 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01006225 int port;
6226
6227 if (l->addr.ss_family == AF_INET6)
6228 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
6229 else
6230 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
6231
willy tarreaudbd3bef2006-01-20 19:35:18 +01006232 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006233 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006234 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01006235 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01006236 /* Another port might have been enabled. Let's stop everything. */
6237 pause_proxy(p);
6238 break;
6239 }
6240 }
6241 }
6242 p = p->next;
6243 }
6244}
6245
6246
willy tarreau0f7af912005-12-17 12:21:26 +01006247/*
6248 * upon SIGUSR1, let's have a soft stop.
6249 */
6250void sig_soft_stop(int sig) {
6251 soft_stop();
6252 signal(sig, SIG_IGN);
6253}
6254
willy tarreaudbd3bef2006-01-20 19:35:18 +01006255/*
6256 * upon SIGTTOU, we pause everything
6257 */
6258void sig_pause(int sig) {
6259 pause_proxies();
6260 signal(sig, sig_pause);
6261}
willy tarreau0f7af912005-12-17 12:21:26 +01006262
willy tarreau8337c6b2005-12-17 13:41:01 +01006263/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01006264 * upon SIGTTIN, let's have a soft stop.
6265 */
6266void sig_listen(int sig) {
6267 listen_proxies();
6268 signal(sig, sig_listen);
6269}
6270
6271/*
willy tarreau8337c6b2005-12-17 13:41:01 +01006272 * this function dumps every server's state when the process receives SIGHUP.
6273 */
6274void sig_dump_state(int sig) {
6275 struct proxy *p = proxy;
6276
6277 Warning("SIGHUP received, dumping servers states.\n");
6278 while (p) {
6279 struct server *s = p->srv;
6280
6281 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
6282 while (s) {
6283 if (s->state & SRV_RUNNING) {
willy tarreau14b4d432006-04-07 18:23:29 +02006284 snprintf(trash, sizeof(trash),
6285 "SIGHUP: Server %s/%s is UP. Conn: %d act, %d tot.",
6286 p->id, s->id, s->cur_sess, s->cum_sess);
6287 } else {
6288 snprintf(trash, sizeof(trash),
6289 "SIGHUP: Server %s/%s is DOWN. Conn: %d act, %d tot.",
6290 p->id, s->id, s->cur_sess, s->cum_sess);
willy tarreau8337c6b2005-12-17 13:41:01 +01006291 }
willy tarreau14b4d432006-04-07 18:23:29 +02006292 Warning("%s\n", trash);
6293 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreau8337c6b2005-12-17 13:41:01 +01006294 s = s->next;
6295 }
willy tarreaudd07e972005-12-18 00:48:48 +01006296
willy tarreau62084d42006-03-24 18:57:41 +01006297 if (p->srv_act == 0) {
6298 if (p->srv_bck) {
willy tarreau14b4d432006-04-07 18:23:29 +02006299 snprintf(trash, sizeof(trash),
6300 "SIGHUP: Proxy %s is running on backup servers ! Conn: %d act, %d tot.",
6301 p->id, p->nbconn, p->cum_conn);
6302 } else {
6303 snprintf(trash, sizeof(trash),
6304 "SIGHUP: Proxy %s has no server availble ! Conn: %d act, %d tot.",
6305 p->id, p->nbconn, p->cum_conn);
6306 }
6307 } else {
6308 snprintf(trash, sizeof(trash),
6309 "SIGHUP: Proxy %s has %d active servers and %d backup servers availble. Conn: %d act, %d tot.",
6310 p->id, p->srv_act, p->srv_bck, p->nbconn, p->cum_conn);
6311 }
6312 Warning("%s\n", trash);
6313 send_log(p, LOG_NOTICE, "%s\n", trash);
willy tarreaudd07e972005-12-18 00:48:48 +01006314
willy tarreau8337c6b2005-12-17 13:41:01 +01006315 p = p->next;
6316 }
6317 signal(sig, sig_dump_state);
6318}
6319
willy tarreau0f7af912005-12-17 12:21:26 +01006320void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006321 struct task *t, *tnext;
6322 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01006323
willy tarreau5cbea6f2005-12-17 12:48:26 +01006324 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
6325 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
6326 tnext = t->next;
6327 s = t->context;
6328 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
6329 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
6330 "req=%d, rep=%d, clifd=%d\n",
6331 s, tv_remain(&now, &t->expire),
6332 s->cli_state,
6333 s->srv_state,
6334 FD_ISSET(s->cli_fd, StaticReadEvent),
6335 FD_ISSET(s->cli_fd, StaticWriteEvent),
6336 FD_ISSET(s->srv_fd, StaticReadEvent),
6337 FD_ISSET(s->srv_fd, StaticWriteEvent),
6338 s->req->l, s->rep?s->rep->l:0, s->cli_fd
6339 );
willy tarreau0f7af912005-12-17 12:21:26 +01006340 }
willy tarreau12350152005-12-18 01:03:27 +01006341}
6342
willy tarreau64a3cc32005-12-18 01:13:11 +01006343#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01006344static void fast_stop(void)
6345{
6346 struct proxy *p;
6347 p = proxy;
6348 while (p) {
6349 p->grace = 0;
6350 p = p->next;
6351 }
6352 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01006353}
6354
willy tarreau12350152005-12-18 01:03:27 +01006355void sig_int(int sig) {
6356 /* This would normally be a hard stop,
6357 but we want to be sure about deallocation,
6358 and so on, so we do a soft stop with
6359 0 GRACE time
6360 */
6361 fast_stop();
6362 /* If we are killed twice, we decide to die*/
6363 signal(sig, SIG_DFL);
6364}
6365
6366void sig_term(int sig) {
6367 /* This would normally be a hard stop,
6368 but we want to be sure about deallocation,
6369 and so on, so we do a soft stop with
6370 0 GRACE time
6371 */
6372 fast_stop();
6373 /* If we are killed twice, we decide to die*/
6374 signal(sig, SIG_DFL);
6375}
willy tarreau64a3cc32005-12-18 01:13:11 +01006376#endif
willy tarreau12350152005-12-18 01:03:27 +01006377
willy tarreauc1f47532005-12-18 01:08:26 +01006378/* returns the pointer to an error in the replacement string, or NULL if OK */
6379char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006380 struct hdr_exp *exp;
6381
willy tarreauc1f47532005-12-18 01:08:26 +01006382 if (replace != NULL) {
6383 char *err;
6384 err = check_replace_string(replace);
6385 if (err)
6386 return err;
6387 }
6388
willy tarreaue39cd132005-12-17 13:00:18 +01006389 while (*head != NULL)
6390 head = &(*head)->next;
6391
6392 exp = calloc(1, sizeof(struct hdr_exp));
6393
6394 exp->preg = preg;
6395 exp->replace = replace;
6396 exp->action = action;
6397 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006398
6399 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006400}
6401
willy tarreau9fe663a2005-12-17 13:02:59 +01006402
willy tarreau0f7af912005-12-17 12:21:26 +01006403/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006405 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006406int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006407
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 if (!strcmp(args[0], "global")) { /* new section */
6409 /* no option, nothing special to do */
6410 return 0;
6411 }
6412 else if (!strcmp(args[0], "daemon")) {
6413 global.mode |= MODE_DAEMON;
6414 }
6415 else if (!strcmp(args[0], "debug")) {
6416 global.mode |= MODE_DEBUG;
6417 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006418 else if (!strcmp(args[0], "noepoll")) {
6419 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6420 }
6421 else if (!strcmp(args[0], "nopoll")) {
6422 cfg_polling_mechanism &= ~POLL_USE_POLL;
6423 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006424 else if (!strcmp(args[0], "quiet")) {
6425 global.mode |= MODE_QUIET;
6426 }
6427 else if (!strcmp(args[0], "stats")) {
6428 global.mode |= MODE_STATS;
6429 }
6430 else if (!strcmp(args[0], "uid")) {
6431 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006432 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006433 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006434 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006435 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006436 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006437 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006439 global.uid = atol(args[1]);
6440 }
6441 else if (!strcmp(args[0], "gid")) {
6442 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006443 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006444 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006445 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006446 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006447 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006448 return -1;
6449 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006450 global.gid = atol(args[1]);
6451 }
6452 else if (!strcmp(args[0], "nbproc")) {
6453 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006454 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006455 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006456 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006457 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006458 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006459 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006460 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006461 global.nbproc = atol(args[1]);
6462 }
6463 else if (!strcmp(args[0], "maxconn")) {
6464 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006465 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006466 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006467 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006468 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006469 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006470 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006471 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006472 global.maxconn = atol(args[1]);
Willy TARREAU13032e72006-03-12 17:31:45 +01006473#ifdef SYSTEM_MAXCONN
6474 if (global.maxconn > DEFAULT_MAXCONN && cfg_maxconn <= DEFAULT_MAXCONN) {
6475 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);
6476 global.maxconn = DEFAULT_MAXCONN;
6477 }
6478#endif /* SYSTEM_MAXCONN */
willy tarreau9fe663a2005-12-17 13:02:59 +01006479 }
willy tarreaub1285d52005-12-18 01:20:14 +01006480 else if (!strcmp(args[0], "ulimit-n")) {
6481 if (global.rlimit_nofile != 0) {
6482 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6483 return 0;
6484 }
6485 if (*(args[1]) == 0) {
6486 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6487 return -1;
6488 }
6489 global.rlimit_nofile = atol(args[1]);
6490 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006491 else if (!strcmp(args[0], "chroot")) {
6492 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006493 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006494 return 0;
6495 }
6496 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006497 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006498 return -1;
6499 }
6500 global.chroot = strdup(args[1]);
6501 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006502 else if (!strcmp(args[0], "pidfile")) {
6503 if (global.pidfile != NULL) {
6504 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6505 return 0;
6506 }
6507 if (*(args[1]) == 0) {
6508 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6509 return -1;
6510 }
6511 global.pidfile = strdup(args[1]);
6512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006513 else if (!strcmp(args[0], "log")) { /* syslog server address */
6514 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006515 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006516
6517 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006518 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006519 return -1;
6520 }
6521
6522 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6523 if (!strcmp(log_facilities[facility], args[2]))
6524 break;
6525
6526 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006527 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006528 exit(1);
6529 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006530
6531 level = 7; /* max syslog level = debug */
6532 if (*(args[3])) {
6533 while (level >= 0 && strcmp(log_levels[level], args[3]))
6534 level--;
6535 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006536 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006537 exit(1);
6538 }
6539 }
6540
willy tarreau9fe663a2005-12-17 13:02:59 +01006541 sa = str2sa(args[1]);
6542 if (!sa->sin_port)
6543 sa->sin_port = htons(SYSLOG_PORT);
6544
6545 if (global.logfac1 == -1) {
6546 global.logsrv1 = *sa;
6547 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006548 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006549 }
6550 else if (global.logfac2 == -1) {
6551 global.logsrv2 = *sa;
6552 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006553 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006554 }
6555 else {
6556 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6557 return -1;
6558 }
6559
6560 }
6561 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006562 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006563 return -1;
6564 }
6565 return 0;
6566}
6567
6568
willy tarreaua41a8b42005-12-17 14:02:24 +01006569void init_default_instance() {
6570 memset(&defproxy, 0, sizeof(defproxy));
6571 defproxy.mode = PR_MODE_TCP;
6572 defproxy.state = PR_STNEW;
6573 defproxy.maxconn = cfg_maxpconn;
6574 defproxy.conn_retries = CONN_RETRIES;
6575 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6576}
6577
willy tarreau9fe663a2005-12-17 13:02:59 +01006578/*
6579 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6580 */
6581int cfg_parse_listen(char *file, int linenum, char **args) {
6582 static struct proxy *curproxy = NULL;
6583 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006584 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006585 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006586
6587 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006588 if (!*args[1]) {
6589 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6590 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006591 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006592 return -1;
6593 }
6594
6595 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006596 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006597 return -1;
6598 }
6599 curproxy->next = proxy;
6600 proxy = curproxy;
6601 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006602
6603 /* parse the listener address if any */
6604 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006605 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006606 if (!curproxy->listen)
6607 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006608 global.maxsock++;
willy tarreaud0fb4652005-12-18 01:32:04 +01006609 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006610
willy tarreau9fe663a2005-12-17 13:02:59 +01006611 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006612 curproxy->state = defproxy.state;
6613 curproxy->maxconn = defproxy.maxconn;
6614 curproxy->conn_retries = defproxy.conn_retries;
6615 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006616
6617 if (defproxy.check_req)
6618 curproxy->check_req = strdup(defproxy.check_req);
6619 curproxy->check_len = defproxy.check_len;
6620
6621 if (defproxy.cookie_name)
6622 curproxy->cookie_name = strdup(defproxy.cookie_name);
6623 curproxy->cookie_len = defproxy.cookie_len;
6624
6625 if (defproxy.capture_name)
6626 curproxy->capture_name = strdup(defproxy.capture_name);
6627 curproxy->capture_namelen = defproxy.capture_namelen;
6628 curproxy->capture_len = defproxy.capture_len;
6629
6630 if (defproxy.errmsg.msg400)
6631 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6632 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6633
6634 if (defproxy.errmsg.msg403)
6635 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6636 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6637
6638 if (defproxy.errmsg.msg408)
6639 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6640 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6641
6642 if (defproxy.errmsg.msg500)
6643 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6644 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6645
6646 if (defproxy.errmsg.msg502)
6647 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6648 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6649
6650 if (defproxy.errmsg.msg503)
6651 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6652 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6653
6654 if (defproxy.errmsg.msg504)
6655 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6656 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6657
willy tarreaua41a8b42005-12-17 14:02:24 +01006658 curproxy->clitimeout = defproxy.clitimeout;
6659 curproxy->contimeout = defproxy.contimeout;
6660 curproxy->srvtimeout = defproxy.srvtimeout;
6661 curproxy->mode = defproxy.mode;
6662 curproxy->logfac1 = defproxy.logfac1;
6663 curproxy->logsrv1 = defproxy.logsrv1;
6664 curproxy->loglev1 = defproxy.loglev1;
6665 curproxy->logfac2 = defproxy.logfac2;
6666 curproxy->logsrv2 = defproxy.logsrv2;
6667 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006668 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006669 curproxy->grace = defproxy.grace;
6670 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006671 curproxy->mon_net = defproxy.mon_net;
6672 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006673 return 0;
6674 }
6675 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006676 /* some variables may have already been initialized earlier */
6677 if (defproxy.check_req) free(defproxy.check_req);
6678 if (defproxy.cookie_name) free(defproxy.cookie_name);
6679 if (defproxy.capture_name) free(defproxy.capture_name);
6680 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6681 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6682 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6683 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6684 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6685 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6686 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6687
6688 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006689 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006690 return 0;
6691 }
6692 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006693 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006694 return -1;
6695 }
6696
willy tarreaua41a8b42005-12-17 14:02:24 +01006697 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6698 if (curproxy == &defproxy) {
6699 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6700 return -1;
6701 }
6702
6703 if (strchr(args[1], ':') == NULL) {
6704 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6705 file, linenum, args[0]);
6706 return -1;
6707 }
6708 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006709 if (!curproxy->listen)
6710 return -1;
Willy TARREAU203b0b62006-03-12 18:00:28 +01006711 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01006712 return 0;
6713 }
willy tarreaub1285d52005-12-18 01:20:14 +01006714 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6715 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6716 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6717 file, linenum, args[0]);
6718 return -1;
6719 }
6720 /* flush useless bits */
6721 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6722 return 0;
6723 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006724 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006725 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6726 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6727 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6728 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006729 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006730 return -1;
6731 }
6732 }
6733 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006734 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006735 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006736 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6737 curproxy->state = PR_STNEW;
6738 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006739 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6740 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006741// if (curproxy == &defproxy) {
6742// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6743// return -1;
6744// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006745
willy tarreau9fe663a2005-12-17 13:02:59 +01006746 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006747// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6748// file, linenum);
6749// return 0;
6750 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006751 }
6752
6753 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006754 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6755 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006756 return -1;
6757 }
6758 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006759 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006760
6761 cur_arg = 2;
6762 while (*(args[cur_arg])) {
6763 if (!strcmp(args[cur_arg], "rewrite")) {
6764 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006765 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006766 else if (!strcmp(args[cur_arg], "indirect")) {
6767 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006768 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006769 else if (!strcmp(args[cur_arg], "insert")) {
6770 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006771 }
willy tarreau240afa62005-12-17 13:14:35 +01006772 else if (!strcmp(args[cur_arg], "nocache")) {
6773 curproxy->options |= PR_O_COOK_NOC;
6774 }
willy tarreaucd878942005-12-17 13:27:43 +01006775 else if (!strcmp(args[cur_arg], "postonly")) {
6776 curproxy->options |= PR_O_COOK_POST;
6777 }
willy tarreau0174f312005-12-18 01:02:42 +01006778 else if (!strcmp(args[cur_arg], "prefix")) {
6779 curproxy->options |= PR_O_COOK_PFX;
6780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006781 else {
willy tarreau0174f312005-12-18 01:02:42 +01006782 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006783 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006784 return -1;
6785 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006786 cur_arg++;
6787 }
willy tarreau0174f312005-12-18 01:02:42 +01006788 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6789 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6790 file, linenum);
6791 return -1;
6792 }
6793
6794 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6795 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006796 file, linenum);
6797 return -1;
6798 }
willy tarreau12350152005-12-18 01:03:27 +01006799 }/* end else if (!strcmp(args[0], "cookie")) */
6800 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6801// if (curproxy == &defproxy) {
6802// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6803// return -1;
6804// }
6805
6806 if (curproxy->appsession_name != NULL) {
6807// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6808// file, linenum);
6809// return 0;
6810 free(curproxy->appsession_name);
6811 }
6812
6813 if (*(args[5]) == 0) {
6814 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6815 file, linenum, args[0]);
6816 return -1;
6817 }
6818 have_appsession = 1;
6819 curproxy->appsession_name = strdup(args[1]);
6820 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6821 curproxy->appsession_len = atoi(args[3]);
6822 curproxy->appsession_timeout = atoi(args[5]);
6823 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6824 if (rc) {
6825 Alert("Error Init Appsession Hashtable.\n");
6826 return -1;
6827 }
6828 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006829 else if (!strcmp(args[0], "capture")) {
6830 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6831 // if (curproxy == &defproxy) {
6832 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6833 // return -1;
6834 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006835
willy tarreau4302f492005-12-18 01:00:37 +01006836 if (curproxy->capture_name != NULL) {
6837 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6838 // file, linenum, args[0]);
6839 // return 0;
6840 free(curproxy->capture_name);
6841 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006842
willy tarreau4302f492005-12-18 01:00:37 +01006843 if (*(args[4]) == 0) {
6844 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6845 file, linenum, args[0]);
6846 return -1;
6847 }
6848 curproxy->capture_name = strdup(args[2]);
6849 curproxy->capture_namelen = strlen(curproxy->capture_name);
6850 curproxy->capture_len = atol(args[4]);
6851 if (curproxy->capture_len >= CAPTURE_LEN) {
6852 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6853 file, linenum, CAPTURE_LEN - 1);
6854 curproxy->capture_len = CAPTURE_LEN - 1;
6855 }
6856 curproxy->to_log |= LW_COOKIE;
6857 }
6858 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6859 struct cap_hdr *hdr;
6860
6861 if (curproxy == &defproxy) {
6862 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6863 return -1;
6864 }
6865
6866 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6867 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6868 file, linenum, args[0], args[1]);
6869 return -1;
6870 }
6871
6872 hdr = calloc(sizeof(struct cap_hdr), 1);
6873 hdr->next = curproxy->req_cap;
6874 hdr->name = strdup(args[3]);
6875 hdr->namelen = strlen(args[3]);
6876 hdr->len = atol(args[5]);
6877 hdr->index = curproxy->nb_req_cap++;
6878 curproxy->req_cap = hdr;
6879 curproxy->to_log |= LW_REQHDR;
6880 }
6881 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6882 struct cap_hdr *hdr;
6883
6884 if (curproxy == &defproxy) {
6885 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6886 return -1;
6887 }
6888
6889 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6890 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6891 file, linenum, args[0], args[1]);
6892 return -1;
6893 }
6894 hdr = calloc(sizeof(struct cap_hdr), 1);
6895 hdr->next = curproxy->rsp_cap;
6896 hdr->name = strdup(args[3]);
6897 hdr->namelen = strlen(args[3]);
6898 hdr->len = atol(args[5]);
6899 hdr->index = curproxy->nb_rsp_cap++;
6900 curproxy->rsp_cap = hdr;
6901 curproxy->to_log |= LW_RSPHDR;
6902 }
6903 else {
6904 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006905 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006906 return -1;
6907 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006908 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006909 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006910 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006911 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 return 0;
6913 }
6914 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006915 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6916 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006917 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919 curproxy->contimeout = atol(args[1]);
6920 }
6921 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006922 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006923 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6924 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006925 return 0;
6926 }
6927 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006928 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6929 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006930 return -1;
6931 }
6932 curproxy->clitimeout = atol(args[1]);
6933 }
6934 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006935 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006936 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006937 return 0;
6938 }
6939 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006940 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6941 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006942 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006943 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006944 curproxy->srvtimeout = atol(args[1]);
6945 }
6946 else if (!strcmp(args[0], "retries")) { /* connection retries */
6947 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006948 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6949 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006950 return -1;
6951 }
6952 curproxy->conn_retries = atol(args[1]);
6953 }
6954 else if (!strcmp(args[0], "option")) {
6955 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006956 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 return -1;
6958 }
6959 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006960 /* enable reconnections to dispatch */
6961 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006962#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006964 /* enable transparent proxy connections */
6965 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006966#endif
6967 else if (!strcmp(args[1], "keepalive"))
6968 /* enable keep-alive */
6969 curproxy->options |= PR_O_KEEPALIVE;
6970 else if (!strcmp(args[1], "forwardfor"))
6971 /* insert x-forwarded-for field */
6972 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006973 else if (!strcmp(args[1], "logasap"))
6974 /* log as soon as possible, without waiting for the session to complete */
6975 curproxy->options |= PR_O_LOGASAP;
6976 else if (!strcmp(args[1], "httpclose"))
6977 /* force connection: close in both directions in HTTP mode */
6978 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006979 else if (!strcmp(args[1], "forceclose"))
6980 /* force connection: close in both directions in HTTP mode and enforce end of session */
6981 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006982 else if (!strcmp(args[1], "checkcache"))
6983 /* require examination of cacheability of the 'set-cookie' field */
6984 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006985 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006986 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006987 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006988 else if (!strcmp(args[1], "tcplog"))
6989 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006990 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006991 else if (!strcmp(args[1], "dontlognull")) {
6992 /* don't log empty requests */
6993 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006994 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006995 else if (!strcmp(args[1], "tcpka")) {
6996 /* enable TCP keep-alives on client and server sessions */
6997 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6998 }
6999 else if (!strcmp(args[1], "clitcpka")) {
7000 /* enable TCP keep-alives on client sessions */
7001 curproxy->options |= PR_O_TCP_CLI_KA;
7002 }
7003 else if (!strcmp(args[1], "srvtcpka")) {
7004 /* enable TCP keep-alives on server sessions */
7005 curproxy->options |= PR_O_TCP_SRV_KA;
7006 }
Willy TARREAU3481c462006-03-01 22:37:57 +01007007 else if (!strcmp(args[1], "allbackups")) {
7008 /* Use all backup servers simultaneously */
7009 curproxy->options |= PR_O_USE_ALL_BK;
7010 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007011 else if (!strcmp(args[1], "httpchk")) {
7012 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007013 if (curproxy->check_req != NULL) {
7014 free(curproxy->check_req);
7015 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007016 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01007017 if (!*args[2]) { /* no argument */
7018 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
7019 curproxy->check_len = strlen(DEF_CHECK_REQ);
7020 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01007021 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
7022 curproxy->check_req = (char *)malloc(reqlen);
7023 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7024 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01007025 } else { /* more arguments : METHOD URI [HTTP_VER] */
7026 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
7027 if (*args[4])
7028 reqlen += strlen(args[4]);
7029 else
7030 reqlen += strlen("HTTP/1.0");
7031
7032 curproxy->check_req = (char *)malloc(reqlen);
7033 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
7034 "%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 +01007035 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01007036 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007037 else if (!strcmp(args[1], "persist")) {
7038 /* persist on using the server specified by the cookie, even when it's down */
7039 curproxy->options |= PR_O_PERSIST;
7040 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007041 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007042 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 return -1;
7044 }
7045 return 0;
7046 }
7047 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
7048 /* enable reconnections to dispatch */
7049 curproxy->options |= PR_O_REDISP;
7050 }
willy tarreaua1598082005-12-17 13:08:06 +01007051#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01007052 else if (!strcmp(args[0], "transparent")) {
7053 /* enable transparent proxy connections */
7054 curproxy->options |= PR_O_TRANSP;
7055 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007056#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01007057 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
7058 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007059 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007060 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007061 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007062 curproxy->maxconn = atol(args[1]);
7063 }
7064 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
7065 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007066 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007067 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007069 curproxy->grace = atol(args[1]);
7070 }
7071 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01007072 if (curproxy == &defproxy) {
7073 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7074 return -1;
7075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007076 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007077 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007078 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007079 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007080 curproxy->dispatch_addr = *str2sa(args[1]);
7081 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007082 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 if (*(args[1])) {
7084 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007085 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01007086 }
willy tarreau1a3442d2006-03-24 21:03:20 +01007087 else if (!strcmp(args[1], "source")) {
7088 curproxy->options |= PR_O_BALANCE_SH;
7089 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007090 else {
willy tarreau1a3442d2006-03-24 21:03:20 +01007091 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007092 return -1;
7093 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007094 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007095 else /* if no option is set, use round-robin by default */
7096 curproxy->options |= PR_O_BALANCE_RR;
7097 }
7098 else if (!strcmp(args[0], "server")) { /* server address */
7099 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007100 char *rport;
7101 char *raddr;
7102 short realport;
7103 int do_check;
7104
7105 if (curproxy == &defproxy) {
7106 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7107 return -1;
7108 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007109
willy tarreaua41a8b42005-12-17 14:02:24 +01007110 if (!*args[2]) {
7111 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007112 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007113 return -1;
7114 }
7115 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
7116 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7117 return -1;
7118 }
willy tarreau0174f312005-12-18 01:02:42 +01007119
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007120 /* the servers are linked backwards first */
7121 newsrv->next = curproxy->srv;
7122 curproxy->srv = newsrv;
willy tarreau9fe663a2005-12-17 13:02:59 +01007123 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007124
willy tarreau18a957c2006-04-12 19:26:23 +02007125 LIST_INIT(&newsrv->pendconns);
willy tarreaua41a8b42005-12-17 14:02:24 +01007126 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01007127 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01007128 newsrv->id = strdup(args[1]);
7129
7130 /* several ways to check the port component :
7131 * - IP => port=+0, relative
7132 * - IP: => port=+0, relative
7133 * - IP:N => port=N, absolute
7134 * - IP:+N => port=+N, relative
7135 * - IP:-N => port=-N, relative
7136 */
7137 raddr = strdup(args[2]);
7138 rport = strchr(raddr, ':');
7139 if (rport) {
7140 *rport++ = 0;
7141 realport = atol(rport);
7142 if (!isdigit((int)*rport))
7143 newsrv->state |= SRV_MAPPORTS;
7144 } else {
7145 realport = 0;
7146 newsrv->state |= SRV_MAPPORTS;
7147 }
7148
7149 newsrv->addr = *str2sa(raddr);
7150 newsrv->addr.sin_port = htons(realport);
7151 free(raddr);
7152
willy tarreau9fe663a2005-12-17 13:02:59 +01007153 newsrv->curfd = -1; /* no health-check in progress */
7154 newsrv->inter = DEF_CHKINTR;
7155 newsrv->rise = DEF_RISETIME;
7156 newsrv->fall = DEF_FALLTIME;
7157 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
7158 cur_arg = 3;
7159 while (*args[cur_arg]) {
7160 if (!strcmp(args[cur_arg], "cookie")) {
7161 newsrv->cookie = strdup(args[cur_arg + 1]);
7162 newsrv->cklen = strlen(args[cur_arg + 1]);
7163 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007164 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007165 else if (!strcmp(args[cur_arg], "rise")) {
7166 newsrv->rise = atol(args[cur_arg + 1]);
7167 newsrv->health = newsrv->rise;
7168 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01007169 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007170 else if (!strcmp(args[cur_arg], "fall")) {
7171 newsrv->fall = atol(args[cur_arg + 1]);
7172 cur_arg += 2;
7173 }
7174 else if (!strcmp(args[cur_arg], "inter")) {
7175 newsrv->inter = atol(args[cur_arg + 1]);
7176 cur_arg += 2;
7177 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007178 else if (!strcmp(args[cur_arg], "port")) {
7179 newsrv->check_port = atol(args[cur_arg + 1]);
7180 cur_arg += 2;
7181 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007182 else if (!strcmp(args[cur_arg], "backup")) {
7183 newsrv->state |= SRV_BACKUP;
7184 cur_arg ++;
7185 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007186 else if (!strcmp(args[cur_arg], "weight")) {
7187 int w;
7188 w = atol(args[cur_arg + 1]);
7189 if (w < 1 || w > 256) {
7190 Alert("parsing [%s:%d] : weight of server %s is not within 1 and 256 (%d).\n",
7191 file, linenum, newsrv->id, w);
7192 return -1;
7193 }
7194 newsrv->uweight = w - 1;
7195 cur_arg += 2;
7196 }
willy tarreau18a957c2006-04-12 19:26:23 +02007197 else if (!strcmp(args[cur_arg], "maxconn")) {
7198 newsrv->maxconn = atol(args[cur_arg + 1]);
7199 cur_arg += 2;
7200 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007201 else if (!strcmp(args[cur_arg], "check")) {
Willy TARREAU203b0b62006-03-12 18:00:28 +01007202 global.maxsock++;
willy tarreaua41a8b42005-12-17 14:02:24 +01007203 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007204 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007205 }
willy tarreau0174f312005-12-18 01:02:42 +01007206 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
7207 if (!*args[cur_arg + 1]) {
7208 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
7209 file, linenum, "source");
7210 return -1;
7211 }
7212 newsrv->state |= SRV_BIND_SRC;
7213 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
7214 cur_arg += 2;
7215 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 else {
willy tarreaue3f023f2006-04-08 21:52:24 +02007217 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 +01007218 file, linenum, newsrv->id);
7219 return -1;
7220 }
7221 }
7222
7223 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007224 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
7225 newsrv->check_port = realport; /* by default */
7226 if (!newsrv->check_port) {
7227 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 +01007228 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007229 return -1;
7230 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007231 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01007232 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007233
willy tarreau62084d42006-03-24 18:57:41 +01007234 if (newsrv->state & SRV_BACKUP)
7235 curproxy->srv_bck++;
7236 else
7237 curproxy->srv_act++;
willy tarreau9fe663a2005-12-17 13:02:59 +01007238 }
7239 else if (!strcmp(args[0], "log")) { /* syslog server address */
7240 struct sockaddr_in *sa;
7241 int facility;
7242
7243 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
7244 curproxy->logfac1 = global.logfac1;
7245 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01007246 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007247 curproxy->logfac2 = global.logfac2;
7248 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01007249 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01007250 }
7251 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01007252 int level;
7253
willy tarreau0f7af912005-12-17 12:21:26 +01007254 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
7255 if (!strcmp(log_facilities[facility], args[2]))
7256 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01007257
willy tarreau0f7af912005-12-17 12:21:26 +01007258 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007259 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01007260 exit(1);
7261 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007262
willy tarreau8337c6b2005-12-17 13:41:01 +01007263 level = 7; /* max syslog level = debug */
7264 if (*(args[3])) {
7265 while (level >= 0 && strcmp(log_levels[level], args[3]))
7266 level--;
7267 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007268 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01007269 exit(1);
7270 }
7271 }
7272
willy tarreau0f7af912005-12-17 12:21:26 +01007273 sa = str2sa(args[1]);
7274 if (!sa->sin_port)
7275 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01007276
willy tarreau0f7af912005-12-17 12:21:26 +01007277 if (curproxy->logfac1 == -1) {
7278 curproxy->logsrv1 = *sa;
7279 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007280 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007281 }
7282 else if (curproxy->logfac2 == -1) {
7283 curproxy->logsrv2 = *sa;
7284 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01007285 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01007286 }
7287 else {
7288 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007290 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007291 }
7292 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007293 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01007294 file, linenum);
7295 return -1;
7296 }
7297 }
willy tarreaua1598082005-12-17 13:08:06 +01007298 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01007299 if (!*args[1]) {
7300 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01007301 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01007302 return -1;
7303 }
7304
7305 curproxy->source_addr = *str2sa(args[1]);
7306 curproxy->options |= PR_O_BIND_SRC;
7307 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007308 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
7309 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007310 if (curproxy == &defproxy) {
7311 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7312 return -1;
7313 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007314
7315 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007316 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7317 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007318 return -1;
7319 }
7320
7321 preg = calloc(1, sizeof(regex_t));
7322 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007323 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007324 return -1;
7325 }
7326
willy tarreauc1f47532005-12-18 01:08:26 +01007327 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7328 if (err) {
7329 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7330 file, linenum, *err);
7331 return -1;
7332 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007333 }
7334 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
7335 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007336 if (curproxy == &defproxy) {
7337 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7338 return -1;
7339 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007340
7341 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007342 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007343 return -1;
7344 }
7345
7346 preg = calloc(1, sizeof(regex_t));
7347 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007348 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007349 return -1;
7350 }
7351
7352 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7353 }
7354 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
7355 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007356 if (curproxy == &defproxy) {
7357 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7358 return -1;
7359 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007360
7361 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007362 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007363 return -1;
7364 }
7365
7366 preg = calloc(1, sizeof(regex_t));
7367 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007368 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007369 return -1;
7370 }
7371
7372 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7373 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007374 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
7375 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007376 if (curproxy == &defproxy) {
7377 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7378 return -1;
7379 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007380
7381 if (*(args[1]) == 0) {
7382 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7383 return -1;
7384 }
7385
7386 preg = calloc(1, sizeof(regex_t));
7387 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7388 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7389 return -1;
7390 }
7391
7392 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7393 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007394 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7395 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007396 if (curproxy == &defproxy) {
7397 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7398 return -1;
7399 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007400
7401 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007402 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007403 return -1;
7404 }
7405
7406 preg = calloc(1, sizeof(regex_t));
7407 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007408 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007409 return -1;
7410 }
7411
7412 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7413 }
7414 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7415 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007416 if (curproxy == &defproxy) {
7417 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7418 return -1;
7419 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007420
7421 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007422 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7423 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007424 return -1;
7425 }
7426
7427 preg = calloc(1, sizeof(regex_t));
7428 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007429 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007430 return -1;
7431 }
7432
willy tarreauc1f47532005-12-18 01:08:26 +01007433 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7434 if (err) {
7435 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7436 file, linenum, *err);
7437 return -1;
7438 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007439 }
7440 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7441 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007442 if (curproxy == &defproxy) {
7443 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7444 return -1;
7445 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007446
7447 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007448 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007449 return -1;
7450 }
7451
7452 preg = calloc(1, sizeof(regex_t));
7453 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007454 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007455 return -1;
7456 }
7457
7458 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7459 }
7460 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7461 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007462 if (curproxy == &defproxy) {
7463 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7464 return -1;
7465 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007466
7467 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007468 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007469 return -1;
7470 }
7471
7472 preg = calloc(1, sizeof(regex_t));
7473 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007474 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007475 return -1;
7476 }
7477
7478 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7479 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007480 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7481 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007482 if (curproxy == &defproxy) {
7483 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7484 return -1;
7485 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007486
7487 if (*(args[1]) == 0) {
7488 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7489 return -1;
7490 }
7491
7492 preg = calloc(1, sizeof(regex_t));
7493 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7494 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7495 return -1;
7496 }
7497
7498 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7499 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007500 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7501 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007502 if (curproxy == &defproxy) {
7503 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7504 return -1;
7505 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007506
7507 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007508 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007509 return -1;
7510 }
7511
7512 preg = calloc(1, sizeof(regex_t));
7513 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007514 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007515 return -1;
7516 }
7517
7518 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7519 }
7520 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007521 if (curproxy == &defproxy) {
7522 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7523 return -1;
7524 }
7525
willy tarreau9fe663a2005-12-17 13:02:59 +01007526 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007527 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 return 0;
7529 }
7530
7531 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007532 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007533 return -1;
7534 }
7535
willy tarreau4302f492005-12-18 01:00:37 +01007536 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7537 }
7538 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7539 regex_t *preg;
7540
7541 if (*(args[1]) == 0 || *(args[2]) == 0) {
7542 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7543 file, linenum, args[0]);
7544 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007545 }
willy tarreau4302f492005-12-18 01:00:37 +01007546
7547 preg = calloc(1, sizeof(regex_t));
7548 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7549 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7550 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007551 }
willy tarreau4302f492005-12-18 01:00:37 +01007552
willy tarreauc1f47532005-12-18 01:08:26 +01007553 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7554 if (err) {
7555 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7556 file, linenum, *err);
7557 return -1;
7558 }
willy tarreau4302f492005-12-18 01:00:37 +01007559 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007560 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7561 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007562 if (curproxy == &defproxy) {
7563 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7564 return -1;
7565 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007566
7567 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007568 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007569 return -1;
7570 }
willy tarreaue39cd132005-12-17 13:00:18 +01007571
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 preg = calloc(1, sizeof(regex_t));
7573 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007574 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007575 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007576 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007577
willy tarreauc1f47532005-12-18 01:08:26 +01007578 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7579 if (err) {
7580 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7581 file, linenum, *err);
7582 return -1;
7583 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007584 }
willy tarreau982249e2005-12-18 00:57:06 +01007585 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7586 regex_t *preg;
7587 if (curproxy == &defproxy) {
7588 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7589 return -1;
7590 }
7591
7592 if (*(args[1]) == 0) {
7593 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7594 return -1;
7595 }
7596
7597 preg = calloc(1, sizeof(regex_t));
7598 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7599 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7600 return -1;
7601 }
7602
willy tarreauc1f47532005-12-18 01:08:26 +01007603 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7604 if (err) {
7605 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7606 file, linenum, *err);
7607 return -1;
7608 }
willy tarreau982249e2005-12-18 00:57:06 +01007609 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007610 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007611 regex_t *preg;
7612 if (curproxy == &defproxy) {
7613 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7614 return -1;
7615 }
willy tarreaue39cd132005-12-17 13:00:18 +01007616
willy tarreaua41a8b42005-12-17 14:02:24 +01007617 if (*(args[1]) == 0 || *(args[2]) == 0) {
7618 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7619 file, linenum, args[0]);
7620 return -1;
7621 }
willy tarreaue39cd132005-12-17 13:00:18 +01007622
willy tarreaua41a8b42005-12-17 14:02:24 +01007623 preg = calloc(1, sizeof(regex_t));
7624 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7625 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7626 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007627 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007628
willy tarreauc1f47532005-12-18 01:08:26 +01007629 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7630 if (err) {
7631 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7632 file, linenum, *err);
7633 return -1;
7634 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007635 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007636 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7637 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007638 if (curproxy == &defproxy) {
7639 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7640 return -1;
7641 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007642
7643 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007644 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007645 return -1;
7646 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007647
willy tarreau9fe663a2005-12-17 13:02:59 +01007648 preg = calloc(1, sizeof(regex_t));
7649 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007650 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007651 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007652 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007653
willy tarreauc1f47532005-12-18 01:08:26 +01007654 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7655 if (err) {
7656 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7657 file, linenum, *err);
7658 return -1;
7659 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007660 }
willy tarreau982249e2005-12-18 00:57:06 +01007661 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7662 regex_t *preg;
7663 if (curproxy == &defproxy) {
7664 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7665 return -1;
7666 }
7667
7668 if (*(args[1]) == 0) {
7669 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7670 return -1;
7671 }
7672
7673 preg = calloc(1, sizeof(regex_t));
7674 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7675 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7676 return -1;
7677 }
7678
willy tarreauc1f47532005-12-18 01:08:26 +01007679 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7680 if (err) {
7681 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7682 file, linenum, *err);
7683 return -1;
7684 }
willy tarreau982249e2005-12-18 00:57:06 +01007685 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007686 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007687 if (curproxy == &defproxy) {
7688 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7689 return -1;
7690 }
7691
willy tarreau9fe663a2005-12-17 13:02:59 +01007692 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007693 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007694 return 0;
7695 }
7696
7697 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007698 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007699 return -1;
7700 }
7701
7702 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7703 }
willy tarreauc1f47532005-12-18 01:08:26 +01007704 else if (!strcmp(args[0], "errorloc") ||
7705 !strcmp(args[0], "errorloc302") ||
7706 !strcmp(args[0], "errorloc303")) { /* error location */
7707 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007708 char *err;
7709
willy tarreaueedaa9f2005-12-17 14:08:03 +01007710 // if (curproxy == &defproxy) {
7711 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7712 // return -1;
7713 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007714
willy tarreau8337c6b2005-12-17 13:41:01 +01007715 if (*(args[2]) == 0) {
7716 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7717 return -1;
7718 }
7719
7720 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007721 if (!strcmp(args[0], "errorloc303")) {
7722 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7723 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7724 } else {
7725 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7726 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7727 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007728
7729 if (errnum == 400) {
7730 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007731 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007732 free(curproxy->errmsg.msg400);
7733 }
7734 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007735 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007736 }
7737 else if (errnum == 403) {
7738 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007739 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007740 free(curproxy->errmsg.msg403);
7741 }
7742 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007743 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007744 }
7745 else if (errnum == 408) {
7746 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007747 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007748 free(curproxy->errmsg.msg408);
7749 }
7750 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007751 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007752 }
7753 else if (errnum == 500) {
7754 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007755 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007756 free(curproxy->errmsg.msg500);
7757 }
7758 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007759 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007760 }
7761 else if (errnum == 502) {
7762 if (curproxy->errmsg.msg502) {
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.msg502);
7765 }
7766 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007767 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007768 }
7769 else if (errnum == 503) {
7770 if (curproxy->errmsg.msg503) {
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.msg503);
7773 }
7774 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007775 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007776 }
7777 else if (errnum == 504) {
7778 if (curproxy->errmsg.msg504) {
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.msg504);
7781 }
7782 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007783 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007784 }
7785 else {
7786 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7787 free(err);
7788 }
7789 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007790 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007791 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007792 return -1;
7793 }
7794 return 0;
7795}
willy tarreaue39cd132005-12-17 13:00:18 +01007796
willy tarreau5cbea6f2005-12-17 12:48:26 +01007797
willy tarreau9fe663a2005-12-17 13:02:59 +01007798/*
7799 * This function reads and parses the configuration file given in the argument.
7800 * returns 0 if OK, -1 if error.
7801 */
7802int readcfgfile(char *file) {
7803 char thisline[256];
7804 char *line;
7805 FILE *f;
7806 int linenum = 0;
7807 char *end;
7808 char *args[MAX_LINE_ARGS];
7809 int arg;
7810 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007811 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007812 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007813
willy tarreau9fe663a2005-12-17 13:02:59 +01007814 struct proxy *curproxy = NULL;
7815 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007816
willy tarreau9fe663a2005-12-17 13:02:59 +01007817 if ((f=fopen(file,"r")) == NULL)
7818 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007819
willy tarreaueedaa9f2005-12-17 14:08:03 +01007820 init_default_instance();
7821
willy tarreau9fe663a2005-12-17 13:02:59 +01007822 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7823 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007824
willy tarreau9fe663a2005-12-17 13:02:59 +01007825 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007826
willy tarreau9fe663a2005-12-17 13:02:59 +01007827 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007828 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007829 line++;
7830
7831 arg = 0;
7832 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007833
willy tarreau9fe663a2005-12-17 13:02:59 +01007834 while (*line && arg < MAX_LINE_ARGS) {
7835 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7836 * C equivalent value. Other combinations left unchanged (eg: \1).
7837 */
7838 if (*line == '\\') {
7839 int skip = 0;
7840 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7841 *line = line[1];
7842 skip = 1;
7843 }
7844 else if (line[1] == 'r') {
7845 *line = '\r';
7846 skip = 1;
7847 }
7848 else if (line[1] == 'n') {
7849 *line = '\n';
7850 skip = 1;
7851 }
7852 else if (line[1] == 't') {
7853 *line = '\t';
7854 skip = 1;
7855 }
willy tarreauc1f47532005-12-18 01:08:26 +01007856 else if (line[1] == 'x') {
7857 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7858 unsigned char hex1, hex2;
7859 hex1 = toupper(line[2]) - '0';
7860 hex2 = toupper(line[3]) - '0';
7861 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7862 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7863 *line = (hex1<<4) + hex2;
7864 skip = 3;
7865 }
7866 else {
7867 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7868 return -1;
7869 }
7870 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007871 if (skip) {
7872 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7873 end -= skip;
7874 }
7875 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007876 }
willy tarreaua1598082005-12-17 13:08:06 +01007877 else if (*line == '#' || *line == '\n' || *line == '\r') {
7878 /* end of string, end of loop */
7879 *line = 0;
7880 break;
7881 }
willy tarreauc29948c2005-12-17 13:10:27 +01007882 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007883 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007884 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007885 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007886 line++;
7887 args[++arg] = line;
7888 }
7889 else {
7890 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007891 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007892 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007893
willy tarreau9fe663a2005-12-17 13:02:59 +01007894 /* empty line */
7895 if (!**args)
7896 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007897
willy tarreau9fe663a2005-12-17 13:02:59 +01007898 /* zero out remaining args */
7899 while (++arg < MAX_LINE_ARGS) {
7900 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007901 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007902
willy tarreaua41a8b42005-12-17 14:02:24 +01007903 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007904 confsect = CFG_LISTEN;
7905 else if (!strcmp(args[0], "global")) /* global config */
7906 confsect = CFG_GLOBAL;
7907 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007908
willy tarreau9fe663a2005-12-17 13:02:59 +01007909 switch (confsect) {
7910 case CFG_LISTEN:
7911 if (cfg_parse_listen(file, linenum, args) < 0)
7912 return -1;
7913 break;
7914 case CFG_GLOBAL:
7915 if (cfg_parse_global(file, linenum, args) < 0)
7916 return -1;
7917 break;
7918 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007919 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007920 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007922
7923
willy tarreau0f7af912005-12-17 12:21:26 +01007924 }
7925 fclose(f);
7926
7927 /*
7928 * Now, check for the integrity of all that we have collected.
7929 */
7930
Willy TARREAU3759f982006-03-01 22:44:17 +01007931 /* will be needed further to delay some tasks */
7932 tv_now(&now);
7933
willy tarreau0f7af912005-12-17 12:21:26 +01007934 if ((curproxy = proxy) == NULL) {
7935 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7936 file);
7937 return -1;
7938 }
7939
7940 while (curproxy != NULL) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007941 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007942 curproxy = curproxy->next;
7943 continue;
7944 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007945
7946 if (curproxy->listen == NULL) {
7947 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);
7948 cfgerr++;
7949 }
7950 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007951 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007952 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007953 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7954 file, curproxy->id);
7955 cfgerr++;
7956 }
7957 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7958 if (curproxy->options & PR_O_TRANSP) {
7959 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7960 file, curproxy->id);
7961 cfgerr++;
7962 }
7963 else if (curproxy->srv == NULL) {
7964 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7965 file, curproxy->id);
7966 cfgerr++;
7967 }
willy tarreaua1598082005-12-17 13:08:06 +01007968 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007969 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7970 file, curproxy->id);
7971 }
7972 }
7973 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007974 if (curproxy->cookie_name != NULL) {
7975 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7976 file, curproxy->id);
7977 }
7978 if ((newsrv = curproxy->srv) != NULL) {
7979 Warning("parsing %s : servers will be ignored for listener %s.\n",
7980 file, curproxy->id);
7981 }
willy tarreaue39cd132005-12-17 13:00:18 +01007982 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007983 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7984 file, curproxy->id);
7985 }
willy tarreaue39cd132005-12-17 13:00:18 +01007986 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007987 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7988 file, curproxy->id);
7989 }
7990 }
7991 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7992 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7993 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7994 file, curproxy->id);
7995 cfgerr++;
7996 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007997 }
willy tarreaue3f023f2006-04-08 21:52:24 +02007998
willy tarreaucc1e2bd2006-04-10 20:32:43 +02007999 /* first, we will invert the servers list order */
8000 newsrv = NULL;
8001 while (curproxy->srv) {
8002 struct server *next;
8003
8004 next = curproxy->srv->next;
8005 curproxy->srv->next = newsrv;
8006 newsrv = curproxy->srv;
8007 if (!next)
8008 break;
8009 curproxy->srv = next;
8010 }
8011
8012 /* now, newsrv == curproxy->srv */
8013 if (newsrv) {
8014 struct server *srv;
8015 int pgcd;
8016 int act, bck;
willy tarreaue3f023f2006-04-08 21:52:24 +02008017
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008018 /* We will factor the weights to reduce the table,
8019 * using Euclide's largest common divisor algorithm
8020 */
8021 pgcd = newsrv->uweight + 1;
8022 for (srv = newsrv->next; srv && pgcd > 1; srv = srv->next) {
8023 int t, w;
8024
8025 w = srv->uweight + 1;
8026 while (w) {
8027 t = pgcd % w;
8028 pgcd = w;
8029 w = t;
willy tarreaue3f023f2006-04-08 21:52:24 +02008030 }
willy tarreau0f7af912005-12-17 12:21:26 +01008031 }
willy tarreaucc1e2bd2006-04-10 20:32:43 +02008032
8033 act = bck = 0;
8034 for (srv = newsrv; srv; srv = srv->next) {
8035 srv->eweight = ((srv->uweight + 1) / pgcd) - 1;
8036 if (srv->state & SRV_BACKUP)
8037 bck += srv->eweight + 1;
8038 else
8039 act += srv->eweight + 1;
8040 }
8041
8042 /* this is the largest map we will ever need for this servers list */
8043 if (act < bck)
8044 act = bck;
8045
8046 curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
8047 /* recounts servers and their weights */
8048 recount_servers(curproxy);
8049 recalc_server_map(curproxy);
willy tarreau0f7af912005-12-17 12:21:26 +01008050 }
willy tarreau25c4ea52005-12-18 00:49:49 +01008051
8052 if (curproxy->options & PR_O_LOGASAP)
8053 curproxy->to_log &= ~LW_BYTES;
8054
willy tarreau8337c6b2005-12-17 13:41:01 +01008055 if (curproxy->errmsg.msg400 == NULL) {
8056 curproxy->errmsg.msg400 = (char *)HTTP_400;
8057 curproxy->errmsg.len400 = strlen(HTTP_400);
8058 }
8059 if (curproxy->errmsg.msg403 == NULL) {
8060 curproxy->errmsg.msg403 = (char *)HTTP_403;
8061 curproxy->errmsg.len403 = strlen(HTTP_403);
8062 }
8063 if (curproxy->errmsg.msg408 == NULL) {
8064 curproxy->errmsg.msg408 = (char *)HTTP_408;
8065 curproxy->errmsg.len408 = strlen(HTTP_408);
8066 }
8067 if (curproxy->errmsg.msg500 == NULL) {
8068 curproxy->errmsg.msg500 = (char *)HTTP_500;
8069 curproxy->errmsg.len500 = strlen(HTTP_500);
8070 }
8071 if (curproxy->errmsg.msg502 == NULL) {
8072 curproxy->errmsg.msg502 = (char *)HTTP_502;
8073 curproxy->errmsg.len502 = strlen(HTTP_502);
8074 }
8075 if (curproxy->errmsg.msg503 == NULL) {
8076 curproxy->errmsg.msg503 = (char *)HTTP_503;
8077 curproxy->errmsg.len503 = strlen(HTTP_503);
8078 }
8079 if (curproxy->errmsg.msg504 == NULL) {
8080 curproxy->errmsg.msg504 = (char *)HTTP_504;
8081 curproxy->errmsg.len504 = strlen(HTTP_504);
8082 }
Willy TARREAU3759f982006-03-01 22:44:17 +01008083
8084 /* now we'll start this proxy's health checks if any */
8085 /* 1- count the checkers to run simultaneously */
8086 nbchk = 0;
8087 mininter = 0;
8088 newsrv = curproxy->srv;
8089 while (newsrv != NULL) {
8090 if (newsrv->state & SRV_CHECKED) {
8091 if (!mininter || mininter > newsrv->inter)
8092 mininter = newsrv->inter;
8093 nbchk++;
8094 }
8095 newsrv = newsrv->next;
8096 }
8097
8098 /* 2- start them as far as possible from each others while respecting
8099 * their own intervals. For this, we will start them after their own
8100 * interval added to the min interval divided by the number of servers,
8101 * weighted by the server's position in the list.
8102 */
8103 if (nbchk > 0) {
8104 struct task *t;
8105 int srvpos;
8106
8107 newsrv = curproxy->srv;
8108 srvpos = 0;
8109 while (newsrv != NULL) {
8110 /* should this server be checked ? */
8111 if (newsrv->state & SRV_CHECKED) {
8112 if ((t = pool_alloc(task)) == NULL) {
8113 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
8114 return -1;
8115 }
8116
8117 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
8118 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
8119 t->state = TASK_IDLE;
8120 t->process = process_chk;
8121 t->context = newsrv;
8122
8123 /* check this every ms */
8124 tv_delayfrom(&t->expire, &now,
8125 newsrv->inter + mininter * srvpos / nbchk);
8126 task_queue(t);
8127 //task_wakeup(&rq, t);
8128 srvpos++;
8129 }
8130 newsrv = newsrv->next;
8131 }
8132 }
8133
willy tarreau0f7af912005-12-17 12:21:26 +01008134 curproxy = curproxy->next;
8135 }
8136 if (cfgerr > 0) {
8137 Alert("Errors found in configuration file, aborting.\n");
8138 return -1;
8139 }
8140 else
8141 return 0;
8142}
8143
8144
8145/*
8146 * This function initializes all the necessary variables. It only returns
8147 * if everything is OK. If something fails, it exits.
8148 */
8149void init(int argc, char **argv) {
8150 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01008151 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01008152 char *old_argv = *argv;
8153 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008154 char *cfg_pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008155
8156 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01008157 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01008158 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01008159 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01008160 exit(1);
8161 }
8162
willy tarreau746e26b2006-03-25 11:14:35 +01008163#ifdef HAPROXY_MEMMAX
8164 global.rlimit_memmax = HAPROXY_MEMMAX;
8165#endif
8166
Willy TARREAUa9e75f62006-03-01 22:27:48 +01008167 /* initialize the libc's localtime structures once for all so that we
8168 * won't be missing memory if we want to send alerts under OOM conditions.
8169 */
8170 tv_now(&now);
8171 localtime(&now.tv_sec);
8172
willy tarreau4302f492005-12-18 01:00:37 +01008173 /* initialize the log header encoding map : '{|}"#' should be encoded with
8174 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
8175 * URL encoding only requires '"', '#' to be encoded as well as non-
8176 * printable characters above.
8177 */
8178 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
8179 memset(url_encode_map, 0, sizeof(url_encode_map));
8180 for (i = 0; i < 32; i++) {
8181 FD_SET(i, hdr_encode_map);
8182 FD_SET(i, url_encode_map);
8183 }
8184 for (i = 127; i < 256; i++) {
8185 FD_SET(i, hdr_encode_map);
8186 FD_SET(i, url_encode_map);
8187 }
8188
8189 tmp = "\"#{|}";
8190 while (*tmp) {
8191 FD_SET(*tmp, hdr_encode_map);
8192 tmp++;
8193 }
8194
8195 tmp = "\"#";
8196 while (*tmp) {
8197 FD_SET(*tmp, url_encode_map);
8198 tmp++;
8199 }
8200
willy tarreau64a3cc32005-12-18 01:13:11 +01008201 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
8202#if defined(ENABLE_POLL)
8203 cfg_polling_mechanism |= POLL_USE_POLL;
8204#endif
8205#if defined(ENABLE_EPOLL)
8206 cfg_polling_mechanism |= POLL_USE_EPOLL;
8207#endif
8208
willy tarreau0f7af912005-12-17 12:21:26 +01008209 pid = getpid();
8210 progname = *argv;
8211 while ((tmp = strchr(progname, '/')) != NULL)
8212 progname = tmp + 1;
8213
8214 argc--; argv++;
8215 while (argc > 0) {
8216 char *flag;
8217
8218 if (**argv == '-') {
8219 flag = *argv+1;
8220
8221 /* 1 arg */
8222 if (*flag == 'v') {
8223 display_version();
8224 exit(0);
8225 }
willy tarreau1c2ad212005-12-18 01:11:29 +01008226#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008227 else if (*flag == 'd' && flag[1] == 'e')
8228 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008229#endif
8230#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008231 else if (*flag == 'd' && flag[1] == 'p')
8232 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008233#endif
willy tarreau982249e2005-12-18 00:57:06 +01008234 else if (*flag == 'V')
8235 arg_mode |= MODE_VERBOSE;
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008236 else if (*flag == 'd' && flag[1] == 'b')
8237 arg_mode |= MODE_FOREGROUND;
willy tarreau0f7af912005-12-17 12:21:26 +01008238 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01008239 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01008240 else if (*flag == 'c')
8241 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01008242 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01008243 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01008244 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01008245 arg_mode |= MODE_QUIET;
willy tarreau53e99702006-03-25 18:53:50 +01008246 else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 't')) {
8247 /* list of pids to finish ('f') or terminate ('t') */
8248
8249 if (flag[1] == 'f')
8250 oldpids_sig = SIGUSR1; /* finish then exit */
8251 else
8252 oldpids_sig = SIGTERM; /* terminate immediately */
8253 argv++; argc--;
8254
8255 if (argc > 0) {
8256 oldpids = calloc(argc, sizeof(int));
8257 while (argc > 0) {
8258 oldpids[nb_oldpids] = atol(*argv);
8259 if (oldpids[nb_oldpids] <= 0)
8260 usage(old_argv);
8261 argc--; argv++;
8262 nb_oldpids++;
8263 }
8264 }
8265 }
willy tarreau2c513732006-04-15 19:25:16 +02008266#if STATTIME > 0
8267 else if (*flag == 's')
8268 arg_mode |= MODE_STATS;
8269 else if (*flag == 'l')
8270 arg_mode |= MODE_LOG;
8271#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008272 else { /* >=2 args */
8273 argv++; argc--;
8274 if (argc == 0)
8275 usage(old_argv);
8276
8277 switch (*flag) {
8278 case 'n' : cfg_maxconn = atol(*argv); break;
willy tarreau746e26b2006-03-25 11:14:35 +01008279 case 'm' : global.rlimit_memmax = atol(*argv); break;
willy tarreau0f7af912005-12-17 12:21:26 +01008280 case 'N' : cfg_maxpconn = atol(*argv); break;
8281 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008282 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01008283 default: usage(old_argv);
8284 }
8285 }
8286 }
8287 else
8288 usage(old_argv);
willy tarreau53e99702006-03-25 18:53:50 +01008289 argv++; argc--;
willy tarreau0f7af912005-12-17 12:21:26 +01008290 }
8291
willy tarreaud0fb4652005-12-18 01:32:04 +01008292 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008293 (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_VERBOSE
8294 | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01008295
willy tarreau0f7af912005-12-17 12:21:26 +01008296 if (!cfg_cfgfile)
8297 usage(old_argv);
8298
8299 gethostname(hostname, MAX_HOSTNAME_LEN);
8300
willy tarreau12350152005-12-18 01:03:27 +01008301 have_appsession = 0;
Willy TARREAU203b0b62006-03-12 18:00:28 +01008302 global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */
willy tarreau0f7af912005-12-17 12:21:26 +01008303 if (readcfgfile(cfg_cfgfile) < 0) {
8304 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
8305 exit(1);
8306 }
willy tarreau12350152005-12-18 01:03:27 +01008307 if (have_appsession)
8308 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01008309
willy tarreau982249e2005-12-18 00:57:06 +01008310 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01008311 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
8312 exit(0);
8313 }
8314
willy tarreau9fe663a2005-12-17 13:02:59 +01008315 if (cfg_maxconn > 0)
8316 global.maxconn = cfg_maxconn;
8317
willy tarreaufe2c5c12005-12-17 14:14:34 +01008318 if (cfg_pidfile) {
8319 if (global.pidfile)
8320 free(global.pidfile);
8321 global.pidfile = strdup(cfg_pidfile);
8322 }
8323
willy tarreau9fe663a2005-12-17 13:02:59 +01008324 if (global.maxconn == 0)
8325 global.maxconn = DEFAULT_MAXCONN;
8326
Willy TARREAU203b0b62006-03-12 18:00:28 +01008327 global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
willy tarreau9fe663a2005-12-17 13:02:59 +01008328
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008329 if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008330 /* command line debug mode inhibits configuration mode */
8331 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8332 }
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008333 global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
8334 MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01008335
8336 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
8337 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
8338 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
8339 }
8340
8341 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
willy tarreaubf8ff3d2006-03-25 19:47:03 +01008342 if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
8343 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
willy tarreau9fe663a2005-12-17 13:02:59 +01008344 global.nbproc = 1;
8345 }
8346
8347 if (global.nbproc < 1)
8348 global.nbproc = 1;
8349
willy tarreau0f7af912005-12-17 12:21:26 +01008350 StaticReadEvent = (fd_set *)calloc(1,
8351 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008352 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008353 StaticWriteEvent = (fd_set *)calloc(1,
8354 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01008355 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01008356
8357 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01008358 sizeof(struct fdtab) * (global.maxsock));
8359 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01008360 fdtab[i].state = FD_STCLOSE;
8361 }
8362}
8363
8364/*
willy tarreau41310e72006-03-25 18:17:56 +01008365 * this function starts all the proxies. Its return value is composed from
8366 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
8367 * if <verbose> is not zero.
willy tarreau0f7af912005-12-17 12:21:26 +01008368 */
willy tarreau41310e72006-03-25 18:17:56 +01008369int start_proxies(int verbose) {
willy tarreau0f7af912005-12-17 12:21:26 +01008370 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01008371 struct listener *listener;
willy tarreau41310e72006-03-25 18:17:56 +01008372 int err = ERR_NONE;
8373 int fd, pxerr;
willy tarreau0f7af912005-12-17 12:21:26 +01008374
8375 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008376 if (curproxy->state != PR_STNEW)
8377 continue; /* already initialized */
willy tarreau0f7af912005-12-17 12:21:26 +01008378
willy tarreau41310e72006-03-25 18:17:56 +01008379 pxerr = 0;
willy tarreaua41a8b42005-12-17 14:02:24 +01008380 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
willy tarreau41310e72006-03-25 18:17:56 +01008381 if (listener->fd != -1)
8382 continue; /* already initialized */
8383
8384 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
8385 if (verbose)
8386 Alert("cannot create listening socket for proxy %s. Aborting.\n",
8387 curproxy->id);
8388 err |= ERR_RETRYABLE;
8389 pxerr |= 1;
8390 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008391 }
willy tarreau0f7af912005-12-17 12:21:26 +01008392
willy tarreaua41a8b42005-12-17 14:02:24 +01008393 if (fd >= global.maxsock) {
8394 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
8395 curproxy->id);
8396 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008397 err |= ERR_FATAL;
8398 pxerr |= 1;
8399 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008400 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01008401
willy tarreaua41a8b42005-12-17 14:02:24 +01008402 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
8403 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
8404 (char *) &one, sizeof(one)) == -1)) {
8405 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
8406 curproxy->id);
8407 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008408 err |= ERR_FATAL;
8409 pxerr |= 1;
8410 break;
willy tarreaua41a8b42005-12-17 14:02:24 +01008411 }
willy tarreau0f7af912005-12-17 12:21:26 +01008412
willy tarreaua41a8b42005-12-17 14:02:24 +01008413 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
8414 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
8415 curproxy->id);
8416 }
willy tarreau0f7af912005-12-17 12:21:26 +01008417
willy tarreaua41a8b42005-12-17 14:02:24 +01008418 if (bind(fd,
8419 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01008420 listener->addr.ss_family == AF_INET6 ?
8421 sizeof(struct sockaddr_in6) :
8422 sizeof(struct sockaddr_in)) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008423 if (verbose)
8424 Alert("cannot bind socket for proxy %s. Aborting.\n",
8425 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008426 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008427 err |= ERR_RETRYABLE;
8428 pxerr |= 1;
8429 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008430 }
willy tarreau0f7af912005-12-17 12:21:26 +01008431
willy tarreaua41a8b42005-12-17 14:02:24 +01008432 if (listen(fd, curproxy->maxconn) == -1) {
willy tarreau41310e72006-03-25 18:17:56 +01008433 if (verbose)
8434 Alert("cannot listen to socket for proxy %s. Aborting.\n",
8435 curproxy->id);
willy tarreaua41a8b42005-12-17 14:02:24 +01008436 close(fd);
willy tarreau41310e72006-03-25 18:17:56 +01008437 err |= ERR_RETRYABLE;
8438 pxerr |= 1;
8439 continue;
willy tarreaua41a8b42005-12-17 14:02:24 +01008440 }
willy tarreau0f7af912005-12-17 12:21:26 +01008441
willy tarreau41310e72006-03-25 18:17:56 +01008442 /* the socket is ready */
8443 listener->fd = fd;
8444
willy tarreaua41a8b42005-12-17 14:02:24 +01008445 /* the function for the accept() event */
8446 fdtab[fd].read = &event_accept;
8447 fdtab[fd].write = NULL; /* never called */
8448 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreaua41a8b42005-12-17 14:02:24 +01008449 fdtab[fd].state = FD_STLISTEN;
8450 FD_SET(fd, StaticReadEvent);
8451 fd_insert(fd);
8452 listeners++;
8453 }
willy tarreau41310e72006-03-25 18:17:56 +01008454
8455 if (!pxerr) {
8456 curproxy->state = PR_STRUN;
8457 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
8458 }
willy tarreau0f7af912005-12-17 12:21:26 +01008459 }
willy tarreau41310e72006-03-25 18:17:56 +01008460
8461 return err;
willy tarreau0f7af912005-12-17 12:21:26 +01008462}
8463
willy tarreaub952e1d2005-12-18 01:31:20 +01008464int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01008465
8466 appsess *temp1,*temp2;
8467 temp1 = (appsess *)key1;
8468 temp2 = (appsess *)key2;
8469
8470 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
8471 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
8472
8473 return (strcmp(temp1->sessid,temp2->sessid) == 0);
8474}/* end match_str */
8475
willy tarreaub952e1d2005-12-18 01:31:20 +01008476void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01008477 appsess *temp1;
8478
8479 //printf("destroy called\n");
8480 temp1 = (appsess *)data;
8481
8482 if (temp1->sessid)
8483 pool_free_to(apools.sessid, temp1->sessid);
8484
8485 if (temp1->serverid)
8486 pool_free_to(apools.serverid, temp1->serverid);
8487
8488 pool_free(appsess, temp1);
8489} /* end destroy */
8490
8491void appsession_cleanup( void )
8492{
8493 struct proxy *p = proxy;
8494
8495 while(p) {
8496 chtbl_destroy(&(p->htbl_proxy));
8497 p = p->next;
8498 }
8499}/* end appsession_cleanup() */
8500
8501void pool_destroy(void **pool)
8502{
8503 void *temp, *next;
8504 next = pool;
8505 while (next) {
8506 temp = next;
8507 next = *(void **)temp;
8508 free(temp);
8509 }
8510}/* end pool_destroy() */
8511
willy tarreaub952e1d2005-12-18 01:31:20 +01008512void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008513 struct proxy *p = proxy;
8514 struct cap_hdr *h,*h_next;
8515 struct server *s,*s_next;
8516 struct listener *l,*l_next;
8517
8518 while (p) {
8519 if (p->id)
8520 free(p->id);
8521
8522 if (p->check_req)
8523 free(p->check_req);
8524
8525 if (p->cookie_name)
8526 free(p->cookie_name);
8527
8528 if (p->capture_name)
8529 free(p->capture_name);
8530
8531 /* only strup if the user have set in config.
8532 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008533 if (p->errmsg.msg400) free(p->errmsg.msg400);
8534 if (p->errmsg.msg403) free(p->errmsg.msg403);
8535 if (p->errmsg.msg408) free(p->errmsg.msg408);
8536 if (p->errmsg.msg500) free(p->errmsg.msg500);
8537 if (p->errmsg.msg502) free(p->errmsg.msg502);
8538 if (p->errmsg.msg503) free(p->errmsg.msg503);
8539 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008540 */
8541 if (p->appsession_name)
8542 free(p->appsession_name);
8543
8544 h = p->req_cap;
8545 while (h) {
8546 h_next = h->next;
8547 if (h->name)
8548 free(h->name);
8549 pool_destroy(h->pool);
8550 free(h);
8551 h = h_next;
8552 }/* end while(h) */
8553
8554 h = p->rsp_cap;
8555 while (h) {
8556 h_next = h->next;
8557 if (h->name)
8558 free(h->name);
8559
8560 pool_destroy(h->pool);
8561 free(h);
8562 h = h_next;
8563 }/* end while(h) */
8564
8565 s = p->srv;
8566 while (s) {
8567 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008568 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008569 free(s->id);
8570
willy tarreaub952e1d2005-12-18 01:31:20 +01008571 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008572 free(s->cookie);
8573
8574 free(s);
8575 s = s_next;
8576 }/* end while(s) */
8577
8578 l = p->listen;
8579 while (l) {
8580 l_next = l->next;
8581 free(l);
8582 l = l_next;
8583 }/* end while(l) */
8584
8585 pool_destroy((void **) p->req_cap_pool);
8586 pool_destroy((void **) p->rsp_cap_pool);
8587 p = p->next;
8588 }/* end while(p) */
8589
8590 if (global.chroot) free(global.chroot);
8591 if (global.pidfile) free(global.pidfile);
8592
willy tarreau12350152005-12-18 01:03:27 +01008593 if (StaticReadEvent) free(StaticReadEvent);
8594 if (StaticWriteEvent) free(StaticWriteEvent);
8595 if (fdtab) free(fdtab);
8596
8597 pool_destroy(pool_session);
8598 pool_destroy(pool_buffer);
8599 pool_destroy(pool_fdtab);
8600 pool_destroy(pool_requri);
8601 pool_destroy(pool_task);
8602 pool_destroy(pool_capture);
8603 pool_destroy(pool_appsess);
8604
8605 if (have_appsession) {
8606 pool_destroy(apools.serverid);
8607 pool_destroy(apools.sessid);
8608 }
8609} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008610
willy tarreau41310e72006-03-25 18:17:56 +01008611/* sends the signal <sig> to all pids found in <oldpids> */
8612static void tell_old_pids(int sig) {
8613 int p;
8614 for (p = 0; p < nb_oldpids; p++)
8615 kill(oldpids[p], sig);
8616}
8617
willy tarreau0f7af912005-12-17 12:21:26 +01008618int main(int argc, char **argv) {
willy tarreau41310e72006-03-25 18:17:56 +01008619 int err, retry;
willy tarreaub1285d52005-12-18 01:20:14 +01008620 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008621 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008622 init(argc, argv);
8623
willy tarreau0f7af912005-12-17 12:21:26 +01008624 signal(SIGQUIT, dump);
8625 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008626 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008627#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008628 signal(SIGINT, sig_int);
8629 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008630#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008631
8632 /* on very high loads, a sigpipe sometimes happen just between the
8633 * getsockopt() which tells "it's OK to write", and the following write :-(
8634 */
willy tarreau3242e862005-12-17 12:27:53 +01008635#ifndef MSG_NOSIGNAL
8636 signal(SIGPIPE, SIG_IGN);
8637#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008638
willy tarreau41310e72006-03-25 18:17:56 +01008639 /* We will loop at most 100 times with 10 ms delay each time.
8640 * That's at most 1 second. We only send a signal to old pids
8641 * if we cannot grab at least one port.
8642 */
8643 retry = MAX_START_RETRIES;
8644 err = ERR_NONE;
8645 while (retry >= 0) {
8646 struct timeval w;
8647 err = start_proxies(retry == 0 || nb_oldpids == 0);
8648 if (err != ERR_RETRYABLE)
8649 break;
8650 if (nb_oldpids == 0)
8651 break;
8652
8653 tell_old_pids(SIGTTOU);
8654 /* give some time to old processes to stop listening */
8655 w.tv_sec = 0;
8656 w.tv_usec = 10*1000;
8657 select(0, NULL, NULL, NULL, &w);
8658 retry--;
8659 }
8660
8661 /* Note: start_proxies() sends an alert when it fails. */
8662 if (err != ERR_NONE) {
8663 if (retry != MAX_START_RETRIES && nb_oldpids)
8664 tell_old_pids(SIGTTIN);
willy tarreau0f7af912005-12-17 12:21:26 +01008665 exit(1);
willy tarreau41310e72006-03-25 18:17:56 +01008666 }
willy tarreaud0fb4652005-12-18 01:32:04 +01008667
8668 if (listeners == 0) {
8669 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008670 /* Note: we don't have to send anything to the old pids because we
8671 * never stopped them. */
willy tarreaud0fb4652005-12-18 01:32:04 +01008672 exit(1);
8673 }
8674
willy tarreaudbd3bef2006-01-20 19:35:18 +01008675 /* prepare pause/play signals */
8676 signal(SIGTTOU, sig_pause);
8677 signal(SIGTTIN, sig_listen);
8678
Willy TARREAUe3283d12006-03-01 22:15:29 +01008679 if (global.mode & MODE_DAEMON) {
8680 global.mode &= ~MODE_VERBOSE;
8681 global.mode |= MODE_QUIET;
8682 }
8683
willy tarreaud0fb4652005-12-18 01:32:04 +01008684 /* MODE_QUIET can inhibit alerts and warnings below this line */
8685
8686 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008687 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008688 /* detach from the tty */
8689 fclose(stdin); fclose(stdout); fclose(stderr);
8690 close(0); close(1); close(2);
8691 }
willy tarreau0f7af912005-12-17 12:21:26 +01008692
willy tarreaufe2c5c12005-12-17 14:14:34 +01008693 /* open log & pid files before the chroot */
8694 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8695 int pidfd;
8696 unlink(global.pidfile);
8697 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8698 if (pidfd < 0) {
8699 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
willy tarreau41310e72006-03-25 18:17:56 +01008700 if (nb_oldpids)
8701 tell_old_pids(SIGTTIN);
willy tarreaufe2c5c12005-12-17 14:14:34 +01008702 exit(1);
8703 }
8704 pidfile = fdopen(pidfd, "w");
8705 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008706
8707 /* chroot if needed */
8708 if (global.chroot != NULL) {
8709 if (chroot(global.chroot) == -1) {
8710 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
willy tarreau41310e72006-03-25 18:17:56 +01008711 if (nb_oldpids)
8712 tell_old_pids(SIGTTIN);
willy tarreau9fe663a2005-12-17 13:02:59 +01008713 }
8714 chdir("/");
8715 }
8716
willy tarreaub1285d52005-12-18 01:20:14 +01008717 /* ulimits */
Willy TARREAUdd676172006-03-12 18:01:33 +01008718 if (!global.rlimit_nofile)
8719 global.rlimit_nofile = global.maxsock;
8720
willy tarreaub1285d52005-12-18 01:20:14 +01008721 if (global.rlimit_nofile) {
8722 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8723 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8724 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8725 }
willy tarreau746e26b2006-03-25 11:14:35 +01008726 }
8727
8728 if (global.rlimit_memmax) {
8729 limit.rlim_cur = limit.rlim_max =
8730 global.rlimit_memmax * 1048576 / global.nbproc;
8731#ifdef RLIMIT_AS
8732 if (setrlimit(RLIMIT_AS, &limit) == -1) {
8733 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8734 argv[0], global.rlimit_memmax);
8735 }
8736#else
8737 if (setrlimit(RLIMIT_DATA, &limit) == -1) {
8738 Warning("[%s.main()] Cannot fix MEM limit to %d megs.\n",
8739 argv[0], global.rlimit_memmax);
8740 }
8741#endif
willy tarreaub1285d52005-12-18 01:20:14 +01008742 }
8743
willy tarreau41310e72006-03-25 18:17:56 +01008744 if (nb_oldpids)
8745 tell_old_pids(oldpids_sig);
8746
8747 /* Note that any error at this stage will be fatal because we will not
8748 * be able to restart the old pids.
8749 */
8750
willy tarreau9fe663a2005-12-17 13:02:59 +01008751 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008752 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008753 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8754 exit(1);
8755 }
8756
willy tarreau036e1ce2005-12-17 13:46:33 +01008757 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008758 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8759 exit(1);
8760 }
8761
willy tarreaub1285d52005-12-18 01:20:14 +01008762 /* check ulimits */
8763 limit.rlim_cur = limit.rlim_max = 0;
8764 getrlimit(RLIMIT_NOFILE, &limit);
8765 if (limit.rlim_cur < global.maxsock) {
8766 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",
8767 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8768 }
8769
willy tarreau9fe663a2005-12-17 13:02:59 +01008770 if (global.mode & MODE_DAEMON) {
8771 int ret = 0;
8772 int proc;
8773
8774 /* the father launches the required number of processes */
8775 for (proc = 0; proc < global.nbproc; proc++) {
8776 ret = fork();
8777 if (ret < 0) {
8778 Alert("[%s.main()] Cannot fork.\n", argv[0]);
willy tarreau41310e72006-03-25 18:17:56 +01008779 if (nb_oldpids)
willy tarreau9fe663a2005-12-17 13:02:59 +01008780 exit(1); /* there has been an error */
8781 }
8782 else if (ret == 0) /* child breaks here */
8783 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008784 if (pidfile != NULL) {
8785 fprintf(pidfile, "%d\n", ret);
8786 fflush(pidfile);
8787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008788 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008789 /* close the pidfile both in children and father */
8790 if (pidfile != NULL)
8791 fclose(pidfile);
8792 free(global.pidfile);
8793
willy tarreau9fe663a2005-12-17 13:02:59 +01008794 if (proc == global.nbproc)
8795 exit(0); /* parent must leave */
8796
willy tarreau750a4722005-12-17 13:21:24 +01008797 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8798 * that we can detach from the TTY. We MUST NOT do it in other cases since
8799 * it would have already be done, and 0-2 would have been affected to listening
8800 * sockets
8801 */
8802 if (!(global.mode & MODE_QUIET)) {
8803 /* detach from the tty */
8804 fclose(stdin); fclose(stdout); fclose(stderr);
8805 close(0); close(1); close(2); /* close all fd's */
8806 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8807 }
willy tarreaua1598082005-12-17 13:08:06 +01008808 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008809 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008810 }
8811
willy tarreau1c2ad212005-12-18 01:11:29 +01008812#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008813 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008814 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8815 epoll_loop(POLL_LOOP_ACTION_RUN);
8816 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008817 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008818 }
8819 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008820 Warning("epoll() is not available. Using poll()/select() instead.\n");
8821 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008822 }
8823 }
8824#endif
8825
8826#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008827 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008828 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8829 poll_loop(POLL_LOOP_ACTION_RUN);
8830 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008831 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008832 }
8833 else {
8834 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008835 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008836 }
8837 }
8838#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008839 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008840 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8841 select_loop(POLL_LOOP_ACTION_RUN);
8842 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008843 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008844 }
8845 }
8846
willy tarreau0f7af912005-12-17 12:21:26 +01008847
willy tarreau12350152005-12-18 01:03:27 +01008848 /* Free all Hash Keys and all Hash elements */
8849 appsession_cleanup();
8850 /* Do some cleanup */
8851 deinit();
8852
willy tarreau0f7af912005-12-17 12:21:26 +01008853 exit(0);
8854}
willy tarreau12350152005-12-18 01:03:27 +01008855
8856#if defined(DEBUG_HASH)
8857static void print_table(const CHTbl *htbl) {
8858
8859 ListElmt *element;
8860 int i;
8861 appsess *asession;
8862
8863 /*****************************************************************************
8864 * *
8865 * Display the chained hash table. *
8866 * *
8867 *****************************************************************************/
8868
8869 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8870
8871 for (i = 0; i < TBLSIZ; i++) {
8872 fprintf(stdout, "Bucket[%03d]\n", i);
8873
8874 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8875 //fprintf(stdout, "%c", *(char *)list_data(element));
8876 asession = (appsess *)list_data(element);
8877 fprintf(stdout, "ELEM :%s:", asession->sessid);
8878 fprintf(stdout, " Server :%s: \n", asession->serverid);
8879 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8880 }
8881
8882 fprintf(stdout, "\n");
8883 }
8884 return;
8885} /* end print_table */
8886#endif
8887
8888static int appsession_init(void)
8889{
8890 static int initialized = 0;
8891 int idlen;
8892 struct server *s;
8893 struct proxy *p = proxy;
8894
8895 if (!initialized) {
8896 if (!appsession_task_init()) {
8897 apools.sessid = NULL;
8898 apools.serverid = NULL;
8899 apools.ser_waste = 0;
8900 apools.ser_use = 0;
8901 apools.ser_msize = sizeof(void *);
8902 apools.ses_waste = 0;
8903 apools.ses_use = 0;
8904 apools.ses_msize = sizeof(void *);
8905 while (p) {
8906 s = p->srv;
8907 if (apools.ses_msize < p->appsession_len)
8908 apools.ses_msize = p->appsession_len;
8909 while (s) {
8910 idlen = strlen(s->id);
8911 if (apools.ser_msize < idlen)
8912 apools.ser_msize = idlen;
8913 s = s->next;
8914 }
8915 p = p->next;
8916 }
8917 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8918 apools.ses_msize ++;
8919 }
8920 else {
8921 fprintf(stderr, "appsession_task_init failed\n");
8922 return -1;
8923 }
8924 initialized ++;
8925 }
8926 return 0;
8927}
8928
8929static int appsession_task_init(void)
8930{
8931 static int initialized = 0;
8932 struct task *t;
8933 if (!initialized) {
8934 if ((t = pool_alloc(task)) == NULL)
8935 return -1;
8936 t->next = t->prev = t->rqnext = NULL;
8937 t->wq = LIST_HEAD(wait_queue);
8938 t->state = TASK_IDLE;
8939 t->context = NULL;
8940 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8941 task_queue(t);
8942 t->process = appsession_refresh;
8943 initialized ++;
8944 }
8945 return 0;
8946}
8947
8948static int appsession_refresh(struct task *t) {
8949 struct proxy *p = proxy;
8950 CHTbl *htbl;
8951 ListElmt *element, *last;
8952 int i;
8953 appsess *asession;
8954 void *data;
8955
8956 while (p) {
8957 if (p->appsession_name != NULL) {
8958 htbl = &p->htbl_proxy;
8959 /* if we ever give up the use of TBLSIZ, we need to change this */
8960 for (i = 0; i < TBLSIZ; i++) {
8961 last = NULL;
8962 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8963 asession = (appsess *)list_data(element);
8964 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8965 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8966 int len;
8967 /*
8968 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8969 */
8970 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8971 asession->sessid, asession->serverid?asession->serverid:"(null)");
8972 write(1, trash, len);
8973 }
8974 /* delete the expired element from within the hash table */
8975 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8976 && (htbl->table[i].destroy != NULL)) {
8977 htbl->table[i].destroy(data);
8978 }
8979 if (last == NULL) {/* patient lost his head, get a new one */
8980 element = list_head(&htbl->table[i]);
8981 if (element == NULL) break; /* no heads left, go to next patient */
8982 }
8983 else
8984 element = last;
8985 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8986 else
8987 last = element;
8988 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8989 }
8990 }
8991 p = p->next;
8992 }
8993 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8994 return TBLCHKINT;
8995} /* end appsession_refresh */
8996
willy tarreau18a957c2006-04-12 19:26:23 +02008997
8998/*
8999 * Local variables:
9000 * c-indent-level: 4
9001 * c-basic-offset: 4
9002 * End:
9003 */