blob: 94839ffd9c5e3d62528b8221ca8a1f50da883e93 [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 tarreau598da412005-12-18 01:07:29 +010084#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010085
willy tarreau065f1c02006-01-29 22:10:07 +010086#define HAPROXY_VERSION "1.2.8"
87#define HAPROXY_DATE "2006/01/29"
willy tarreau0f7af912005-12-17 12:21:26 +010088
89/* this is for libc5 for example */
90#ifndef TCP_NODELAY
91#define TCP_NODELAY 1
92#endif
93
94#ifndef SHUT_RD
95#define SHUT_RD 0
96#endif
97
98#ifndef SHUT_WR
99#define SHUT_WR 1
100#endif
101
willy tarreau0174f312005-12-18 01:02:42 +0100102/*
103 * BUFSIZE defines the size of a read and write buffer. It is the maximum
104 * amount of bytes which can be stored by the proxy for each session. However,
105 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
106 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
107 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
108 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
109 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
110 */
111#ifndef BUFSIZE
112#define BUFSIZE 16384
113#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100114
115// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100116#ifndef MAXREWRITE
117#define MAXREWRITE (BUFSIZE / 2)
118#endif
119
willy tarreau9fe663a2005-12-17 13:02:59 +0100120#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100121#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100122
willy tarreau5cbea6f2005-12-17 12:48:26 +0100123// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100124#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100125
willy tarreaue39cd132005-12-17 13:00:18 +0100126// max # of added headers per request
127#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100128
129// max # of matches per regexp
130#define MAX_MATCH 10
131
willy tarreau0174f312005-12-18 01:02:42 +0100132// cookie delimitor in "prefix" mode. This character is inserted between the
133// persistence cookie and the original value. The '~' is allowed by RFC2965,
134// and should not be too common in server names.
135#ifndef COOKIE_DELIM
136#define COOKIE_DELIM '~'
137#endif
138
willy tarreau0f7af912005-12-17 12:21:26 +0100139#define CONN_RETRIES 3
140
willy tarreau5cbea6f2005-12-17 12:48:26 +0100141#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100142#define DEF_CHKINTR 2000
143#define DEF_FALLTIME 3
144#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100145#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100146
willy tarreau9fe663a2005-12-17 13:02:59 +0100147/* default connections limit */
148#define DEFAULT_MAXCONN 2000
149
willy tarreau0f7af912005-12-17 12:21:26 +0100150/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
151#define INTBITS 5
152
153/* show stats this every millisecond, 0 to disable */
154#ifndef STATTIME
155#define STATTIME 2000
156#endif
157
willy tarreau5cbea6f2005-12-17 12:48:26 +0100158/* this reduces the number of calls to select() by choosing appropriate
159 * sheduler precision in milliseconds. It should be near the minimum
160 * time that is needed by select() to collect all events. All timeouts
161 * are rounded up by adding this value prior to pass it to select().
162 */
163#define SCHEDULER_RESOLUTION 9
164
willy tarreaub952e1d2005-12-18 01:31:20 +0100165#define TIME_ETERNITY -1
166/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100167#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
168#define SETNOW(a) (*a=now)
169
willy tarreau9da061b2005-12-17 12:29:56 +0100170/****** string-specific macros and functions ******/
171/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
172#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
173
174/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
175#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
176
willy tarreau0174f312005-12-18 01:02:42 +0100177/* returns 1 only if only zero or one bit is set in X, which means that X is a
178 * power of 2, and 0 otherwise */
179#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100180/*
181 * copies at most <size-1> chars from <src> to <dst>. Last char is always
182 * set to 0, unless <size> is 0. The number of chars copied is returned
183 * (excluding the terminating zero).
184 * This code has been optimized for size and speed : on x86, it's 45 bytes
185 * long, uses only registers, and consumes only 4 cycles per char.
186 */
willy tarreau750a4722005-12-17 13:21:24 +0100187int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100188 char *orig = dst;
189 if (size) {
190 while (--size && (*dst = *src)) {
191 src++; dst++;
192 }
193 *dst = 0;
194 }
195 return dst - orig;
196}
willy tarreau9da061b2005-12-17 12:29:56 +0100197
willy tarreau4302f492005-12-18 01:00:37 +0100198/*
199 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
200 * dynamically allocated. In the first case, <__pool> is updated to point to
201 * the next element in the list.
202 */
203#define pool_alloc_from(__pool, __len) ({ \
204 void *__p; \
205 if ((__p = (__pool)) == NULL) \
206 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
207 else { \
208 __pool = *(void **)(__pool); \
209 } \
210 __p; \
211})
212
213/*
214 * Puts a memory area back to the corresponding pool.
215 * Items are chained directly through a pointer that
216 * is written in the beginning of the memory area, so
217 * there's no need for any carrier cell. This implies
218 * that each memory area is at least as big as one
219 * pointer.
220 */
221#define pool_free_to(__pool, __ptr) ({ \
222 *(void **)(__ptr) = (void *)(__pool); \
223 __pool = (void *)(__ptr); \
224})
225
226
willy tarreau0f7af912005-12-17 12:21:26 +0100227#define MEM_OPTIM
228#ifdef MEM_OPTIM
229/*
230 * Returns a pointer to type <type> taken from the
231 * pool <pool_type> or dynamically allocated. In the
232 * first case, <pool_type> is updated to point to the
233 * next element in the list.
234 */
235#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100236 void *__p; \
237 if ((__p = pool_##type) == NULL) \
238 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100239 else { \
240 pool_##type = *(void **)pool_##type; \
241 } \
willy tarreau4302f492005-12-18 01:00:37 +0100242 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100243})
244
245/*
246 * Puts a memory area back to the corresponding pool.
247 * Items are chained directly through a pointer that
248 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100249 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100250 * that each memory area is at least as big as one
251 * pointer.
252 */
253#define pool_free(type, ptr) ({ \
254 *(void **)ptr = (void *)pool_##type; \
255 pool_##type = (void *)ptr; \
256})
257
258#else
259#define pool_alloc(type) (calloc(1,sizeof_##type));
260#define pool_free(type, ptr) (free(ptr));
261#endif /* MEM_OPTIM */
262
willy tarreau5cbea6f2005-12-17 12:48:26 +0100263#define sizeof_task sizeof(struct task)
264#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100265#define sizeof_buffer sizeof(struct buffer)
266#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100267#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100268#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100269#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100270#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100271
willy tarreau5cbea6f2005-12-17 12:48:26 +0100272/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100273#define FD_STCLOSE 0
274#define FD_STLISTEN 1
275#define FD_STCONN 2
276#define FD_STREADY 3
277#define FD_STERROR 4
278
willy tarreau5cbea6f2005-12-17 12:48:26 +0100279/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100280#define TASK_IDLE 0
281#define TASK_RUNNING 1
282
willy tarreau5cbea6f2005-12-17 12:48:26 +0100283/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100284#define PR_STNEW 0
285#define PR_STIDLE 1
286#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100287#define PR_STSTOPPED 3
288#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100289
willy tarreau5cbea6f2005-12-17 12:48:26 +0100290/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define PR_MODE_TCP 0
292#define PR_MODE_HTTP 1
293#define PR_MODE_HEALTH 2
294
willy tarreau1c2ad212005-12-18 01:11:29 +0100295/* possible actions for the *poll() loops */
296#define POLL_LOOP_ACTION_INIT 0
297#define POLL_LOOP_ACTION_RUN 1
298#define POLL_LOOP_ACTION_CLEAN 2
299
willy tarreau64a3cc32005-12-18 01:13:11 +0100300/* poll mechanisms available */
301#define POLL_USE_SELECT (1<<0)
302#define POLL_USE_POLL (1<<1)
303#define POLL_USE_EPOLL (1<<2)
304
willy tarreau5cbea6f2005-12-17 12:48:26 +0100305/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100306#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
307#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
308#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
309#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
310#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
311#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
312#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
313#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100314#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100315#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
316#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
317#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
318#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
319#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
320#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
321#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
322#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
323#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
324#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
325#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100326#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
327#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
Willy TARREAU3481c462006-03-01 22:37:57 +0100328#define PR_O_USE_ALL_BK 0x00100000 /* load-balance between backup servers */
Willy TARREAU767ba712006-03-01 22:40:50 +0100329#define PR_O_FORCE_CLO 0x00200000 /* enforce the connection close immediately after server response */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330
willy tarreaue39cd132005-12-17 13:00:18 +0100331/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100332#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
333#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
334#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
335#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
336#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
337#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100338#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100339
340#define SN_CK_NONE 0x00000000 /* this session had no cookie */
341#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
342#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
343#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
344#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
345#define SN_CK_SHIFT 6 /* bit shift */
346
willy tarreaub1285d52005-12-18 01:20:14 +0100347#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100348#define SN_ERR_CLITO 0x00000100 /* client time-out */
349#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
350#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
351#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
352#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100353#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
354#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100355#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
356#define SN_ERR_SHIFT 8 /* bit shift */
357
358#define SN_FINST_R 0x00001000 /* session ended during client request */
359#define SN_FINST_C 0x00002000 /* session ended during server connect */
360#define SN_FINST_H 0x00003000 /* session ended during server headers */
361#define SN_FINST_D 0x00004000 /* session ended during data phase */
362#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
363#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
364#define SN_FINST_SHIFT 12 /* bit shift */
365
366#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
367#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
368#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
369#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
370#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100371#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100372#define SN_SCK_SHIFT 16 /* bit shift */
373
willy tarreau97f58572005-12-18 00:53:44 +0100374#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
375#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
376#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100377
378/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100379#define CL_STHEADERS 0
380#define CL_STDATA 1
381#define CL_STSHUTR 2
382#define CL_STSHUTW 3
383#define CL_STCLOSE 4
384
willy tarreau5cbea6f2005-12-17 12:48:26 +0100385/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100386#define SV_STIDLE 0
387#define SV_STCONN 1
388#define SV_STHEADERS 2
389#define SV_STDATA 3
390#define SV_STSHUTR 4
391#define SV_STSHUTW 5
392#define SV_STCLOSE 6
393
394/* result of an I/O event */
395#define RES_SILENT 0 /* didn't happen */
396#define RES_DATA 1 /* data were sent or received */
397#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
398#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
399
willy tarreau9fe663a2005-12-17 13:02:59 +0100400/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100401#define MODE_DEBUG 1
402#define MODE_STATS 2
403#define MODE_LOG 4
404#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100405#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100406#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100407#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100408#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100409
410/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100411#define SRV_RUNNING 1 /* the server is UP */
412#define SRV_BACKUP 2 /* this server is a backup server */
413#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100414#define SRV_BIND_SRC 8 /* this server uses a specific source address */
Willy TARREAU3759f982006-03-01 22:44:17 +0100415#define SRV_CHECKED 16 /* this server needs to be checked */
willy tarreau0f7af912005-12-17 12:21:26 +0100416
willy tarreaue39cd132005-12-17 13:00:18 +0100417/* what to do when a header matches a regex */
418#define ACT_ALLOW 0 /* allow the request */
419#define ACT_REPLACE 1 /* replace the matching header */
420#define ACT_REMOVE 2 /* remove the matching header */
421#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100422#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100423
willy tarreau9fe663a2005-12-17 13:02:59 +0100424/* configuration sections */
425#define CFG_NONE 0
426#define CFG_GLOBAL 1
427#define CFG_LISTEN 2
428
willy tarreaua1598082005-12-17 13:08:06 +0100429/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100430#define LW_DATE 1 /* date */
431#define LW_CLIP 2 /* CLient IP */
432#define LW_SVIP 4 /* SerVer IP */
433#define LW_SVID 8 /* server ID */
434#define LW_REQ 16 /* http REQuest */
435#define LW_RESP 32 /* http RESPonse */
436#define LW_PXIP 64 /* proxy IP */
437#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100438#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100439#define LW_COOKIE 512 /* captured cookie */
440#define LW_REQHDR 1024 /* request header(s) */
441#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100442
willy tarreau0f7af912005-12-17 12:21:26 +0100443/*********************************************************************/
444
445#define LIST_HEAD(a) ((void *)(&(a)))
446
447/*********************************************************************/
448
willy tarreau4302f492005-12-18 01:00:37 +0100449struct cap_hdr {
450 struct cap_hdr *next;
451 char *name; /* header name, case insensitive */
452 int namelen; /* length of the header name, to speed-up lookups */
453 int len; /* capture length, not including terminal zero */
454 int index; /* index in the output array */
455 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
456};
457
willy tarreau0f7af912005-12-17 12:21:26 +0100458struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100459 struct hdr_exp *next;
460 regex_t *preg; /* expression to look for */
461 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
462 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100463};
464
465struct buffer {
466 unsigned int l; /* data length */
467 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100468 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100469 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100470 char data[BUFSIZE];
471};
472
473struct server {
474 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100475 int state; /* server state (SRV_*) */
476 int cklen; /* the len of the cookie, to speed up checks */
477 char *cookie; /* the id set in the cookie */
478 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100480 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100481 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100482 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100483 int rise, fall; /* time in iterations */
484 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100485 int result; /* 0 = connect OK, -1 = connect KO */
486 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100487 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100488};
489
willy tarreau5cbea6f2005-12-17 12:48:26 +0100490/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100491struct task {
492 struct task *next, *prev; /* chaining ... */
493 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100494 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100495 int state; /* task state : IDLE or RUNNING */
496 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 int (*process)(struct task *t); /* the function which processes the task */
498 void *context; /* the task's context */
499};
500
501/* WARNING: if new fields are added, they must be initialized in event_accept() */
502struct session {
503 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100504 /* application specific below */
505 struct timeval crexpire; /* expiration date for a client read */
506 struct timeval cwexpire; /* expiration date for a client write */
507 struct timeval srexpire; /* expiration date for a server read */
508 struct timeval swexpire; /* expiration date for a server write */
509 struct timeval cnexpire; /* expiration date for a connect */
510 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
511 struct proxy *proxy; /* the proxy this socket belongs to */
512 int cli_fd; /* the client side fd */
513 int srv_fd; /* the server side fd */
514 int cli_state; /* state of the client side */
515 int srv_state; /* state of the server side */
516 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100517 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100518 struct buffer *req; /* request buffer */
519 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100520 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100521 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100522 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100523 char **req_cap; /* array of captured request headers (may be NULL) */
524 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100525 struct {
526 int logwait; /* log fields waiting to be collected : LW_* */
527 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
528 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
529 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
530 long t_data; /* delay before the first data byte from the server ... */
531 unsigned long t_close; /* total session duration */
532 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100533 char *cli_cookie; /* cookie presented by the client, in capture mode */
534 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100535 int status; /* HTTP status from the server, negative if from proxy */
536 long long bytes; /* number of bytes transferred from the server */
537 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100538 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100539};
540
willy tarreaua41a8b42005-12-17 14:02:24 +0100541struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100542 int fd; /* the listen socket */
543 struct sockaddr_storage addr; /* the address we listen to */
544 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100545};
546
547
willy tarreau0f7af912005-12-17 12:21:26 +0100548struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100549 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100550 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 +0100551 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100552 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100553 struct server *srv, *cursrv; /* known servers, current server */
554 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100555 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100556 int cookie_len; /* strlen(cookie_name), computed only once */
557 char *appsession_name; /* name of the cookie to look for */
558 int appsession_name_len; /* strlen(appsession_name), computed only once */
559 int appsession_len; /* length of the appsession cookie value to be used */
560 int appsession_timeout;
561 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100562 char *capture_name; /* beginning of the name of the cookie to capture */
563 int capture_namelen; /* length of the cookie name to match */
564 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100565 int clitimeout; /* client I/O timeout (in milliseconds) */
566 int srvtimeout; /* server I/O timeout (in milliseconds) */
567 int contimeout; /* connect timeout (in milliseconds) */
568 char *id; /* proxy id */
569 int nbconn; /* # of active sessions */
570 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100571 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100572 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100573 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100574 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100575 struct proxy *next;
576 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100577 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100578 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100579 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100580 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100581 int nb_reqadd, nb_rspadd;
582 struct hdr_exp *req_exp; /* regular expressions for request headers */
583 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100584 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
585 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
586 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
587 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100588 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100589 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100590 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
591 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100592 struct {
593 char *msg400; /* message for error 400 */
594 int len400; /* message length for error 400 */
595 char *msg403; /* message for error 403 */
596 int len403; /* message length for error 403 */
597 char *msg408; /* message for error 408 */
598 int len408; /* message length for error 408 */
599 char *msg500; /* message for error 500 */
600 int len500; /* message length for error 500 */
601 char *msg502; /* message for error 502 */
602 int len502; /* message length for error 502 */
603 char *msg503; /* message for error 503 */
604 int len503; /* message length for error 503 */
605 char *msg504; /* message for error 504 */
606 int len504; /* message length for error 504 */
607 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100608};
609
610/* info about one given fd */
611struct fdtab {
612 int (*read)(int fd); /* read function */
613 int (*write)(int fd); /* write function */
614 struct task *owner; /* the session (or proxy) associated with this fd */
615 int state; /* the state of this fd */
616};
617
618/*********************************************************************/
619
willy tarreaub952e1d2005-12-18 01:31:20 +0100620int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100621char *cfg_cfgfile = NULL; /* configuration file */
622char *progname = NULL; /* program name */
623int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100624
625/* global options */
626static struct {
627 int uid;
628 int gid;
629 int nbproc;
630 int maxconn;
631 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100632 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100633 int mode;
634 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100635 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100636 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100637 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100638 struct sockaddr_in logsrv1, logsrv2;
639} global = {
640 logfac1 : -1,
641 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100642 loglev1 : 7, /* max syslog level : debug */
643 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100644 /* others NULL OK */
645};
646
willy tarreau0f7af912005-12-17 12:21:26 +0100647/*********************************************************************/
648
willy tarreau1c2ad212005-12-18 01:11:29 +0100649fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100650 *StaticWriteEvent;
651
willy tarreau64a3cc32005-12-18 01:13:11 +0100652int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100653
willy tarreau0f7af912005-12-17 12:21:26 +0100654void **pool_session = NULL,
655 **pool_buffer = NULL,
656 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100657 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100658 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100659 **pool_capture = NULL,
660 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100661
662struct proxy *proxy = NULL; /* list of all existing proxies */
663struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100664struct task *rq = NULL; /* global run queue */
665struct task wait_queue = { /* global wait queue */
666 prev:LIST_HEAD(wait_queue),
667 next:LIST_HEAD(wait_queue)
668};
willy tarreau0f7af912005-12-17 12:21:26 +0100669
willy tarreau0f7af912005-12-17 12:21:26 +0100670static int totalconn = 0; /* total # of terminated sessions */
671static int actconn = 0; /* # of active sessions */
672static int maxfd = 0; /* # of the highest fd + 1 */
673static int listeners = 0; /* # of listeners */
674static int stopping = 0; /* non zero means stopping in progress */
675static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100676static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100677
willy tarreau08dedbe2005-12-18 01:13:48 +0100678#if defined(ENABLE_EPOLL)
679/* FIXME: this is dirty, but at the moment, there's no other solution to remove
680 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
681 * structure with pointers to functions such as init_fd() and close_fd(), plus
682 * a private structure with several pointers to places such as below.
683 */
684
685static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
686#endif
687
willy tarreau0f7af912005-12-17 12:21:26 +0100688static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100689/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100690static char trash[BUFSIZE];
691
willy tarreaudd07e972005-12-18 00:48:48 +0100692const int zero = 0;
693const int one = 1;
694
willy tarreau0f7af912005-12-17 12:21:26 +0100695/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100696 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100697 */
698
699#define MAX_SYSLOG_LEN 1024
700#define NB_LOG_FACILITIES 24
701const char *log_facilities[NB_LOG_FACILITIES] = {
702 "kern", "user", "mail", "daemon",
703 "auth", "syslog", "lpr", "news",
704 "uucp", "cron", "auth2", "ftp",
705 "ntp", "audit", "alert", "cron2",
706 "local0", "local1", "local2", "local3",
707 "local4", "local5", "local6", "local7"
708};
709
710
711#define NB_LOG_LEVELS 8
712const char *log_levels[NB_LOG_LEVELS] = {
713 "emerg", "alert", "crit", "err",
714 "warning", "notice", "info", "debug"
715};
716
717#define SYSLOG_PORT 514
718
719const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
720 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100721
willy tarreaub1285d52005-12-18 01:20:14 +0100722const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100723const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
724const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
725const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
726 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
727 unknown, Set-cookie Rewritten */
728
willy tarreau0f7af912005-12-17 12:21:26 +0100729#define MAX_HOSTNAME_LEN 32
730static char hostname[MAX_HOSTNAME_LEN] = "";
731
willy tarreau8337c6b2005-12-17 13:41:01 +0100732const char *HTTP_302 =
733 "HTTP/1.0 302 Found\r\n"
734 "Cache-Control: no-cache\r\n"
735 "Connection: close\r\n"
736 "Location: "; /* not terminated since it will be concatenated with the URL */
737
willy tarreauc1f47532005-12-18 01:08:26 +0100738/* same as 302 except that the browser MUST retry with the GET method */
739const char *HTTP_303 =
740 "HTTP/1.0 303 See Other\r\n"
741 "Cache-Control: no-cache\r\n"
742 "Connection: close\r\n"
743 "Location: "; /* not terminated since it will be concatenated with the URL */
744
willy tarreaua1598082005-12-17 13:08:06 +0100745const char *HTTP_400 =
746 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100747 "Cache-Control: no-cache\r\n"
748 "Connection: close\r\n"
749 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100750 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100751
willy tarreaua1598082005-12-17 13:08:06 +0100752const char *HTTP_403 =
753 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100754 "Cache-Control: no-cache\r\n"
755 "Connection: close\r\n"
756 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100757 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
758
willy tarreau8337c6b2005-12-17 13:41:01 +0100759const char *HTTP_408 =
760 "HTTP/1.0 408 Request Time-out\r\n"
761 "Cache-Control: no-cache\r\n"
762 "Connection: close\r\n"
763 "\r\n"
764 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
765
willy tarreau750a4722005-12-17 13:21:24 +0100766const char *HTTP_500 =
767 "HTTP/1.0 500 Server Error\r\n"
768 "Cache-Control: no-cache\r\n"
769 "Connection: close\r\n"
770 "\r\n"
771 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100772
773const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100774 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100775 "Cache-Control: no-cache\r\n"
776 "Connection: close\r\n"
777 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100778 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
779
780const char *HTTP_503 =
781 "HTTP/1.0 503 Service Unavailable\r\n"
782 "Cache-Control: no-cache\r\n"
783 "Connection: close\r\n"
784 "\r\n"
785 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
786
787const char *HTTP_504 =
788 "HTTP/1.0 504 Gateway Time-out\r\n"
789 "Cache-Control: no-cache\r\n"
790 "Connection: close\r\n"
791 "\r\n"
792 "<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 +0100793
willy tarreau0f7af912005-12-17 12:21:26 +0100794/*********************************************************************/
795/* statistics ******************************************************/
796/*********************************************************************/
797
willy tarreau750a4722005-12-17 13:21:24 +0100798#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100799static int stats_tsk_lsrch, stats_tsk_rsrch,
800 stats_tsk_good, stats_tsk_right, stats_tsk_left,
801 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100802#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100803
804
805/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100806/* debugging *******************************************************/
807/*********************************************************************/
808#ifdef DEBUG_FULL
809static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
810static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
811#endif
812
813/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100814/* function prototypes *********************************************/
815/*********************************************************************/
816
817int event_accept(int fd);
818int event_cli_read(int fd);
819int event_cli_write(int fd);
820int event_srv_read(int fd);
821int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100822int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100823
willy tarreau12350152005-12-18 01:03:27 +0100824static int appsession_task_init(void);
825static int appsession_init(void);
826static int appsession_refresh(struct task *t);
827
willy tarreau0f7af912005-12-17 12:21:26 +0100828/*********************************************************************/
829/* general purpose functions ***************************************/
830/*********************************************************************/
831
832void display_version() {
833 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100834 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100835}
836
837/*
838 * This function prints the command line usage and exits
839 */
840void usage(char *name) {
841 display_version();
842 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100843 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100844#if STATTIME > 0
845 "sl"
846#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100847 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100848 " -v displays version\n"
849 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100850 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100851#if STATTIME > 0
852 " -s enables statistics output\n"
853 " -l enables long statistics format\n"
854#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100855 " -D goes daemon ; implies -q\n"
856 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100857 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100858 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100859 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100860 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100861#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100862 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100863#endif
864#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100865 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100866#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100867 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100868 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100869 exit(1);
870}
871
872
873/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100874 * Displays the message on stderr with the date and pid. Overrides the quiet
875 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100876 */
877void Alert(char *fmt, ...) {
878 va_list argp;
879 struct timeval tv;
880 struct tm *tm;
881
willy tarreaud0fb4652005-12-18 01:32:04 +0100882 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100883 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100884
willy tarreau5cbea6f2005-12-17 12:48:26 +0100885 gettimeofday(&tv, NULL);
886 tm=localtime(&tv.tv_sec);
887 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100888 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100889 vfprintf(stderr, fmt, argp);
890 fflush(stderr);
891 va_end(argp);
892 }
willy tarreau0f7af912005-12-17 12:21:26 +0100893}
894
895
896/*
897 * Displays the message on stderr with the date and pid.
898 */
899void Warning(char *fmt, ...) {
900 va_list argp;
901 struct timeval tv;
902 struct tm *tm;
903
willy tarreau982249e2005-12-18 00:57:06 +0100904 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100905 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100906
willy tarreau5cbea6f2005-12-17 12:48:26 +0100907 gettimeofday(&tv, NULL);
908 tm=localtime(&tv.tv_sec);
909 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100910 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100911 vfprintf(stderr, fmt, argp);
912 fflush(stderr);
913 va_end(argp);
914 }
915}
916
917/*
918 * Displays the message on <out> only if quiet mode is not set.
919 */
920void qfprintf(FILE *out, char *fmt, ...) {
921 va_list argp;
922
willy tarreau982249e2005-12-18 00:57:06 +0100923 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924 va_start(argp, fmt);
925 vfprintf(out, fmt, argp);
926 fflush(out);
927 va_end(argp);
928 }
willy tarreau0f7af912005-12-17 12:21:26 +0100929}
930
931
932/*
933 * converts <str> to a struct sockaddr_in* which is locally allocated.
934 * The format is "addr:port", where "addr" can be empty or "*" to indicate
935 * INADDR_ANY.
936 */
937struct sockaddr_in *str2sa(char *str) {
938 static struct sockaddr_in sa;
939 char *c;
940 int port;
941
willy tarreaua1598082005-12-17 13:08:06 +0100942 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100943 str=strdup(str);
944
945 if ((c=strrchr(str,':')) != NULL) {
946 *c++=0;
947 port=atol(c);
948 }
949 else
950 port=0;
951
952 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
953 sa.sin_addr.s_addr = INADDR_ANY;
954 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100955 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100956 struct hostent *he;
957
958 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100959 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100960 }
961 else
962 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
963 }
964 sa.sin_port=htons(port);
965 sa.sin_family=AF_INET;
966
967 free(str);
968 return &sa;
969}
970
willy tarreaub1285d52005-12-18 01:20:14 +0100971/*
972 * converts <str> to a two struct in_addr* which are locally allocated.
973 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
974 * is optionnal and either in the dotted or CIDR notation.
975 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
976 */
977int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
978 char *c;
979 unsigned long len;
980
981 memset(mask, 0, sizeof(*mask));
982 memset(addr, 0, sizeof(*addr));
983 str=strdup(str);
984
985 if ((c = strrchr(str, '/')) != NULL) {
986 *c++ = 0;
987 /* c points to the mask */
988 if (strchr(c, '.') != NULL) { /* dotted notation */
989 if (!inet_pton(AF_INET, c, mask))
990 return 0;
991 }
992 else { /* mask length */
993 char *err;
994 len = strtol(c, &err, 10);
995 if (!*c || (err && *err) || (unsigned)len > 32)
996 return 0;
997 if (len)
998 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
999 else
1000 mask->s_addr = 0;
1001 }
1002 }
1003 else {
1004 mask->s_addr = 0xFFFFFFFF;
1005 }
1006 if (!inet_pton(AF_INET, str, addr)) {
1007 struct hostent *he;
1008
1009 if ((he = gethostbyname(str)) == NULL) {
1010 return 0;
1011 }
1012 else
1013 *addr = *(struct in_addr *) *(he->h_addr_list);
1014 }
1015 free(str);
1016 return 1;
1017}
1018
willy tarreau9fe663a2005-12-17 13:02:59 +01001019
1020/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001021 * converts <str> to a list of listeners which are dynamically allocated.
1022 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1023 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1024 * - <port> is a numerical port from 1 to 65535 ;
1025 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1026 * This can be repeated as many times as necessary, separated by a coma.
1027 * The <tail> argument is a pointer to a current list which should be appended
1028 * to the tail of the new list. The pointer to the new list is returned.
1029 */
1030struct listener *str2listener(char *str, struct listener *tail) {
1031 struct listener *l;
1032 char *c, *next, *range, *dupstr;
1033 int port, end;
1034
1035 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001036
willy tarreaua41a8b42005-12-17 14:02:24 +01001037 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001038 struct sockaddr_storage ss;
1039
willy tarreaua41a8b42005-12-17 14:02:24 +01001040 str = next;
1041 /* 1) look for the end of the first address */
1042 if ((next = strrchr(str, ',')) != NULL) {
1043 *next++ = 0;
1044 }
1045
willy tarreau8a86dbf2005-12-18 00:45:59 +01001046 /* 2) look for the addr/port delimiter, it's the last colon. */
1047 if ((range = strrchr(str, ':')) == NULL) {
1048 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001049 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001050 }
1051
1052 *range++ = 0;
1053
1054 if (strrchr(str, ':') != NULL) {
1055 /* IPv6 address contains ':' */
1056 memset(&ss, 0, sizeof(ss));
1057 ss.ss_family = AF_INET6;
1058
1059 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1060 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001061 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001062 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001063 }
1064 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001065 memset(&ss, 0, sizeof(ss));
1066 ss.ss_family = AF_INET;
1067
1068 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1069 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1070 }
1071 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1072 struct hostent *he;
1073
1074 if ((he = gethostbyname(str)) == NULL) {
1075 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001076 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001077 }
1078 else
1079 ((struct sockaddr_in *)&ss)->sin_addr =
1080 *(struct in_addr *) *(he->h_addr_list);
1081 }
1082 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001083
1084 /* 3) look for the port-end delimiter */
1085 if ((c = strchr(range, '-')) != NULL) {
1086 *c++ = 0;
1087 end = atol(c);
1088 }
1089 else {
1090 end = atol(range);
1091 }
1092
willy tarreaud0fb4652005-12-18 01:32:04 +01001093 port = atol(range);
1094
1095 if (port < 1 || port > 65535) {
1096 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1097 goto fail;
1098 }
1099
1100 if (end < 1 || end > 65535) {
1101 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1102 goto fail;
1103 }
1104
1105 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001106 l = (struct listener *)calloc(1, sizeof(struct listener));
1107 l->next = tail;
1108 tail = l;
1109
willy tarreau8a86dbf2005-12-18 00:45:59 +01001110 l->addr = ss;
1111 if (ss.ss_family == AF_INET6)
1112 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1113 else
1114 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1115
willy tarreaua41a8b42005-12-17 14:02:24 +01001116 } /* end for(port) */
1117 } /* end while(next) */
1118 free(dupstr);
1119 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001120 fail:
1121 free(dupstr);
1122 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001123}
1124
willy tarreau4302f492005-12-18 01:00:37 +01001125
1126#define FD_SETS_ARE_BITFIELDS
1127#ifdef FD_SETS_ARE_BITFIELDS
1128/*
1129 * This map is used with all the FD_* macros to check whether a particular bit
1130 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1131 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1132 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1133 * exclusively to the macros.
1134 */
1135fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1136fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1137
1138#else
1139#error "Check if your OS uses bitfields for fd_sets"
1140#endif
1141
1142/* will try to encode the string <string> replacing all characters tagged in
1143 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1144 * prefixed by <escape>, and will store the result between <start> (included
1145 *) and <stop> (excluded), and will always terminate the string with a '\0'
1146 * before <stop>. The position of the '\0' is returned if the conversion
1147 * completes. If bytes are missing between <start> and <stop>, then the
1148 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1149 * cannot even be stored so we return <start> without writing the 0.
1150 * The input string must also be zero-terminated.
1151 */
1152char hextab[16] = "0123456789ABCDEF";
1153char *encode_string(char *start, char *stop,
1154 const char escape, const fd_set *map,
1155 const char *string)
1156{
1157 if (start < stop) {
1158 stop--; /* reserve one byte for the final '\0' */
1159 while (start < stop && *string != 0) {
1160 if (!FD_ISSET((unsigned char)(*string), map))
1161 *start++ = *string;
1162 else {
1163 if (start + 3 >= stop)
1164 break;
1165 *start++ = escape;
1166 *start++ = hextab[(*string >> 4) & 15];
1167 *start++ = hextab[*string & 15];
1168 }
1169 string++;
1170 }
1171 *start = '\0';
1172 }
1173 return start;
1174}
willy tarreaua41a8b42005-12-17 14:02:24 +01001175
1176/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001177 * This function sends a syslog message to both log servers of a proxy,
1178 * or to global log servers if the proxy is NULL.
1179 * It also tries not to waste too much time computing the message header.
1180 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001181 */
1182void send_log(struct proxy *p, int level, char *message, ...) {
1183 static int logfd = -1; /* syslog UDP socket */
1184 static long tvsec = -1; /* to force the string to be initialized */
1185 struct timeval tv;
1186 va_list argp;
1187 static char logmsg[MAX_SYSLOG_LEN];
1188 static char *dataptr = NULL;
1189 int fac_level;
1190 int hdr_len, data_len;
1191 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001192 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001193 int nbloggers = 0;
1194 char *log_ptr;
1195
1196 if (logfd < 0) {
1197 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1198 return;
1199 }
1200
1201 if (level < 0 || progname == NULL || message == NULL)
1202 return;
1203
1204 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001205 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001206 /* this string is rebuild only once a second */
1207 struct tm *tm = localtime(&tv.tv_sec);
1208 tvsec = tv.tv_sec;
1209
willy tarreauc29948c2005-12-17 13:10:27 +01001210 hdr_len = snprintf(logmsg, sizeof(logmsg),
1211 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1212 monthname[tm->tm_mon],
1213 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1214 progname, pid);
1215 /* WARNING: depending upon implementations, snprintf may return
1216 * either -1 or the number of bytes that would be needed to store
1217 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001218 */
willy tarreauc29948c2005-12-17 13:10:27 +01001219 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1220 hdr_len = sizeof(logmsg);
1221
1222 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001223 }
1224
1225 va_start(argp, message);
1226 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001227 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1228 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001229 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001230 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001231
1232 if (p == NULL) {
1233 if (global.logfac1 >= 0) {
1234 sa[nbloggers] = &global.logsrv1;
1235 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001236 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001237 nbloggers++;
1238 }
1239 if (global.logfac2 >= 0) {
1240 sa[nbloggers] = &global.logsrv2;
1241 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001242 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001243 nbloggers++;
1244 }
1245 } else {
1246 if (p->logfac1 >= 0) {
1247 sa[nbloggers] = &p->logsrv1;
1248 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001249 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001250 nbloggers++;
1251 }
1252 if (p->logfac2 >= 0) {
1253 sa[nbloggers] = &p->logsrv2;
1254 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001255 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001256 nbloggers++;
1257 }
1258 }
1259
1260 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001261 /* we can filter the level of the messages that are sent to each logger */
1262 if (level > loglevel[nbloggers])
1263 continue;
1264
willy tarreauc29948c2005-12-17 13:10:27 +01001265 /* For each target, we may have a different facility.
1266 * We can also have a different log level for each message.
1267 * This induces variations in the message header length.
1268 * Since we don't want to recompute it each time, nor copy it every
1269 * time, we only change the facility in the pre-computed header,
1270 * and we change the pointer to the header accordingly.
1271 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001272 fac_level = (facilities[nbloggers] << 3) + level;
1273 log_ptr = logmsg + 3; /* last digit of the log level */
1274 do {
1275 *log_ptr = '0' + fac_level % 10;
1276 fac_level /= 10;
1277 log_ptr--;
1278 } while (fac_level && log_ptr > logmsg);
1279 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001280
willy tarreauc29948c2005-12-17 13:10:27 +01001281 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001282
1283#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001284 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1286#else
willy tarreauc29948c2005-12-17 13:10:27 +01001287 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001288 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1289#endif
1290 }
willy tarreau0f7af912005-12-17 12:21:26 +01001291}
1292
1293
1294/* sets <tv> to the current time */
1295static inline struct timeval *tv_now(struct timeval *tv) {
1296 if (tv)
1297 gettimeofday(tv, NULL);
1298 return tv;
1299}
1300
1301/*
1302 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1303 */
1304static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1305 if (!tv || !from)
1306 return NULL;
1307 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1308 tv->tv_sec = from->tv_sec + (ms/1000);
1309 while (tv->tv_usec >= 1000000) {
1310 tv->tv_usec -= 1000000;
1311 tv->tv_sec++;
1312 }
1313 return tv;
1314}
1315
1316/*
1317 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001318 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001319 */
1320static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001321 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001322 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001323 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001324 return 1;
1325 else if (tv1->tv_usec < tv2->tv_usec)
1326 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001327 else if (tv1->tv_usec > tv2->tv_usec)
1328 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001329 else
1330 return 0;
1331}
1332
1333/*
1334 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001335 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001336 */
1337unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1338 int cmp;
1339 unsigned long ret;
1340
1341
willy tarreauef900ab2005-12-17 12:52:52 +01001342 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001343 if (!cmp)
1344 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001345 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001346 struct timeval *tmp = tv1;
1347 tv1 = tv2;
1348 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001349 }
willy tarreauef900ab2005-12-17 12:52:52 +01001350 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001351 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001352 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001353 else
willy tarreauef900ab2005-12-17 12:52:52 +01001354 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001355 return (unsigned long) ret;
1356}
1357
1358/*
willy tarreau750a4722005-12-17 13:21:24 +01001359 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001360 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001361 */
1362static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1363 unsigned long ret;
1364
willy tarreau6e682ce2005-12-17 13:26:49 +01001365 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1366 if (tv2->tv_usec > tv1->tv_usec)
1367 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001368 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001369 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001370 return (unsigned long) ret;
1371}
1372
1373/*
willy tarreau0f7af912005-12-17 12:21:26 +01001374 * 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 +01001375 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001376 */
1377static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001378 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001379 if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001380 return -1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001381 else if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreau750a4722005-12-17 13:21:24 +01001382 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001383 else
1384 return 0;
1385 }
willy tarreau0f7af912005-12-17 12:21:26 +01001386 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001387 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001388 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001389 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001390 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau750a4722005-12-17 13:21:24 +01001391 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001392 else
1393 return 0;
1394}
1395
1396/*
1397 * returns the remaining time between tv1=now and event=tv2
1398 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001399 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001400 */
1401static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1402 unsigned long ret;
1403
willy tarreau0f7af912005-12-17 12:21:26 +01001404 if (tv_cmp_ms(tv1, tv2) >= 0)
1405 return 0; /* event elapsed */
1406
willy tarreauef900ab2005-12-17 12:52:52 +01001407 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001408 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001409 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001410 else
willy tarreauef900ab2005-12-17 12:52:52 +01001411 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001412 return (unsigned long) ret;
1413}
1414
1415
1416/*
1417 * zeroes a struct timeval
1418 */
1419
1420static inline struct timeval *tv_eternity(struct timeval *tv) {
1421 tv->tv_sec = tv->tv_usec = 0;
1422 return tv;
1423}
1424
1425/*
1426 * returns 1 if tv is null, else 0
1427 */
1428static inline int tv_iseternity(struct timeval *tv) {
1429 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1430 return 1;
1431 else
1432 return 0;
1433}
1434
1435/*
1436 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1437 * considering that 0 is the eternity.
1438 */
1439static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1440 if (tv_iseternity(tv1))
1441 if (tv_iseternity(tv2))
1442 return 0; /* same */
1443 else
1444 return 1; /* tv1 later than tv2 */
1445 else if (tv_iseternity(tv2))
1446 return -1; /* tv2 later than tv1 */
1447
1448 if (tv1->tv_sec > tv2->tv_sec)
1449 return 1;
1450 else if (tv1->tv_sec < tv2->tv_sec)
1451 return -1;
1452 else if (tv1->tv_usec > tv2->tv_usec)
1453 return 1;
1454 else if (tv1->tv_usec < tv2->tv_usec)
1455 return -1;
1456 else
1457 return 0;
1458}
1459
1460/*
1461 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1462 * considering that 0 is the eternity.
1463 */
1464static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1465 if (tv_iseternity(tv1))
1466 if (tv_iseternity(tv2))
1467 return 0; /* same */
1468 else
1469 return 1; /* tv1 later than tv2 */
1470 else if (tv_iseternity(tv2))
1471 return -1; /* tv2 later than tv1 */
1472
willy tarreauefae1842005-12-17 12:51:03 +01001473 if (tv1->tv_sec == tv2->tv_sec) {
Willy TARREAUc9a64392006-03-01 22:30:20 +01001474 if (tv1->tv_usec >= tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001475 return 1;
Willy TARREAUc9a64392006-03-01 22:30:20 +01001476 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001477 return -1;
1478 else
1479 return 0;
1480 }
1481 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001482 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001483 return 1;
1484 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
Willy TARREAUc9a64392006-03-01 22:30:20 +01001485 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001486 return -1;
1487 else
1488 return 0;
1489}
1490
1491/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001492 * returns the remaining time between tv1=now and event=tv2
1493 * if tv2 is passed, 0 is returned.
1494 * Returns TIME_ETERNITY if tv2 is eternity.
1495 */
1496static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1497 unsigned long ret;
1498
1499 if (tv_iseternity(tv2))
1500 return TIME_ETERNITY;
1501
1502 if (tv_cmp_ms(tv1, tv2) >= 0)
1503 return 0; /* event elapsed */
1504
1505 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1506 if (tv2->tv_usec > tv1->tv_usec)
1507 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1508 else
1509 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1510 return (unsigned long) ret;
1511}
1512
1513/*
willy tarreau0f7af912005-12-17 12:21:26 +01001514 * returns the first event between tv1 and tv2 into tvmin.
1515 * a zero tv is ignored. tvmin is returned.
1516 */
1517static inline struct timeval *tv_min(struct timeval *tvmin,
1518 struct timeval *tv1, struct timeval *tv2) {
1519
1520 if (tv_cmp2(tv1, tv2) <= 0)
1521 *tvmin = *tv1;
1522 else
1523 *tvmin = *tv2;
1524
1525 return tvmin;
1526}
1527
1528
1529
1530/***********************************************************/
1531/* fd management ***************************************/
1532/***********************************************************/
1533
1534
1535
willy tarreau5cbea6f2005-12-17 12:48:26 +01001536/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1537 * The file descriptor is also closed.
1538 */
willy tarreau0f7af912005-12-17 12:21:26 +01001539static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001540 FD_CLR(fd, StaticReadEvent);
1541 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001542#if defined(ENABLE_EPOLL)
1543 if (PrevReadEvent) {
1544 FD_CLR(fd, PrevReadEvent);
1545 FD_CLR(fd, PrevWriteEvent);
1546 }
1547#endif
1548
willy tarreau5cbea6f2005-12-17 12:48:26 +01001549 close(fd);
1550 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001551
1552 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1553 maxfd--;
1554}
1555
1556/* recomputes the maxfd limit from the fd */
1557static inline void fd_insert(int fd) {
1558 if (fd+1 > maxfd)
1559 maxfd = fd+1;
1560}
1561
1562/*************************************************************/
1563/* task management ***************************************/
1564/*************************************************************/
1565
willy tarreau5cbea6f2005-12-17 12:48:26 +01001566/* puts the task <t> in run queue <q>, and returns <t> */
1567static inline struct task *task_wakeup(struct task **q, struct task *t) {
1568 if (t->state == TASK_RUNNING)
1569 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001570 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001571 t->rqnext = *q;
1572 t->state = TASK_RUNNING;
1573 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001574 }
1575}
1576
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577/* removes the task <t> from the queue <q>
1578 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001579 * set the run queue to point to the next one, and return it
1580 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581static inline struct task *task_sleep(struct task **q, struct task *t) {
1582 if (t->state == TASK_RUNNING) {
1583 *q = t->rqnext;
1584 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001585 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001587}
1588
1589/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001591 * from the run queue. A pointer to the task itself is returned.
1592 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001593static inline struct task *task_delete(struct task *t) {
1594 t->prev->next = t->next;
1595 t->next->prev = t->prev;
1596 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001597}
1598
1599/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001601 */
1602static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001604}
1605
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001607 * may be only moved or left where it was, depending on its timing requirements.
1608 * <task> is returned.
1609 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001610struct task *task_queue(struct task *task) {
1611 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001612 struct task *start_from;
1613
1614 /* first, test if the task was already in a list */
1615 if (task->prev == NULL) {
1616 // start_from = list;
1617 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001618#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001619 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001620#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001621 /* insert the unlinked <task> into the list, searching back from the last entry */
1622 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1623 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001624#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001625 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001626#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001627 }
1628
1629 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1630 // start_from = start_from->next;
1631 // stats_tsk_nsrch++;
1632 // }
1633 }
1634 else if (task->prev == list ||
1635 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1636 start_from = task->next;
1637 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001638#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001639 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001640#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001641 return task; /* it's already in the right place */
1642 }
1643
willy tarreau750a4722005-12-17 13:21:24 +01001644#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001645 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001646#endif
1647
1648 /* if the task is not at the right place, there's little chance that
1649 * it has only shifted a bit, and it will nearly always be queued
1650 * at the end of the list because of constant timeouts
1651 * (observed in real case).
1652 */
1653#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1654 start_from = list->prev; /* assume we'll queue to the end of the list */
1655 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1656 start_from = start_from->prev;
1657#if STATTIME > 0
1658 stats_tsk_lsrch++;
1659#endif
1660 }
1661#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001662 /* insert the unlinked <task> into the list, searching after position <start_from> */
1663 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1664 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001665#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001666 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001667#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001668 }
willy tarreau750a4722005-12-17 13:21:24 +01001669#endif /* WE_REALLY_... */
1670
willy tarreau0f7af912005-12-17 12:21:26 +01001671 /* we need to unlink it now */
1672 task_delete(task);
1673 }
1674 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001675#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001676 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001677#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001678#ifdef LEFT_TO_TOP /* not very good */
1679 start_from = list;
1680 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1681 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001682#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001683 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001684#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001685 }
1686#else
1687 start_from = task->prev->prev; /* valid because of the previous test above */
1688 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1689 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001690#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001691 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001692#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001693 }
1694#endif
1695 /* we need to unlink it now */
1696 task_delete(task);
1697 }
1698 task->prev = start_from;
1699 task->next = start_from->next;
1700 task->next->prev = task;
1701 start_from->next = task;
1702 return task;
1703}
1704
1705
1706/*********************************************************************/
1707/* more specific functions ***************************************/
1708/*********************************************************************/
1709
1710/* some prototypes */
1711static int maintain_proxies(void);
1712
willy tarreaub952e1d2005-12-18 01:31:20 +01001713/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001714 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1715 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001716static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001717#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001718 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1719#else
willy tarreaua1598082005-12-17 13:08:06 +01001720#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001721 return getsockname(fd, (struct sockaddr *)sa, salen);
1722#else
1723 return -1;
1724#endif
1725#endif
1726}
1727
1728/*
1729 * frees the context associated to a session. It must have been removed first.
1730 */
1731static inline void session_free(struct session *s) {
1732 if (s->req)
1733 pool_free(buffer, s->req);
1734 if (s->rep)
1735 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001736
1737 if (s->rsp_cap != NULL) {
1738 struct cap_hdr *h;
1739 for (h = s->proxy->rsp_cap; h; h = h->next) {
1740 if (s->rsp_cap[h->index] != NULL)
1741 pool_free_to(h->pool, s->rsp_cap[h->index]);
1742 }
1743 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1744 }
1745 if (s->req_cap != NULL) {
1746 struct cap_hdr *h;
1747 for (h = s->proxy->req_cap; h; h = h->next) {
1748 if (s->req_cap[h->index] != NULL)
1749 pool_free_to(h->pool, s->req_cap[h->index]);
1750 }
1751 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1752 }
1753
willy tarreaua1598082005-12-17 13:08:06 +01001754 if (s->logs.uri)
1755 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001756 if (s->logs.cli_cookie)
1757 pool_free(capture, s->logs.cli_cookie);
1758 if (s->logs.srv_cookie)
1759 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001760
willy tarreau5cbea6f2005-12-17 12:48:26 +01001761 pool_free(session, s);
1762}
1763
willy tarreau0f7af912005-12-17 12:21:26 +01001764
1765/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001766 * This function tries to find a running server for the proxy <px>. A first
1767 * pass looks for active servers, and if none is found, a second pass also
1768 * looks for backup servers.
1769 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1770 */
1771static inline struct server *find_server(struct proxy *px) {
1772 struct server *srv = px->cursrv;
1773 int ignore_backup = 1;
1774
1775 do {
1776 do {
1777 if (srv == NULL)
1778 srv = px->srv;
1779 if (srv->state & SRV_RUNNING
1780 && !((srv->state & SRV_BACKUP) && ignore_backup))
1781 return srv;
1782 srv = srv->next;
1783 } while (srv != px->cursrv);
Willy TARREAU3481c462006-03-01 22:37:57 +01001784
1785 /* By default, we look for the first backup server if all others are
1786 * DOWN. But in some cases, it may be desirable to load-balance across
1787 * all backup servers.
1788 */
1789 if (!(px->options & PR_O_USE_ALL_BK))
1790 srv = px->srv;
1791
willy tarreau8337c6b2005-12-17 13:41:01 +01001792 } while (ignore_backup--);
1793 return NULL;
1794}
1795
1796/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001797 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001798 * is set, or to the dispatch server if (s->direct) is 0.
1799 * It can return one of :
1800 * - SN_ERR_NONE if everything's OK
1801 * - SN_ERR_SRVTO if there are no more servers
1802 * - SN_ERR_SRVCL if the connection was refused by the server
1803 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1804 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1805 * - SN_ERR_INTERNAL for any other purely internal errors
1806 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001807 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001809 int fd;
1810
willy tarreau12350152005-12-18 01:03:27 +01001811#ifdef DEBUG_FULL
1812 fprintf(stderr,"connect_server : s=%p\n",s);
1813#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001814
willy tarreaue39cd132005-12-17 13:00:18 +01001815 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001816 s->srv_addr = s->srv->addr;
1817 }
1818 else if (s->proxy->options & PR_O_BALANCE) {
1819 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001820 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001821
willy tarreau8337c6b2005-12-17 13:41:01 +01001822 srv = find_server(s->proxy);
1823
1824 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001825 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001826
willy tarreau8337c6b2005-12-17 13:41:01 +01001827 s->srv_addr = srv->addr;
1828 s->srv = srv;
1829 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001830 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001831 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001832 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001833 }
willy tarreaua1598082005-12-17 13:08:06 +01001834 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001835 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001836 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001837 }
1838 else if (s->proxy->options & PR_O_TRANSP) {
1839 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001840 socklen_t salen = sizeof(s->srv_addr);
1841
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1843 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001844 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001845 }
1846 }
willy tarreau0f7af912005-12-17 12:21:26 +01001847
willy tarreaua41a8b42005-12-17 14:02:24 +01001848 /* if this server remaps proxied ports, we'll use
1849 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001850 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001851 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001852 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001853
willy tarreaub952e1d2005-12-18 01:31:20 +01001854 if (!(s->proxy->options & PR_O_TRANSP) ||
1855 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001856 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1857 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1858 }
1859
willy tarreau0f7af912005-12-17 12:21:26 +01001860 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001861 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001862
1863 if (errno == ENFILE)
1864 send_log(s->proxy, LOG_EMERG,
1865 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1866 s->proxy->id, maxfd);
1867 else if (errno == EMFILE)
1868 send_log(s->proxy, LOG_EMERG,
1869 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1870 s->proxy->id, maxfd);
1871 else if (errno == ENOBUFS || errno == ENOMEM)
1872 send_log(s->proxy, LOG_EMERG,
1873 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1874 s->proxy->id, maxfd);
1875 /* this is a resource error */
1876 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001877 }
1878
willy tarreau9fe663a2005-12-17 13:02:59 +01001879 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001880 /* do not log anything there, it's a normal condition when this option
1881 * is used to serialize connections to a server !
1882 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001883 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1884 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001885 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001886 }
1887
willy tarreau0f7af912005-12-17 12:21:26 +01001888 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1889 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001890 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001891 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001892 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001893 }
1894
willy tarreaub952e1d2005-12-18 01:31:20 +01001895 if (s->proxy->options & PR_O_TCP_SRV_KA)
1896 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1897
willy tarreau0174f312005-12-18 01:02:42 +01001898 /* allow specific binding :
1899 * - server-specific at first
1900 * - proxy-specific next
1901 */
1902 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1903 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1904 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1905 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1906 s->proxy->id, s->srv->id);
1907 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001908 send_log(s->proxy, LOG_EMERG,
1909 "Cannot bind to source address before connect() for server %s/%s.\n",
1910 s->proxy->id, s->srv->id);
1911 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001912 }
1913 }
1914 else if (s->proxy->options & PR_O_BIND_SRC) {
1915 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1916 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1917 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1918 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001919 send_log(s->proxy, LOG_EMERG,
1920 "Cannot bind to source address before connect() for server %s/%s.\n",
1921 s->proxy->id, s->srv->id);
1922 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001923 }
willy tarreaua1598082005-12-17 13:08:06 +01001924 }
1925
willy tarreaub1285d52005-12-18 01:20:14 +01001926 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1927 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1928
1929 if (errno == EAGAIN || errno == EADDRINUSE) {
1930 char *msg;
1931 if (errno == EAGAIN) /* no free ports left, try again later */
1932 msg = "no free ports";
1933 else
1934 msg = "local address already in use";
1935
1936 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001937 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001938 send_log(s->proxy, LOG_EMERG,
1939 "Connect() failed for server %s/%s: %s.\n",
1940 s->proxy->id, s->srv->id, msg);
1941 return SN_ERR_RESOURCE;
1942 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001943 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001944 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001945 return SN_ERR_SRVTO;
1946 } else {
1947 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001948 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001949 close(fd);
1950 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001951 }
1952 }
1953
willy tarreau5cbea6f2005-12-17 12:48:26 +01001954 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001955 fdtab[fd].read = &event_srv_read;
1956 fdtab[fd].write = &event_srv_write;
1957 fdtab[fd].state = FD_STCONN; /* connection in progress */
1958
1959 FD_SET(fd, StaticWriteEvent); /* for connect status */
1960
1961 fd_insert(fd);
1962
1963 if (s->proxy->contimeout)
1964 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1965 else
1966 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001967 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001968}
1969
1970/*
1971 * this function is called on a read event from a client socket.
1972 * It returns 0.
1973 */
1974int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001975 struct task *t = fdtab[fd].owner;
1976 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001977 struct buffer *b = s->req;
1978 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001979
willy tarreau12350152005-12-18 01:03:27 +01001980#ifdef DEBUG_FULL
1981 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1982#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001983
willy tarreau0f7af912005-12-17 12:21:26 +01001984 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001985#ifdef FILL_BUFFERS
1986 while (1)
1987#else
1988 do
1989#endif
1990 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001991 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1992 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001993 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994 }
1995 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001996 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001997 }
1998 else {
1999 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002000 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2001 * since it means that the rewrite protection has been removed. This
2002 * implies that the if statement can be removed.
2003 */
2004 if (max > b->rlim - b->data)
2005 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 }
2007
2008 if (max == 0) { /* not anymore room to store data */
2009 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002010 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002011 }
2012
willy tarreau3242e862005-12-17 12:27:53 +01002013#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002015 int skerr;
2016 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017
willy tarreau5cbea6f2005-12-17 12:48:26 +01002018 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2019 if (skerr)
2020 ret = -1;
2021 else
2022 ret = recv(fd, b->r, max, 0);
2023 }
willy tarreau3242e862005-12-17 12:27:53 +01002024#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002026#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002027 if (ret > 0) {
2028 b->r += ret;
2029 b->l += ret;
2030 s->res_cr = RES_DATA;
2031
2032 if (b->r == b->data + BUFSIZE) {
2033 b->r = b->data; /* wrap around the buffer */
2034 }
willy tarreaua1598082005-12-17 13:08:06 +01002035
2036 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002037 /* we hope to read more data or to get a close on next round */
2038 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002039 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002040 else if (ret == 0) {
2041 s->res_cr = RES_NULL;
2042 break;
2043 }
2044 else if (errno == EAGAIN) {/* ignore EAGAIN */
2045 break;
2046 }
2047 else {
2048 s->res_cr = RES_ERROR;
2049 fdtab[fd].state = FD_STERROR;
2050 break;
2051 }
2052 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002053#ifndef FILL_BUFFERS
2054 while (0);
2055#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002056 }
2057 else {
2058 s->res_cr = RES_ERROR;
2059 fdtab[fd].state = FD_STERROR;
2060 }
2061
willy tarreau5cbea6f2005-12-17 12:48:26 +01002062 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002063 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2065 else
2066 tv_eternity(&s->crexpire);
2067
2068 task_wakeup(&rq, t);
2069 }
willy tarreau0f7af912005-12-17 12:21:26 +01002070
willy tarreau0f7af912005-12-17 12:21:26 +01002071 return 0;
2072}
2073
2074
2075/*
2076 * this function is called on a read event from a server socket.
2077 * It returns 0.
2078 */
2079int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002080 struct task *t = fdtab[fd].owner;
2081 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002082 struct buffer *b = s->rep;
2083 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002084
willy tarreau12350152005-12-18 01:03:27 +01002085#ifdef DEBUG_FULL
2086 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2087#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002088
willy tarreau0f7af912005-12-17 12:21:26 +01002089 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002090#ifdef FILL_BUFFERS
2091 while (1)
2092#else
2093 do
2094#endif
2095 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002096 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2097 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002098 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002099 }
2100 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002101 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002102 }
2103 else {
2104 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002105 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2106 * since it means that the rewrite protection has been removed. This
2107 * implies that the if statement can be removed.
2108 */
2109 if (max > b->rlim - b->data)
2110 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111 }
2112
2113 if (max == 0) { /* not anymore room to store data */
2114 FD_CLR(fd, StaticReadEvent);
2115 break;
2116 }
2117
willy tarreau3242e862005-12-17 12:27:53 +01002118#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002119 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002120 int skerr;
2121 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002122
willy tarreau5cbea6f2005-12-17 12:48:26 +01002123 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2124 if (skerr)
2125 ret = -1;
2126 else
2127 ret = recv(fd, b->r, max, 0);
2128 }
willy tarreau3242e862005-12-17 12:27:53 +01002129#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002130 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002131#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002132 if (ret > 0) {
2133 b->r += ret;
2134 b->l += ret;
2135 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002136
willy tarreau5cbea6f2005-12-17 12:48:26 +01002137 if (b->r == b->data + BUFSIZE) {
2138 b->r = b->data; /* wrap around the buffer */
2139 }
willy tarreaua1598082005-12-17 13:08:06 +01002140
2141 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002142 /* we hope to read more data or to get a close on next round */
2143 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002144 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 else if (ret == 0) {
2146 s->res_sr = RES_NULL;
2147 break;
2148 }
2149 else if (errno == EAGAIN) {/* ignore EAGAIN */
2150 break;
2151 }
2152 else {
2153 s->res_sr = RES_ERROR;
2154 fdtab[fd].state = FD_STERROR;
2155 break;
2156 }
2157 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002158#ifndef FILL_BUFFERS
2159 while (0);
2160#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002161 }
2162 else {
2163 s->res_sr = RES_ERROR;
2164 fdtab[fd].state = FD_STERROR;
2165 }
2166
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002168 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002169 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2170 else
2171 tv_eternity(&s->srexpire);
2172
2173 task_wakeup(&rq, t);
2174 }
willy tarreau0f7af912005-12-17 12:21:26 +01002175
willy tarreau0f7af912005-12-17 12:21:26 +01002176 return 0;
2177}
2178
2179/*
2180 * this function is called on a write event from a client socket.
2181 * It returns 0.
2182 */
2183int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002184 struct task *t = fdtab[fd].owner;
2185 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002186 struct buffer *b = s->rep;
2187 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002188
willy tarreau12350152005-12-18 01:03:27 +01002189#ifdef DEBUG_FULL
2190 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2191#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002192
2193 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002194 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002195 // max = BUFSIZE; BUG !!!!
2196 max = 0;
2197 }
2198 else if (b->r > b->w) {
2199 max = b->r - b->w;
2200 }
2201 else
2202 max = b->data + BUFSIZE - b->w;
2203
willy tarreau0f7af912005-12-17 12:21:26 +01002204 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002205 if (max == 0) {
2206 s->res_cw = RES_NULL;
2207 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002208 tv_eternity(&s->cwexpire);
2209 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002210 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002211 }
2212
willy tarreau3242e862005-12-17 12:27:53 +01002213#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002214 {
2215 int skerr;
2216 socklen_t lskerr = sizeof(skerr);
2217
2218 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2219 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002220 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002221 else
willy tarreau3242e862005-12-17 12:27:53 +01002222 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002223 }
willy tarreau3242e862005-12-17 12:27:53 +01002224#else
willy tarreau0f7af912005-12-17 12:21:26 +01002225 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002226#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002227
2228 if (ret > 0) {
2229 b->l -= ret;
2230 b->w += ret;
2231
2232 s->res_cw = RES_DATA;
2233
2234 if (b->w == b->data + BUFSIZE) {
2235 b->w = b->data; /* wrap around the buffer */
2236 }
2237 }
2238 else if (ret == 0) {
2239 /* nothing written, just make as if we were never called */
2240// s->res_cw = RES_NULL;
2241 return 0;
2242 }
2243 else if (errno == EAGAIN) /* ignore EAGAIN */
2244 return 0;
2245 else {
2246 s->res_cw = RES_ERROR;
2247 fdtab[fd].state = FD_STERROR;
2248 }
2249 }
2250 else {
2251 s->res_cw = RES_ERROR;
2252 fdtab[fd].state = FD_STERROR;
2253 }
2254
willy tarreaub1ff9db2005-12-17 13:51:03 +01002255 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002256 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002257 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2258 s->crexpire = s->cwexpire;
2259 }
willy tarreau0f7af912005-12-17 12:21:26 +01002260 else
2261 tv_eternity(&s->cwexpire);
2262
willy tarreau5cbea6f2005-12-17 12:48:26 +01002263 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002264 return 0;
2265}
2266
2267
2268/*
2269 * this function is called on a write event from a server socket.
2270 * It returns 0.
2271 */
2272int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002273 struct task *t = fdtab[fd].owner;
2274 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002275 struct buffer *b = s->req;
2276 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002277
willy tarreau12350152005-12-18 01:03:27 +01002278#ifdef DEBUG_FULL
2279 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2280#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002281
2282 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002283 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002284 // max = BUFSIZE; BUG !!!!
2285 max = 0;
2286 }
2287 else if (b->r > b->w) {
2288 max = b->r - b->w;
2289 }
2290 else
2291 max = b->data + BUFSIZE - b->w;
2292
willy tarreau0f7af912005-12-17 12:21:26 +01002293 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002294 if (max == 0) {
2295 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002296 if (s->srv_state == SV_STCONN) {
2297 int skerr;
2298 socklen_t lskerr = sizeof(skerr);
2299 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2300 if (skerr) {
2301 s->res_sw = RES_ERROR;
2302 fdtab[fd].state = FD_STERROR;
2303 task_wakeup(&rq, t);
2304 tv_eternity(&s->swexpire);
2305 FD_CLR(fd, StaticWriteEvent);
2306 return 0;
2307 }
2308 }
2309
willy tarreau0f7af912005-12-17 12:21:26 +01002310 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002312 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002313 tv_eternity(&s->swexpire);
2314 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002315 return 0;
2316 }
2317
willy tarreau3242e862005-12-17 12:27:53 +01002318#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002319 {
2320 int skerr;
2321 socklen_t lskerr = sizeof(skerr);
2322 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2323 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002324 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002325 else
willy tarreau3242e862005-12-17 12:27:53 +01002326 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002327 }
willy tarreau3242e862005-12-17 12:27:53 +01002328#else
willy tarreau0f7af912005-12-17 12:21:26 +01002329 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002330#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002331 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002332 if (ret > 0) {
2333 b->l -= ret;
2334 b->w += ret;
2335
2336 s->res_sw = RES_DATA;
2337
2338 if (b->w == b->data + BUFSIZE) {
2339 b->w = b->data; /* wrap around the buffer */
2340 }
2341 }
2342 else if (ret == 0) {
2343 /* nothing written, just make as if we were never called */
2344 // s->res_sw = RES_NULL;
2345 return 0;
2346 }
2347 else if (errno == EAGAIN) /* ignore EAGAIN */
2348 return 0;
2349 else {
2350 s->res_sw = RES_ERROR;
2351 fdtab[fd].state = FD_STERROR;
2352 }
2353 }
2354 else {
2355 s->res_sw = RES_ERROR;
2356 fdtab[fd].state = FD_STERROR;
2357 }
2358
Willy TARREAU1cec83c2006-03-01 22:33:49 +01002359 /* We don't want to re-arm read/write timeouts if we're trying to connect,
2360 * otherwise it could loop indefinitely !
2361 */
2362 if (s->srv_state != SV_STCONN) {
2363 if (s->proxy->srvtimeout) {
2364 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
2365 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2366 s->srexpire = s->swexpire;
2367 }
2368 else
2369 tv_eternity(&s->swexpire);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002370 }
willy tarreau0f7af912005-12-17 12:21:26 +01002371
willy tarreau5cbea6f2005-12-17 12:48:26 +01002372 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002373 return 0;
2374}
2375
2376
2377/*
willy tarreaue39cd132005-12-17 13:00:18 +01002378 * returns a message to the client ; the connection is shut down for read,
2379 * and the request is cleared so that no server connection can be initiated.
2380 * The client must be in a valid state for this (HEADER, DATA ...).
2381 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002382 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002383 */
2384void client_retnclose(struct session *s, int len, const char *msg) {
2385 FD_CLR(s->cli_fd, StaticReadEvent);
2386 FD_SET(s->cli_fd, StaticWriteEvent);
2387 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002388 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002389 shutdown(s->cli_fd, SHUT_RD);
2390 s->cli_state = CL_STSHUTR;
2391 strcpy(s->rep->data, msg);
2392 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002393 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002394 s->rep->r += len;
2395 s->req->l = 0;
2396}
2397
2398
2399/*
2400 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002401 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002402 */
2403void client_return(struct session *s, int len, const char *msg) {
2404 strcpy(s->rep->data, msg);
2405 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002406 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002407 s->rep->r += len;
2408 s->req->l = 0;
2409}
2410
willy tarreau9fe663a2005-12-17 13:02:59 +01002411/*
2412 * send a log for the session when we have enough info about it
2413 */
2414void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002415 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002416 struct proxy *p = s->proxy;
2417 int log;
2418 char *uri;
2419 char *pxid;
2420 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002421 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002422
2423 /* This is a first attempt at a better logging system.
2424 * For now, we rely on send_log() to provide the date, although it obviously
2425 * is the date of the log and not of the request, and most fields are not
2426 * computed.
2427 */
2428
willy tarreaua1598082005-12-17 13:08:06 +01002429 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002430
willy tarreau8a86dbf2005-12-18 00:45:59 +01002431 if (s->cli_addr.ss_family == AF_INET)
2432 inet_ntop(AF_INET,
2433 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2434 pn, sizeof(pn));
2435 else
2436 inet_ntop(AF_INET6,
2437 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2438 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002439
willy tarreauc1cae632005-12-17 14:12:23 +01002440 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002441 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002442 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002443
willy tarreauc1cae632005-12-17 14:12:23 +01002444 tm = localtime(&s->logs.tv_accept.tv_sec);
2445 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002446 char tmpline[MAX_SYSLOG_LEN], *h;
2447 int hdr;
2448
2449 h = tmpline;
2450 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2451 *(h++) = ' ';
2452 *(h++) = '{';
2453 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2454 if (hdr)
2455 *(h++) = '|';
2456 if (s->req_cap[hdr] != NULL)
2457 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2458 }
2459 *(h++) = '}';
2460 }
2461
2462 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2463 *(h++) = ' ';
2464 *(h++) = '{';
2465 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2466 if (hdr)
2467 *(h++) = '|';
2468 if (s->rsp_cap[hdr] != NULL)
2469 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2470 }
2471 *(h++) = '}';
2472 }
2473
2474 if (h < tmpline + sizeof(tmpline) - 4) {
2475 *(h++) = ' ';
2476 *(h++) = '"';
2477 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2478 *(h++) = '"';
2479 }
2480 *h = '\0';
2481
willy tarreau0fe39652005-12-18 01:25:24 +01002482 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%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002483 pn,
2484 (s->cli_addr.ss_family == AF_INET) ?
2485 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2486 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002487 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2488 tm->tm_hour, tm->tm_min, tm->tm_sec,
2489 pxid, srv,
2490 s->logs.t_request,
2491 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2492 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002493 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2494 s->logs.status,
2495 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002496 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2497 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002498 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2499 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2500 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2501 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002502 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002503 }
2504 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002505 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002506 pn,
2507 (s->cli_addr.ss_family == AF_INET) ?
2508 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2509 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002510 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2511 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002512 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002513 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002514 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2515 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002516 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002517 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2518 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002519 }
2520
2521 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002522}
2523
willy tarreaue39cd132005-12-17 13:00:18 +01002524
2525/*
willy tarreau0f7af912005-12-17 12:21:26 +01002526 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002527 * to an accept. It tries to accept as many connections as possible.
2528 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002529 */
2530int event_accept(int fd) {
2531 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002532 struct session *s;
2533 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002534 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002535
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002537 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002538 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002539
willy tarreaub1285d52005-12-18 01:20:14 +01002540 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2541 switch (errno) {
2542 case EAGAIN:
2543 case EINTR:
2544 case ECONNABORTED:
2545 return 0; /* nothing more to accept */
2546 case ENFILE:
2547 send_log(p, LOG_EMERG,
2548 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2549 p->id, maxfd);
2550 return 0;
2551 case EMFILE:
2552 send_log(p, LOG_EMERG,
2553 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2554 p->id, maxfd);
2555 return 0;
2556 case ENOBUFS:
2557 case ENOMEM:
2558 send_log(p, LOG_EMERG,
2559 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2560 p->id, maxfd);
2561 return 0;
2562 default:
2563 return 0;
2564 }
2565 }
willy tarreau0f7af912005-12-17 12:21:26 +01002566
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2568 Alert("out of memory in event_accept().\n");
2569 FD_CLR(fd, StaticReadEvent);
2570 p->state = PR_STIDLE;
2571 close(cfd);
2572 return 0;
2573 }
willy tarreau0f7af912005-12-17 12:21:26 +01002574
willy tarreaub1285d52005-12-18 01:20:14 +01002575 /* if this session comes from a known monitoring system, we want to ignore
2576 * it as soon as possible, which means closing it immediately for TCP.
2577 */
2578 s->flags = 0;
2579 if (addr.ss_family == AF_INET &&
2580 p->mon_mask.s_addr &&
2581 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2582 if (p->mode == PR_MODE_TCP) {
2583 close(cfd);
2584 pool_free(session, s);
2585 continue;
2586 }
2587 s->flags |= SN_MONITOR;
2588 }
2589
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2591 Alert("out of memory in event_accept().\n");
2592 FD_CLR(fd, StaticReadEvent);
2593 p->state = PR_STIDLE;
2594 close(cfd);
2595 pool_free(session, s);
2596 return 0;
2597 }
willy tarreau0f7af912005-12-17 12:21:26 +01002598
willy tarreau5cbea6f2005-12-17 12:48:26 +01002599 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002600 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002601 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2602 close(cfd);
2603 pool_free(task, t);
2604 pool_free(session, s);
2605 return 0;
2606 }
willy tarreau0f7af912005-12-17 12:21:26 +01002607
willy tarreau5cbea6f2005-12-17 12:48:26 +01002608 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2609 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2610 (char *) &one, sizeof(one)) == -1)) {
2611 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2612 close(cfd);
2613 pool_free(task, t);
2614 pool_free(session, s);
2615 return 0;
2616 }
willy tarreau0f7af912005-12-17 12:21:26 +01002617
willy tarreaub952e1d2005-12-18 01:31:20 +01002618 if (p->options & PR_O_TCP_CLI_KA)
2619 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2620
willy tarreau9fe663a2005-12-17 13:02:59 +01002621 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2622 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2623 t->state = TASK_IDLE;
2624 t->process = process_session;
2625 t->context = s;
2626
2627 s->task = t;
2628 s->proxy = p;
2629 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2630 s->srv_state = SV_STIDLE;
2631 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002632
willy tarreau9fe663a2005-12-17 13:02:59 +01002633 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2634 s->cli_fd = cfd;
2635 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002636 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002637 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002638
willy tarreaub1285d52005-12-18 01:20:14 +01002639 if (s->flags & SN_MONITOR)
2640 s->logs.logwait = 0;
2641 else
2642 s->logs.logwait = p->to_log;
2643
willy tarreaua1598082005-12-17 13:08:06 +01002644 s->logs.tv_accept = now;
2645 s->logs.t_request = -1;
2646 s->logs.t_connect = -1;
2647 s->logs.t_data = -1;
2648 s->logs.t_close = 0;
2649 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002650 s->logs.cli_cookie = NULL;
2651 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002652 s->logs.status = -1;
2653 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002654
willy tarreau2f6ba652005-12-17 13:57:42 +01002655 s->uniq_id = totalconn;
2656
willy tarreau4302f492005-12-18 01:00:37 +01002657 if (p->nb_req_cap > 0) {
2658 if ((s->req_cap =
2659 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2660 == NULL) { /* no memory */
2661 close(cfd); /* nothing can be done for this fd without memory */
2662 pool_free(task, t);
2663 pool_free(session, s);
2664 return 0;
2665 }
2666 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2667 }
2668 else
2669 s->req_cap = NULL;
2670
2671 if (p->nb_rsp_cap > 0) {
2672 if ((s->rsp_cap =
2673 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2674 == NULL) { /* no memory */
2675 if (s->req_cap != NULL)
2676 pool_free_to(p->req_cap_pool, s->req_cap);
2677 close(cfd); /* nothing can be done for this fd without memory */
2678 pool_free(task, t);
2679 pool_free(session, s);
2680 return 0;
2681 }
2682 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2683 }
2684 else
2685 s->rsp_cap = NULL;
2686
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2688 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002689 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002690 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002691
willy tarreau8a86dbf2005-12-18 00:45:59 +01002692 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002693 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002694 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002695 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002696
willy tarreau9fe663a2005-12-17 13:02:59 +01002697 if (p->to_log) {
2698 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002699 if (s->logs.logwait & LW_CLIP)
2700 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002701 sess_log(s);
2702 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002703 else if (s->cli_addr.ss_family == AF_INET) {
2704 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2705 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2706 sn, sizeof(sn)) &&
2707 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2708 pn, sizeof(pn))) {
2709 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2710 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2711 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2712 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2713 }
2714 }
2715 else {
2716 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2717 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2718 sn, sizeof(sn)) &&
2719 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2720 pn, sizeof(pn))) {
2721 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2722 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2723 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2724 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2725 }
2726 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002727 }
willy tarreau0f7af912005-12-17 12:21:26 +01002728
willy tarreau982249e2005-12-18 00:57:06 +01002729 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002730 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002731 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002732 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002733 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002734 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002735 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002736 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002737
willy tarreau8a86dbf2005-12-18 00:45:59 +01002738 if (s->cli_addr.ss_family == AF_INET) {
2739 char pn[INET_ADDRSTRLEN];
2740 inet_ntop(AF_INET,
2741 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2742 pn, sizeof(pn));
2743
2744 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2745 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2746 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2747 }
2748 else {
2749 char pn[INET6_ADDRSTRLEN];
2750 inet_ntop(AF_INET6,
2751 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2752 pn, sizeof(pn));
2753
2754 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2755 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2756 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2757 }
2758
willy tarreauef900ab2005-12-17 12:52:52 +01002759 write(1, trash, len);
2760 }
willy tarreau0f7af912005-12-17 12:21:26 +01002761
willy tarreau5cbea6f2005-12-17 12:48:26 +01002762 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002763 if (s->rsp_cap != NULL)
2764 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2765 if (s->req_cap != NULL)
2766 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002767 close(cfd); /* nothing can be done for this fd without memory */
2768 pool_free(task, t);
2769 pool_free(session, s);
2770 return 0;
2771 }
willy tarreau4302f492005-12-18 01:00:37 +01002772
willy tarreau5cbea6f2005-12-17 12:48:26 +01002773 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002774 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002775 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2776 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002777 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002778 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002779
willy tarreau5cbea6f2005-12-17 12:48:26 +01002780 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2781 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002782 if (s->rsp_cap != NULL)
2783 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2784 if (s->req_cap != NULL)
2785 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002786 close(cfd); /* nothing can be done for this fd without memory */
2787 pool_free(task, t);
2788 pool_free(session, s);
2789 return 0;
2790 }
2791 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002792 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002793 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 +01002794
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795 fdtab[cfd].read = &event_cli_read;
2796 fdtab[cfd].write = &event_cli_write;
2797 fdtab[cfd].owner = t;
2798 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreaub1285d52005-12-18 01:20:14 +01002800 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2801 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2802 /* Either we got a request from a monitoring system on an HTTP instance,
2803 * or we're in health check mode with the 'httpchk' option enabled. In
2804 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2805 */
2806 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2807 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2808 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 }
2810 else {
2811 FD_SET(cfd, StaticReadEvent);
2812 }
2813
willy tarreaub952e1d2005-12-18 01:31:20 +01002814#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2815 if (PrevReadEvent) {
2816 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2817 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2818 }
2819#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002820 fd_insert(cfd);
2821
2822 tv_eternity(&s->cnexpire);
2823 tv_eternity(&s->srexpire);
2824 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002825 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002826 tv_eternity(&s->cwexpire);
2827
willy tarreaub1285d52005-12-18 01:20:14 +01002828 if (s->proxy->clitimeout) {
2829 if (FD_ISSET(cfd, StaticReadEvent))
2830 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2831 if (FD_ISSET(cfd, StaticWriteEvent))
2832 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2833 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002834
willy tarreaub1285d52005-12-18 01:20:14 +01002835 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836
2837 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002838
2839 if (p->mode != PR_MODE_HEALTH)
2840 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002841
2842 p->nbconn++;
2843 actconn++;
2844 totalconn++;
2845
willy tarreaub952e1d2005-12-18 01:31:20 +01002846 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002847 } /* end of while (p->nbconn < p->maxconn) */
2848 return 0;
2849}
willy tarreau0f7af912005-12-17 12:21:26 +01002850
willy tarreau0f7af912005-12-17 12:21:26 +01002851
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852/*
2853 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002854 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2855 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002856 * or -1 if an error occured.
2857 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002858int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002859 struct task *t = fdtab[fd].owner;
2860 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002861
willy tarreauc5f73ed2005-12-18 01:26:38 +01002862 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002863 socklen_t lskerr = sizeof(skerr);
2864
willy tarreau5cbea6f2005-12-17 12:48:26 +01002865 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002866 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867 if (skerr)
2868 s->result = -1;
willy tarreaua4a583a2005-12-18 01:39:19 +01002869 else if (s->result != -1) {
2870 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002871 if (s->proxy->options & PR_O_HTTP_CHK) {
2872 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002873 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002874 * so we'll send the request, and won't wake the checker up now.
2875 */
2876#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002877 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002878#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002879 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002880#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002881 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002882 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2883 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2884 return 0;
2885 }
2886 else
2887 s->result = -1;
2888 }
2889 else {
2890 /* good TCP connection is enough */
2891 s->result = 1;
2892 }
2893 }
2894
2895 task_wakeup(&rq, t);
2896 return 0;
2897}
2898
willy tarreau0f7af912005-12-17 12:21:26 +01002899
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002900/*
2901 * This function is used only for server health-checks. It handles
2902 * the server's reply to an HTTP request. It returns 1 if the server replies
2903 * 2xx or 3xx (valid responses), or -1 in other cases.
2904 */
2905int event_srv_chk_r(int fd) {
2906 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002907 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002908 struct task *t = fdtab[fd].owner;
2909 struct server *s = t->context;
2910
willy tarreaua4a583a2005-12-18 01:39:19 +01002911 result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002912#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002913 {
2914 int skerr;
2915 socklen_t lskerr = sizeof(skerr);
2916
2917 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2918 if (!skerr)
2919 len = recv(fd, reply, sizeof(reply), 0);
2920 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002921#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002922 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2923 * but the connection was closed on the remote end. Fortunately, recv still
2924 * works correctly and we don't need to do the getsockopt() on linux.
2925 */
2926 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002927#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002928 if ((len >= sizeof("HTTP/1.0 000")) &&
2929 !memcmp(reply, "HTTP/1.", 7) &&
2930 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
willy tarreaua4a583a2005-12-18 01:39:19 +01002931 result = 1;
2932
2933 if (s->result != -1)
2934 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002935
2936 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002938 return 0;
2939}
2940
2941
2942/*
2943 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2944 * and moves <end> just after the end of <str>.
2945 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2946 * the shift value (positive or negative) is returned.
2947 * If there's no space left, the move is not done.
2948 *
2949 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002950int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002951 int delta;
2952 int len;
2953
2954 len = strlen(str);
2955 delta = len - (end - pos);
2956
2957 if (delta + b->r >= b->data + BUFSIZE)
2958 return 0; /* no space left */
2959
2960 /* first, protect the end of the buffer */
2961 memmove(end + delta, end, b->data + b->l - end);
2962
2963 /* now, copy str over pos */
2964 memcpy(pos, str,len);
2965
willy tarreau5cbea6f2005-12-17 12:48:26 +01002966 /* we only move data after the displaced zone */
2967 if (b->r > pos) b->r += delta;
2968 if (b->w > pos) b->w += delta;
2969 if (b->h > pos) b->h += delta;
2970 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002971 b->l += delta;
2972
2973 return delta;
2974}
2975
willy tarreau8337c6b2005-12-17 13:41:01 +01002976/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002977 * len is 0.
2978 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002979int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002980 int delta;
2981
2982 delta = len - (end - pos);
2983
2984 if (delta + b->r >= b->data + BUFSIZE)
2985 return 0; /* no space left */
2986
Willy TARREAUe78ae262006-01-08 01:24:12 +01002987 if (b->data + b->l < end)
2988 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
2989 return 0;
2990
willy tarreau0f7af912005-12-17 12:21:26 +01002991 /* first, protect the end of the buffer */
2992 memmove(end + delta, end, b->data + b->l - end);
2993
2994 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002995 if (len)
2996 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002997
willy tarreau5cbea6f2005-12-17 12:48:26 +01002998 /* we only move data after the displaced zone */
2999 if (b->r > pos) b->r += delta;
3000 if (b->w > pos) b->w += delta;
3001 if (b->h > pos) b->h += delta;
3002 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01003003 b->l += delta;
3004
3005 return delta;
3006}
3007
3008
3009int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
3010 char *old_dst = dst;
3011
3012 while (*str) {
3013 if (*str == '\\') {
3014 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01003015 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003016 int len, num;
3017
3018 num = *str - '0';
3019 str++;
3020
willy tarreau8a86dbf2005-12-18 00:45:59 +01003021 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003022 len = matches[num].rm_eo - matches[num].rm_so;
3023 memcpy(dst, src + matches[num].rm_so, len);
3024 dst += len;
3025 }
3026
3027 }
3028 else if (*str == 'x') {
3029 unsigned char hex1, hex2;
3030 str++;
3031
willy tarreauc1f47532005-12-18 01:08:26 +01003032 hex1 = toupper(*str++) - '0';
3033 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003034
3035 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3036 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3037 *dst++ = (hex1<<4) + hex2;
3038 }
3039 else
3040 *dst++ = *str++;
3041 }
3042 else
3043 *dst++ = *str++;
3044 }
3045 *dst = 0;
3046 return dst - old_dst;
3047}
3048
willy tarreauc1f47532005-12-18 01:08:26 +01003049static int ishex(char s)
3050{
3051 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3052}
3053
3054/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3055char *check_replace_string(char *str)
3056{
3057 char *err = NULL;
3058 while (*str) {
3059 if (*str == '\\') {
3060 err = str; /* in case of a backslash, we return the pointer to it */
3061 str++;
3062 if (!*str)
3063 return err;
3064 else if (isdigit((int)*str))
3065 err = NULL;
3066 else if (*str == 'x') {
3067 str++;
3068 if (!ishex(*str))
3069 return err;
3070 str++;
3071 if (!ishex(*str))
3072 return err;
3073 err = NULL;
3074 }
3075 else {
3076 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3077 err = NULL;
3078 }
3079 }
3080 str++;
3081 }
3082 return err;
3083}
3084
3085
willy tarreau9fe663a2005-12-17 13:02:59 +01003086
willy tarreau0f7af912005-12-17 12:21:26 +01003087/*
3088 * manages the client FSM and its socket. BTW, it also tries to handle the
3089 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3090 * 0 else.
3091 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003092int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003093 int s = t->srv_state;
3094 int c = t->cli_state;
3095 struct buffer *req = t->req;
3096 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003097 int method_checked = 0;
3098 appsess *asession_temp = NULL;
3099 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003100
willy tarreau750a4722005-12-17 13:21:24 +01003101#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003102 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3103 cli_stnames[c], srv_stnames[s],
3104 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3105 t->crexpire.tv_sec, t->crexpire.tv_usec,
3106 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003107#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003108 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3109 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3110 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3111 //);
3112 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003113 /* now parse the partial (or complete) headers */
3114 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3115 char *ptr;
3116 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003117 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003118
willy tarreau5cbea6f2005-12-17 12:48:26 +01003119 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003120
willy tarreau0f7af912005-12-17 12:21:26 +01003121 /* look for the end of the current header */
3122 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3123 ptr++;
3124
willy tarreau5cbea6f2005-12-17 12:48:26 +01003125 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003126 int line, len;
3127 /* we can only get here after an end of headers */
3128 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003129
willy tarreaue39cd132005-12-17 13:00:18 +01003130 if (t->flags & SN_CLDENY) {
3131 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003132 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003133 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003134 if (!(t->flags & SN_ERR_MASK))
3135 t->flags |= SN_ERR_PRXCOND;
3136 if (!(t->flags & SN_FINST_MASK))
3137 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003138 return 1;
3139 }
3140
willy tarreau5cbea6f2005-12-17 12:48:26 +01003141 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003142 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3143 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144 }
willy tarreau0f7af912005-12-17 12:21:26 +01003145
willy tarreau9fe663a2005-12-17 13:02:59 +01003146 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003147 if (t->cli_addr.ss_family == AF_INET) {
3148 unsigned char *pn;
3149 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3150 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3151 pn[0], pn[1], pn[2], pn[3]);
3152 buffer_replace2(req, req->h, req->h, trash, len);
3153 }
3154 else if (t->cli_addr.ss_family == AF_INET6) {
3155 char pn[INET6_ADDRSTRLEN];
3156 inet_ntop(AF_INET6,
3157 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3158 pn, sizeof(pn));
3159 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3160 buffer_replace2(req, req->h, req->h, trash, len);
3161 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003162 }
3163
willy tarreau25c4ea52005-12-18 00:49:49 +01003164 /* add a "connection: close" line if needed */
3165 if (t->proxy->options & PR_O_HTTP_CLOSE)
3166 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3167
willy tarreau982249e2005-12-18 00:57:06 +01003168 if (!memcmp(req->data, "POST ", 5)) {
3169 /* this is a POST request, which is not cacheable by default */
3170 t->flags |= SN_POST;
3171 }
willy tarreaucd878942005-12-17 13:27:43 +01003172
willy tarreau5cbea6f2005-12-17 12:48:26 +01003173 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003174 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003175
willy tarreau750a4722005-12-17 13:21:24 +01003176 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003177 /* FIXME: we'll set the client in a wait state while we try to
3178 * connect to the server. Is this really needed ? wouldn't it be
3179 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003180 //FD_CLR(t->cli_fd, StaticReadEvent);
3181 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003182
3183 /* FIXME: if we break here (as up to 1.1.23), having the client
3184 * shutdown its connection can lead to an abort further.
3185 * it's better to either return 1 or even jump directly to the
3186 * data state which will save one schedule.
3187 */
3188 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003189
3190 if (!t->proxy->clitimeout ||
3191 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3192 /* If the client has no timeout, or if the server is not ready yet,
3193 * and we know for sure that it can expire, then it's cleaner to
3194 * disable the timeout on the client side so that too low values
3195 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003196 *
3197 * FIXME-20050705: the server needs a way to re-enable this time-out
3198 * when it switches its state, otherwise a client can stay connected
3199 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003200 */
3201 tv_eternity(&t->crexpire);
3202
willy tarreau197e8ec2005-12-17 14:10:59 +01003203 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003204 }
willy tarreau0f7af912005-12-17 12:21:26 +01003205
willy tarreau5cbea6f2005-12-17 12:48:26 +01003206 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3207 if (ptr > req->r - 2) {
3208 /* this is a partial header, let's wait for more to come */
3209 req->lr = ptr;
3210 break;
3211 }
willy tarreau0f7af912005-12-17 12:21:26 +01003212
willy tarreau5cbea6f2005-12-17 12:48:26 +01003213 /* now we know that *ptr is either \r or \n,
3214 * and that there are at least 1 char after it.
3215 */
3216 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3217 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3218 else
3219 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003220
willy tarreau5cbea6f2005-12-17 12:48:26 +01003221 /*
3222 * now we know that we have a full header ; we can do whatever
3223 * we want with these pointers :
3224 * req->h = beginning of header
3225 * ptr = end of header (first \r or \n)
3226 * req->lr = beginning of next line (next rep->h)
3227 * req->r = end of data (not used at this stage)
3228 */
willy tarreau0f7af912005-12-17 12:21:26 +01003229
willy tarreau12350152005-12-18 01:03:27 +01003230 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3231 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3232 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3233
3234 /* skip ; */
3235 request_line++;
3236
3237 /* look if we have a jsessionid */
3238
3239 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3240
3241 /* skip jsessionid= */
3242 request_line += t->proxy->appsession_name_len + 1;
3243
3244 /* First try if we allready have an appsession */
3245 asession_temp = &local_asession;
3246
3247 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3248 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3249 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3250 return 0;
3251 }
3252
3253 /* Copy the sessionid */
3254 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3255 asession_temp->sessid[t->proxy->appsession_len] = 0;
3256 asession_temp->serverid = NULL;
3257
3258 /* only do insert, if lookup fails */
3259 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3260 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3261 Alert("Not enough memory process_cli():asession:calloc().\n");
3262 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3263 return 0;
3264 }
3265 asession_temp->sessid = local_asession.sessid;
3266 asession_temp->serverid = local_asession.serverid;
3267 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003268 } /* end if (chtbl_lookup()) */
3269 else {
willy tarreau12350152005-12-18 01:03:27 +01003270 /*free wasted memory;*/
3271 pool_free_to(apools.sessid, local_asession.sessid);
3272 }
3273
3274 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3275 asession_temp->request_count++;
3276
3277#if defined(DEBUG_HASH)
3278 print_table(&(t->proxy->htbl_proxy));
3279#endif
3280
3281 if (asession_temp->serverid == NULL) {
3282 Alert("Found Application Session without matching server.\n");
3283 } else {
3284 struct server *srv = t->proxy->srv;
3285 while (srv) {
3286 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3287 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3288 /* we found the server and it's usable */
3289 t->flags &= ~SN_CK_MASK;
3290 t->flags |= SN_CK_VALID | SN_DIRECT;
3291 t->srv = srv;
3292 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003293 } else {
willy tarreau12350152005-12-18 01:03:27 +01003294 t->flags &= ~SN_CK_MASK;
3295 t->flags |= SN_CK_DOWN;
3296 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003297 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003298 srv = srv->next;
3299 }/* end while(srv) */
3300 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003301 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003302 else {
3303 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3304 }
willy tarreau598da412005-12-18 01:07:29 +01003305 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003306 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003307 else{
3308 //printf("No Methode-Header with Session-String\n");
3309 }
3310
willy tarreau8337c6b2005-12-17 13:41:01 +01003311 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003312 /* we have a complete HTTP request that we must log */
3313 int urilen;
3314
willy tarreaua1598082005-12-17 13:08:06 +01003315 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003316 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003317 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003318 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003319 if (!(t->flags & SN_ERR_MASK))
3320 t->flags |= SN_ERR_PRXCOND;
3321 if (!(t->flags & SN_FINST_MASK))
3322 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003323 return 1;
3324 }
3325
3326 urilen = ptr - req->h;
3327 if (urilen >= REQURI_LEN)
3328 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003329 memcpy(t->logs.uri, req->h, urilen);
3330 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003331
willy tarreaua1598082005-12-17 13:08:06 +01003332 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003333 sess_log(t);
3334 }
willy tarreau4302f492005-12-18 01:00:37 +01003335 else if (t->logs.logwait & LW_REQHDR) {
3336 struct cap_hdr *h;
3337 int len;
3338 for (h = t->proxy->req_cap; h; h = h->next) {
3339 if ((h->namelen + 2 <= ptr - req->h) &&
3340 (req->h[h->namelen] == ':') &&
3341 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3342
3343 if (t->req_cap[h->index] == NULL)
3344 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3345
3346 len = ptr - (req->h + h->namelen + 2);
3347 if (len > h->len)
3348 len = h->len;
3349
3350 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3351 t->req_cap[h->index][len]=0;
3352 }
3353 }
3354
3355 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003356
willy tarreau5cbea6f2005-12-17 12:48:26 +01003357 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003358
willy tarreau982249e2005-12-18 00:57:06 +01003359 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003361 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 +01003362 max = ptr - req->h;
3363 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003364 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003365 trash[len++] = '\n';
3366 write(1, trash, len);
3367 }
willy tarreau0f7af912005-12-17 12:21:26 +01003368
willy tarreau25c4ea52005-12-18 00:49:49 +01003369
3370 /* remove "connection: " if needed */
3371 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3372 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3373 delete_header = 1;
3374 }
3375
willy tarreau5cbea6f2005-12-17 12:48:26 +01003376 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003377 if (!delete_header && t->proxy->req_exp != NULL
3378 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003379 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003380 char term;
3381
3382 term = *ptr;
3383 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003384 exp = t->proxy->req_exp;
3385 do {
3386 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3387 switch (exp->action) {
3388 case ACT_ALLOW:
3389 if (!(t->flags & SN_CLDENY))
3390 t->flags |= SN_CLALLOW;
3391 break;
3392 case ACT_REPLACE:
3393 if (!(t->flags & SN_CLDENY)) {
3394 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3395 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3396 }
3397 break;
3398 case ACT_REMOVE:
3399 if (!(t->flags & SN_CLDENY))
3400 delete_header = 1;
3401 break;
3402 case ACT_DENY:
3403 if (!(t->flags & SN_CLALLOW))
3404 t->flags |= SN_CLDENY;
3405 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003406 case ACT_PASS: /* we simply don't deny this one */
3407 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003408 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003409 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003410 }
willy tarreaue39cd132005-12-17 13:00:18 +01003411 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003413 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003414
willy tarreau240afa62005-12-17 13:14:35 +01003415 /* Now look for cookies. Conforming to RFC2109, we have to support
3416 * attributes whose name begin with a '$', and associate them with
3417 * the right cookie, if we want to delete this cookie.
3418 * So there are 3 cases for each cookie read :
3419 * 1) it's a special attribute, beginning with a '$' : ignore it.
3420 * 2) it's a server id cookie that we *MAY* want to delete : save
3421 * some pointers on it (last semi-colon, beginning of cookie...)
3422 * 3) it's an application cookie : we *MAY* have to delete a previous
3423 * "special" cookie.
3424 * At the end of loop, if a "special" cookie remains, we may have to
3425 * remove it. If no application cookie persists in the header, we
3426 * *MUST* delete it
3427 */
willy tarreau12350152005-12-18 01:03:27 +01003428 if (!delete_header &&
3429 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003430 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003431 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003432 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003433 char *del_colon, *del_cookie, *colon;
3434 int app_cookies;
3435
willy tarreau5cbea6f2005-12-17 12:48:26 +01003436 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003437 colon = p1;
3438 /* del_cookie == NULL => nothing to be deleted */
3439 del_colon = del_cookie = NULL;
3440 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003441
3442 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003443 /* skip spaces and colons, but keep an eye on these ones */
3444 while (p1 < ptr) {
3445 if (*p1 == ';' || *p1 == ',')
3446 colon = p1;
3447 else if (!isspace((int)*p1))
3448 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003450 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003451
3452 if (p1 == ptr)
3453 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003454
3455 /* p1 is at the beginning of the cookie name */
3456 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003457 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003458 p2++;
3459
3460 if (p2 == ptr)
3461 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462
3463 p3 = p2 + 1; /* skips the '=' sign */
3464 if (p3 == ptr)
3465 break;
3466
willy tarreau240afa62005-12-17 13:14:35 +01003467 p4 = p3;
3468 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003469 p4++;
3470
3471 /* here, we have the cookie name between p1 and p2,
3472 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003473 * we can process it :
3474 *
3475 * Cookie: NAME=VALUE;
3476 * | || || |
3477 * | || || +--> p4
3478 * | || |+-------> p3
3479 * | || +--------> p2
3480 * | |+------------> p1
3481 * | +-------------> colon
3482 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003483 */
3484
willy tarreau240afa62005-12-17 13:14:35 +01003485 if (*p1 == '$') {
3486 /* skip this one */
3487 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003488 else {
3489 /* first, let's see if we want to capture it */
3490 if (t->proxy->capture_name != NULL &&
3491 t->logs.cli_cookie == NULL &&
3492 (p4 - p1 >= t->proxy->capture_namelen) &&
3493 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3494 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003495
willy tarreau8337c6b2005-12-17 13:41:01 +01003496 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3497 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003498 } else {
3499 if (log_len > t->proxy->capture_len)
3500 log_len = t->proxy->capture_len;
3501 memcpy(t->logs.cli_cookie, p1, log_len);
3502 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003503 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003504 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003505
3506 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3507 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3508 /* Cool... it's the right one */
3509 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003510 char *delim;
3511
3512 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3513 * have the server ID betweek p3 and delim, and the original cookie between
3514 * delim+1 and p4. Otherwise, delim==p4 :
3515 *
3516 * Cookie: NAME=SRV~VALUE;
3517 * | || || | |
3518 * | || || | +--> p4
3519 * | || || +--------> delim
3520 * | || |+-----------> p3
3521 * | || +------------> p2
3522 * | |+----------------> p1
3523 * | +-----------------> colon
3524 * +------------------------> req->h
3525 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003526
willy tarreau0174f312005-12-18 01:02:42 +01003527 if (t->proxy->options & PR_O_COOK_PFX) {
3528 for (delim = p3; delim < p4; delim++)
3529 if (*delim == COOKIE_DELIM)
3530 break;
3531 }
3532 else
3533 delim = p4;
3534
3535
3536 /* Here, we'll look for the first running server which supports the cookie.
3537 * This allows to share a same cookie between several servers, for example
3538 * to dedicate backup servers to specific servers only.
3539 */
3540 while (srv) {
3541 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3542 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3543 /* we found the server and it's usable */
3544 t->flags &= ~SN_CK_MASK;
3545 t->flags |= SN_CK_VALID | SN_DIRECT;
3546 t->srv = srv;
3547 break;
willy tarreau12350152005-12-18 01:03:27 +01003548 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003549 /* we found a server, but it's down */
3550 t->flags &= ~SN_CK_MASK;
3551 t->flags |= SN_CK_DOWN;
3552 }
3553 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003554 srv = srv->next;
3555 }
3556
willy tarreau0174f312005-12-18 01:02:42 +01003557 if (!srv && !(t->flags & SN_CK_DOWN)) {
3558 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003559 t->flags &= ~SN_CK_MASK;
3560 t->flags |= SN_CK_INVALID;
3561 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003562
willy tarreau0174f312005-12-18 01:02:42 +01003563 /* depending on the cookie mode, we may have to either :
3564 * - delete the complete cookie if we're in insert+indirect mode, so that
3565 * the server never sees it ;
3566 * - remove the server id from the cookie value, and tag the cookie as an
3567 * application cookie so that it does not get accidentely removed later,
3568 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003569 */
willy tarreau0174f312005-12-18 01:02:42 +01003570 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3571 buffer_replace2(req, p3, delim + 1, NULL, 0);
3572 p4 -= (delim + 1 - p3);
3573 ptr -= (delim + 1 - p3);
3574 del_cookie = del_colon = NULL;
3575 app_cookies++; /* protect the header from deletion */
3576 }
3577 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003578 (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 +01003579 del_cookie = p1;
3580 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003581 }
willy tarreau12350152005-12-18 01:03:27 +01003582 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003583 /* now we know that we must keep this cookie since it's
3584 * not ours. But if we wanted to delete our cookie
3585 * earlier, we cannot remove the complete header, but we
3586 * can remove the previous block itself.
3587 */
3588 app_cookies++;
3589
3590 if (del_cookie != NULL) {
3591 buffer_replace2(req, del_cookie, p1, NULL, 0);
3592 p4 -= (p1 - del_cookie);
3593 ptr -= (p1 - del_cookie);
3594 del_cookie = del_colon = NULL;
3595 }
willy tarreau240afa62005-12-17 13:14:35 +01003596 }
willy tarreau12350152005-12-18 01:03:27 +01003597
3598 if ((t->proxy->appsession_name != NULL) &&
3599 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3600 /* first, let's see if the cookie is our appcookie*/
3601
3602 /* Cool... it's the right one */
3603
3604 asession_temp = &local_asession;
3605
3606 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3607 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3608 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3609 return 0;
3610 }
3611
3612 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3613 asession_temp->sessid[t->proxy->appsession_len] = 0;
3614 asession_temp->serverid = NULL;
3615
3616 /* only do insert, if lookup fails */
3617 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3618 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3619 Alert("Not enough memory process_cli():asession:calloc().\n");
3620 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3621 return 0;
3622 }
3623
3624 asession_temp->sessid = local_asession.sessid;
3625 asession_temp->serverid = local_asession.serverid;
3626 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3627 }
3628 else{
3629 /* free wasted memory */
3630 pool_free_to(apools.sessid, local_asession.sessid);
3631 }
3632
3633 if (asession_temp->serverid == NULL) {
3634 Alert("Found Application Session without matching server.\n");
3635 } else {
3636 struct server *srv = t->proxy->srv;
3637 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003638 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003639 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3640 /* we found the server and it's usable */
3641 t->flags &= ~SN_CK_MASK;
3642 t->flags |= SN_CK_VALID | SN_DIRECT;
3643 t->srv = srv;
3644 break;
3645 } else {
3646 t->flags &= ~SN_CK_MASK;
3647 t->flags |= SN_CK_DOWN;
3648 }
3649 }
3650 srv = srv->next;
3651 }/* end while(srv) */
3652 }/* end else if server == NULL */
3653
3654 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003655 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003656 }
willy tarreau240afa62005-12-17 13:14:35 +01003657
willy tarreau5cbea6f2005-12-17 12:48:26 +01003658 /* we'll have to look for another cookie ... */
3659 p1 = p4;
3660 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003661
3662 /* There's no more cookie on this line.
3663 * We may have marked the last one(s) for deletion.
3664 * We must do this now in two ways :
3665 * - if there is no app cookie, we simply delete the header ;
3666 * - if there are app cookies, we must delete the end of the
3667 * string properly, including the colon/semi-colon before
3668 * the cookie name.
3669 */
3670 if (del_cookie != NULL) {
3671 if (app_cookies) {
3672 buffer_replace2(req, del_colon, ptr, NULL, 0);
3673 /* WARNING! <ptr> becomes invalid for now. If some code
3674 * below needs to rely on it before the end of the global
3675 * header loop, we need to correct it with this code :
3676 * ptr = del_colon;
3677 */
3678 }
3679 else
3680 delete_header = 1;
3681 }
3682 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683
3684 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003685 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003686 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003687 }
willy tarreau240afa62005-12-17 13:14:35 +01003688 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3689
willy tarreau5cbea6f2005-12-17 12:48:26 +01003690 req->h = req->lr;
3691 } /* while (req->lr < req->r) */
3692
3693 /* end of header processing (even if incomplete) */
3694
willy tarreauef900ab2005-12-17 12:52:52 +01003695 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3696 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3697 * full. We cannot loop here since event_cli_read will disable it only if
3698 * req->l == rlim-data
3699 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003700 FD_SET(t->cli_fd, StaticReadEvent);
3701 if (t->proxy->clitimeout)
3702 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3703 else
3704 tv_eternity(&t->crexpire);
3705 }
3706
willy tarreaue39cd132005-12-17 13:00:18 +01003707 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003708 * won't be able to free more later, so the session will never terminate.
3709 */
willy tarreaue39cd132005-12-17 13:00:18 +01003710 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003711 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003712 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003713 if (!(t->flags & SN_ERR_MASK))
3714 t->flags |= SN_ERR_PRXCOND;
3715 if (!(t->flags & SN_FINST_MASK))
3716 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003717 return 1;
3718 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003719 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003720 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721 tv_eternity(&t->crexpire);
3722 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003723 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003724 if (!(t->flags & SN_ERR_MASK))
3725 t->flags |= SN_ERR_CLICL;
3726 if (!(t->flags & SN_FINST_MASK))
3727 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003728 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003729 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003730 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3731
3732 /* read timeout : give up with an error message.
3733 */
3734 t->logs.status = 408;
3735 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003736 if (!(t->flags & SN_ERR_MASK))
3737 t->flags |= SN_ERR_CLITO;
3738 if (!(t->flags & SN_FINST_MASK))
3739 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003740 return 1;
3741 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003742
3743 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003744 }
3745 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003746 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003747 /* FIXME: this error handling is partly buggy because we always report
3748 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3749 * or HEADER phase. BTW, it's not logical to expire the client while
3750 * we're waiting for the server to connect.
3751 */
willy tarreau0f7af912005-12-17 12:21:26 +01003752 /* read or write error */
3753 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003754 tv_eternity(&t->crexpire);
3755 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003756 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003757 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003758 if (!(t->flags & SN_ERR_MASK))
3759 t->flags |= SN_ERR_CLICL;
3760 if (!(t->flags & SN_FINST_MASK))
3761 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003762 return 1;
3763 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003764 /* last read, or end of server write */
3765 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003766 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003767 tv_eternity(&t->crexpire);
3768 shutdown(t->cli_fd, SHUT_RD);
3769 t->cli_state = CL_STSHUTR;
3770 return 1;
3771 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003772 /* last server read and buffer empty */
3773 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003774 FD_CLR(t->cli_fd, StaticWriteEvent);
3775 tv_eternity(&t->cwexpire);
3776 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003777 /* We must ensure that the read part is still alive when switching
3778 * to shutw */
3779 FD_SET(t->cli_fd, StaticReadEvent);
3780 if (t->proxy->clitimeout)
3781 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003782 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003783 //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 +01003784 return 1;
3785 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003786 /* read timeout */
3787 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3788 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003789 tv_eternity(&t->crexpire);
3790 shutdown(t->cli_fd, SHUT_RD);
3791 t->cli_state = CL_STSHUTR;
3792 if (!(t->flags & SN_ERR_MASK))
3793 t->flags |= SN_ERR_CLITO;
3794 if (!(t->flags & SN_FINST_MASK))
3795 t->flags |= SN_FINST_D;
3796 return 1;
3797 }
3798 /* write timeout */
3799 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3800 FD_CLR(t->cli_fd, StaticWriteEvent);
3801 tv_eternity(&t->cwexpire);
3802 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003803 /* We must ensure that the read part is still alive when switching
3804 * to shutw */
3805 FD_SET(t->cli_fd, StaticReadEvent);
3806 if (t->proxy->clitimeout)
3807 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3808
willy tarreau036e1ce2005-12-17 13:46:33 +01003809 t->cli_state = CL_STSHUTW;
3810 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003811 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003812 if (!(t->flags & SN_FINST_MASK))
3813 t->flags |= SN_FINST_D;
3814 return 1;
3815 }
willy tarreau0f7af912005-12-17 12:21:26 +01003816
willy tarreauc58fc692005-12-17 14:13:08 +01003817 if (req->l >= req->rlim - req->data) {
3818 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003819 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003820 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003821 FD_CLR(t->cli_fd, StaticReadEvent);
3822 tv_eternity(&t->crexpire);
3823 }
3824 }
3825 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003826 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003827 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3828 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003829 if (!t->proxy->clitimeout ||
3830 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3831 /* If the client has no timeout, or if the server not ready yet, and we
3832 * know for sure that it can expire, then it's cleaner to disable the
3833 * timeout on the client side so that too low values cannot make the
3834 * sessions abort too early.
3835 */
willy tarreau0f7af912005-12-17 12:21:26 +01003836 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003837 else
3838 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003839 }
3840 }
3841
3842 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003843 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003844 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3845 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3846 tv_eternity(&t->cwexpire);
3847 }
3848 }
3849 else { /* buffer not empty */
3850 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3851 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003852 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003853 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003854 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3855 t->crexpire = t->cwexpire;
3856 }
willy tarreau0f7af912005-12-17 12:21:26 +01003857 else
3858 tv_eternity(&t->cwexpire);
3859 }
3860 }
3861 return 0; /* other cases change nothing */
3862 }
3863 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003864 if (t->res_cw == RES_ERROR) {
3865 tv_eternity(&t->cwexpire);
3866 fd_delete(t->cli_fd);
3867 t->cli_state = CL_STCLOSE;
3868 if (!(t->flags & SN_ERR_MASK))
3869 t->flags |= SN_ERR_CLICL;
3870 if (!(t->flags & SN_FINST_MASK))
3871 t->flags |= SN_FINST_D;
3872 return 1;
3873 }
3874 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003875 tv_eternity(&t->cwexpire);
3876 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003877 t->cli_state = CL_STCLOSE;
3878 return 1;
3879 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003880 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3881 tv_eternity(&t->cwexpire);
3882 fd_delete(t->cli_fd);
3883 t->cli_state = CL_STCLOSE;
3884 if (!(t->flags & SN_ERR_MASK))
3885 t->flags |= SN_ERR_CLITO;
3886 if (!(t->flags & SN_FINST_MASK))
3887 t->flags |= SN_FINST_D;
3888 return 1;
3889 }
willy tarreau0f7af912005-12-17 12:21:26 +01003890 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003891 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003892 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3893 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3894 tv_eternity(&t->cwexpire);
3895 }
3896 }
3897 else { /* buffer not empty */
3898 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3899 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003900 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003901 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003902 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3903 t->crexpire = t->cwexpire;
3904 }
willy tarreau0f7af912005-12-17 12:21:26 +01003905 else
3906 tv_eternity(&t->cwexpire);
3907 }
3908 }
3909 return 0;
3910 }
3911 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003912 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003913 tv_eternity(&t->crexpire);
3914 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003915 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003916 if (!(t->flags & SN_ERR_MASK))
3917 t->flags |= SN_ERR_CLICL;
3918 if (!(t->flags & SN_FINST_MASK))
3919 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003920 return 1;
3921 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003922 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3923 tv_eternity(&t->crexpire);
3924 fd_delete(t->cli_fd);
3925 t->cli_state = CL_STCLOSE;
3926 return 1;
3927 }
3928 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3929 tv_eternity(&t->crexpire);
3930 fd_delete(t->cli_fd);
3931 t->cli_state = CL_STCLOSE;
3932 if (!(t->flags & SN_ERR_MASK))
3933 t->flags |= SN_ERR_CLITO;
3934 if (!(t->flags & SN_FINST_MASK))
3935 t->flags |= SN_FINST_D;
3936 return 1;
3937 }
willy tarreauef900ab2005-12-17 12:52:52 +01003938 else if (req->l >= req->rlim - req->data) {
3939 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003940
3941 /* FIXME-20050705: is it possible for a client to maintain a session
3942 * after the timeout by sending more data after it receives a close ?
3943 */
3944
willy tarreau0f7af912005-12-17 12:21:26 +01003945 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003946 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003947 FD_CLR(t->cli_fd, StaticReadEvent);
3948 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003949 //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 +01003950 }
3951 }
3952 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003953 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003954 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3955 FD_SET(t->cli_fd, StaticReadEvent);
3956 if (t->proxy->clitimeout)
3957 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3958 else
3959 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003960 //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 +01003961 }
3962 }
3963 return 0;
3964 }
3965 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003966 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003967 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003968 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 +01003969 write(1, trash, len);
3970 }
3971 return 0;
3972 }
3973 return 0;
3974}
3975
3976
3977/*
3978 * manages the server FSM and its socket. It returns 1 if a state has changed
3979 * (and a resync may be needed), 0 else.
3980 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003981int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003982 int s = t->srv_state;
3983 int c = t->cli_state;
3984 struct buffer *req = t->req;
3985 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003986 appsess *asession_temp = NULL;
3987 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003988 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003989
willy tarreau750a4722005-12-17 13:21:24 +01003990#ifdef DEBUG_FULL
3991 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3992#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3994 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3995 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3996 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003997 if (s == SV_STIDLE) {
3998 if (c == CL_STHEADERS)
3999 return 0; /* stay in idle, waiting for data to reach the client side */
4000 else if (c == CL_STCLOSE ||
4001 c == CL_STSHUTW ||
4002 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
4003 tv_eternity(&t->cnexpire);
4004 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004005 if (!(t->flags & SN_ERR_MASK))
4006 t->flags |= SN_ERR_CLICL;
4007 if (!(t->flags & SN_FINST_MASK))
4008 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004009 return 1;
4010 }
4011 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01004012 /* initiate a connection to the server */
4013 conn_err = connect_server(t);
4014 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004015 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4016 t->srv_state = SV_STCONN;
4017 }
4018 else { /* try again */
4019 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004020 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004021 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004022 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004023 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4024 t->flags &= ~SN_CK_MASK;
4025 t->flags |= SN_CK_DOWN;
4026 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027 }
4028
willy tarreaub1285d52005-12-18 01:20:14 +01004029 conn_err = connect_server(t);
4030 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004031 t->srv_state = SV_STCONN;
4032 break;
4033 }
4034 }
4035 if (t->conn_retries < 0) {
4036 /* if conn_retries < 0 or other error, let's abort */
4037 tv_eternity(&t->cnexpire);
4038 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004039 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004040 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004041 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004042 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004043 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004044 if (!(t->flags & SN_FINST_MASK))
4045 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004046 }
4047 }
4048 return 1;
4049 }
4050 }
4051 else if (s == SV_STCONN) { /* connection in progress */
4052 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
Willy TARREAUb4512472006-03-01 22:34:48 +01004053 //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 +01004054 return 0; /* nothing changed */
4055 }
4056 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4057 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4058 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004059 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004060 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004061 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004062 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004063 if (t->conn_retries >= 0) {
4064 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004065 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004066 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004067 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4068 t->flags &= ~SN_CK_MASK;
4069 t->flags |= SN_CK_DOWN;
4070 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004071 }
willy tarreaub1285d52005-12-18 01:20:14 +01004072 conn_err = connect_server(t);
4073 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004074 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004075 }
willy tarreaub1285d52005-12-18 01:20:14 +01004076 else if (t->res_sw == RES_SILENT)
4077 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4078 else
4079 conn_err = SN_ERR_SRVCL; // it was a connect error.
4080
willy tarreau0f7af912005-12-17 12:21:26 +01004081 /* if conn_retries < 0 or other error, let's abort */
4082 tv_eternity(&t->cnexpire);
4083 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004084 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004085 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004086 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004087 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004088 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004089 if (!(t->flags & SN_FINST_MASK))
4090 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004091 return 1;
4092 }
4093 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004094 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004095
willy tarreau0f7af912005-12-17 12:21:26 +01004096 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004097 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004098 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004099 tv_eternity(&t->swexpire);
4100 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004101 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004102 if (t->proxy->srvtimeout) {
4103 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4104 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4105 t->srexpire = t->swexpire;
4106 }
4107 else
4108 tv_eternity(&t->swexpire);
4109 }
willy tarreau0f7af912005-12-17 12:21:26 +01004110
4111 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4112 FD_SET(t->srv_fd, StaticReadEvent);
4113 if (t->proxy->srvtimeout)
4114 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4115 else
4116 tv_eternity(&t->srexpire);
4117
4118 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004119 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004120
4121 /* if the user wants to log as soon as possible, without counting
4122 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004123 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004124 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4125 sess_log(t);
4126 }
willy tarreau0f7af912005-12-17 12:21:26 +01004127 }
willy tarreauef900ab2005-12-17 12:52:52 +01004128 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004129 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004130 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4131 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004132 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004133 return 1;
4134 }
4135 }
4136 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004137 /* now parse the partial (or complete) headers */
4138 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4139 char *ptr;
4140 int delete_header;
4141
4142 ptr = rep->lr;
4143
4144 /* look for the end of the current header */
4145 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4146 ptr++;
4147
4148 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004149 int line, len;
4150
4151 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004152
4153 /* first, we'll block if security checks have caught nasty things */
4154 if (t->flags & SN_CACHEABLE) {
4155 if ((t->flags & SN_CACHE_COOK) &&
4156 (t->flags & SN_SCK_ANY) &&
4157 (t->proxy->options & PR_O_CHK_CACHE)) {
4158
4159 /* we're in presence of a cacheable response containing
4160 * a set-cookie header. We'll block it as requested by
4161 * the 'checkcache' option, and send an alert.
4162 */
4163 tv_eternity(&t->srexpire);
4164 tv_eternity(&t->swexpire);
4165 fd_delete(t->srv_fd);
4166 t->srv_state = SV_STCLOSE;
4167 t->logs.status = 502;
4168 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4169 if (!(t->flags & SN_ERR_MASK))
4170 t->flags |= SN_ERR_PRXCOND;
4171 if (!(t->flags & SN_FINST_MASK))
4172 t->flags |= SN_FINST_H;
4173
4174 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4175 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4176
4177 return 1;
4178 }
4179 }
4180
willy tarreau982249e2005-12-18 00:57:06 +01004181 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4182 if (t->flags & SN_SVDENY) {
4183 tv_eternity(&t->srexpire);
4184 tv_eternity(&t->swexpire);
4185 fd_delete(t->srv_fd);
4186 t->srv_state = SV_STCLOSE;
4187 t->logs.status = 502;
4188 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4189 if (!(t->flags & SN_ERR_MASK))
4190 t->flags |= SN_ERR_PRXCOND;
4191 if (!(t->flags & SN_FINST_MASK))
4192 t->flags |= SN_FINST_H;
4193 return 1;
4194 }
4195
willy tarreau5cbea6f2005-12-17 12:48:26 +01004196 /* we'll have something else to do here : add new headers ... */
4197
willy tarreaucd878942005-12-17 13:27:43 +01004198 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4199 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004200 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004201 * insert a set-cookie here, except if we want to insert only on POST
4202 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004203 */
willy tarreau750a4722005-12-17 13:21:24 +01004204 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004205 t->proxy->cookie_name,
4206 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004207
willy tarreau036e1ce2005-12-17 13:46:33 +01004208 t->flags |= SN_SCK_INSERTED;
4209
willy tarreau750a4722005-12-17 13:21:24 +01004210 /* Here, we will tell an eventual cache on the client side that we don't
4211 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4212 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4213 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4214 */
willy tarreau240afa62005-12-17 13:14:35 +01004215 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004216 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4217 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004218
4219 if (rep->data + rep->l < rep->h)
4220 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4221 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004222 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004223 }
4224
4225 /* headers to be added */
4226 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004227 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4228 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004229 }
4230
willy tarreau25c4ea52005-12-18 00:49:49 +01004231 /* add a "connection: close" line if needed */
4232 if (t->proxy->options & PR_O_HTTP_CLOSE)
4233 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4234
willy tarreau5cbea6f2005-12-17 12:48:26 +01004235 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004236 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004237 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004238
Willy TARREAU767ba712006-03-01 22:40:50 +01004239 /* client connection already closed or option 'httpclose' required :
4240 * we close the server's outgoing connection right now.
4241 */
4242 if ((req->l == 0) &&
4243 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
4244 FD_CLR(t->srv_fd, StaticWriteEvent);
4245 tv_eternity(&t->swexpire);
4246
4247 /* We must ensure that the read part is still alive when switching
4248 * to shutw */
4249 FD_SET(t->srv_fd, StaticReadEvent);
4250 if (t->proxy->srvtimeout)
4251 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4252
4253 shutdown(t->srv_fd, SHUT_WR);
4254 t->srv_state = SV_STSHUTW;
4255 }
4256
willy tarreau25c4ea52005-12-18 00:49:49 +01004257 /* if the user wants to log as soon as possible, without counting
4258 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004259 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004260 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4261 t->logs.bytes = rep->h - rep->data;
4262 sess_log(t);
4263 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004264 break;
4265 }
4266
4267 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4268 if (ptr > rep->r - 2) {
4269 /* this is a partial header, let's wait for more to come */
4270 rep->lr = ptr;
4271 break;
4272 }
4273
4274 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4275 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4276
4277 /* now we know that *ptr is either \r or \n,
4278 * and that there are at least 1 char after it.
4279 */
4280 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4281 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4282 else
4283 rep->lr = ptr + 2; /* \r\n or \n\r */
4284
4285 /*
4286 * now we know that we have a full header ; we can do whatever
4287 * we want with these pointers :
4288 * rep->h = beginning of header
4289 * ptr = end of header (first \r or \n)
4290 * rep->lr = beginning of next line (next rep->h)
4291 * rep->r = end of data (not used at this stage)
4292 */
4293
willy tarreaua1598082005-12-17 13:08:06 +01004294
willy tarreau982249e2005-12-18 00:57:06 +01004295 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004296 t->logs.logwait &= ~LW_RESP;
4297 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004298 switch (t->logs.status) {
4299 case 200:
4300 case 203:
4301 case 206:
4302 case 300:
4303 case 301:
4304 case 410:
4305 /* RFC2616 @13.4:
4306 * "A response received with a status code of
4307 * 200, 203, 206, 300, 301 or 410 MAY be stored
4308 * by a cache (...) unless a cache-control
4309 * directive prohibits caching."
4310 *
4311 * RFC2616 @9.5: POST method :
4312 * "Responses to this method are not cacheable,
4313 * unless the response includes appropriate
4314 * Cache-Control or Expires header fields."
4315 */
4316 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4317 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4318 break;
4319 default:
4320 break;
4321 }
willy tarreau4302f492005-12-18 01:00:37 +01004322 }
4323 else if (t->logs.logwait & LW_RSPHDR) {
4324 struct cap_hdr *h;
4325 int len;
4326 for (h = t->proxy->rsp_cap; h; h = h->next) {
4327 if ((h->namelen + 2 <= ptr - rep->h) &&
4328 (rep->h[h->namelen] == ':') &&
4329 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4330
4331 if (t->rsp_cap[h->index] == NULL)
4332 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4333
4334 len = ptr - (rep->h + h->namelen + 2);
4335 if (len > h->len)
4336 len = h->len;
4337
4338 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4339 t->rsp_cap[h->index][len]=0;
4340 }
4341 }
4342
willy tarreaua1598082005-12-17 13:08:06 +01004343 }
4344
willy tarreau5cbea6f2005-12-17 12:48:26 +01004345 delete_header = 0;
4346
willy tarreau982249e2005-12-18 00:57:06 +01004347 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004348 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004349 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 +01004350 max = ptr - rep->h;
4351 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004352 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004353 trash[len++] = '\n';
4354 write(1, trash, len);
4355 }
4356
willy tarreau25c4ea52005-12-18 00:49:49 +01004357 /* remove "connection: " if needed */
4358 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4359 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4360 delete_header = 1;
4361 }
4362
willy tarreau5cbea6f2005-12-17 12:48:26 +01004363 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004364 if (!delete_header && t->proxy->rsp_exp != NULL
4365 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004366 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004367 char term;
4368
4369 term = *ptr;
4370 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004371 exp = t->proxy->rsp_exp;
4372 do {
4373 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4374 switch (exp->action) {
4375 case ACT_ALLOW:
4376 if (!(t->flags & SN_SVDENY))
4377 t->flags |= SN_SVALLOW;
4378 break;
4379 case ACT_REPLACE:
4380 if (!(t->flags & SN_SVDENY)) {
4381 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4382 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4383 }
4384 break;
4385 case ACT_REMOVE:
4386 if (!(t->flags & SN_SVDENY))
4387 delete_header = 1;
4388 break;
4389 case ACT_DENY:
4390 if (!(t->flags & SN_SVALLOW))
4391 t->flags |= SN_SVDENY;
4392 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004393 case ACT_PASS: /* we simply don't deny this one */
4394 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004395 }
4396 break;
4397 }
willy tarreaue39cd132005-12-17 13:00:18 +01004398 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399 *ptr = term; /* restore the string terminator */
4400 }
4401
willy tarreau97f58572005-12-18 00:53:44 +01004402 /* check for cache-control: or pragma: headers */
4403 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4404 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4405 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4406 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4407 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004408 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004409 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4410 else {
4411 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004412 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004413 t->flags &= ~SN_CACHE_COOK;
4414 }
4415 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004416 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004417 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004418 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004419 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4420 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004421 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004422 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004423 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4424 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4425 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4426 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4427 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4428 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004429 }
4430 }
4431 }
4432
willy tarreau5cbea6f2005-12-17 12:48:26 +01004433 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004434 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004435 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004436 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004437 char *p1, *p2, *p3, *p4;
4438
willy tarreau97f58572005-12-18 00:53:44 +01004439 t->flags |= SN_SCK_ANY;
4440
willy tarreau5cbea6f2005-12-17 12:48:26 +01004441 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4442
4443 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004444 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004445 p1++;
4446
4447 if (p1 == ptr || *p1 == ';') /* end of cookie */
4448 break;
4449
4450 /* p1 is at the beginning of the cookie name */
4451 p2 = p1;
4452
4453 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4454 p2++;
4455
4456 if (p2 == ptr || *p2 == ';') /* next cookie */
4457 break;
4458
4459 p3 = p2 + 1; /* skips the '=' sign */
4460 if (p3 == ptr)
4461 break;
4462
4463 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004464 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004465 p4++;
4466
4467 /* here, we have the cookie name between p1 and p2,
4468 * and its value between p3 and p4.
4469 * we can process it.
4470 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004471
4472 /* first, let's see if we want to capture it */
4473 if (t->proxy->capture_name != NULL &&
4474 t->logs.srv_cookie == NULL &&
4475 (p4 - p1 >= t->proxy->capture_namelen) &&
4476 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4477 int log_len = p4 - p1;
4478
4479 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4480 Alert("HTTP logging : out of memory.\n");
4481 }
4482
4483 if (log_len > t->proxy->capture_len)
4484 log_len = t->proxy->capture_len;
4485 memcpy(t->logs.srv_cookie, p1, log_len);
4486 t->logs.srv_cookie[log_len] = 0;
4487 }
4488
4489 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4490 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004491 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004492 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004493
4494 /* If the cookie is in insert mode on a known server, we'll delete
4495 * this occurrence because we'll insert another one later.
4496 * We'll delete it too if the "indirect" option is set and we're in
4497 * a direct access. */
4498 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004499 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004500 /* this header must be deleted */
4501 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004502 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004503 }
4504 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4505 /* replace bytes p3->p4 with the cookie name associated
4506 * with this server since we know it.
4507 */
4508 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004509 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004510 }
willy tarreau0174f312005-12-18 01:02:42 +01004511 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4512 /* insert the cookie name associated with this server
4513 * before existing cookie, and insert a delimitor between them..
4514 */
4515 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4516 p3[t->srv->cklen] = COOKIE_DELIM;
4517 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4518 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004519 break;
4520 }
willy tarreau12350152005-12-18 01:03:27 +01004521
4522 /* first, let's see if the cookie is our appcookie*/
4523 if ((t->proxy->appsession_name != NULL) &&
4524 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4525
4526 /* Cool... it's the right one */
4527
willy tarreaub952e1d2005-12-18 01:31:20 +01004528 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004529 asession_temp = &local_asession;
4530
willy tarreaub952e1d2005-12-18 01:31:20 +01004531 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004532 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4533 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4534 }
4535 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4536 asession_temp->sessid[t->proxy->appsession_len] = 0;
4537 asession_temp->serverid = NULL;
4538
4539 /* only do insert, if lookup fails */
4540 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4541 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4542 Alert("Not enought Memory process_srv():asession:calloc().\n");
4543 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4544 return 0;
4545 }
4546 asession_temp->sessid = local_asession.sessid;
4547 asession_temp->serverid = local_asession.serverid;
4548 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004549 }/* end if (chtbl_lookup()) */
4550 else {
willy tarreau12350152005-12-18 01:03:27 +01004551 /* free wasted memory */
4552 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004553 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004554
willy tarreaub952e1d2005-12-18 01:31:20 +01004555 if (asession_temp->serverid == NULL) {
4556 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004557 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4558 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4559 }
4560 asession_temp->serverid[0] = '\0';
4561 }
4562
willy tarreaub952e1d2005-12-18 01:31:20 +01004563 if (asession_temp->serverid[0] == '\0')
4564 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004565
4566 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4567
4568#if defined(DEBUG_HASH)
4569 print_table(&(t->proxy->htbl_proxy));
4570#endif
4571 break;
4572 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004573 else {
4574 // fprintf(stderr,"Ignoring unknown cookie : ");
4575 // write(2, p1, p2-p1);
4576 // fprintf(stderr," = ");
4577 // write(2, p3, p4-p3);
4578 // fprintf(stderr,"\n");
4579 }
4580 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4581 } /* we're now at the end of the cookie value */
4582 } /* end of cookie processing */
4583
willy tarreau97f58572005-12-18 00:53:44 +01004584 /* check for any set-cookie in case we check for cacheability */
4585 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4586 (t->proxy->options & PR_O_CHK_CACHE) &&
4587 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4588 t->flags |= SN_SCK_ANY;
4589 }
4590
willy tarreau5cbea6f2005-12-17 12:48:26 +01004591 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004592 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004593 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004594
willy tarreau5cbea6f2005-12-17 12:48:26 +01004595 rep->h = rep->lr;
4596 } /* while (rep->lr < rep->r) */
4597
4598 /* end of header processing (even if incomplete) */
4599
willy tarreauef900ab2005-12-17 12:52:52 +01004600 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4601 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4602 * full. We cannot loop here since event_srv_read will disable it only if
4603 * rep->l == rlim-data
4604 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004605 FD_SET(t->srv_fd, StaticReadEvent);
4606 if (t->proxy->srvtimeout)
4607 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4608 else
4609 tv_eternity(&t->srexpire);
4610 }
willy tarreau0f7af912005-12-17 12:21:26 +01004611
willy tarreau8337c6b2005-12-17 13:41:01 +01004612 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004613 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004614 tv_eternity(&t->srexpire);
4615 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004616 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004617 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004618 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004619 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004620 if (!(t->flags & SN_ERR_MASK))
4621 t->flags |= SN_ERR_SRVCL;
4622 if (!(t->flags & SN_FINST_MASK))
4623 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004624 return 1;
4625 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004626 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004627 * since we are in header mode, if there's no space left for headers, we
4628 * won't be able to free more later, so the session will never terminate.
4629 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004630 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 +01004631 FD_CLR(t->srv_fd, StaticReadEvent);
4632 tv_eternity(&t->srexpire);
4633 shutdown(t->srv_fd, SHUT_RD);
4634 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004635 //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 +01004636 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004637 }
4638 /* read timeout : return a 504 to the client.
4639 */
4640 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4641 tv_eternity(&t->srexpire);
4642 tv_eternity(&t->swexpire);
4643 fd_delete(t->srv_fd);
4644 t->srv_state = SV_STCLOSE;
4645 t->logs.status = 504;
4646 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004647 if (!(t->flags & SN_ERR_MASK))
4648 t->flags |= SN_ERR_SRVTO;
4649 if (!(t->flags & SN_FINST_MASK))
4650 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004651 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004652
4653 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004654 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004655 /* FIXME!!! here, we don't want to switch to SHUTW if the
4656 * client shuts read too early, because we may still have
4657 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004658 * The side-effect is that if the client completely closes its
4659 * connection during SV_STHEADER, the connection to the server
4660 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004661 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004662 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004663 FD_CLR(t->srv_fd, StaticWriteEvent);
4664 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004665
4666 /* We must ensure that the read part is still alive when switching
4667 * to shutw */
4668 FD_SET(t->srv_fd, StaticReadEvent);
4669 if (t->proxy->srvtimeout)
4670 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4671
willy tarreau0f7af912005-12-17 12:21:26 +01004672 shutdown(t->srv_fd, SHUT_WR);
4673 t->srv_state = SV_STSHUTW;
4674 return 1;
4675 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004676 /* write timeout */
4677 /* FIXME!!! here, we don't want to switch to SHUTW if the
4678 * client shuts read too early, because we may still have
4679 * some work to do on the headers.
4680 */
4681 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4682 FD_CLR(t->srv_fd, StaticWriteEvent);
4683 tv_eternity(&t->swexpire);
4684 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004685 /* We must ensure that the read part is still alive when switching
4686 * to shutw */
4687 FD_SET(t->srv_fd, StaticReadEvent);
4688 if (t->proxy->srvtimeout)
4689 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4690
4691 /* We must ensure that the read part is still alive when switching
4692 * to shutw */
4693 FD_SET(t->srv_fd, StaticReadEvent);
4694 if (t->proxy->srvtimeout)
4695 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4696
willy tarreau036e1ce2005-12-17 13:46:33 +01004697 t->srv_state = SV_STSHUTW;
4698 if (!(t->flags & SN_ERR_MASK))
4699 t->flags |= SN_ERR_SRVTO;
4700 if (!(t->flags & SN_FINST_MASK))
4701 t->flags |= SN_FINST_H;
4702 return 1;
4703 }
willy tarreau0f7af912005-12-17 12:21:26 +01004704
4705 if (req->l == 0) {
4706 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4707 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4708 tv_eternity(&t->swexpire);
4709 }
4710 }
4711 else { /* client buffer not empty */
4712 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4713 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004714 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004715 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004716 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4717 t->srexpire = t->swexpire;
4718 }
willy tarreau0f7af912005-12-17 12:21:26 +01004719 else
4720 tv_eternity(&t->swexpire);
4721 }
4722 }
4723
willy tarreau5cbea6f2005-12-17 12:48:26 +01004724 /* be nice with the client side which would like to send a complete header
4725 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4726 * would read all remaining data at once ! The client should not write past rep->lr
4727 * when the server is in header state.
4728 */
4729 //return header_processed;
4730 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004731 }
4732 else if (s == SV_STDATA) {
4733 /* read or write error */
4734 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004735 tv_eternity(&t->srexpire);
4736 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004737 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004738 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004739 if (!(t->flags & SN_ERR_MASK))
4740 t->flags |= SN_ERR_SRVCL;
4741 if (!(t->flags & SN_FINST_MASK))
4742 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004743 return 1;
4744 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004745 /* last read, or end of client write */
4746 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004747 FD_CLR(t->srv_fd, StaticReadEvent);
4748 tv_eternity(&t->srexpire);
4749 shutdown(t->srv_fd, SHUT_RD);
4750 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004751 //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 +01004752 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004753 }
4754 /* end of client read and no more data to send */
4755 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4756 FD_CLR(t->srv_fd, StaticWriteEvent);
4757 tv_eternity(&t->swexpire);
4758 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004759 /* We must ensure that the read part is still alive when switching
4760 * to shutw */
4761 FD_SET(t->srv_fd, StaticReadEvent);
4762 if (t->proxy->srvtimeout)
4763 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4764
willy tarreaua41a8b42005-12-17 14:02:24 +01004765 t->srv_state = SV_STSHUTW;
4766 return 1;
4767 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004768 /* read timeout */
4769 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4770 FD_CLR(t->srv_fd, StaticReadEvent);
4771 tv_eternity(&t->srexpire);
4772 shutdown(t->srv_fd, SHUT_RD);
4773 t->srv_state = SV_STSHUTR;
4774 if (!(t->flags & SN_ERR_MASK))
4775 t->flags |= SN_ERR_SRVTO;
4776 if (!(t->flags & SN_FINST_MASK))
4777 t->flags |= SN_FINST_D;
4778 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004779 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004780 /* write timeout */
4781 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004782 FD_CLR(t->srv_fd, StaticWriteEvent);
4783 tv_eternity(&t->swexpire);
4784 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004785 /* We must ensure that the read part is still alive when switching
4786 * to shutw */
4787 FD_SET(t->srv_fd, StaticReadEvent);
4788 if (t->proxy->srvtimeout)
4789 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004790 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004791 if (!(t->flags & SN_ERR_MASK))
4792 t->flags |= SN_ERR_SRVTO;
4793 if (!(t->flags & SN_FINST_MASK))
4794 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004795 return 1;
4796 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004797
4798 /* recompute request time-outs */
4799 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004800 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4801 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4802 tv_eternity(&t->swexpire);
4803 }
4804 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004805 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004806 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4807 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004808 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004809 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004810 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4811 t->srexpire = t->swexpire;
4812 }
willy tarreau0f7af912005-12-17 12:21:26 +01004813 else
4814 tv_eternity(&t->swexpire);
4815 }
4816 }
4817
willy tarreaub1ff9db2005-12-17 13:51:03 +01004818 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004819 if (rep->l == BUFSIZE) { /* no room to read more data */
4820 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4821 FD_CLR(t->srv_fd, StaticReadEvent);
4822 tv_eternity(&t->srexpire);
4823 }
4824 }
4825 else {
4826 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4827 FD_SET(t->srv_fd, StaticReadEvent);
4828 if (t->proxy->srvtimeout)
4829 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4830 else
4831 tv_eternity(&t->srexpire);
4832 }
4833 }
4834
4835 return 0; /* other cases change nothing */
4836 }
4837 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004838 if (t->res_sw == RES_ERROR) {
4839 //FD_CLR(t->srv_fd, StaticWriteEvent);
4840 tv_eternity(&t->swexpire);
4841 fd_delete(t->srv_fd);
4842 //close(t->srv_fd);
4843 t->srv_state = SV_STCLOSE;
4844 if (!(t->flags & SN_ERR_MASK))
4845 t->flags |= SN_ERR_SRVCL;
4846 if (!(t->flags & SN_FINST_MASK))
4847 t->flags |= SN_FINST_D;
4848 return 1;
4849 }
4850 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004851 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004852 tv_eternity(&t->swexpire);
4853 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004854 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004855 t->srv_state = SV_STCLOSE;
4856 return 1;
4857 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004858 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4859 //FD_CLR(t->srv_fd, StaticWriteEvent);
4860 tv_eternity(&t->swexpire);
4861 fd_delete(t->srv_fd);
4862 //close(t->srv_fd);
4863 t->srv_state = SV_STCLOSE;
4864 if (!(t->flags & SN_ERR_MASK))
4865 t->flags |= SN_ERR_SRVTO;
4866 if (!(t->flags & SN_FINST_MASK))
4867 t->flags |= SN_FINST_D;
4868 return 1;
4869 }
willy tarreau0f7af912005-12-17 12:21:26 +01004870 else if (req->l == 0) {
4871 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4872 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4873 tv_eternity(&t->swexpire);
4874 }
4875 }
4876 else { /* buffer not empty */
4877 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4878 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004879 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004880 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004881 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4882 t->srexpire = t->swexpire;
4883 }
willy tarreau0f7af912005-12-17 12:21:26 +01004884 else
4885 tv_eternity(&t->swexpire);
4886 }
4887 }
4888 return 0;
4889 }
4890 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004891 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004893 tv_eternity(&t->srexpire);
4894 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004895 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004896 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004897 if (!(t->flags & SN_ERR_MASK))
4898 t->flags |= SN_ERR_SRVCL;
4899 if (!(t->flags & SN_FINST_MASK))
4900 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004901 return 1;
4902 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004903 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4904 //FD_CLR(t->srv_fd, StaticReadEvent);
4905 tv_eternity(&t->srexpire);
4906 fd_delete(t->srv_fd);
4907 //close(t->srv_fd);
4908 t->srv_state = SV_STCLOSE;
4909 return 1;
4910 }
4911 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4912 //FD_CLR(t->srv_fd, StaticReadEvent);
4913 tv_eternity(&t->srexpire);
4914 fd_delete(t->srv_fd);
4915 //close(t->srv_fd);
4916 t->srv_state = SV_STCLOSE;
4917 if (!(t->flags & SN_ERR_MASK))
4918 t->flags |= SN_ERR_SRVTO;
4919 if (!(t->flags & SN_FINST_MASK))
4920 t->flags |= SN_FINST_D;
4921 return 1;
4922 }
willy tarreau0f7af912005-12-17 12:21:26 +01004923 else if (rep->l == BUFSIZE) { /* no room to read more data */
4924 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4925 FD_CLR(t->srv_fd, StaticReadEvent);
4926 tv_eternity(&t->srexpire);
4927 }
4928 }
4929 else {
4930 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4931 FD_SET(t->srv_fd, StaticReadEvent);
4932 if (t->proxy->srvtimeout)
4933 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4934 else
4935 tv_eternity(&t->srexpire);
4936 }
4937 }
4938 return 0;
4939 }
4940 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004941 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004942 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004943 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 +01004944 write(1, trash, len);
4945 }
4946 return 0;
4947 }
4948 return 0;
4949}
4950
4951
willy tarreau5cbea6f2005-12-17 12:48:26 +01004952/* Processes the client and server jobs of a session task, then
4953 * puts it back to the wait queue in a clean state, or
4954 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004955 * the time the task accepts to wait, or TIME_ETERNITY for
4956 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004957 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004958int process_session(struct task *t) {
4959 struct session *s = t->context;
4960 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004961
willy tarreau5cbea6f2005-12-17 12:48:26 +01004962 do {
4963 fsm_resync = 0;
Willy TARREAUb4512472006-03-01 22:34:48 +01004964 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004965 fsm_resync |= process_cli(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004966 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004967 fsm_resync |= process_srv(s);
Willy TARREAUb4512472006-03-01 22:34:48 +01004968 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004969 } while (fsm_resync);
4970
4971 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004972 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004973 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004974
willy tarreau5cbea6f2005-12-17 12:48:26 +01004975 tv_min(&min1, &s->crexpire, &s->cwexpire);
4976 tv_min(&min2, &s->srexpire, &s->swexpire);
4977 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004978 tv_min(&t->expire, &min1, &min2);
4979
4980 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004981 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004982
Willy TARREAU1cec83c2006-03-01 22:33:49 +01004983#ifdef DEBUG_FULL
4984 /* DEBUG code : this should never ever happen, otherwise it indicates
4985 * that a task still has something to do and will provoke a quick loop.
4986 */
4987 if (tv_remain2(&now, &t->expire) <= 0)
4988 exit(100);
4989#endif
4990
willy tarreaub952e1d2005-12-18 01:31:20 +01004991 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004992 }
4993
willy tarreau5cbea6f2005-12-17 12:48:26 +01004994 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004995 actconn--;
4996
willy tarreau982249e2005-12-18 00:57:06 +01004997 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004998 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004999 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 +01005000 write(1, trash, len);
5001 }
5002
willy tarreau750a4722005-12-17 13:21:24 +01005003 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01005004 if (s->rep != NULL)
5005 s->logs.bytes = s->rep->total;
5006
willy tarreau9fe663a2005-12-17 13:02:59 +01005007 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01005008 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01005009 sess_log(s);
5010
willy tarreau0f7af912005-12-17 12:21:26 +01005011 /* the task MUST not be in the run queue anymore */
5012 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005013 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01005014 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01005015 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005016}
5017
5018
5019
5020/*
5021 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01005022 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01005023 */
5024int process_chk(struct task *t) {
5025 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01005026 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005027 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005028
willy tarreauef900ab2005-12-17 12:52:52 +01005029 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005030
5031 if (fd < 0) { /* no check currently running */
5032 //fprintf(stderr, "process_chk: 2\n");
5033 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
5034 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005035 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005036 }
Willy TARREAU3759f982006-03-01 22:44:17 +01005037
5038 /* we don't send any health-checks when the proxy is stopped or when
5039 * the server should not be checked.
5040 */
5041 if (!(s->state & SRV_CHECKED) || s->proxy->state == PR_STSTOPPED) {
5042 tv_delayfrom(&t->expire, &now, s->inter);
5043 task_queue(t); /* restore t to its place in the task list */
5044 return tv_remain2(&now, &t->expire);
5045 }
5046
willy tarreau5cbea6f2005-12-17 12:48:26 +01005047 /* we'll initiate a new check */
5048 s->result = 0; /* no result yet */
5049 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01005050 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005051 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5052 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5053 //fprintf(stderr, "process_chk: 3\n");
5054
willy tarreaua41a8b42005-12-17 14:02:24 +01005055 /* we'll connect to the check port on the server */
5056 sa = s->addr;
5057 sa.sin_port = htons(s->check_port);
5058
willy tarreau0174f312005-12-18 01:02:42 +01005059 /* allow specific binding :
5060 * - server-specific at first
5061 * - proxy-specific next
5062 */
5063 if (s->state & SRV_BIND_SRC) {
5064 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5065 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5066 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5067 s->proxy->id, s->id);
5068 s->result = -1;
5069 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005070 }
willy tarreau0174f312005-12-18 01:02:42 +01005071 else if (s->proxy->options & PR_O_BIND_SRC) {
5072 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5073 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5074 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5075 s->proxy->id);
5076 s->result = -1;
5077 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005078 }
willy tarreau0174f312005-12-18 01:02:42 +01005079
5080 if (!s->result) {
5081 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5082 /* OK, connection in progress or established */
5083
5084 //fprintf(stderr, "process_chk: 4\n");
5085
5086 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5087 fdtab[fd].owner = t;
5088 fdtab[fd].read = &event_srv_chk_r;
5089 fdtab[fd].write = &event_srv_chk_w;
5090 fdtab[fd].state = FD_STCONN; /* connection in progress */
5091 FD_SET(fd, StaticWriteEvent); /* for connect status */
5092 fd_insert(fd);
5093 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5094 tv_delayfrom(&t->expire, &now, s->inter);
5095 task_queue(t); /* restore t to its place in the task list */
5096 return tv_remain(&now, &t->expire);
5097 }
5098 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5099 s->result = -1; /* a real error */
5100 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005101 }
5102 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005103 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005104 }
5105
5106 if (!s->result) { /* nothing done */
5107 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005108 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005109 task_queue(t); /* restore t to its place in the task list */
5110 return tv_remain(&now, &t->expire);
5111 }
5112
5113 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005114 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005115 s->health--; /* still good */
5116 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005117 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005118 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005119 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005120 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005121
willy tarreaudd07e972005-12-18 00:48:48 +01005122 if (find_server(s->proxy) == NULL) {
5123 Alert("Proxy %s has no server available !\n", s->proxy->id);
5124 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5125 }
5126 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005127 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005128 }
5129
5130 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005131 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5132 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005133 }
5134 else {
5135 //fprintf(stderr, "process_chk: 8\n");
5136 /* there was a test running */
5137 if (s->result > 0) { /* good server detected */
5138 //fprintf(stderr, "process_chk: 9\n");
5139 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005140 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005141 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005142 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005143 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005144 }
willy tarreauef900ab2005-12-17 12:52:52 +01005145
willy tarreaue47c8d72005-12-17 12:55:52 +01005146 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005147 s->state |= SRV_RUNNING;
5148 }
willy tarreauef900ab2005-12-17 12:52:52 +01005149 s->curfd = -1; /* no check running anymore */
5150 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005151 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005152 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005153 }
5154 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5155 //fprintf(stderr, "process_chk: 10\n");
5156 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005157 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158 s->health--; /* still good */
5159 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005160 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005161
willy tarreaudd07e972005-12-18 00:48:48 +01005162 if (s->health == s->rise) {
5163 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005164 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005165
5166 if (find_server(s->proxy) == NULL) {
5167 Alert("Proxy %s has no server available !\n", s->proxy->id);
5168 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5169 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005170 }
willy tarreauef900ab2005-12-17 12:52:52 +01005171
willy tarreau5cbea6f2005-12-17 12:48:26 +01005172 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005173 }
5174 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005175 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005176 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005177 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005178 }
5179 /* if result is 0 and there's no timeout, we have to wait again */
5180 }
5181 //fprintf(stderr, "process_chk: 11\n");
5182 s->result = 0;
5183 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005184 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005185}
5186
5187
willy tarreau5cbea6f2005-12-17 12:48:26 +01005188
willy tarreau0f7af912005-12-17 12:21:26 +01005189#if STATTIME > 0
5190int stats(void);
5191#endif
5192
5193/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005194 * This does 4 things :
5195 * - wake up all expired tasks
5196 * - call all runnable tasks
5197 * - call maintain_proxies() to enable/disable the listeners
5198 * - return the delay till next event in ms, -1 = wait indefinitely
5199 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5200 *
willy tarreau0f7af912005-12-17 12:21:26 +01005201 */
5202
willy tarreau1c2ad212005-12-18 01:11:29 +01005203int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005204 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005205 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005206 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005207
willy tarreaub952e1d2005-12-18 01:31:20 +01005208 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005209
willy tarreau1c2ad212005-12-18 01:11:29 +01005210 /* look for expired tasks and add them to the run queue.
5211 */
5212 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5213 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5214 tnext = t->next;
5215 if (t->state & TASK_RUNNING)
5216 continue;
5217
willy tarreaub952e1d2005-12-18 01:31:20 +01005218 if (tv_iseternity(&t->expire))
5219 continue;
5220
willy tarreau1c2ad212005-12-18 01:11:29 +01005221 /* wakeup expired entries. It doesn't matter if they are
5222 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005223 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005224 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005225 task_wakeup(&rq, t);
5226 }
5227 else {
5228 /* first non-runnable task. Use its expiration date as an upper bound */
5229 int temp_time = tv_remain(&now, &t->expire);
5230 if (temp_time)
5231 next_time = temp_time;
5232 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005233 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005234 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235
willy tarreau1c2ad212005-12-18 01:11:29 +01005236 /* process each task in the run queue now. Each task may be deleted
5237 * since we only use tnext.
5238 */
5239 tnext = rq;
5240 while ((t = tnext) != NULL) {
5241 int temp_time;
5242
5243 tnext = t->rqnext;
5244 task_sleep(&rq, t);
5245 temp_time = t->process(t);
5246 next_time = MINTIME(temp_time, next_time);
5247 }
5248
5249 /* maintain all proxies in a consistent state. This should quickly become a task */
5250 time2 = maintain_proxies();
5251 return MINTIME(time2, next_time);
5252}
5253
5254
5255#if defined(ENABLE_EPOLL)
5256
5257/*
5258 * Main epoll() loop.
5259 */
5260
5261/* does 3 actions :
5262 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5263 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5264 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5265 *
5266 * returns 0 if initialization failed, !0 otherwise.
5267 */
5268
5269int epoll_loop(int action) {
5270 int next_time;
5271 int status;
5272 int fd;
5273
5274 int fds, count;
5275 int pr, pw, sr, sw;
5276 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5277 struct epoll_event ev;
5278
5279 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005280 static struct epoll_event *epoll_events = NULL;
5281 static int epoll_fd;
5282
5283 if (action == POLL_LOOP_ACTION_INIT) {
5284 epoll_fd = epoll_create(global.maxsock + 1);
5285 if (epoll_fd < 0)
5286 return 0;
5287 else {
5288 epoll_events = (struct epoll_event*)
5289 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5290 PrevReadEvent = (fd_set *)
5291 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5292 PrevWriteEvent = (fd_set *)
5293 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005294 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005295 return 1;
5296 }
5297 else if (action == POLL_LOOP_ACTION_CLEAN) {
5298 if (PrevWriteEvent) free(PrevWriteEvent);
5299 if (PrevReadEvent) free(PrevReadEvent);
5300 if (epoll_events) free(epoll_events);
5301 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005302 epoll_fd = 0;
5303 return 1;
5304 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005305
willy tarreau1c2ad212005-12-18 01:11:29 +01005306 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005307
willy tarreau1c2ad212005-12-18 01:11:29 +01005308 tv_now(&now);
5309
5310 while (1) {
5311 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312
5313 /* stop when there's no connection left and we don't allow them anymore */
5314 if (!actconn && listeners == 0)
5315 break;
5316
willy tarreau0f7af912005-12-17 12:21:26 +01005317#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005318 {
5319 int time2;
5320 time2 = stats();
5321 next_time = MINTIME(time2, next_time);
5322 }
willy tarreau0f7af912005-12-17 12:21:26 +01005323#endif
5324
willy tarreau1c2ad212005-12-18 01:11:29 +01005325 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5326
5327 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5328 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5329
5330 if ((ro^rn) | (wo^wn)) {
5331 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5332#define FDSETS_ARE_INT_ALIGNED
5333#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005334
willy tarreauad90a0c2005-12-18 01:09:15 +01005335#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5336#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005337 pr = (ro >> count) & 1;
5338 pw = (wo >> count) & 1;
5339 sr = (rn >> count) & 1;
5340 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005341#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005342 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5343 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5344 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5345 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005346#endif
5347#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005348 pr = FD_ISSET(fd, PrevReadEvent);
5349 pw = FD_ISSET(fd, PrevWriteEvent);
5350 sr = FD_ISSET(fd, StaticReadEvent);
5351 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005352#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005353 if (!((sr^pr) | (sw^pw)))
5354 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005355
willy tarreau1c2ad212005-12-18 01:11:29 +01005356 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5357 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005358
willy tarreaub952e1d2005-12-18 01:31:20 +01005359#ifdef EPOLL_CTL_MOD_WORKAROUND
5360 /* I encountered a rarely reproducible problem with
5361 * EPOLL_CTL_MOD where a modified FD (systematically
5362 * the one in epoll_events[0], fd#7) would sometimes
5363 * be set EPOLL_OUT while asked for a read ! This is
5364 * with the 2.4 epoll patch. The workaround is to
5365 * delete then recreate in case of modification.
5366 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5367 * nor RHEL kernels.
5368 */
5369
5370 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5371 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5372
5373 if ((sr | sw))
5374 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5375#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005376 if ((pr | pw)) {
5377 /* the file-descriptor already exists... */
5378 if ((sr | sw)) {
5379 /* ...and it will still exist */
5380 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5381 // perror("epoll_ctl(MOD)");
5382 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005383 }
5384 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005385 /* ...and it will be removed */
5386 if (fdtab[fd].state != FD_STCLOSE &&
5387 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5388 // perror("epoll_ctl(DEL)");
5389 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005390 }
5391 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005392 } else {
5393 /* the file-descriptor did not exist, let's add it */
5394 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5395 // perror("epoll_ctl(ADD)");
5396 // exit(1);
5397 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005398 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005399#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005400 }
5401 ((int*)PrevReadEvent)[fds] = rn;
5402 ((int*)PrevWriteEvent)[fds] = wn;
5403 }
5404 }
5405
5406 /* now let's wait for events */
5407 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5408 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005409
willy tarreau1c2ad212005-12-18 01:11:29 +01005410 for (count = 0; count < status; count++) {
5411 fd = epoll_events[count].data.fd;
5412
5413 if (fdtab[fd].state == FD_STCLOSE)
5414 continue;
5415
Willy TARREAUe78ae262006-01-08 01:24:12 +01005416 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) {
5417 if (FD_ISSET(fd, StaticReadEvent))
5418 fdtab[fd].read(fd);
5419 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005420
5421 if (fdtab[fd].state == FD_STCLOSE)
5422 continue;
5423
Willy TARREAUe78ae262006-01-08 01:24:12 +01005424 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) {
5425 if (FD_ISSET(fd, StaticWriteEvent))
5426 fdtab[fd].write(fd);
5427 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005428 }
5429 }
5430 return 1;
5431}
5432#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005433
willy tarreauad90a0c2005-12-18 01:09:15 +01005434
willy tarreau5cbea6f2005-12-17 12:48:26 +01005435
willy tarreau1c2ad212005-12-18 01:11:29 +01005436#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005437
willy tarreau1c2ad212005-12-18 01:11:29 +01005438/*
5439 * Main poll() loop.
5440 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005441
willy tarreau1c2ad212005-12-18 01:11:29 +01005442/* does 3 actions :
5443 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5444 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5445 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5446 *
5447 * returns 0 if initialization failed, !0 otherwise.
5448 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005449
willy tarreau1c2ad212005-12-18 01:11:29 +01005450int poll_loop(int action) {
5451 int next_time;
5452 int status;
5453 int fd, nbfd;
5454
5455 int fds, count;
5456 int sr, sw;
5457 unsigned rn, wn; /* read new, write new */
5458
5459 /* private data */
5460 static struct pollfd *poll_events = NULL;
5461
5462 if (action == POLL_LOOP_ACTION_INIT) {
5463 poll_events = (struct pollfd*)
5464 calloc(1, sizeof(struct pollfd) * global.maxsock);
5465 return 1;
5466 }
5467 else if (action == POLL_LOOP_ACTION_CLEAN) {
5468 if (poll_events)
5469 free(poll_events);
5470 return 1;
5471 }
5472
5473 /* OK, it's POLL_LOOP_ACTION_RUN */
5474
5475 tv_now(&now);
5476
5477 while (1) {
5478 next_time = process_runnable_tasks();
5479
5480 /* stop when there's no connection left and we don't allow them anymore */
5481 if (!actconn && listeners == 0)
5482 break;
5483
5484#if STATTIME > 0
5485 {
5486 int time2;
5487 time2 = stats();
5488 next_time = MINTIME(time2, next_time);
5489 }
5490#endif
5491
5492
5493 nbfd = 0;
5494 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5495
5496 rn = ((int*)StaticReadEvent)[fds];
5497 wn = ((int*)StaticWriteEvent)[fds];
5498
5499 if ((rn|wn)) {
5500 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5501#define FDSETS_ARE_INT_ALIGNED
5502#ifdef FDSETS_ARE_INT_ALIGNED
5503
5504#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5505#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5506 sr = (rn >> count) & 1;
5507 sw = (wn >> count) & 1;
5508#else
5509 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5510 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5511#endif
5512#else
5513 sr = FD_ISSET(fd, StaticReadEvent);
5514 sw = FD_ISSET(fd, StaticWriteEvent);
5515#endif
5516 if ((sr|sw)) {
5517 poll_events[nbfd].fd = fd;
5518 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5519 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005520 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005521 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005522 }
5523 }
5524
5525 /* now let's wait for events */
5526 status = poll(poll_events, nbfd, next_time);
5527 tv_now(&now);
5528
5529 for (count = 0; status > 0 && count < nbfd; count++) {
5530 fd = poll_events[count].fd;
5531
5532 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5533 continue;
5534
5535 /* ok, we found one active fd */
5536 status--;
5537
5538 if (fdtab[fd].state == FD_STCLOSE)
5539 continue;
5540
Willy TARREAUe78ae262006-01-08 01:24:12 +01005541 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) {
5542 if (FD_ISSET(fd, StaticReadEvent))
5543 fdtab[fd].read(fd);
5544 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005545
5546 if (fdtab[fd].state == FD_STCLOSE)
5547 continue;
5548
Willy TARREAUe78ae262006-01-08 01:24:12 +01005549 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) {
5550 if (FD_ISSET(fd, StaticWriteEvent))
5551 fdtab[fd].write(fd);
5552 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005553 }
5554 }
5555 return 1;
5556}
willy tarreauad90a0c2005-12-18 01:09:15 +01005557#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005558
willy tarreauad90a0c2005-12-18 01:09:15 +01005559
willy tarreauad90a0c2005-12-18 01:09:15 +01005560
willy tarreau1c2ad212005-12-18 01:11:29 +01005561/*
5562 * Main select() loop.
5563 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005564
willy tarreau1c2ad212005-12-18 01:11:29 +01005565/* does 3 actions :
5566 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5567 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5568 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5569 *
5570 * returns 0 if initialization failed, !0 otherwise.
5571 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005572
willy tarreauad90a0c2005-12-18 01:09:15 +01005573
willy tarreau1c2ad212005-12-18 01:11:29 +01005574int select_loop(int action) {
5575 int next_time;
5576 int status;
5577 int fd,i;
5578 struct timeval delta;
5579 int readnotnull, writenotnull;
5580 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005581
willy tarreau1c2ad212005-12-18 01:11:29 +01005582 if (action == POLL_LOOP_ACTION_INIT) {
5583 ReadEvent = (fd_set *)
5584 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5585 WriteEvent = (fd_set *)
5586 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5587 return 1;
5588 }
5589 else if (action == POLL_LOOP_ACTION_CLEAN) {
5590 if (WriteEvent) free(WriteEvent);
5591 if (ReadEvent) free(ReadEvent);
5592 return 1;
5593 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005594
willy tarreau1c2ad212005-12-18 01:11:29 +01005595 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005596
willy tarreau1c2ad212005-12-18 01:11:29 +01005597 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005598
willy tarreau1c2ad212005-12-18 01:11:29 +01005599 while (1) {
5600 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005601
willy tarreau1c2ad212005-12-18 01:11:29 +01005602 /* stop when there's no connection left and we don't allow them anymore */
5603 if (!actconn && listeners == 0)
5604 break;
5605
5606#if STATTIME > 0
5607 {
5608 int time2;
5609 time2 = stats();
5610 next_time = MINTIME(time2, next_time);
5611 }
5612#endif
5613
willy tarreau1c2ad212005-12-18 01:11:29 +01005614 if (next_time > 0) { /* FIXME */
5615 /* Convert to timeval */
5616 /* to avoid eventual select loops due to timer precision */
5617 next_time += SCHEDULER_RESOLUTION;
5618 delta.tv_sec = next_time / 1000;
5619 delta.tv_usec = (next_time % 1000) * 1000;
5620 }
5621 else if (next_time == 0) { /* allow select to return immediately when needed */
5622 delta.tv_sec = delta.tv_usec = 0;
5623 }
5624
5625
5626 /* let's restore fdset state */
5627
5628 readnotnull = 0; writenotnull = 0;
5629 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5630 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5631 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5632 }
5633
5634 // /* just a verification code, needs to be removed for performance */
5635 // for (i=0; i<maxfd; i++) {
5636 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5637 // abort();
5638 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5639 // abort();
5640 //
5641 // }
5642
5643 status = select(maxfd,
5644 readnotnull ? ReadEvent : NULL,
5645 writenotnull ? WriteEvent : NULL,
5646 NULL,
5647 (next_time >= 0) ? &delta : NULL);
5648
5649 /* this is an experiment on the separation of the select work */
5650 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5651 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5652
5653 tv_now(&now);
5654
5655 if (status > 0) { /* must proceed with events */
5656
5657 int fds;
5658 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005659
willy tarreau1c2ad212005-12-18 01:11:29 +01005660 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5661 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5662 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5663
5664 /* if we specify read first, the accepts and zero reads will be
5665 * seen first. Moreover, system buffers will be flushed faster.
5666 */
5667 if (fdtab[fd].state == FD_STCLOSE)
5668 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005669
willy tarreau1c2ad212005-12-18 01:11:29 +01005670 if (FD_ISSET(fd, ReadEvent))
5671 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005672
willy tarreau1c2ad212005-12-18 01:11:29 +01005673 if (FD_ISSET(fd, WriteEvent))
5674 fdtab[fd].write(fd);
5675 }
5676 }
5677 else {
5678 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005679 }
willy tarreau0f7af912005-12-17 12:21:26 +01005680 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005681 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005682}
5683
5684
5685#if STATTIME > 0
5686/*
5687 * Display proxy statistics regularly. It is designed to be called from the
5688 * select_loop().
5689 */
5690int stats(void) {
5691 static int lines;
5692 static struct timeval nextevt;
5693 static struct timeval lastevt;
5694 static struct timeval starttime = {0,0};
5695 unsigned long totaltime, deltatime;
5696 int ret;
5697
willy tarreau750a4722005-12-17 13:21:24 +01005698 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005699 deltatime = (tv_diff(&lastevt, &now)?:1);
5700 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005701
willy tarreau9fe663a2005-12-17 13:02:59 +01005702 if (global.mode & MODE_STATS) {
5703 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005704 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005705 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5706 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005707 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005708 actconn, totalconn,
5709 stats_tsk_new, stats_tsk_good,
5710 stats_tsk_left, stats_tsk_right,
5711 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5712 }
5713 }
5714
5715 tv_delayfrom(&nextevt, &now, STATTIME);
5716
5717 lastevt=now;
5718 }
5719 ret = tv_remain(&now, &nextevt);
5720 return ret;
5721}
5722#endif
5723
5724
5725/*
5726 * this function enables proxies when there are enough free sessions,
5727 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005728 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005729 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005730 */
5731static int maintain_proxies(void) {
5732 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005733 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005734 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005735
5736 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005737 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005738
5739 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005740 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005741 while (p) {
5742 if (p->nbconn < p->maxconn) {
5743 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005744 for (l = p->listen; l != NULL; l = l->next) {
5745 FD_SET(l->fd, StaticReadEvent);
5746 }
willy tarreau0f7af912005-12-17 12:21:26 +01005747 p->state = PR_STRUN;
5748 }
5749 }
5750 else {
5751 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005752 for (l = p->listen; l != NULL; l = l->next) {
5753 FD_CLR(l->fd, StaticReadEvent);
5754 }
willy tarreau0f7af912005-12-17 12:21:26 +01005755 p->state = PR_STIDLE;
5756 }
5757 }
5758 p = p->next;
5759 }
5760 }
5761 else { /* block all proxies */
5762 while (p) {
5763 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005764 for (l = p->listen; l != NULL; l = l->next) {
5765 FD_CLR(l->fd, StaticReadEvent);
5766 }
willy tarreau0f7af912005-12-17 12:21:26 +01005767 p->state = PR_STIDLE;
5768 }
5769 p = p->next;
5770 }
5771 }
5772
willy tarreau5cbea6f2005-12-17 12:48:26 +01005773 if (stopping) {
5774 p = proxy;
5775 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005776 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005777 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005778 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005779 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005780 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005781 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005782
willy tarreaua41a8b42005-12-17 14:02:24 +01005783 for (l = p->listen; l != NULL; l = l->next) {
5784 fd_delete(l->fd);
5785 listeners--;
5786 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005787 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005788 }
5789 else {
5790 tleft = MINTIME(t, tleft);
5791 }
5792 }
5793 p = p->next;
5794 }
5795 }
5796 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005797}
5798
5799/*
5800 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005801 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5802 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005803 */
5804static void soft_stop(void) {
5805 struct proxy *p;
5806
5807 stopping = 1;
5808 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005809 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005810 while (p) {
willy tarreau808b4e62006-01-20 19:46:44 +01005811 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005812 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005813 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005814 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005815 }
willy tarreau0f7af912005-12-17 12:21:26 +01005816 p = p->next;
5817 }
5818}
5819
willy tarreaudbd3bef2006-01-20 19:35:18 +01005820static void pause_proxy(struct proxy *p) {
5821 struct listener *l;
5822 for (l = p->listen; l != NULL; l = l->next) {
5823 shutdown(l->fd, SHUT_RD);
5824 FD_CLR(l->fd, StaticReadEvent);
5825 p->state = PR_STPAUSED;
5826 }
5827}
5828
5829/*
5830 * This function temporarily disables listening so that another new instance
5831 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005832 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005833 * the proxy, or a SIGTTIN can be sent to listen again.
5834 */
5835static void pause_proxies(void) {
5836 struct proxy *p;
5837
5838 p = proxy;
5839 tv_now(&now); /* else, the old time before select will be used */
5840 while (p) {
5841 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5842 Warning("Pausing proxy %s.\n", p->id);
5843 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5844 pause_proxy(p);
5845 }
5846 p = p->next;
5847 }
5848}
5849
5850
5851/*
5852 * This function reactivates listening. This can be used after a call to
5853 * sig_pause(), for example when a new instance has failed starting up.
5854 * It is designed to be called upon reception of a SIGTTIN.
5855 */
5856static void listen_proxies(void) {
5857 struct proxy *p;
5858 struct listener *l;
5859
5860 p = proxy;
5861 tv_now(&now); /* else, the old time before select will be used */
5862 while (p) {
5863 if (p->state == PR_STPAUSED) {
5864 Warning("Enabling proxy %s.\n", p->id);
5865 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5866
5867 for (l = p->listen; l != NULL; l = l->next) {
5868 if (listen(l->fd, p->maxconn) == 0) {
5869 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5870 FD_SET(l->fd, StaticReadEvent);
5871 p->state = PR_STRUN;
5872 }
5873 else
5874 p->state = PR_STIDLE;
5875 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005876 int port;
5877
5878 if (l->addr.ss_family == AF_INET6)
5879 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5880 else
5881 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5882
willy tarreaudbd3bef2006-01-20 19:35:18 +01005883 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005884 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005885 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005886 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005887 /* Another port might have been enabled. Let's stop everything. */
5888 pause_proxy(p);
5889 break;
5890 }
5891 }
5892 }
5893 p = p->next;
5894 }
5895}
5896
5897
willy tarreau0f7af912005-12-17 12:21:26 +01005898/*
5899 * upon SIGUSR1, let's have a soft stop.
5900 */
5901void sig_soft_stop(int sig) {
5902 soft_stop();
5903 signal(sig, SIG_IGN);
5904}
5905
willy tarreaudbd3bef2006-01-20 19:35:18 +01005906/*
5907 * upon SIGTTOU, we pause everything
5908 */
5909void sig_pause(int sig) {
5910 pause_proxies();
5911 signal(sig, sig_pause);
5912}
willy tarreau0f7af912005-12-17 12:21:26 +01005913
willy tarreau8337c6b2005-12-17 13:41:01 +01005914/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005915 * upon SIGTTIN, let's have a soft stop.
5916 */
5917void sig_listen(int sig) {
5918 listen_proxies();
5919 signal(sig, sig_listen);
5920}
5921
5922/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005923 * this function dumps every server's state when the process receives SIGHUP.
5924 */
5925void sig_dump_state(int sig) {
5926 struct proxy *p = proxy;
5927
5928 Warning("SIGHUP received, dumping servers states.\n");
5929 while (p) {
5930 struct server *s = p->srv;
5931
5932 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5933 while (s) {
5934 if (s->state & SRV_RUNNING) {
5935 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5936 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5937 }
5938 else {
5939 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5940 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5941 }
5942 s = s->next;
5943 }
willy tarreaudd07e972005-12-18 00:48:48 +01005944
5945 if (find_server(p) == NULL) {
5946 Warning("SIGHUP: proxy %s has no server available !\n", p);
5947 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5948 }
5949
willy tarreau8337c6b2005-12-17 13:41:01 +01005950 p = p->next;
5951 }
5952 signal(sig, sig_dump_state);
5953}
5954
willy tarreau0f7af912005-12-17 12:21:26 +01005955void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005956 struct task *t, *tnext;
5957 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005958
willy tarreau5cbea6f2005-12-17 12:48:26 +01005959 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5960 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5961 tnext = t->next;
5962 s = t->context;
5963 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5964 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5965 "req=%d, rep=%d, clifd=%d\n",
5966 s, tv_remain(&now, &t->expire),
5967 s->cli_state,
5968 s->srv_state,
5969 FD_ISSET(s->cli_fd, StaticReadEvent),
5970 FD_ISSET(s->cli_fd, StaticWriteEvent),
5971 FD_ISSET(s->srv_fd, StaticReadEvent),
5972 FD_ISSET(s->srv_fd, StaticWriteEvent),
5973 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5974 );
willy tarreau0f7af912005-12-17 12:21:26 +01005975 }
willy tarreau12350152005-12-18 01:03:27 +01005976}
5977
willy tarreau64a3cc32005-12-18 01:13:11 +01005978#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005979static void fast_stop(void)
5980{
5981 struct proxy *p;
5982 p = proxy;
5983 while (p) {
5984 p->grace = 0;
5985 p = p->next;
5986 }
5987 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005988}
5989
willy tarreau12350152005-12-18 01:03:27 +01005990void sig_int(int sig) {
5991 /* This would normally be a hard stop,
5992 but we want to be sure about deallocation,
5993 and so on, so we do a soft stop with
5994 0 GRACE time
5995 */
5996 fast_stop();
5997 /* If we are killed twice, we decide to die*/
5998 signal(sig, SIG_DFL);
5999}
6000
6001void sig_term(int sig) {
6002 /* This would normally be a hard stop,
6003 but we want to be sure about deallocation,
6004 and so on, so we do a soft stop with
6005 0 GRACE time
6006 */
6007 fast_stop();
6008 /* If we are killed twice, we decide to die*/
6009 signal(sig, SIG_DFL);
6010}
willy tarreau64a3cc32005-12-18 01:13:11 +01006011#endif
willy tarreau12350152005-12-18 01:03:27 +01006012
willy tarreauc1f47532005-12-18 01:08:26 +01006013/* returns the pointer to an error in the replacement string, or NULL if OK */
6014char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01006015 struct hdr_exp *exp;
6016
willy tarreauc1f47532005-12-18 01:08:26 +01006017 if (replace != NULL) {
6018 char *err;
6019 err = check_replace_string(replace);
6020 if (err)
6021 return err;
6022 }
6023
willy tarreaue39cd132005-12-17 13:00:18 +01006024 while (*head != NULL)
6025 head = &(*head)->next;
6026
6027 exp = calloc(1, sizeof(struct hdr_exp));
6028
6029 exp->preg = preg;
6030 exp->replace = replace;
6031 exp->action = action;
6032 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01006033
6034 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006035}
6036
willy tarreau9fe663a2005-12-17 13:02:59 +01006037
willy tarreau0f7af912005-12-17 12:21:26 +01006038/*
willy tarreau9fe663a2005-12-17 13:02:59 +01006039 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01006040 */
willy tarreau9fe663a2005-12-17 13:02:59 +01006041int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01006042
willy tarreau9fe663a2005-12-17 13:02:59 +01006043 if (!strcmp(args[0], "global")) { /* new section */
6044 /* no option, nothing special to do */
6045 return 0;
6046 }
6047 else if (!strcmp(args[0], "daemon")) {
6048 global.mode |= MODE_DAEMON;
6049 }
6050 else if (!strcmp(args[0], "debug")) {
6051 global.mode |= MODE_DEBUG;
6052 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006053 else if (!strcmp(args[0], "noepoll")) {
6054 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6055 }
6056 else if (!strcmp(args[0], "nopoll")) {
6057 cfg_polling_mechanism &= ~POLL_USE_POLL;
6058 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006059 else if (!strcmp(args[0], "quiet")) {
6060 global.mode |= MODE_QUIET;
6061 }
6062 else if (!strcmp(args[0], "stats")) {
6063 global.mode |= MODE_STATS;
6064 }
6065 else if (!strcmp(args[0], "uid")) {
6066 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006067 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006068 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006069 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006070 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006071 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006072 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006074 global.uid = atol(args[1]);
6075 }
6076 else if (!strcmp(args[0], "gid")) {
6077 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006078 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006079 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006080 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006081 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006082 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006083 return -1;
6084 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006085 global.gid = atol(args[1]);
6086 }
6087 else if (!strcmp(args[0], "nbproc")) {
6088 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006089 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006090 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006091 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006092 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006093 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006094 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006095 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006096 global.nbproc = atol(args[1]);
6097 }
6098 else if (!strcmp(args[0], "maxconn")) {
6099 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006100 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006101 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006102 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006103 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006104 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006105 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006107 global.maxconn = atol(args[1]);
6108 }
willy tarreaub1285d52005-12-18 01:20:14 +01006109 else if (!strcmp(args[0], "ulimit-n")) {
6110 if (global.rlimit_nofile != 0) {
6111 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6112 return 0;
6113 }
6114 if (*(args[1]) == 0) {
6115 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6116 return -1;
6117 }
6118 global.rlimit_nofile = atol(args[1]);
6119 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006120 else if (!strcmp(args[0], "chroot")) {
6121 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006122 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006123 return 0;
6124 }
6125 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006126 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 return -1;
6128 }
6129 global.chroot = strdup(args[1]);
6130 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006131 else if (!strcmp(args[0], "pidfile")) {
6132 if (global.pidfile != NULL) {
6133 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6134 return 0;
6135 }
6136 if (*(args[1]) == 0) {
6137 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6138 return -1;
6139 }
6140 global.pidfile = strdup(args[1]);
6141 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006142 else if (!strcmp(args[0], "log")) { /* syslog server address */
6143 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006144 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006145
6146 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006147 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006148 return -1;
6149 }
6150
6151 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6152 if (!strcmp(log_facilities[facility], args[2]))
6153 break;
6154
6155 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006156 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006157 exit(1);
6158 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006159
6160 level = 7; /* max syslog level = debug */
6161 if (*(args[3])) {
6162 while (level >= 0 && strcmp(log_levels[level], args[3]))
6163 level--;
6164 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006165 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006166 exit(1);
6167 }
6168 }
6169
willy tarreau9fe663a2005-12-17 13:02:59 +01006170 sa = str2sa(args[1]);
6171 if (!sa->sin_port)
6172 sa->sin_port = htons(SYSLOG_PORT);
6173
6174 if (global.logfac1 == -1) {
6175 global.logsrv1 = *sa;
6176 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006177 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006178 }
6179 else if (global.logfac2 == -1) {
6180 global.logsrv2 = *sa;
6181 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006182 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006183 }
6184 else {
6185 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6186 return -1;
6187 }
6188
6189 }
6190 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006191 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006192 return -1;
6193 }
6194 return 0;
6195}
6196
6197
willy tarreaua41a8b42005-12-17 14:02:24 +01006198void init_default_instance() {
6199 memset(&defproxy, 0, sizeof(defproxy));
6200 defproxy.mode = PR_MODE_TCP;
6201 defproxy.state = PR_STNEW;
6202 defproxy.maxconn = cfg_maxpconn;
6203 defproxy.conn_retries = CONN_RETRIES;
6204 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6205}
6206
willy tarreau9fe663a2005-12-17 13:02:59 +01006207/*
6208 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6209 */
6210int cfg_parse_listen(char *file, int linenum, char **args) {
6211 static struct proxy *curproxy = NULL;
6212 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006213 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006214 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006215
6216 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006217 if (!*args[1]) {
6218 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6219 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006220 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006221 return -1;
6222 }
6223
6224 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006225 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006226 return -1;
6227 }
6228 curproxy->next = proxy;
6229 proxy = curproxy;
6230 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006231
6232 /* parse the listener address if any */
6233 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006234 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006235 if (!curproxy->listen)
6236 return -1;
6237 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006238
willy tarreau9fe663a2005-12-17 13:02:59 +01006239 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006240 curproxy->state = defproxy.state;
6241 curproxy->maxconn = defproxy.maxconn;
6242 curproxy->conn_retries = defproxy.conn_retries;
6243 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006244
6245 if (defproxy.check_req)
6246 curproxy->check_req = strdup(defproxy.check_req);
6247 curproxy->check_len = defproxy.check_len;
6248
6249 if (defproxy.cookie_name)
6250 curproxy->cookie_name = strdup(defproxy.cookie_name);
6251 curproxy->cookie_len = defproxy.cookie_len;
6252
6253 if (defproxy.capture_name)
6254 curproxy->capture_name = strdup(defproxy.capture_name);
6255 curproxy->capture_namelen = defproxy.capture_namelen;
6256 curproxy->capture_len = defproxy.capture_len;
6257
6258 if (defproxy.errmsg.msg400)
6259 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6260 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6261
6262 if (defproxy.errmsg.msg403)
6263 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6264 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6265
6266 if (defproxy.errmsg.msg408)
6267 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6268 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6269
6270 if (defproxy.errmsg.msg500)
6271 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6272 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6273
6274 if (defproxy.errmsg.msg502)
6275 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6276 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6277
6278 if (defproxy.errmsg.msg503)
6279 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6280 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6281
6282 if (defproxy.errmsg.msg504)
6283 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6284 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6285
willy tarreaua41a8b42005-12-17 14:02:24 +01006286 curproxy->clitimeout = defproxy.clitimeout;
6287 curproxy->contimeout = defproxy.contimeout;
6288 curproxy->srvtimeout = defproxy.srvtimeout;
6289 curproxy->mode = defproxy.mode;
6290 curproxy->logfac1 = defproxy.logfac1;
6291 curproxy->logsrv1 = defproxy.logsrv1;
6292 curproxy->loglev1 = defproxy.loglev1;
6293 curproxy->logfac2 = defproxy.logfac2;
6294 curproxy->logsrv2 = defproxy.logsrv2;
6295 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006296 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006297 curproxy->grace = defproxy.grace;
6298 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006299 curproxy->mon_net = defproxy.mon_net;
6300 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006301 return 0;
6302 }
6303 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006304 /* some variables may have already been initialized earlier */
6305 if (defproxy.check_req) free(defproxy.check_req);
6306 if (defproxy.cookie_name) free(defproxy.cookie_name);
6307 if (defproxy.capture_name) free(defproxy.capture_name);
6308 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6309 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6310 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6311 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6312 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6313 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6314 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6315
6316 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006317 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006318 return 0;
6319 }
6320 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006321 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006322 return -1;
6323 }
6324
willy tarreaua41a8b42005-12-17 14:02:24 +01006325 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6326 if (curproxy == &defproxy) {
6327 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6328 return -1;
6329 }
6330
6331 if (strchr(args[1], ':') == NULL) {
6332 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6333 file, linenum, args[0]);
6334 return -1;
6335 }
6336 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006337 if (!curproxy->listen)
6338 return -1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006339 return 0;
6340 }
willy tarreaub1285d52005-12-18 01:20:14 +01006341 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6342 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6343 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6344 file, linenum, args[0]);
6345 return -1;
6346 }
6347 /* flush useless bits */
6348 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6349 return 0;
6350 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006351 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006352 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6353 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6354 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6355 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006356 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 return -1;
6358 }
6359 }
6360 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006361 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006362 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006363 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6364 curproxy->state = PR_STNEW;
6365 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006366 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6367 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006368// if (curproxy == &defproxy) {
6369// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6370// return -1;
6371// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006372
willy tarreau9fe663a2005-12-17 13:02:59 +01006373 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006374// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6375// file, linenum);
6376// return 0;
6377 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 }
6379
6380 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006381 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6382 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 return -1;
6384 }
6385 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006386 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006387
6388 cur_arg = 2;
6389 while (*(args[cur_arg])) {
6390 if (!strcmp(args[cur_arg], "rewrite")) {
6391 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006392 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006393 else if (!strcmp(args[cur_arg], "indirect")) {
6394 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006395 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006396 else if (!strcmp(args[cur_arg], "insert")) {
6397 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006398 }
willy tarreau240afa62005-12-17 13:14:35 +01006399 else if (!strcmp(args[cur_arg], "nocache")) {
6400 curproxy->options |= PR_O_COOK_NOC;
6401 }
willy tarreaucd878942005-12-17 13:27:43 +01006402 else if (!strcmp(args[cur_arg], "postonly")) {
6403 curproxy->options |= PR_O_COOK_POST;
6404 }
willy tarreau0174f312005-12-18 01:02:42 +01006405 else if (!strcmp(args[cur_arg], "prefix")) {
6406 curproxy->options |= PR_O_COOK_PFX;
6407 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 else {
willy tarreau0174f312005-12-18 01:02:42 +01006409 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006410 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006411 return -1;
6412 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006413 cur_arg++;
6414 }
willy tarreau0174f312005-12-18 01:02:42 +01006415 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6416 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6417 file, linenum);
6418 return -1;
6419 }
6420
6421 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6422 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006423 file, linenum);
6424 return -1;
6425 }
willy tarreau12350152005-12-18 01:03:27 +01006426 }/* end else if (!strcmp(args[0], "cookie")) */
6427 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6428// if (curproxy == &defproxy) {
6429// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6430// return -1;
6431// }
6432
6433 if (curproxy->appsession_name != NULL) {
6434// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6435// file, linenum);
6436// return 0;
6437 free(curproxy->appsession_name);
6438 }
6439
6440 if (*(args[5]) == 0) {
6441 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6442 file, linenum, args[0]);
6443 return -1;
6444 }
6445 have_appsession = 1;
6446 curproxy->appsession_name = strdup(args[1]);
6447 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6448 curproxy->appsession_len = atoi(args[3]);
6449 curproxy->appsession_timeout = atoi(args[5]);
6450 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6451 if (rc) {
6452 Alert("Error Init Appsession Hashtable.\n");
6453 return -1;
6454 }
6455 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006456 else if (!strcmp(args[0], "capture")) {
6457 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6458 // if (curproxy == &defproxy) {
6459 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6460 // return -1;
6461 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006462
willy tarreau4302f492005-12-18 01:00:37 +01006463 if (curproxy->capture_name != NULL) {
6464 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6465 // file, linenum, args[0]);
6466 // return 0;
6467 free(curproxy->capture_name);
6468 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006469
willy tarreau4302f492005-12-18 01:00:37 +01006470 if (*(args[4]) == 0) {
6471 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6472 file, linenum, args[0]);
6473 return -1;
6474 }
6475 curproxy->capture_name = strdup(args[2]);
6476 curproxy->capture_namelen = strlen(curproxy->capture_name);
6477 curproxy->capture_len = atol(args[4]);
6478 if (curproxy->capture_len >= CAPTURE_LEN) {
6479 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6480 file, linenum, CAPTURE_LEN - 1);
6481 curproxy->capture_len = CAPTURE_LEN - 1;
6482 }
6483 curproxy->to_log |= LW_COOKIE;
6484 }
6485 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6486 struct cap_hdr *hdr;
6487
6488 if (curproxy == &defproxy) {
6489 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6490 return -1;
6491 }
6492
6493 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6494 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6495 file, linenum, args[0], args[1]);
6496 return -1;
6497 }
6498
6499 hdr = calloc(sizeof(struct cap_hdr), 1);
6500 hdr->next = curproxy->req_cap;
6501 hdr->name = strdup(args[3]);
6502 hdr->namelen = strlen(args[3]);
6503 hdr->len = atol(args[5]);
6504 hdr->index = curproxy->nb_req_cap++;
6505 curproxy->req_cap = hdr;
6506 curproxy->to_log |= LW_REQHDR;
6507 }
6508 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6509 struct cap_hdr *hdr;
6510
6511 if (curproxy == &defproxy) {
6512 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6513 return -1;
6514 }
6515
6516 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6517 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6518 file, linenum, args[0], args[1]);
6519 return -1;
6520 }
6521 hdr = calloc(sizeof(struct cap_hdr), 1);
6522 hdr->next = curproxy->rsp_cap;
6523 hdr->name = strdup(args[3]);
6524 hdr->namelen = strlen(args[3]);
6525 hdr->len = atol(args[5]);
6526 hdr->index = curproxy->nb_rsp_cap++;
6527 curproxy->rsp_cap = hdr;
6528 curproxy->to_log |= LW_RSPHDR;
6529 }
6530 else {
6531 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006532 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006533 return -1;
6534 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006535 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006536 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006537 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006538 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006539 return 0;
6540 }
6541 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006542 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6543 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006544 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006545 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006546 curproxy->contimeout = atol(args[1]);
6547 }
6548 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006549 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006550 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6551 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006552 return 0;
6553 }
6554 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006555 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6556 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006557 return -1;
6558 }
6559 curproxy->clitimeout = atol(args[1]);
6560 }
6561 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006562 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006563 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006564 return 0;
6565 }
6566 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006567 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6568 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006569 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006570 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006571 curproxy->srvtimeout = atol(args[1]);
6572 }
6573 else if (!strcmp(args[0], "retries")) { /* connection retries */
6574 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006575 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6576 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006577 return -1;
6578 }
6579 curproxy->conn_retries = atol(args[1]);
6580 }
6581 else if (!strcmp(args[0], "option")) {
6582 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006583 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006584 return -1;
6585 }
6586 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006587 /* enable reconnections to dispatch */
6588 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006589#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006590 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006591 /* enable transparent proxy connections */
6592 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006593#endif
6594 else if (!strcmp(args[1], "keepalive"))
6595 /* enable keep-alive */
6596 curproxy->options |= PR_O_KEEPALIVE;
6597 else if (!strcmp(args[1], "forwardfor"))
6598 /* insert x-forwarded-for field */
6599 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006600 else if (!strcmp(args[1], "logasap"))
6601 /* log as soon as possible, without waiting for the session to complete */
6602 curproxy->options |= PR_O_LOGASAP;
6603 else if (!strcmp(args[1], "httpclose"))
6604 /* force connection: close in both directions in HTTP mode */
6605 curproxy->options |= PR_O_HTTP_CLOSE;
Willy TARREAU767ba712006-03-01 22:40:50 +01006606 else if (!strcmp(args[1], "forceclose"))
6607 /* force connection: close in both directions in HTTP mode and enforce end of session */
6608 curproxy->options |= PR_O_FORCE_CLO | PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006609 else if (!strcmp(args[1], "checkcache"))
6610 /* require examination of cacheability of the 'set-cookie' field */
6611 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006612 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006613 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006614 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006615 else if (!strcmp(args[1], "tcplog"))
6616 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006617 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006618 else if (!strcmp(args[1], "dontlognull")) {
6619 /* don't log empty requests */
6620 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006621 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006622 else if (!strcmp(args[1], "tcpka")) {
6623 /* enable TCP keep-alives on client and server sessions */
6624 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6625 }
6626 else if (!strcmp(args[1], "clitcpka")) {
6627 /* enable TCP keep-alives on client sessions */
6628 curproxy->options |= PR_O_TCP_CLI_KA;
6629 }
6630 else if (!strcmp(args[1], "srvtcpka")) {
6631 /* enable TCP keep-alives on server sessions */
6632 curproxy->options |= PR_O_TCP_SRV_KA;
6633 }
Willy TARREAU3481c462006-03-01 22:37:57 +01006634 else if (!strcmp(args[1], "allbackups")) {
6635 /* Use all backup servers simultaneously */
6636 curproxy->options |= PR_O_USE_ALL_BK;
6637 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006638 else if (!strcmp(args[1], "httpchk")) {
6639 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006640 if (curproxy->check_req != NULL) {
6641 free(curproxy->check_req);
6642 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006643 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006644 if (!*args[2]) { /* no argument */
6645 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6646 curproxy->check_len = strlen(DEF_CHECK_REQ);
6647 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006648 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6649 curproxy->check_req = (char *)malloc(reqlen);
6650 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6651 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006652 } else { /* more arguments : METHOD URI [HTTP_VER] */
6653 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6654 if (*args[4])
6655 reqlen += strlen(args[4]);
6656 else
6657 reqlen += strlen("HTTP/1.0");
6658
6659 curproxy->check_req = (char *)malloc(reqlen);
6660 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6661 "%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 +01006662 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006663 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006664 else if (!strcmp(args[1], "persist")) {
6665 /* persist on using the server specified by the cookie, even when it's down */
6666 curproxy->options |= PR_O_PERSIST;
6667 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006668 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006669 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006670 return -1;
6671 }
6672 return 0;
6673 }
6674 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6675 /* enable reconnections to dispatch */
6676 curproxy->options |= PR_O_REDISP;
6677 }
willy tarreaua1598082005-12-17 13:08:06 +01006678#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006679 else if (!strcmp(args[0], "transparent")) {
6680 /* enable transparent proxy connections */
6681 curproxy->options |= PR_O_TRANSP;
6682 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006683#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006684 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6685 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006686 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006687 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006688 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006689 curproxy->maxconn = atol(args[1]);
6690 }
6691 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6692 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006693 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006694 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006695 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006696 curproxy->grace = atol(args[1]);
6697 }
6698 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006699 if (curproxy == &defproxy) {
6700 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6701 return -1;
6702 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006703 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006704 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006705 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006706 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006707 curproxy->dispatch_addr = *str2sa(args[1]);
6708 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006709 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006710 if (*(args[1])) {
6711 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006712 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006713 }
6714 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006715 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006716 return -1;
6717 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006718 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006719 else /* if no option is set, use round-robin by default */
6720 curproxy->options |= PR_O_BALANCE_RR;
6721 }
6722 else if (!strcmp(args[0], "server")) { /* server address */
6723 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006724 char *rport;
6725 char *raddr;
6726 short realport;
6727 int do_check;
6728
6729 if (curproxy == &defproxy) {
6730 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6731 return -1;
6732 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006733
willy tarreaua41a8b42005-12-17 14:02:24 +01006734 if (!*args[2]) {
6735 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006736 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006737 return -1;
6738 }
6739 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6740 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6741 return -1;
6742 }
willy tarreau0174f312005-12-18 01:02:42 +01006743
6744 if (curproxy->srv == NULL)
6745 curproxy->srv = newsrv;
6746 else
6747 curproxy->cursrv->next = newsrv;
6748 curproxy->cursrv = newsrv;
6749
6750 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006751 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006752
6753 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006754 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006755 newsrv->id = strdup(args[1]);
6756
6757 /* several ways to check the port component :
6758 * - IP => port=+0, relative
6759 * - IP: => port=+0, relative
6760 * - IP:N => port=N, absolute
6761 * - IP:+N => port=+N, relative
6762 * - IP:-N => port=-N, relative
6763 */
6764 raddr = strdup(args[2]);
6765 rport = strchr(raddr, ':');
6766 if (rport) {
6767 *rport++ = 0;
6768 realport = atol(rport);
6769 if (!isdigit((int)*rport))
6770 newsrv->state |= SRV_MAPPORTS;
6771 } else {
6772 realport = 0;
6773 newsrv->state |= SRV_MAPPORTS;
6774 }
6775
6776 newsrv->addr = *str2sa(raddr);
6777 newsrv->addr.sin_port = htons(realport);
6778 free(raddr);
6779
willy tarreau9fe663a2005-12-17 13:02:59 +01006780 newsrv->curfd = -1; /* no health-check in progress */
6781 newsrv->inter = DEF_CHKINTR;
6782 newsrv->rise = DEF_RISETIME;
6783 newsrv->fall = DEF_FALLTIME;
6784 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6785 cur_arg = 3;
6786 while (*args[cur_arg]) {
6787 if (!strcmp(args[cur_arg], "cookie")) {
6788 newsrv->cookie = strdup(args[cur_arg + 1]);
6789 newsrv->cklen = strlen(args[cur_arg + 1]);
6790 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006791 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006792 else if (!strcmp(args[cur_arg], "rise")) {
6793 newsrv->rise = atol(args[cur_arg + 1]);
6794 newsrv->health = newsrv->rise;
6795 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006796 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006797 else if (!strcmp(args[cur_arg], "fall")) {
6798 newsrv->fall = atol(args[cur_arg + 1]);
6799 cur_arg += 2;
6800 }
6801 else if (!strcmp(args[cur_arg], "inter")) {
6802 newsrv->inter = atol(args[cur_arg + 1]);
6803 cur_arg += 2;
6804 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006805 else if (!strcmp(args[cur_arg], "port")) {
6806 newsrv->check_port = atol(args[cur_arg + 1]);
6807 cur_arg += 2;
6808 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006809 else if (!strcmp(args[cur_arg], "backup")) {
6810 newsrv->state |= SRV_BACKUP;
6811 cur_arg ++;
6812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006814 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006815 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006816 }
willy tarreau0174f312005-12-18 01:02:42 +01006817 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6818 if (!*args[cur_arg + 1]) {
6819 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6820 file, linenum, "source");
6821 return -1;
6822 }
6823 newsrv->state |= SRV_BIND_SRC;
6824 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6825 cur_arg += 2;
6826 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006827 else {
willy tarreau0174f312005-12-18 01:02:42 +01006828 Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n",
willy tarreaua41a8b42005-12-17 14:02:24 +01006829 file, linenum, newsrv->id);
6830 return -1;
6831 }
6832 }
6833
6834 if (do_check) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006835 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6836 newsrv->check_port = realport; /* by default */
6837 if (!newsrv->check_port) {
6838 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 +01006839 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006840 return -1;
6841 }
Willy TARREAU3759f982006-03-01 22:44:17 +01006842 newsrv->state |= SRV_CHECKED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006843 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006844
willy tarreau9fe663a2005-12-17 13:02:59 +01006845 curproxy->nbservers++;
6846 }
6847 else if (!strcmp(args[0], "log")) { /* syslog server address */
6848 struct sockaddr_in *sa;
6849 int facility;
6850
6851 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6852 curproxy->logfac1 = global.logfac1;
6853 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006854 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006855 curproxy->logfac2 = global.logfac2;
6856 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006857 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006858 }
6859 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006860 int level;
6861
willy tarreau0f7af912005-12-17 12:21:26 +01006862 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6863 if (!strcmp(log_facilities[facility], args[2]))
6864 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006865
willy tarreau0f7af912005-12-17 12:21:26 +01006866 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006867 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006868 exit(1);
6869 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006870
willy tarreau8337c6b2005-12-17 13:41:01 +01006871 level = 7; /* max syslog level = debug */
6872 if (*(args[3])) {
6873 while (level >= 0 && strcmp(log_levels[level], args[3]))
6874 level--;
6875 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006876 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006877 exit(1);
6878 }
6879 }
6880
willy tarreau0f7af912005-12-17 12:21:26 +01006881 sa = str2sa(args[1]);
6882 if (!sa->sin_port)
6883 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006884
willy tarreau0f7af912005-12-17 12:21:26 +01006885 if (curproxy->logfac1 == -1) {
6886 curproxy->logsrv1 = *sa;
6887 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006888 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006889 }
6890 else if (curproxy->logfac2 == -1) {
6891 curproxy->logsrv2 = *sa;
6892 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006893 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006894 }
6895 else {
6896 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006897 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006898 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006899 }
6900 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006901 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006902 file, linenum);
6903 return -1;
6904 }
6905 }
willy tarreaua1598082005-12-17 13:08:06 +01006906 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006907 if (!*args[1]) {
6908 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006909 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006910 return -1;
6911 }
6912
6913 curproxy->source_addr = *str2sa(args[1]);
6914 curproxy->options |= PR_O_BIND_SRC;
6915 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006916 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6917 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006918 if (curproxy == &defproxy) {
6919 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6920 return -1;
6921 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006922
6923 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006924 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6925 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006926 return -1;
6927 }
6928
6929 preg = calloc(1, sizeof(regex_t));
6930 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006931 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006932 return -1;
6933 }
6934
willy tarreauc1f47532005-12-18 01:08:26 +01006935 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6936 if (err) {
6937 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6938 file, linenum, *err);
6939 return -1;
6940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 }
6942 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6943 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006944 if (curproxy == &defproxy) {
6945 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6946 return -1;
6947 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006948
6949 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006950 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006951 return -1;
6952 }
6953
6954 preg = calloc(1, sizeof(regex_t));
6955 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006956 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006957 return -1;
6958 }
6959
6960 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6961 }
6962 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6963 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006964 if (curproxy == &defproxy) {
6965 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6966 return -1;
6967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006968
6969 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006970 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006971 return -1;
6972 }
6973
6974 preg = calloc(1, sizeof(regex_t));
6975 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006976 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006977 return -1;
6978 }
6979
6980 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6981 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006982 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6983 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006984 if (curproxy == &defproxy) {
6985 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6986 return -1;
6987 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006988
6989 if (*(args[1]) == 0) {
6990 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6991 return -1;
6992 }
6993
6994 preg = calloc(1, sizeof(regex_t));
6995 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6996 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6997 return -1;
6998 }
6999
7000 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7001 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007002 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
7003 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007004 if (curproxy == &defproxy) {
7005 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7006 return -1;
7007 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007008
7009 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007010 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007011 return -1;
7012 }
7013
7014 preg = calloc(1, sizeof(regex_t));
7015 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007016 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 return -1;
7018 }
7019
7020 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7021 }
7022 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
7023 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007024 if (curproxy == &defproxy) {
7025 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7026 return -1;
7027 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007028
7029 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007030 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7031 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007032 return -1;
7033 }
7034
7035 preg = calloc(1, sizeof(regex_t));
7036 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007037 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007038 return -1;
7039 }
7040
willy tarreauc1f47532005-12-18 01:08:26 +01007041 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7042 if (err) {
7043 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7044 file, linenum, *err);
7045 return -1;
7046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007047 }
7048 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7049 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007050 if (curproxy == &defproxy) {
7051 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7052 return -1;
7053 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007054
7055 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007056 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007057 return -1;
7058 }
7059
7060 preg = calloc(1, sizeof(regex_t));
7061 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007062 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007063 return -1;
7064 }
7065
7066 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7067 }
7068 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7069 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007070 if (curproxy == &defproxy) {
7071 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7072 return -1;
7073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007074
7075 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007076 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007077 return -1;
7078 }
7079
7080 preg = calloc(1, sizeof(regex_t));
7081 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 return -1;
7084 }
7085
7086 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7087 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007088 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7089 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007090 if (curproxy == &defproxy) {
7091 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7092 return -1;
7093 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007094
7095 if (*(args[1]) == 0) {
7096 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7097 return -1;
7098 }
7099
7100 preg = calloc(1, sizeof(regex_t));
7101 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7102 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7103 return -1;
7104 }
7105
7106 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007108 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7109 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007110 if (curproxy == &defproxy) {
7111 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7112 return -1;
7113 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007114
7115 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007116 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007117 return -1;
7118 }
7119
7120 preg = calloc(1, sizeof(regex_t));
7121 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007122 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007123 return -1;
7124 }
7125
7126 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7127 }
7128 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007129 if (curproxy == &defproxy) {
7130 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7131 return -1;
7132 }
7133
willy tarreau9fe663a2005-12-17 13:02:59 +01007134 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007135 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007136 return 0;
7137 }
7138
7139 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007140 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007141 return -1;
7142 }
7143
willy tarreau4302f492005-12-18 01:00:37 +01007144 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7145 }
7146 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7147 regex_t *preg;
7148
7149 if (*(args[1]) == 0 || *(args[2]) == 0) {
7150 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7151 file, linenum, args[0]);
7152 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007153 }
willy tarreau4302f492005-12-18 01:00:37 +01007154
7155 preg = calloc(1, sizeof(regex_t));
7156 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7157 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7158 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007159 }
willy tarreau4302f492005-12-18 01:00:37 +01007160
willy tarreauc1f47532005-12-18 01:08:26 +01007161 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7162 if (err) {
7163 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7164 file, linenum, *err);
7165 return -1;
7166 }
willy tarreau4302f492005-12-18 01:00:37 +01007167 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007168 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7169 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007170 if (curproxy == &defproxy) {
7171 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7172 return -1;
7173 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007174
7175 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007176 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007177 return -1;
7178 }
willy tarreaue39cd132005-12-17 13:00:18 +01007179
willy tarreau9fe663a2005-12-17 13:02:59 +01007180 preg = calloc(1, sizeof(regex_t));
7181 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007182 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007183 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007184 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007185
willy tarreauc1f47532005-12-18 01:08:26 +01007186 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7187 if (err) {
7188 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7189 file, linenum, *err);
7190 return -1;
7191 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007192 }
willy tarreau982249e2005-12-18 00:57:06 +01007193 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7194 regex_t *preg;
7195 if (curproxy == &defproxy) {
7196 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7197 return -1;
7198 }
7199
7200 if (*(args[1]) == 0) {
7201 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7202 return -1;
7203 }
7204
7205 preg = calloc(1, sizeof(regex_t));
7206 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7207 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7208 return -1;
7209 }
7210
willy tarreauc1f47532005-12-18 01:08:26 +01007211 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7212 if (err) {
7213 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7214 file, linenum, *err);
7215 return -1;
7216 }
willy tarreau982249e2005-12-18 00:57:06 +01007217 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007218 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007219 regex_t *preg;
7220 if (curproxy == &defproxy) {
7221 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7222 return -1;
7223 }
willy tarreaue39cd132005-12-17 13:00:18 +01007224
willy tarreaua41a8b42005-12-17 14:02:24 +01007225 if (*(args[1]) == 0 || *(args[2]) == 0) {
7226 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7227 file, linenum, args[0]);
7228 return -1;
7229 }
willy tarreaue39cd132005-12-17 13:00:18 +01007230
willy tarreaua41a8b42005-12-17 14:02:24 +01007231 preg = calloc(1, sizeof(regex_t));
7232 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7233 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7234 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007235 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007236
willy tarreauc1f47532005-12-18 01:08:26 +01007237 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7238 if (err) {
7239 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7240 file, linenum, *err);
7241 return -1;
7242 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007243 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007244 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7245 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007246 if (curproxy == &defproxy) {
7247 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7248 return -1;
7249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007250
7251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007252 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007253 return -1;
7254 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007255
willy tarreau9fe663a2005-12-17 13:02:59 +01007256 preg = calloc(1, sizeof(regex_t));
7257 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007258 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007259 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007260 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007261
willy tarreauc1f47532005-12-18 01:08:26 +01007262 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7263 if (err) {
7264 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7265 file, linenum, *err);
7266 return -1;
7267 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 }
willy tarreau982249e2005-12-18 00:57:06 +01007269 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7270 regex_t *preg;
7271 if (curproxy == &defproxy) {
7272 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7273 return -1;
7274 }
7275
7276 if (*(args[1]) == 0) {
7277 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7278 return -1;
7279 }
7280
7281 preg = calloc(1, sizeof(regex_t));
7282 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7283 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7284 return -1;
7285 }
7286
willy tarreauc1f47532005-12-18 01:08:26 +01007287 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7288 if (err) {
7289 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7290 file, linenum, *err);
7291 return -1;
7292 }
willy tarreau982249e2005-12-18 00:57:06 +01007293 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007294 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007295 if (curproxy == &defproxy) {
7296 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7297 return -1;
7298 }
7299
willy tarreau9fe663a2005-12-17 13:02:59 +01007300 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007301 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007302 return 0;
7303 }
7304
7305 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007306 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007307 return -1;
7308 }
7309
7310 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7311 }
willy tarreauc1f47532005-12-18 01:08:26 +01007312 else if (!strcmp(args[0], "errorloc") ||
7313 !strcmp(args[0], "errorloc302") ||
7314 !strcmp(args[0], "errorloc303")) { /* error location */
7315 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007316 char *err;
7317
willy tarreaueedaa9f2005-12-17 14:08:03 +01007318 // if (curproxy == &defproxy) {
7319 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7320 // return -1;
7321 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007322
willy tarreau8337c6b2005-12-17 13:41:01 +01007323 if (*(args[2]) == 0) {
7324 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7325 return -1;
7326 }
7327
7328 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007329 if (!strcmp(args[0], "errorloc303")) {
7330 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7331 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7332 } else {
7333 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7334 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7335 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007336
7337 if (errnum == 400) {
7338 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007339 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007340 free(curproxy->errmsg.msg400);
7341 }
7342 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007343 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007344 }
7345 else if (errnum == 403) {
7346 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007347 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007348 free(curproxy->errmsg.msg403);
7349 }
7350 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007351 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007352 }
7353 else if (errnum == 408) {
7354 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007355 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007356 free(curproxy->errmsg.msg408);
7357 }
7358 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007359 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007360 }
7361 else if (errnum == 500) {
7362 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007363 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007364 free(curproxy->errmsg.msg500);
7365 }
7366 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007367 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007368 }
7369 else if (errnum == 502) {
7370 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007371 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007372 free(curproxy->errmsg.msg502);
7373 }
7374 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007375 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007376 }
7377 else if (errnum == 503) {
7378 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007379 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007380 free(curproxy->errmsg.msg503);
7381 }
7382 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007383 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007384 }
7385 else if (errnum == 504) {
7386 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007387 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007388 free(curproxy->errmsg.msg504);
7389 }
7390 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007391 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007392 }
7393 else {
7394 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7395 free(err);
7396 }
7397 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007398 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007399 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007400 return -1;
7401 }
7402 return 0;
7403}
willy tarreaue39cd132005-12-17 13:00:18 +01007404
willy tarreau5cbea6f2005-12-17 12:48:26 +01007405
willy tarreau9fe663a2005-12-17 13:02:59 +01007406/*
7407 * This function reads and parses the configuration file given in the argument.
7408 * returns 0 if OK, -1 if error.
7409 */
7410int readcfgfile(char *file) {
7411 char thisline[256];
7412 char *line;
7413 FILE *f;
7414 int linenum = 0;
7415 char *end;
7416 char *args[MAX_LINE_ARGS];
7417 int arg;
7418 int cfgerr = 0;
Willy TARREAU3759f982006-03-01 22:44:17 +01007419 int nbchk, mininter;
willy tarreau9fe663a2005-12-17 13:02:59 +01007420 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007421
willy tarreau9fe663a2005-12-17 13:02:59 +01007422 struct proxy *curproxy = NULL;
7423 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007424
willy tarreau9fe663a2005-12-17 13:02:59 +01007425 if ((f=fopen(file,"r")) == NULL)
7426 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007427
willy tarreaueedaa9f2005-12-17 14:08:03 +01007428 init_default_instance();
7429
willy tarreau9fe663a2005-12-17 13:02:59 +01007430 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7431 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007432
willy tarreau9fe663a2005-12-17 13:02:59 +01007433 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007434
willy tarreau9fe663a2005-12-17 13:02:59 +01007435 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007436 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007437 line++;
7438
7439 arg = 0;
7440 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007441
willy tarreau9fe663a2005-12-17 13:02:59 +01007442 while (*line && arg < MAX_LINE_ARGS) {
7443 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7444 * C equivalent value. Other combinations left unchanged (eg: \1).
7445 */
7446 if (*line == '\\') {
7447 int skip = 0;
7448 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7449 *line = line[1];
7450 skip = 1;
7451 }
7452 else if (line[1] == 'r') {
7453 *line = '\r';
7454 skip = 1;
7455 }
7456 else if (line[1] == 'n') {
7457 *line = '\n';
7458 skip = 1;
7459 }
7460 else if (line[1] == 't') {
7461 *line = '\t';
7462 skip = 1;
7463 }
willy tarreauc1f47532005-12-18 01:08:26 +01007464 else if (line[1] == 'x') {
7465 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7466 unsigned char hex1, hex2;
7467 hex1 = toupper(line[2]) - '0';
7468 hex2 = toupper(line[3]) - '0';
7469 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7470 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7471 *line = (hex1<<4) + hex2;
7472 skip = 3;
7473 }
7474 else {
7475 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7476 return -1;
7477 }
7478 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007479 if (skip) {
7480 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7481 end -= skip;
7482 }
7483 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007484 }
willy tarreaua1598082005-12-17 13:08:06 +01007485 else if (*line == '#' || *line == '\n' || *line == '\r') {
7486 /* end of string, end of loop */
7487 *line = 0;
7488 break;
7489 }
willy tarreauc29948c2005-12-17 13:10:27 +01007490 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007492 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007493 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007494 line++;
7495 args[++arg] = line;
7496 }
7497 else {
7498 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007499 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007500 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007501
willy tarreau9fe663a2005-12-17 13:02:59 +01007502 /* empty line */
7503 if (!**args)
7504 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007505
willy tarreau9fe663a2005-12-17 13:02:59 +01007506 /* zero out remaining args */
7507 while (++arg < MAX_LINE_ARGS) {
7508 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007509 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007510
willy tarreaua41a8b42005-12-17 14:02:24 +01007511 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007512 confsect = CFG_LISTEN;
7513 else if (!strcmp(args[0], "global")) /* global config */
7514 confsect = CFG_GLOBAL;
7515 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007516
willy tarreau9fe663a2005-12-17 13:02:59 +01007517 switch (confsect) {
7518 case CFG_LISTEN:
7519 if (cfg_parse_listen(file, linenum, args) < 0)
7520 return -1;
7521 break;
7522 case CFG_GLOBAL:
7523 if (cfg_parse_global(file, linenum, args) < 0)
7524 return -1;
7525 break;
7526 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007527 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007529 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007530
7531
willy tarreau0f7af912005-12-17 12:21:26 +01007532 }
7533 fclose(f);
7534
7535 /*
7536 * Now, check for the integrity of all that we have collected.
7537 */
7538
Willy TARREAU3759f982006-03-01 22:44:17 +01007539 /* will be needed further to delay some tasks */
7540 tv_now(&now);
7541
willy tarreau0f7af912005-12-17 12:21:26 +01007542 if ((curproxy = proxy) == NULL) {
7543 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7544 file);
7545 return -1;
7546 }
7547
7548 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007549 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007550 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007551 curproxy = curproxy->next;
7552 continue;
7553 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007554
7555 if (curproxy->listen == NULL) {
7556 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);
7557 cfgerr++;
7558 }
7559 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007560 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007561 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007562 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7563 file, curproxy->id);
7564 cfgerr++;
7565 }
7566 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7567 if (curproxy->options & PR_O_TRANSP) {
7568 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7569 file, curproxy->id);
7570 cfgerr++;
7571 }
7572 else if (curproxy->srv == NULL) {
7573 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7574 file, curproxy->id);
7575 cfgerr++;
7576 }
willy tarreaua1598082005-12-17 13:08:06 +01007577 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007578 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7579 file, curproxy->id);
7580 }
7581 }
7582 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007583 if (curproxy->cookie_name != NULL) {
7584 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7585 file, curproxy->id);
7586 }
7587 if ((newsrv = curproxy->srv) != NULL) {
7588 Warning("parsing %s : servers will be ignored for listener %s.\n",
7589 file, curproxy->id);
7590 }
willy tarreaue39cd132005-12-17 13:00:18 +01007591 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007592 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7593 file, curproxy->id);
7594 }
willy tarreaue39cd132005-12-17 13:00:18 +01007595 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007596 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7597 file, curproxy->id);
7598 }
7599 }
7600 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7601 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7602 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7603 file, curproxy->id);
7604 cfgerr++;
7605 }
7606 else {
7607 while (newsrv != NULL) {
7608 /* nothing to check for now */
7609 newsrv = newsrv->next;
7610 }
7611 }
7612 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007613
7614 if (curproxy->options & PR_O_LOGASAP)
7615 curproxy->to_log &= ~LW_BYTES;
7616
willy tarreau8337c6b2005-12-17 13:41:01 +01007617 if (curproxy->errmsg.msg400 == NULL) {
7618 curproxy->errmsg.msg400 = (char *)HTTP_400;
7619 curproxy->errmsg.len400 = strlen(HTTP_400);
7620 }
7621 if (curproxy->errmsg.msg403 == NULL) {
7622 curproxy->errmsg.msg403 = (char *)HTTP_403;
7623 curproxy->errmsg.len403 = strlen(HTTP_403);
7624 }
7625 if (curproxy->errmsg.msg408 == NULL) {
7626 curproxy->errmsg.msg408 = (char *)HTTP_408;
7627 curproxy->errmsg.len408 = strlen(HTTP_408);
7628 }
7629 if (curproxy->errmsg.msg500 == NULL) {
7630 curproxy->errmsg.msg500 = (char *)HTTP_500;
7631 curproxy->errmsg.len500 = strlen(HTTP_500);
7632 }
7633 if (curproxy->errmsg.msg502 == NULL) {
7634 curproxy->errmsg.msg502 = (char *)HTTP_502;
7635 curproxy->errmsg.len502 = strlen(HTTP_502);
7636 }
7637 if (curproxy->errmsg.msg503 == NULL) {
7638 curproxy->errmsg.msg503 = (char *)HTTP_503;
7639 curproxy->errmsg.len503 = strlen(HTTP_503);
7640 }
7641 if (curproxy->errmsg.msg504 == NULL) {
7642 curproxy->errmsg.msg504 = (char *)HTTP_504;
7643 curproxy->errmsg.len504 = strlen(HTTP_504);
7644 }
Willy TARREAU3759f982006-03-01 22:44:17 +01007645
7646 /* now we'll start this proxy's health checks if any */
7647 /* 1- count the checkers to run simultaneously */
7648 nbchk = 0;
7649 mininter = 0;
7650 newsrv = curproxy->srv;
7651 while (newsrv != NULL) {
7652 if (newsrv->state & SRV_CHECKED) {
7653 if (!mininter || mininter > newsrv->inter)
7654 mininter = newsrv->inter;
7655 nbchk++;
7656 }
7657 newsrv = newsrv->next;
7658 }
7659
7660 /* 2- start them as far as possible from each others while respecting
7661 * their own intervals. For this, we will start them after their own
7662 * interval added to the min interval divided by the number of servers,
7663 * weighted by the server's position in the list.
7664 */
7665 if (nbchk > 0) {
7666 struct task *t;
7667 int srvpos;
7668
7669 newsrv = curproxy->srv;
7670 srvpos = 0;
7671 while (newsrv != NULL) {
7672 /* should this server be checked ? */
7673 if (newsrv->state & SRV_CHECKED) {
7674 if ((t = pool_alloc(task)) == NULL) {
7675 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
7676 return -1;
7677 }
7678
7679 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
7680 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
7681 t->state = TASK_IDLE;
7682 t->process = process_chk;
7683 t->context = newsrv;
7684
7685 /* check this every ms */
7686 tv_delayfrom(&t->expire, &now,
7687 newsrv->inter + mininter * srvpos / nbchk);
7688 task_queue(t);
7689 //task_wakeup(&rq, t);
7690 srvpos++;
7691 }
7692 newsrv = newsrv->next;
7693 }
7694 }
7695
willy tarreau0f7af912005-12-17 12:21:26 +01007696 curproxy = curproxy->next;
7697 }
7698 if (cfgerr > 0) {
7699 Alert("Errors found in configuration file, aborting.\n");
7700 return -1;
7701 }
7702 else
7703 return 0;
7704}
7705
7706
7707/*
7708 * This function initializes all the necessary variables. It only returns
7709 * if everything is OK. If something fails, it exits.
7710 */
7711void init(int argc, char **argv) {
7712 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007713 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007714 char *old_argv = *argv;
7715 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007716 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007717 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007718
7719 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007720 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007721 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007722 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007723 exit(1);
7724 }
7725
Willy TARREAUa9e75f62006-03-01 22:27:48 +01007726 /* initialize the libc's localtime structures once for all so that we
7727 * won't be missing memory if we want to send alerts under OOM conditions.
7728 */
7729 tv_now(&now);
7730 localtime(&now.tv_sec);
7731
willy tarreau4302f492005-12-18 01:00:37 +01007732 /* initialize the log header encoding map : '{|}"#' should be encoded with
7733 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7734 * URL encoding only requires '"', '#' to be encoded as well as non-
7735 * printable characters above.
7736 */
7737 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7738 memset(url_encode_map, 0, sizeof(url_encode_map));
7739 for (i = 0; i < 32; i++) {
7740 FD_SET(i, hdr_encode_map);
7741 FD_SET(i, url_encode_map);
7742 }
7743 for (i = 127; i < 256; i++) {
7744 FD_SET(i, hdr_encode_map);
7745 FD_SET(i, url_encode_map);
7746 }
7747
7748 tmp = "\"#{|}";
7749 while (*tmp) {
7750 FD_SET(*tmp, hdr_encode_map);
7751 tmp++;
7752 }
7753
7754 tmp = "\"#";
7755 while (*tmp) {
7756 FD_SET(*tmp, url_encode_map);
7757 tmp++;
7758 }
7759
willy tarreau64a3cc32005-12-18 01:13:11 +01007760 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7761#if defined(ENABLE_POLL)
7762 cfg_polling_mechanism |= POLL_USE_POLL;
7763#endif
7764#if defined(ENABLE_EPOLL)
7765 cfg_polling_mechanism |= POLL_USE_EPOLL;
7766#endif
7767
willy tarreau0f7af912005-12-17 12:21:26 +01007768 pid = getpid();
7769 progname = *argv;
7770 while ((tmp = strchr(progname, '/')) != NULL)
7771 progname = tmp + 1;
7772
7773 argc--; argv++;
7774 while (argc > 0) {
7775 char *flag;
7776
7777 if (**argv == '-') {
7778 flag = *argv+1;
7779
7780 /* 1 arg */
7781 if (*flag == 'v') {
7782 display_version();
7783 exit(0);
7784 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007785#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007786 else if (*flag == 'd' && flag[1] == 'e')
7787 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007788#endif
7789#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007790 else if (*flag == 'd' && flag[1] == 'p')
7791 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007792#endif
willy tarreau982249e2005-12-18 00:57:06 +01007793 else if (*flag == 'V')
7794 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007795 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007796 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007797 else if (*flag == 'c')
7798 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007799 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007800 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007801 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007802 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007803#if STATTIME > 0
7804 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007805 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007806 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007807 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007808#endif
7809 else { /* >=2 args */
7810 argv++; argc--;
7811 if (argc == 0)
7812 usage(old_argv);
7813
7814 switch (*flag) {
7815 case 'n' : cfg_maxconn = atol(*argv); break;
7816 case 'N' : cfg_maxpconn = atol(*argv); break;
7817 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007818 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007819 default: usage(old_argv);
7820 }
7821 }
7822 }
7823 else
7824 usage(old_argv);
7825 argv++; argc--;
7826 }
7827
willy tarreaud0fb4652005-12-18 01:32:04 +01007828 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7829 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007830
willy tarreau0f7af912005-12-17 12:21:26 +01007831 if (!cfg_cfgfile)
7832 usage(old_argv);
7833
7834 gethostname(hostname, MAX_HOSTNAME_LEN);
7835
willy tarreau12350152005-12-18 01:03:27 +01007836 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007837 if (readcfgfile(cfg_cfgfile) < 0) {
7838 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7839 exit(1);
7840 }
willy tarreau12350152005-12-18 01:03:27 +01007841 if (have_appsession)
7842 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007843
willy tarreau982249e2005-12-18 00:57:06 +01007844 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007845 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7846 exit(0);
7847 }
7848
willy tarreau9fe663a2005-12-17 13:02:59 +01007849 if (cfg_maxconn > 0)
7850 global.maxconn = cfg_maxconn;
7851
willy tarreaufe2c5c12005-12-17 14:14:34 +01007852 if (cfg_pidfile) {
7853 if (global.pidfile)
7854 free(global.pidfile);
7855 global.pidfile = strdup(cfg_pidfile);
7856 }
7857
willy tarreau9fe663a2005-12-17 13:02:59 +01007858 if (global.maxconn == 0)
7859 global.maxconn = DEFAULT_MAXCONN;
7860
7861 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7862
7863 if (arg_mode & MODE_DEBUG) {
7864 /* command line debug mode inhibits configuration mode */
7865 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7866 }
willy tarreau982249e2005-12-18 00:57:06 +01007867 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7868 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007869
7870 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7871 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7872 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7873 }
7874
7875 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7876 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7877 global.nbproc = 1;
7878 }
7879
7880 if (global.nbproc < 1)
7881 global.nbproc = 1;
7882
willy tarreau0f7af912005-12-17 12:21:26 +01007883 StaticReadEvent = (fd_set *)calloc(1,
7884 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007885 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007886 StaticWriteEvent = (fd_set *)calloc(1,
7887 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007888 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007889
7890 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007891 sizeof(struct fdtab) * (global.maxsock));
7892 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007893 fdtab[i].state = FD_STCLOSE;
7894 }
7895}
7896
7897/*
7898 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7899 */
7900int start_proxies() {
7901 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007902 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007903 int fd;
7904
7905 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007906 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007907 continue;
7908
willy tarreaua41a8b42005-12-17 14:02:24 +01007909 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7910 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007911 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007912 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7913 curproxy->id);
7914 return -1;
7915 }
willy tarreau0f7af912005-12-17 12:21:26 +01007916
willy tarreaua41a8b42005-12-17 14:02:24 +01007917 if (fd >= global.maxsock) {
7918 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7919 curproxy->id);
7920 close(fd);
7921 return -1;
7922 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007923
willy tarreaua41a8b42005-12-17 14:02:24 +01007924 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7925 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7926 (char *) &one, sizeof(one)) == -1)) {
7927 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7928 curproxy->id);
7929 close(fd);
7930 return -1;
7931 }
willy tarreau0f7af912005-12-17 12:21:26 +01007932
willy tarreaua41a8b42005-12-17 14:02:24 +01007933 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7934 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7935 curproxy->id);
7936 }
willy tarreau0f7af912005-12-17 12:21:26 +01007937
willy tarreaua41a8b42005-12-17 14:02:24 +01007938 if (bind(fd,
7939 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007940 listener->addr.ss_family == AF_INET6 ?
7941 sizeof(struct sockaddr_in6) :
7942 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007943 Alert("cannot bind socket for proxy %s. Aborting.\n",
7944 curproxy->id);
7945 close(fd);
7946 return -1;
7947 }
willy tarreau0f7af912005-12-17 12:21:26 +01007948
willy tarreaua41a8b42005-12-17 14:02:24 +01007949 if (listen(fd, curproxy->maxconn) == -1) {
7950 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7951 curproxy->id);
7952 close(fd);
7953 return -1;
7954 }
willy tarreau0f7af912005-12-17 12:21:26 +01007955
willy tarreaua41a8b42005-12-17 14:02:24 +01007956 /* the function for the accept() event */
7957 fdtab[fd].read = &event_accept;
7958 fdtab[fd].write = NULL; /* never called */
7959 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7960 curproxy->state = PR_STRUN;
7961 fdtab[fd].state = FD_STLISTEN;
7962 FD_SET(fd, StaticReadEvent);
7963 fd_insert(fd);
7964 listeners++;
7965 }
willy tarreaua1598082005-12-17 13:08:06 +01007966 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007967 }
7968 return 0;
7969}
7970
willy tarreaub952e1d2005-12-18 01:31:20 +01007971int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007972
7973 appsess *temp1,*temp2;
7974 temp1 = (appsess *)key1;
7975 temp2 = (appsess *)key2;
7976
7977 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7978 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7979
7980 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7981}/* end match_str */
7982
willy tarreaub952e1d2005-12-18 01:31:20 +01007983void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007984 appsess *temp1;
7985
7986 //printf("destroy called\n");
7987 temp1 = (appsess *)data;
7988
7989 if (temp1->sessid)
7990 pool_free_to(apools.sessid, temp1->sessid);
7991
7992 if (temp1->serverid)
7993 pool_free_to(apools.serverid, temp1->serverid);
7994
7995 pool_free(appsess, temp1);
7996} /* end destroy */
7997
7998void appsession_cleanup( void )
7999{
8000 struct proxy *p = proxy;
8001
8002 while(p) {
8003 chtbl_destroy(&(p->htbl_proxy));
8004 p = p->next;
8005 }
8006}/* end appsession_cleanup() */
8007
8008void pool_destroy(void **pool)
8009{
8010 void *temp, *next;
8011 next = pool;
8012 while (next) {
8013 temp = next;
8014 next = *(void **)temp;
8015 free(temp);
8016 }
8017}/* end pool_destroy() */
8018
willy tarreaub952e1d2005-12-18 01:31:20 +01008019void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01008020 struct proxy *p = proxy;
8021 struct cap_hdr *h,*h_next;
8022 struct server *s,*s_next;
8023 struct listener *l,*l_next;
8024
8025 while (p) {
8026 if (p->id)
8027 free(p->id);
8028
8029 if (p->check_req)
8030 free(p->check_req);
8031
8032 if (p->cookie_name)
8033 free(p->cookie_name);
8034
8035 if (p->capture_name)
8036 free(p->capture_name);
8037
8038 /* only strup if the user have set in config.
8039 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01008040 if (p->errmsg.msg400) free(p->errmsg.msg400);
8041 if (p->errmsg.msg403) free(p->errmsg.msg403);
8042 if (p->errmsg.msg408) free(p->errmsg.msg408);
8043 if (p->errmsg.msg500) free(p->errmsg.msg500);
8044 if (p->errmsg.msg502) free(p->errmsg.msg502);
8045 if (p->errmsg.msg503) free(p->errmsg.msg503);
8046 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01008047 */
8048 if (p->appsession_name)
8049 free(p->appsession_name);
8050
8051 h = p->req_cap;
8052 while (h) {
8053 h_next = h->next;
8054 if (h->name)
8055 free(h->name);
8056 pool_destroy(h->pool);
8057 free(h);
8058 h = h_next;
8059 }/* end while(h) */
8060
8061 h = p->rsp_cap;
8062 while (h) {
8063 h_next = h->next;
8064 if (h->name)
8065 free(h->name);
8066
8067 pool_destroy(h->pool);
8068 free(h);
8069 h = h_next;
8070 }/* end while(h) */
8071
8072 s = p->srv;
8073 while (s) {
8074 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01008075 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01008076 free(s->id);
8077
willy tarreaub952e1d2005-12-18 01:31:20 +01008078 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01008079 free(s->cookie);
8080
8081 free(s);
8082 s = s_next;
8083 }/* end while(s) */
8084
8085 l = p->listen;
8086 while (l) {
8087 l_next = l->next;
8088 free(l);
8089 l = l_next;
8090 }/* end while(l) */
8091
8092 pool_destroy((void **) p->req_cap_pool);
8093 pool_destroy((void **) p->rsp_cap_pool);
8094 p = p->next;
8095 }/* end while(p) */
8096
8097 if (global.chroot) free(global.chroot);
8098 if (global.pidfile) free(global.pidfile);
8099
willy tarreau12350152005-12-18 01:03:27 +01008100 if (StaticReadEvent) free(StaticReadEvent);
8101 if (StaticWriteEvent) free(StaticWriteEvent);
8102 if (fdtab) free(fdtab);
8103
8104 pool_destroy(pool_session);
8105 pool_destroy(pool_buffer);
8106 pool_destroy(pool_fdtab);
8107 pool_destroy(pool_requri);
8108 pool_destroy(pool_task);
8109 pool_destroy(pool_capture);
8110 pool_destroy(pool_appsess);
8111
8112 if (have_appsession) {
8113 pool_destroy(apools.serverid);
8114 pool_destroy(apools.sessid);
8115 }
8116} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008117
8118int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008119 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008120 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008121 init(argc, argv);
8122
willy tarreau0f7af912005-12-17 12:21:26 +01008123 signal(SIGQUIT, dump);
8124 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008125 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008126#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008127 signal(SIGINT, sig_int);
8128 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008129#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008130
8131 /* on very high loads, a sigpipe sometimes happen just between the
8132 * getsockopt() which tells "it's OK to write", and the following write :-(
8133 */
willy tarreau3242e862005-12-17 12:27:53 +01008134#ifndef MSG_NOSIGNAL
8135 signal(SIGPIPE, SIG_IGN);
8136#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008137
willy tarreaud0fb4652005-12-18 01:32:04 +01008138 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008139 if (start_proxies() < 0)
8140 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008141
8142 if (listeners == 0) {
8143 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8144 exit(1);
8145 }
8146
willy tarreaudbd3bef2006-01-20 19:35:18 +01008147 /* prepare pause/play signals */
8148 signal(SIGTTOU, sig_pause);
8149 signal(SIGTTIN, sig_listen);
8150
Willy TARREAUe3283d12006-03-01 22:15:29 +01008151 if (global.mode & MODE_DAEMON) {
8152 global.mode &= ~MODE_VERBOSE;
8153 global.mode |= MODE_QUIET;
8154 }
8155
willy tarreaud0fb4652005-12-18 01:32:04 +01008156 /* MODE_QUIET can inhibit alerts and warnings below this line */
8157
8158 global.mode &= ~MODE_STARTING;
Willy TARREAUe3283d12006-03-01 22:15:29 +01008159 if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
willy tarreaud0fb4652005-12-18 01:32:04 +01008160 /* detach from the tty */
8161 fclose(stdin); fclose(stdout); fclose(stderr);
8162 close(0); close(1); close(2);
8163 }
willy tarreau0f7af912005-12-17 12:21:26 +01008164
willy tarreaufe2c5c12005-12-17 14:14:34 +01008165 /* open log & pid files before the chroot */
8166 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8167 int pidfd;
8168 unlink(global.pidfile);
8169 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8170 if (pidfd < 0) {
8171 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8172 exit(1);
8173 }
8174 pidfile = fdopen(pidfd, "w");
8175 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008176
8177 /* chroot if needed */
8178 if (global.chroot != NULL) {
8179 if (chroot(global.chroot) == -1) {
8180 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8181 exit(1);
8182 }
8183 chdir("/");
8184 }
8185
willy tarreaub1285d52005-12-18 01:20:14 +01008186 /* ulimits */
8187 if (global.rlimit_nofile) {
8188 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8189 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8190 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8191 }
8192 }
8193
willy tarreau9fe663a2005-12-17 13:02:59 +01008194 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008195 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008196 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8197 exit(1);
8198 }
8199
willy tarreau036e1ce2005-12-17 13:46:33 +01008200 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008201 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8202 exit(1);
8203 }
8204
willy tarreaub1285d52005-12-18 01:20:14 +01008205 /* check ulimits */
8206 limit.rlim_cur = limit.rlim_max = 0;
8207 getrlimit(RLIMIT_NOFILE, &limit);
8208 if (limit.rlim_cur < global.maxsock) {
8209 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",
8210 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8211 }
8212
willy tarreau9fe663a2005-12-17 13:02:59 +01008213 if (global.mode & MODE_DAEMON) {
8214 int ret = 0;
8215 int proc;
8216
8217 /* the father launches the required number of processes */
8218 for (proc = 0; proc < global.nbproc; proc++) {
8219 ret = fork();
8220 if (ret < 0) {
8221 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8222 exit(1); /* there has been an error */
8223 }
8224 else if (ret == 0) /* child breaks here */
8225 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008226 if (pidfile != NULL) {
8227 fprintf(pidfile, "%d\n", ret);
8228 fflush(pidfile);
8229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008230 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008231 /* close the pidfile both in children and father */
8232 if (pidfile != NULL)
8233 fclose(pidfile);
8234 free(global.pidfile);
8235
willy tarreau9fe663a2005-12-17 13:02:59 +01008236 if (proc == global.nbproc)
8237 exit(0); /* parent must leave */
8238
willy tarreau750a4722005-12-17 13:21:24 +01008239 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8240 * that we can detach from the TTY. We MUST NOT do it in other cases since
8241 * it would have already be done, and 0-2 would have been affected to listening
8242 * sockets
8243 */
8244 if (!(global.mode & MODE_QUIET)) {
8245 /* detach from the tty */
8246 fclose(stdin); fclose(stdout); fclose(stderr);
8247 close(0); close(1); close(2); /* close all fd's */
8248 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8249 }
willy tarreaua1598082005-12-17 13:08:06 +01008250 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008251 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008252 }
8253
willy tarreau1c2ad212005-12-18 01:11:29 +01008254#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008255 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008256 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8257 epoll_loop(POLL_LOOP_ACTION_RUN);
8258 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008259 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008260 }
8261 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008262 Warning("epoll() is not available. Using poll()/select() instead.\n");
8263 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008264 }
8265 }
8266#endif
8267
8268#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008269 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008270 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8271 poll_loop(POLL_LOOP_ACTION_RUN);
8272 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008273 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008274 }
8275 else {
8276 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008277 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008278 }
8279 }
8280#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008281 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008282 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8283 select_loop(POLL_LOOP_ACTION_RUN);
8284 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008285 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008286 }
8287 }
8288
willy tarreau0f7af912005-12-17 12:21:26 +01008289
willy tarreau12350152005-12-18 01:03:27 +01008290 /* Free all Hash Keys and all Hash elements */
8291 appsession_cleanup();
8292 /* Do some cleanup */
8293 deinit();
8294
willy tarreau0f7af912005-12-17 12:21:26 +01008295 exit(0);
8296}
willy tarreau12350152005-12-18 01:03:27 +01008297
8298#if defined(DEBUG_HASH)
8299static void print_table(const CHTbl *htbl) {
8300
8301 ListElmt *element;
8302 int i;
8303 appsess *asession;
8304
8305 /*****************************************************************************
8306 * *
8307 * Display the chained hash table. *
8308 * *
8309 *****************************************************************************/
8310
8311 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8312
8313 for (i = 0; i < TBLSIZ; i++) {
8314 fprintf(stdout, "Bucket[%03d]\n", i);
8315
8316 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8317 //fprintf(stdout, "%c", *(char *)list_data(element));
8318 asession = (appsess *)list_data(element);
8319 fprintf(stdout, "ELEM :%s:", asession->sessid);
8320 fprintf(stdout, " Server :%s: \n", asession->serverid);
8321 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8322 }
8323
8324 fprintf(stdout, "\n");
8325 }
8326 return;
8327} /* end print_table */
8328#endif
8329
8330static int appsession_init(void)
8331{
8332 static int initialized = 0;
8333 int idlen;
8334 struct server *s;
8335 struct proxy *p = proxy;
8336
8337 if (!initialized) {
8338 if (!appsession_task_init()) {
8339 apools.sessid = NULL;
8340 apools.serverid = NULL;
8341 apools.ser_waste = 0;
8342 apools.ser_use = 0;
8343 apools.ser_msize = sizeof(void *);
8344 apools.ses_waste = 0;
8345 apools.ses_use = 0;
8346 apools.ses_msize = sizeof(void *);
8347 while (p) {
8348 s = p->srv;
8349 if (apools.ses_msize < p->appsession_len)
8350 apools.ses_msize = p->appsession_len;
8351 while (s) {
8352 idlen = strlen(s->id);
8353 if (apools.ser_msize < idlen)
8354 apools.ser_msize = idlen;
8355 s = s->next;
8356 }
8357 p = p->next;
8358 }
8359 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8360 apools.ses_msize ++;
8361 }
8362 else {
8363 fprintf(stderr, "appsession_task_init failed\n");
8364 return -1;
8365 }
8366 initialized ++;
8367 }
8368 return 0;
8369}
8370
8371static int appsession_task_init(void)
8372{
8373 static int initialized = 0;
8374 struct task *t;
8375 if (!initialized) {
8376 if ((t = pool_alloc(task)) == NULL)
8377 return -1;
8378 t->next = t->prev = t->rqnext = NULL;
8379 t->wq = LIST_HEAD(wait_queue);
8380 t->state = TASK_IDLE;
8381 t->context = NULL;
8382 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8383 task_queue(t);
8384 t->process = appsession_refresh;
8385 initialized ++;
8386 }
8387 return 0;
8388}
8389
8390static int appsession_refresh(struct task *t) {
8391 struct proxy *p = proxy;
8392 CHTbl *htbl;
8393 ListElmt *element, *last;
8394 int i;
8395 appsess *asession;
8396 void *data;
8397
8398 while (p) {
8399 if (p->appsession_name != NULL) {
8400 htbl = &p->htbl_proxy;
8401 /* if we ever give up the use of TBLSIZ, we need to change this */
8402 for (i = 0; i < TBLSIZ; i++) {
8403 last = NULL;
8404 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8405 asession = (appsess *)list_data(element);
8406 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8407 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8408 int len;
8409 /*
8410 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8411 */
8412 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8413 asession->sessid, asession->serverid?asession->serverid:"(null)");
8414 write(1, trash, len);
8415 }
8416 /* delete the expired element from within the hash table */
8417 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8418 && (htbl->table[i].destroy != NULL)) {
8419 htbl->table[i].destroy(data);
8420 }
8421 if (last == NULL) {/* patient lost his head, get a new one */
8422 element = list_head(&htbl->table[i]);
8423 if (element == NULL) break; /* no heads left, go to next patient */
8424 }
8425 else
8426 element = last;
8427 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8428 else
8429 last = element;
8430 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8431 }
8432 }
8433 p = p->next;
8434 }
8435 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8436 return TBLCHKINT;
8437} /* end appsession_refresh */
8438