blob: 723c15fbbed8afa7af30b1086176a8ef5b40e79e [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 tarreau0174f312005-12-18 01:02:42 +01003 * 2000-2005 - 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 tarreaub952e1d2005-12-18 01:31:20 +010086#define HAPROXY_VERSION "1.2.7rc"
87#define HAPROXY_DATE "2005/10/09"
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
287#define PR_STDISABLED 3
288
willy tarreau5cbea6f2005-12-17 12:48:26 +0100289/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100290#define PR_MODE_TCP 0
291#define PR_MODE_HTTP 1
292#define PR_MODE_HEALTH 2
293
willy tarreau1c2ad212005-12-18 01:11:29 +0100294/* possible actions for the *poll() loops */
295#define POLL_LOOP_ACTION_INIT 0
296#define POLL_LOOP_ACTION_RUN 1
297#define POLL_LOOP_ACTION_CLEAN 2
298
willy tarreau64a3cc32005-12-18 01:13:11 +0100299/* poll mechanisms available */
300#define POLL_USE_SELECT (1<<0)
301#define POLL_USE_POLL (1<<1)
302#define POLL_USE_EPOLL (1<<2)
303
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100305#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
306#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
307#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
308#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
309#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
310#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
311#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
312#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100313#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100314#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
315#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
316#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
317#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
318#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
319#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
320#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
321#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
322#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
323#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
324#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100325#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
326#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100327
willy tarreaue39cd132005-12-17 13:00:18 +0100328/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100329#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
330#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
331#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
332#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
333#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
334#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100335#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100336
337#define SN_CK_NONE 0x00000000 /* this session had no cookie */
338#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
339#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
340#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
341#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
342#define SN_CK_SHIFT 6 /* bit shift */
343
willy tarreaub1285d52005-12-18 01:20:14 +0100344#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100345#define SN_ERR_CLITO 0x00000100 /* client time-out */
346#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
347#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
348#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
349#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100350#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
351#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100352#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
353#define SN_ERR_SHIFT 8 /* bit shift */
354
355#define SN_FINST_R 0x00001000 /* session ended during client request */
356#define SN_FINST_C 0x00002000 /* session ended during server connect */
357#define SN_FINST_H 0x00003000 /* session ended during server headers */
358#define SN_FINST_D 0x00004000 /* session ended during data phase */
359#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
360#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
361#define SN_FINST_SHIFT 12 /* bit shift */
362
363#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
364#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
365#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
366#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
367#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100368#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100369#define SN_SCK_SHIFT 16 /* bit shift */
370
willy tarreau97f58572005-12-18 00:53:44 +0100371#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
372#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
373#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100374
375/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100376#define CL_STHEADERS 0
377#define CL_STDATA 1
378#define CL_STSHUTR 2
379#define CL_STSHUTW 3
380#define CL_STCLOSE 4
381
willy tarreau5cbea6f2005-12-17 12:48:26 +0100382/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100383#define SV_STIDLE 0
384#define SV_STCONN 1
385#define SV_STHEADERS 2
386#define SV_STDATA 3
387#define SV_STSHUTR 4
388#define SV_STSHUTW 5
389#define SV_STCLOSE 6
390
391/* result of an I/O event */
392#define RES_SILENT 0 /* didn't happen */
393#define RES_DATA 1 /* data were sent or received */
394#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
395#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
396
willy tarreau9fe663a2005-12-17 13:02:59 +0100397/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100398#define MODE_DEBUG 1
399#define MODE_STATS 2
400#define MODE_LOG 4
401#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100402#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100403#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100404#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100405
406/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100407#define SRV_RUNNING 1 /* the server is UP */
408#define SRV_BACKUP 2 /* this server is a backup server */
409#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100410#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100411
willy tarreaue39cd132005-12-17 13:00:18 +0100412/* what to do when a header matches a regex */
413#define ACT_ALLOW 0 /* allow the request */
414#define ACT_REPLACE 1 /* replace the matching header */
415#define ACT_REMOVE 2 /* remove the matching header */
416#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100417#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100418
willy tarreau9fe663a2005-12-17 13:02:59 +0100419/* configuration sections */
420#define CFG_NONE 0
421#define CFG_GLOBAL 1
422#define CFG_LISTEN 2
423
willy tarreaua1598082005-12-17 13:08:06 +0100424/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100425#define LW_DATE 1 /* date */
426#define LW_CLIP 2 /* CLient IP */
427#define LW_SVIP 4 /* SerVer IP */
428#define LW_SVID 8 /* server ID */
429#define LW_REQ 16 /* http REQuest */
430#define LW_RESP 32 /* http RESPonse */
431#define LW_PXIP 64 /* proxy IP */
432#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100433#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100434#define LW_COOKIE 512 /* captured cookie */
435#define LW_REQHDR 1024 /* request header(s) */
436#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100437
willy tarreau0f7af912005-12-17 12:21:26 +0100438/*********************************************************************/
439
440#define LIST_HEAD(a) ((void *)(&(a)))
441
442/*********************************************************************/
443
willy tarreau4302f492005-12-18 01:00:37 +0100444struct cap_hdr {
445 struct cap_hdr *next;
446 char *name; /* header name, case insensitive */
447 int namelen; /* length of the header name, to speed-up lookups */
448 int len; /* capture length, not including terminal zero */
449 int index; /* index in the output array */
450 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
451};
452
willy tarreau0f7af912005-12-17 12:21:26 +0100453struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100454 struct hdr_exp *next;
455 regex_t *preg; /* expression to look for */
456 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
457 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100458};
459
460struct buffer {
461 unsigned int l; /* data length */
462 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100463 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100464 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100465 char data[BUFSIZE];
466};
467
468struct server {
469 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100470 int state; /* server state (SRV_*) */
471 int cklen; /* the len of the cookie, to speed up checks */
472 char *cookie; /* the id set in the cookie */
473 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100474 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100475 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100476 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100478 int rise, fall; /* time in iterations */
479 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100480 int result; /* 0 = connect OK, -1 = connect KO */
481 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100482 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100483};
484
willy tarreau5cbea6f2005-12-17 12:48:26 +0100485/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100486struct task {
487 struct task *next, *prev; /* chaining ... */
488 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100489 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100490 int state; /* task state : IDLE or RUNNING */
491 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100492 int (*process)(struct task *t); /* the function which processes the task */
493 void *context; /* the task's context */
494};
495
496/* WARNING: if new fields are added, they must be initialized in event_accept() */
497struct session {
498 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100499 /* application specific below */
500 struct timeval crexpire; /* expiration date for a client read */
501 struct timeval cwexpire; /* expiration date for a client write */
502 struct timeval srexpire; /* expiration date for a server read */
503 struct timeval swexpire; /* expiration date for a server write */
504 struct timeval cnexpire; /* expiration date for a connect */
505 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
506 struct proxy *proxy; /* the proxy this socket belongs to */
507 int cli_fd; /* the client side fd */
508 int srv_fd; /* the server side fd */
509 int cli_state; /* state of the client side */
510 int srv_state; /* state of the server side */
511 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100513 struct buffer *req; /* request buffer */
514 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100515 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100516 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100517 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100518 char **req_cap; /* array of captured request headers (may be NULL) */
519 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100520 struct {
521 int logwait; /* log fields waiting to be collected : LW_* */
522 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
523 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
524 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
525 long t_data; /* delay before the first data byte from the server ... */
526 unsigned long t_close; /* total session duration */
527 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100528 char *cli_cookie; /* cookie presented by the client, in capture mode */
529 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100530 int status; /* HTTP status from the server, negative if from proxy */
531 long long bytes; /* number of bytes transferred from the server */
532 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100533 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100534};
535
willy tarreaua41a8b42005-12-17 14:02:24 +0100536struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100537 int fd; /* the listen socket */
538 struct sockaddr_storage addr; /* the address we listen to */
539 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100540};
541
542
willy tarreau0f7af912005-12-17 12:21:26 +0100543struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100544 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100545 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 +0100546 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100547 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100548 struct server *srv, *cursrv; /* known servers, current server */
549 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100550 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100551 int cookie_len; /* strlen(cookie_name), computed only once */
552 char *appsession_name; /* name of the cookie to look for */
553 int appsession_name_len; /* strlen(appsession_name), computed only once */
554 int appsession_len; /* length of the appsession cookie value to be used */
555 int appsession_timeout;
556 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100557 char *capture_name; /* beginning of the name of the cookie to capture */
558 int capture_namelen; /* length of the cookie name to match */
559 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100560 int clitimeout; /* client I/O timeout (in milliseconds) */
561 int srvtimeout; /* server I/O timeout (in milliseconds) */
562 int contimeout; /* connect timeout (in milliseconds) */
563 char *id; /* proxy id */
564 int nbconn; /* # of active sessions */
565 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100566 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100567 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100568 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100569 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100570 struct proxy *next;
571 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100572 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100573 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100574 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100575 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100576 int nb_reqadd, nb_rspadd;
577 struct hdr_exp *req_exp; /* regular expressions for request headers */
578 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100579 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
580 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
581 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
582 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100583 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100584 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100585 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
586 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100587 struct {
588 char *msg400; /* message for error 400 */
589 int len400; /* message length for error 400 */
590 char *msg403; /* message for error 403 */
591 int len403; /* message length for error 403 */
592 char *msg408; /* message for error 408 */
593 int len408; /* message length for error 408 */
594 char *msg500; /* message for error 500 */
595 int len500; /* message length for error 500 */
596 char *msg502; /* message for error 502 */
597 int len502; /* message length for error 502 */
598 char *msg503; /* message for error 503 */
599 int len503; /* message length for error 503 */
600 char *msg504; /* message for error 504 */
601 int len504; /* message length for error 504 */
602 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100603};
604
605/* info about one given fd */
606struct fdtab {
607 int (*read)(int fd); /* read function */
608 int (*write)(int fd); /* write function */
609 struct task *owner; /* the session (or proxy) associated with this fd */
610 int state; /* the state of this fd */
611};
612
613/*********************************************************************/
614
willy tarreaub952e1d2005-12-18 01:31:20 +0100615int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100616char *cfg_cfgfile = NULL; /* configuration file */
617char *progname = NULL; /* program name */
618int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100619
620/* global options */
621static struct {
622 int uid;
623 int gid;
624 int nbproc;
625 int maxconn;
626 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100627 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100628 int mode;
629 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100630 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100631 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100632 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100633 struct sockaddr_in logsrv1, logsrv2;
634} global = {
635 logfac1 : -1,
636 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100637 loglev1 : 7, /* max syslog level : debug */
638 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100639 /* others NULL OK */
640};
641
willy tarreau0f7af912005-12-17 12:21:26 +0100642/*********************************************************************/
643
willy tarreau1c2ad212005-12-18 01:11:29 +0100644fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100645 *StaticWriteEvent;
646
willy tarreau64a3cc32005-12-18 01:13:11 +0100647int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100648
willy tarreau0f7af912005-12-17 12:21:26 +0100649void **pool_session = NULL,
650 **pool_buffer = NULL,
651 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100652 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100653 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100654 **pool_capture = NULL,
655 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100656
657struct proxy *proxy = NULL; /* list of all existing proxies */
658struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100659struct task *rq = NULL; /* global run queue */
660struct task wait_queue = { /* global wait queue */
661 prev:LIST_HEAD(wait_queue),
662 next:LIST_HEAD(wait_queue)
663};
willy tarreau0f7af912005-12-17 12:21:26 +0100664
willy tarreau0f7af912005-12-17 12:21:26 +0100665static int totalconn = 0; /* total # of terminated sessions */
666static int actconn = 0; /* # of active sessions */
667static int maxfd = 0; /* # of the highest fd + 1 */
668static int listeners = 0; /* # of listeners */
669static int stopping = 0; /* non zero means stopping in progress */
670static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100671static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100672
willy tarreau08dedbe2005-12-18 01:13:48 +0100673#if defined(ENABLE_EPOLL)
674/* FIXME: this is dirty, but at the moment, there's no other solution to remove
675 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
676 * structure with pointers to functions such as init_fd() and close_fd(), plus
677 * a private structure with several pointers to places such as below.
678 */
679
680static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
681#endif
682
willy tarreau0f7af912005-12-17 12:21:26 +0100683static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100684/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100685static char trash[BUFSIZE];
686
willy tarreaudd07e972005-12-18 00:48:48 +0100687const int zero = 0;
688const int one = 1;
689
willy tarreau0f7af912005-12-17 12:21:26 +0100690/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100691 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100692 */
693
694#define MAX_SYSLOG_LEN 1024
695#define NB_LOG_FACILITIES 24
696const char *log_facilities[NB_LOG_FACILITIES] = {
697 "kern", "user", "mail", "daemon",
698 "auth", "syslog", "lpr", "news",
699 "uucp", "cron", "auth2", "ftp",
700 "ntp", "audit", "alert", "cron2",
701 "local0", "local1", "local2", "local3",
702 "local4", "local5", "local6", "local7"
703};
704
705
706#define NB_LOG_LEVELS 8
707const char *log_levels[NB_LOG_LEVELS] = {
708 "emerg", "alert", "crit", "err",
709 "warning", "notice", "info", "debug"
710};
711
712#define SYSLOG_PORT 514
713
714const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
715 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100716
willy tarreaub1285d52005-12-18 01:20:14 +0100717const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100718const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
719const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
720const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
721 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
722 unknown, Set-cookie Rewritten */
723
willy tarreau0f7af912005-12-17 12:21:26 +0100724#define MAX_HOSTNAME_LEN 32
725static char hostname[MAX_HOSTNAME_LEN] = "";
726
willy tarreau8337c6b2005-12-17 13:41:01 +0100727const char *HTTP_302 =
728 "HTTP/1.0 302 Found\r\n"
729 "Cache-Control: no-cache\r\n"
730 "Connection: close\r\n"
731 "Location: "; /* not terminated since it will be concatenated with the URL */
732
willy tarreauc1f47532005-12-18 01:08:26 +0100733/* same as 302 except that the browser MUST retry with the GET method */
734const char *HTTP_303 =
735 "HTTP/1.0 303 See Other\r\n"
736 "Cache-Control: no-cache\r\n"
737 "Connection: close\r\n"
738 "Location: "; /* not terminated since it will be concatenated with the URL */
739
willy tarreaua1598082005-12-17 13:08:06 +0100740const char *HTTP_400 =
741 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100742 "Cache-Control: no-cache\r\n"
743 "Connection: close\r\n"
744 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100745 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100746
willy tarreaua1598082005-12-17 13:08:06 +0100747const char *HTTP_403 =
748 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100749 "Cache-Control: no-cache\r\n"
750 "Connection: close\r\n"
751 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100752 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
753
willy tarreau8337c6b2005-12-17 13:41:01 +0100754const char *HTTP_408 =
755 "HTTP/1.0 408 Request Time-out\r\n"
756 "Cache-Control: no-cache\r\n"
757 "Connection: close\r\n"
758 "\r\n"
759 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
760
willy tarreau750a4722005-12-17 13:21:24 +0100761const char *HTTP_500 =
762 "HTTP/1.0 500 Server Error\r\n"
763 "Cache-Control: no-cache\r\n"
764 "Connection: close\r\n"
765 "\r\n"
766 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100767
768const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100769 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100770 "Cache-Control: no-cache\r\n"
771 "Connection: close\r\n"
772 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100773 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
774
775const char *HTTP_503 =
776 "HTTP/1.0 503 Service Unavailable\r\n"
777 "Cache-Control: no-cache\r\n"
778 "Connection: close\r\n"
779 "\r\n"
780 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
781
782const char *HTTP_504 =
783 "HTTP/1.0 504 Gateway Time-out\r\n"
784 "Cache-Control: no-cache\r\n"
785 "Connection: close\r\n"
786 "\r\n"
787 "<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 +0100788
willy tarreau0f7af912005-12-17 12:21:26 +0100789/*********************************************************************/
790/* statistics ******************************************************/
791/*********************************************************************/
792
willy tarreau750a4722005-12-17 13:21:24 +0100793#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100794static int stats_tsk_lsrch, stats_tsk_rsrch,
795 stats_tsk_good, stats_tsk_right, stats_tsk_left,
796 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100797#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100798
799
800/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100801/* debugging *******************************************************/
802/*********************************************************************/
803#ifdef DEBUG_FULL
804static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
805static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
806#endif
807
808/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100809/* function prototypes *********************************************/
810/*********************************************************************/
811
812int event_accept(int fd);
813int event_cli_read(int fd);
814int event_cli_write(int fd);
815int event_srv_read(int fd);
816int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100817int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100818
willy tarreau12350152005-12-18 01:03:27 +0100819static int appsession_task_init(void);
820static int appsession_init(void);
821static int appsession_refresh(struct task *t);
822
willy tarreau0f7af912005-12-17 12:21:26 +0100823/*********************************************************************/
824/* general purpose functions ***************************************/
825/*********************************************************************/
826
827void display_version() {
828 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100829 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100830}
831
832/*
833 * This function prints the command line usage and exits
834 */
835void usage(char *name) {
836 display_version();
837 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100838 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100839#if STATTIME > 0
840 "sl"
841#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100842 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100843 " -v displays version\n"
844 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100845 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100846#if STATTIME > 0
847 " -s enables statistics output\n"
848 " -l enables long statistics format\n"
849#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100850 " -D goes daemon ; implies -q\n"
851 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100852 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100853 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100854 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100855 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100856#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100857 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100858#endif
859#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100860 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100861#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100862 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100863 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100864 exit(1);
865}
866
867
868/*
869 * Displays the message on stderr with the date and pid.
870 */
871void Alert(char *fmt, ...) {
872 va_list argp;
873 struct timeval tv;
874 struct tm *tm;
875
willy tarreau982249e2005-12-18 00:57:06 +0100876 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100877 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100878
willy tarreau5cbea6f2005-12-17 12:48:26 +0100879 gettimeofday(&tv, NULL);
880 tm=localtime(&tv.tv_sec);
881 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100882 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100883 vfprintf(stderr, fmt, argp);
884 fflush(stderr);
885 va_end(argp);
886 }
willy tarreau0f7af912005-12-17 12:21:26 +0100887}
888
889
890/*
891 * Displays the message on stderr with the date and pid.
892 */
893void Warning(char *fmt, ...) {
894 va_list argp;
895 struct timeval tv;
896 struct tm *tm;
897
willy tarreau982249e2005-12-18 00:57:06 +0100898 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100899 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100900
willy tarreau5cbea6f2005-12-17 12:48:26 +0100901 gettimeofday(&tv, NULL);
902 tm=localtime(&tv.tv_sec);
903 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100904 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100905 vfprintf(stderr, fmt, argp);
906 fflush(stderr);
907 va_end(argp);
908 }
909}
910
911/*
912 * Displays the message on <out> only if quiet mode is not set.
913 */
914void qfprintf(FILE *out, char *fmt, ...) {
915 va_list argp;
916
willy tarreau982249e2005-12-18 00:57:06 +0100917 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100918 va_start(argp, fmt);
919 vfprintf(out, fmt, argp);
920 fflush(out);
921 va_end(argp);
922 }
willy tarreau0f7af912005-12-17 12:21:26 +0100923}
924
925
926/*
927 * converts <str> to a struct sockaddr_in* which is locally allocated.
928 * The format is "addr:port", where "addr" can be empty or "*" to indicate
929 * INADDR_ANY.
930 */
931struct sockaddr_in *str2sa(char *str) {
932 static struct sockaddr_in sa;
933 char *c;
934 int port;
935
willy tarreaua1598082005-12-17 13:08:06 +0100936 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100937 str=strdup(str);
938
939 if ((c=strrchr(str,':')) != NULL) {
940 *c++=0;
941 port=atol(c);
942 }
943 else
944 port=0;
945
946 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
947 sa.sin_addr.s_addr = INADDR_ANY;
948 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100949 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100950 struct hostent *he;
951
952 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100953 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100954 }
955 else
956 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
957 }
958 sa.sin_port=htons(port);
959 sa.sin_family=AF_INET;
960
961 free(str);
962 return &sa;
963}
964
willy tarreaub1285d52005-12-18 01:20:14 +0100965/*
966 * converts <str> to a two struct in_addr* which are locally allocated.
967 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
968 * is optionnal and either in the dotted or CIDR notation.
969 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
970 */
971int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
972 char *c;
973 unsigned long len;
974
975 memset(mask, 0, sizeof(*mask));
976 memset(addr, 0, sizeof(*addr));
977 str=strdup(str);
978
979 if ((c = strrchr(str, '/')) != NULL) {
980 *c++ = 0;
981 /* c points to the mask */
982 if (strchr(c, '.') != NULL) { /* dotted notation */
983 if (!inet_pton(AF_INET, c, mask))
984 return 0;
985 }
986 else { /* mask length */
987 char *err;
988 len = strtol(c, &err, 10);
989 if (!*c || (err && *err) || (unsigned)len > 32)
990 return 0;
991 if (len)
992 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
993 else
994 mask->s_addr = 0;
995 }
996 }
997 else {
998 mask->s_addr = 0xFFFFFFFF;
999 }
1000 if (!inet_pton(AF_INET, str, addr)) {
1001 struct hostent *he;
1002
1003 if ((he = gethostbyname(str)) == NULL) {
1004 return 0;
1005 }
1006 else
1007 *addr = *(struct in_addr *) *(he->h_addr_list);
1008 }
1009 free(str);
1010 return 1;
1011}
1012
willy tarreau9fe663a2005-12-17 13:02:59 +01001013
1014/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001015 * converts <str> to a list of listeners which are dynamically allocated.
1016 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1017 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1018 * - <port> is a numerical port from 1 to 65535 ;
1019 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1020 * This can be repeated as many times as necessary, separated by a coma.
1021 * The <tail> argument is a pointer to a current list which should be appended
1022 * to the tail of the new list. The pointer to the new list is returned.
1023 */
1024struct listener *str2listener(char *str, struct listener *tail) {
1025 struct listener *l;
1026 char *c, *next, *range, *dupstr;
1027 int port, end;
1028
1029 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001030
willy tarreaua41a8b42005-12-17 14:02:24 +01001031 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001032 struct sockaddr_storage ss;
1033
willy tarreaua41a8b42005-12-17 14:02:24 +01001034 str = next;
1035 /* 1) look for the end of the first address */
1036 if ((next = strrchr(str, ',')) != NULL) {
1037 *next++ = 0;
1038 }
1039
willy tarreau8a86dbf2005-12-18 00:45:59 +01001040 /* 2) look for the addr/port delimiter, it's the last colon. */
1041 if ((range = strrchr(str, ':')) == NULL) {
1042 Alert("Missing port number: '%s'\n", str);
1043 }
1044
1045 *range++ = 0;
1046
1047 if (strrchr(str, ':') != NULL) {
1048 /* IPv6 address contains ':' */
1049 memset(&ss, 0, sizeof(ss));
1050 ss.ss_family = AF_INET6;
1051
1052 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1053 Alert("Invalid server address: '%s'\n", str);
1054 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001055 }
1056 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001057 memset(&ss, 0, sizeof(ss));
1058 ss.ss_family = AF_INET;
1059
1060 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1061 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1062 }
1063 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1064 struct hostent *he;
1065
1066 if ((he = gethostbyname(str)) == NULL) {
1067 Alert("Invalid server name: '%s'\n", str);
1068 }
1069 else
1070 ((struct sockaddr_in *)&ss)->sin_addr =
1071 *(struct in_addr *) *(he->h_addr_list);
1072 }
1073 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001074
1075 /* 3) look for the port-end delimiter */
1076 if ((c = strchr(range, '-')) != NULL) {
1077 *c++ = 0;
1078 end = atol(c);
1079 }
1080 else {
1081 end = atol(range);
1082 }
1083
1084 for (port = atol(range); port <= end; port++) {
1085 l = (struct listener *)calloc(1, sizeof(struct listener));
1086 l->next = tail;
1087 tail = l;
1088
willy tarreau8a86dbf2005-12-18 00:45:59 +01001089 l->addr = ss;
1090 if (ss.ss_family == AF_INET6)
1091 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1092 else
1093 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1094
willy tarreaua41a8b42005-12-17 14:02:24 +01001095 } /* end for(port) */
1096 } /* end while(next) */
1097 free(dupstr);
1098 return tail;
1099}
1100
willy tarreau4302f492005-12-18 01:00:37 +01001101
1102#define FD_SETS_ARE_BITFIELDS
1103#ifdef FD_SETS_ARE_BITFIELDS
1104/*
1105 * This map is used with all the FD_* macros to check whether a particular bit
1106 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1107 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1108 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1109 * exclusively to the macros.
1110 */
1111fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1112fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1113
1114#else
1115#error "Check if your OS uses bitfields for fd_sets"
1116#endif
1117
1118/* will try to encode the string <string> replacing all characters tagged in
1119 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1120 * prefixed by <escape>, and will store the result between <start> (included
1121 *) and <stop> (excluded), and will always terminate the string with a '\0'
1122 * before <stop>. The position of the '\0' is returned if the conversion
1123 * completes. If bytes are missing between <start> and <stop>, then the
1124 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1125 * cannot even be stored so we return <start> without writing the 0.
1126 * The input string must also be zero-terminated.
1127 */
1128char hextab[16] = "0123456789ABCDEF";
1129char *encode_string(char *start, char *stop,
1130 const char escape, const fd_set *map,
1131 const char *string)
1132{
1133 if (start < stop) {
1134 stop--; /* reserve one byte for the final '\0' */
1135 while (start < stop && *string != 0) {
1136 if (!FD_ISSET((unsigned char)(*string), map))
1137 *start++ = *string;
1138 else {
1139 if (start + 3 >= stop)
1140 break;
1141 *start++ = escape;
1142 *start++ = hextab[(*string >> 4) & 15];
1143 *start++ = hextab[*string & 15];
1144 }
1145 string++;
1146 }
1147 *start = '\0';
1148 }
1149 return start;
1150}
willy tarreaua41a8b42005-12-17 14:02:24 +01001151
1152/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001153 * This function sends a syslog message to both log servers of a proxy,
1154 * or to global log servers if the proxy is NULL.
1155 * It also tries not to waste too much time computing the message header.
1156 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001157 */
1158void send_log(struct proxy *p, int level, char *message, ...) {
1159 static int logfd = -1; /* syslog UDP socket */
1160 static long tvsec = -1; /* to force the string to be initialized */
1161 struct timeval tv;
1162 va_list argp;
1163 static char logmsg[MAX_SYSLOG_LEN];
1164 static char *dataptr = NULL;
1165 int fac_level;
1166 int hdr_len, data_len;
1167 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001168 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001169 int nbloggers = 0;
1170 char *log_ptr;
1171
1172 if (logfd < 0) {
1173 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1174 return;
1175 }
1176
1177 if (level < 0 || progname == NULL || message == NULL)
1178 return;
1179
1180 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001181 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001182 /* this string is rebuild only once a second */
1183 struct tm *tm = localtime(&tv.tv_sec);
1184 tvsec = tv.tv_sec;
1185
willy tarreauc29948c2005-12-17 13:10:27 +01001186 hdr_len = snprintf(logmsg, sizeof(logmsg),
1187 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1188 monthname[tm->tm_mon],
1189 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1190 progname, pid);
1191 /* WARNING: depending upon implementations, snprintf may return
1192 * either -1 or the number of bytes that would be needed to store
1193 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001194 */
willy tarreauc29948c2005-12-17 13:10:27 +01001195 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1196 hdr_len = sizeof(logmsg);
1197
1198 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001199 }
1200
1201 va_start(argp, message);
1202 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001203 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1204 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001205 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001206 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001207
1208 if (p == NULL) {
1209 if (global.logfac1 >= 0) {
1210 sa[nbloggers] = &global.logsrv1;
1211 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001212 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001213 nbloggers++;
1214 }
1215 if (global.logfac2 >= 0) {
1216 sa[nbloggers] = &global.logsrv2;
1217 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001218 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001219 nbloggers++;
1220 }
1221 } else {
1222 if (p->logfac1 >= 0) {
1223 sa[nbloggers] = &p->logsrv1;
1224 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001225 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001226 nbloggers++;
1227 }
1228 if (p->logfac2 >= 0) {
1229 sa[nbloggers] = &p->logsrv2;
1230 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001231 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001232 nbloggers++;
1233 }
1234 }
1235
1236 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001237 /* we can filter the level of the messages that are sent to each logger */
1238 if (level > loglevel[nbloggers])
1239 continue;
1240
willy tarreauc29948c2005-12-17 13:10:27 +01001241 /* For each target, we may have a different facility.
1242 * We can also have a different log level for each message.
1243 * This induces variations in the message header length.
1244 * Since we don't want to recompute it each time, nor copy it every
1245 * time, we only change the facility in the pre-computed header,
1246 * and we change the pointer to the header accordingly.
1247 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001248 fac_level = (facilities[nbloggers] << 3) + level;
1249 log_ptr = logmsg + 3; /* last digit of the log level */
1250 do {
1251 *log_ptr = '0' + fac_level % 10;
1252 fac_level /= 10;
1253 log_ptr--;
1254 } while (fac_level && log_ptr > logmsg);
1255 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001256
willy tarreauc29948c2005-12-17 13:10:27 +01001257 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001258
1259#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001260 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001261 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1262#else
willy tarreauc29948c2005-12-17 13:10:27 +01001263 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001264 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1265#endif
1266 }
willy tarreau0f7af912005-12-17 12:21:26 +01001267}
1268
1269
1270/* sets <tv> to the current time */
1271static inline struct timeval *tv_now(struct timeval *tv) {
1272 if (tv)
1273 gettimeofday(tv, NULL);
1274 return tv;
1275}
1276
1277/*
1278 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1279 */
1280static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1281 if (!tv || !from)
1282 return NULL;
1283 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1284 tv->tv_sec = from->tv_sec + (ms/1000);
1285 while (tv->tv_usec >= 1000000) {
1286 tv->tv_usec -= 1000000;
1287 tv->tv_sec++;
1288 }
1289 return tv;
1290}
1291
1292/*
1293 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001294 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001295 */
1296static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001297 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001298 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001299 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001300 return 1;
1301 else if (tv1->tv_usec < tv2->tv_usec)
1302 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001303 else if (tv1->tv_usec > tv2->tv_usec)
1304 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001305 else
1306 return 0;
1307}
1308
1309/*
1310 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001311 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001312 */
1313unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1314 int cmp;
1315 unsigned long ret;
1316
1317
willy tarreauef900ab2005-12-17 12:52:52 +01001318 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001319 if (!cmp)
1320 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001321 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001322 struct timeval *tmp = tv1;
1323 tv1 = tv2;
1324 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001325 }
willy tarreauef900ab2005-12-17 12:52:52 +01001326 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001327 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001328 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001329 else
willy tarreauef900ab2005-12-17 12:52:52 +01001330 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001331 return (unsigned long) ret;
1332}
1333
1334/*
willy tarreau750a4722005-12-17 13:21:24 +01001335 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001336 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001337 */
1338static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1339 unsigned long ret;
1340
willy tarreau6e682ce2005-12-17 13:26:49 +01001341 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1342 if (tv2->tv_usec > tv1->tv_usec)
1343 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001344 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001345 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001346 return (unsigned long) ret;
1347}
1348
1349/*
willy tarreau0f7af912005-12-17 12:21:26 +01001350 * 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 +01001351 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001352 */
1353static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001354 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001355 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001356 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001357 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1358 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001359 else
1360 return 0;
1361 }
willy tarreau0f7af912005-12-17 12:21:26 +01001362 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001363 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001364 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001365 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1366 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1367 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 else
1369 return 0;
1370}
1371
1372/*
1373 * returns the remaining time between tv1=now and event=tv2
1374 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001375 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001376 */
1377static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1378 unsigned long ret;
1379
willy tarreau0f7af912005-12-17 12:21:26 +01001380 if (tv_cmp_ms(tv1, tv2) >= 0)
1381 return 0; /* event elapsed */
1382
willy tarreauef900ab2005-12-17 12:52:52 +01001383 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001384 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001385 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001386 else
willy tarreauef900ab2005-12-17 12:52:52 +01001387 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001388 return (unsigned long) ret;
1389}
1390
1391
1392/*
1393 * zeroes a struct timeval
1394 */
1395
1396static inline struct timeval *tv_eternity(struct timeval *tv) {
1397 tv->tv_sec = tv->tv_usec = 0;
1398 return tv;
1399}
1400
1401/*
1402 * returns 1 if tv is null, else 0
1403 */
1404static inline int tv_iseternity(struct timeval *tv) {
1405 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1406 return 1;
1407 else
1408 return 0;
1409}
1410
1411/*
1412 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1413 * considering that 0 is the eternity.
1414 */
1415static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1416 if (tv_iseternity(tv1))
1417 if (tv_iseternity(tv2))
1418 return 0; /* same */
1419 else
1420 return 1; /* tv1 later than tv2 */
1421 else if (tv_iseternity(tv2))
1422 return -1; /* tv2 later than tv1 */
1423
1424 if (tv1->tv_sec > tv2->tv_sec)
1425 return 1;
1426 else if (tv1->tv_sec < tv2->tv_sec)
1427 return -1;
1428 else if (tv1->tv_usec > tv2->tv_usec)
1429 return 1;
1430 else if (tv1->tv_usec < tv2->tv_usec)
1431 return -1;
1432 else
1433 return 0;
1434}
1435
1436/*
1437 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1438 * considering that 0 is the eternity.
1439 */
1440static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1441 if (tv_iseternity(tv1))
1442 if (tv_iseternity(tv2))
1443 return 0; /* same */
1444 else
1445 return 1; /* tv1 later than tv2 */
1446 else if (tv_iseternity(tv2))
1447 return -1; /* tv2 later than tv1 */
1448
willy tarreauefae1842005-12-17 12:51:03 +01001449 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001450 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001451 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001452 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001453 return -1;
1454 else
1455 return 0;
1456 }
1457 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001458 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001459 return 1;
1460 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001461 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001462 return -1;
1463 else
1464 return 0;
1465}
1466
1467/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001468 * returns the remaining time between tv1=now and event=tv2
1469 * if tv2 is passed, 0 is returned.
1470 * Returns TIME_ETERNITY if tv2 is eternity.
1471 */
1472static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1473 unsigned long ret;
1474
1475 if (tv_iseternity(tv2))
1476 return TIME_ETERNITY;
1477
1478 if (tv_cmp_ms(tv1, tv2) >= 0)
1479 return 0; /* event elapsed */
1480
1481 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1482 if (tv2->tv_usec > tv1->tv_usec)
1483 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1484 else
1485 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1486 return (unsigned long) ret;
1487}
1488
1489/*
willy tarreau0f7af912005-12-17 12:21:26 +01001490 * returns the first event between tv1 and tv2 into tvmin.
1491 * a zero tv is ignored. tvmin is returned.
1492 */
1493static inline struct timeval *tv_min(struct timeval *tvmin,
1494 struct timeval *tv1, struct timeval *tv2) {
1495
1496 if (tv_cmp2(tv1, tv2) <= 0)
1497 *tvmin = *tv1;
1498 else
1499 *tvmin = *tv2;
1500
1501 return tvmin;
1502}
1503
1504
1505
1506/***********************************************************/
1507/* fd management ***************************************/
1508/***********************************************************/
1509
1510
1511
willy tarreau5cbea6f2005-12-17 12:48:26 +01001512/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1513 * The file descriptor is also closed.
1514 */
willy tarreau0f7af912005-12-17 12:21:26 +01001515static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001516 FD_CLR(fd, StaticReadEvent);
1517 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001518#if defined(ENABLE_EPOLL)
1519 if (PrevReadEvent) {
1520 FD_CLR(fd, PrevReadEvent);
1521 FD_CLR(fd, PrevWriteEvent);
1522 }
1523#endif
1524
willy tarreau5cbea6f2005-12-17 12:48:26 +01001525 close(fd);
1526 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001527
1528 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1529 maxfd--;
1530}
1531
1532/* recomputes the maxfd limit from the fd */
1533static inline void fd_insert(int fd) {
1534 if (fd+1 > maxfd)
1535 maxfd = fd+1;
1536}
1537
1538/*************************************************************/
1539/* task management ***************************************/
1540/*************************************************************/
1541
willy tarreau5cbea6f2005-12-17 12:48:26 +01001542/* puts the task <t> in run queue <q>, and returns <t> */
1543static inline struct task *task_wakeup(struct task **q, struct task *t) {
1544 if (t->state == TASK_RUNNING)
1545 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001546 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 t->rqnext = *q;
1548 t->state = TASK_RUNNING;
1549 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001550 }
1551}
1552
willy tarreau5cbea6f2005-12-17 12:48:26 +01001553/* removes the task <t> from the queue <q>
1554 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001555 * set the run queue to point to the next one, and return it
1556 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001557static inline struct task *task_sleep(struct task **q, struct task *t) {
1558 if (t->state == TASK_RUNNING) {
1559 *q = t->rqnext;
1560 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001561 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001563}
1564
1565/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001566 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001567 * from the run queue. A pointer to the task itself is returned.
1568 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001569static inline struct task *task_delete(struct task *t) {
1570 t->prev->next = t->next;
1571 t->next->prev = t->prev;
1572 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001573}
1574
1575/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001577 */
1578static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001579 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001580}
1581
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001583 * may be only moved or left where it was, depending on its timing requirements.
1584 * <task> is returned.
1585 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586struct task *task_queue(struct task *task) {
1587 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001588 struct task *start_from;
1589
1590 /* first, test if the task was already in a list */
1591 if (task->prev == NULL) {
1592 // start_from = list;
1593 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001594#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001595 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001596#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001597 /* insert the unlinked <task> into the list, searching back from the last entry */
1598 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1599 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001600#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001601 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001602#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001603 }
1604
1605 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1606 // start_from = start_from->next;
1607 // stats_tsk_nsrch++;
1608 // }
1609 }
1610 else if (task->prev == list ||
1611 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1612 start_from = task->next;
1613 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001614#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001615 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001616#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001617 return task; /* it's already in the right place */
1618 }
1619
willy tarreau750a4722005-12-17 13:21:24 +01001620#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001621 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001622#endif
1623
1624 /* if the task is not at the right place, there's little chance that
1625 * it has only shifted a bit, and it will nearly always be queued
1626 * at the end of the list because of constant timeouts
1627 * (observed in real case).
1628 */
1629#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1630 start_from = list->prev; /* assume we'll queue to the end of the list */
1631 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1632 start_from = start_from->prev;
1633#if STATTIME > 0
1634 stats_tsk_lsrch++;
1635#endif
1636 }
1637#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001638 /* insert the unlinked <task> into the list, searching after position <start_from> */
1639 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1640 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001642 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001643#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001644 }
willy tarreau750a4722005-12-17 13:21:24 +01001645#endif /* WE_REALLY_... */
1646
willy tarreau0f7af912005-12-17 12:21:26 +01001647 /* we need to unlink it now */
1648 task_delete(task);
1649 }
1650 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001651#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001652 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001653#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001654#ifdef LEFT_TO_TOP /* not very good */
1655 start_from = list;
1656 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1657 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001658#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001659 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001660#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001661 }
1662#else
1663 start_from = task->prev->prev; /* valid because of the previous test above */
1664 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1665 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001666#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001667 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001668#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001669 }
1670#endif
1671 /* we need to unlink it now */
1672 task_delete(task);
1673 }
1674 task->prev = start_from;
1675 task->next = start_from->next;
1676 task->next->prev = task;
1677 start_from->next = task;
1678 return task;
1679}
1680
1681
1682/*********************************************************************/
1683/* more specific functions ***************************************/
1684/*********************************************************************/
1685
1686/* some prototypes */
1687static int maintain_proxies(void);
1688
willy tarreaub952e1d2005-12-18 01:31:20 +01001689/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001690 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1691 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001692static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001693#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001694 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1695#else
willy tarreaua1598082005-12-17 13:08:06 +01001696#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001697 return getsockname(fd, (struct sockaddr *)sa, salen);
1698#else
1699 return -1;
1700#endif
1701#endif
1702}
1703
1704/*
1705 * frees the context associated to a session. It must have been removed first.
1706 */
1707static inline void session_free(struct session *s) {
1708 if (s->req)
1709 pool_free(buffer, s->req);
1710 if (s->rep)
1711 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001712
1713 if (s->rsp_cap != NULL) {
1714 struct cap_hdr *h;
1715 for (h = s->proxy->rsp_cap; h; h = h->next) {
1716 if (s->rsp_cap[h->index] != NULL)
1717 pool_free_to(h->pool, s->rsp_cap[h->index]);
1718 }
1719 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1720 }
1721 if (s->req_cap != NULL) {
1722 struct cap_hdr *h;
1723 for (h = s->proxy->req_cap; h; h = h->next) {
1724 if (s->req_cap[h->index] != NULL)
1725 pool_free_to(h->pool, s->req_cap[h->index]);
1726 }
1727 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1728 }
1729
willy tarreaua1598082005-12-17 13:08:06 +01001730 if (s->logs.uri)
1731 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001732 if (s->logs.cli_cookie)
1733 pool_free(capture, s->logs.cli_cookie);
1734 if (s->logs.srv_cookie)
1735 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001736
willy tarreau5cbea6f2005-12-17 12:48:26 +01001737 pool_free(session, s);
1738}
1739
willy tarreau0f7af912005-12-17 12:21:26 +01001740
1741/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001742 * This function tries to find a running server for the proxy <px>. A first
1743 * pass looks for active servers, and if none is found, a second pass also
1744 * looks for backup servers.
1745 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1746 */
1747static inline struct server *find_server(struct proxy *px) {
1748 struct server *srv = px->cursrv;
1749 int ignore_backup = 1;
1750
1751 do {
1752 do {
1753 if (srv == NULL)
1754 srv = px->srv;
1755 if (srv->state & SRV_RUNNING
1756 && !((srv->state & SRV_BACKUP) && ignore_backup))
1757 return srv;
1758 srv = srv->next;
1759 } while (srv != px->cursrv);
1760 } while (ignore_backup--);
1761 return NULL;
1762}
1763
1764/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001765 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001766 * is set, or to the dispatch server if (s->direct) is 0.
1767 * It can return one of :
1768 * - SN_ERR_NONE if everything's OK
1769 * - SN_ERR_SRVTO if there are no more servers
1770 * - SN_ERR_SRVCL if the connection was refused by the server
1771 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1772 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1773 * - SN_ERR_INTERNAL for any other purely internal errors
1774 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001775 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001776int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001777 int fd;
1778
willy tarreau12350152005-12-18 01:03:27 +01001779#ifdef DEBUG_FULL
1780 fprintf(stderr,"connect_server : s=%p\n",s);
1781#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001782
willy tarreaue39cd132005-12-17 13:00:18 +01001783 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001784 s->srv_addr = s->srv->addr;
1785 }
1786 else if (s->proxy->options & PR_O_BALANCE) {
1787 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001788 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001789
willy tarreau8337c6b2005-12-17 13:41:01 +01001790 srv = find_server(s->proxy);
1791
1792 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001793 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001794
willy tarreau8337c6b2005-12-17 13:41:01 +01001795 s->srv_addr = srv->addr;
1796 s->srv = srv;
1797 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001798 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001799 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001800 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001801 }
willy tarreaua1598082005-12-17 13:08:06 +01001802 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001803 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001804 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001805 }
1806 else if (s->proxy->options & PR_O_TRANSP) {
1807 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001808 socklen_t salen = sizeof(s->srv_addr);
1809
willy tarreau5cbea6f2005-12-17 12:48:26 +01001810 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1811 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001812 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001813 }
1814 }
willy tarreau0f7af912005-12-17 12:21:26 +01001815
willy tarreaua41a8b42005-12-17 14:02:24 +01001816 /* if this server remaps proxied ports, we'll use
1817 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001818 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001819 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001820 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001821
willy tarreaub952e1d2005-12-18 01:31:20 +01001822 if (!(s->proxy->options & PR_O_TRANSP) ||
1823 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001824 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1825 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1826 }
1827
willy tarreau0f7af912005-12-17 12:21:26 +01001828 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001829 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001830
1831 if (errno == ENFILE)
1832 send_log(s->proxy, LOG_EMERG,
1833 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1834 s->proxy->id, maxfd);
1835 else if (errno == EMFILE)
1836 send_log(s->proxy, LOG_EMERG,
1837 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1838 s->proxy->id, maxfd);
1839 else if (errno == ENOBUFS || errno == ENOMEM)
1840 send_log(s->proxy, LOG_EMERG,
1841 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1842 s->proxy->id, maxfd);
1843 /* this is a resource error */
1844 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001845 }
1846
willy tarreau9fe663a2005-12-17 13:02:59 +01001847 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001848 /* do not log anything there, it's a normal condition when this option
1849 * is used to serialize connections to a server !
1850 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001851 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1852 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001853 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001854 }
1855
willy tarreau0f7af912005-12-17 12:21:26 +01001856 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1857 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001859 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001860 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001861 }
1862
willy tarreaub952e1d2005-12-18 01:31:20 +01001863 if (s->proxy->options & PR_O_TCP_SRV_KA)
1864 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1865
willy tarreau0174f312005-12-18 01:02:42 +01001866 /* allow specific binding :
1867 * - server-specific at first
1868 * - proxy-specific next
1869 */
1870 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1871 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1872 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1873 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1874 s->proxy->id, s->srv->id);
1875 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001876 send_log(s->proxy, LOG_EMERG,
1877 "Cannot bind to source address before connect() for server %s/%s.\n",
1878 s->proxy->id, s->srv->id);
1879 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001880 }
1881 }
1882 else if (s->proxy->options & PR_O_BIND_SRC) {
1883 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1884 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1885 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1886 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001887 send_log(s->proxy, LOG_EMERG,
1888 "Cannot bind to source address before connect() for server %s/%s.\n",
1889 s->proxy->id, s->srv->id);
1890 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001891 }
willy tarreaua1598082005-12-17 13:08:06 +01001892 }
1893
willy tarreaub1285d52005-12-18 01:20:14 +01001894 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1895 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1896
1897 if (errno == EAGAIN || errno == EADDRINUSE) {
1898 char *msg;
1899 if (errno == EAGAIN) /* no free ports left, try again later */
1900 msg = "no free ports";
1901 else
1902 msg = "local address already in use";
1903
1904 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001905 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001906 send_log(s->proxy, LOG_EMERG,
1907 "Connect() failed for server %s/%s: %s.\n",
1908 s->proxy->id, s->srv->id, msg);
1909 return SN_ERR_RESOURCE;
1910 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001911 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001912 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001913 return SN_ERR_SRVTO;
1914 } else {
1915 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001916 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001917 close(fd);
1918 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001919 }
1920 }
1921
willy tarreau5cbea6f2005-12-17 12:48:26 +01001922 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001923 fdtab[fd].read = &event_srv_read;
1924 fdtab[fd].write = &event_srv_write;
1925 fdtab[fd].state = FD_STCONN; /* connection in progress */
1926
1927 FD_SET(fd, StaticWriteEvent); /* for connect status */
1928
1929 fd_insert(fd);
1930
1931 if (s->proxy->contimeout)
1932 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1933 else
1934 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001935 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001936}
1937
1938/*
1939 * this function is called on a read event from a client socket.
1940 * It returns 0.
1941 */
1942int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001943 struct task *t = fdtab[fd].owner;
1944 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001945 struct buffer *b = s->req;
1946 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001947
willy tarreau12350152005-12-18 01:03:27 +01001948#ifdef DEBUG_FULL
1949 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1950#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001951
willy tarreau0f7af912005-12-17 12:21:26 +01001952 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001953#ifdef FILL_BUFFERS
1954 while (1)
1955#else
1956 do
1957#endif
1958 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001959 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1960 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001961 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001962 }
1963 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001964 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001965 }
1966 else {
1967 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001968 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1969 * since it means that the rewrite protection has been removed. This
1970 * implies that the if statement can be removed.
1971 */
1972 if (max > b->rlim - b->data)
1973 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001974 }
1975
1976 if (max == 0) { /* not anymore room to store data */
1977 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001978 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 }
1980
willy tarreau3242e862005-12-17 12:27:53 +01001981#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001982 {
willy tarreaub952e1d2005-12-18 01:31:20 +01001983 int skerr;
1984 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001985
willy tarreau5cbea6f2005-12-17 12:48:26 +01001986 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1987 if (skerr)
1988 ret = -1;
1989 else
1990 ret = recv(fd, b->r, max, 0);
1991 }
willy tarreau3242e862005-12-17 12:27:53 +01001992#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001993 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001994#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001995 if (ret > 0) {
1996 b->r += ret;
1997 b->l += ret;
1998 s->res_cr = RES_DATA;
1999
2000 if (b->r == b->data + BUFSIZE) {
2001 b->r = b->data; /* wrap around the buffer */
2002 }
willy tarreaua1598082005-12-17 13:08:06 +01002003
2004 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002005 /* we hope to read more data or to get a close on next round */
2006 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002007 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002008 else if (ret == 0) {
2009 s->res_cr = RES_NULL;
2010 break;
2011 }
2012 else if (errno == EAGAIN) {/* ignore EAGAIN */
2013 break;
2014 }
2015 else {
2016 s->res_cr = RES_ERROR;
2017 fdtab[fd].state = FD_STERROR;
2018 break;
2019 }
2020 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002021#ifndef FILL_BUFFERS
2022 while (0);
2023#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002024 }
2025 else {
2026 s->res_cr = RES_ERROR;
2027 fdtab[fd].state = FD_STERROR;
2028 }
2029
willy tarreau5cbea6f2005-12-17 12:48:26 +01002030 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002031 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002032 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2033 else
2034 tv_eternity(&s->crexpire);
2035
2036 task_wakeup(&rq, t);
2037 }
willy tarreau0f7af912005-12-17 12:21:26 +01002038
willy tarreau0f7af912005-12-17 12:21:26 +01002039 return 0;
2040}
2041
2042
2043/*
2044 * this function is called on a read event from a server socket.
2045 * It returns 0.
2046 */
2047int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002048 struct task *t = fdtab[fd].owner;
2049 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002050 struct buffer *b = s->rep;
2051 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002052
willy tarreau12350152005-12-18 01:03:27 +01002053#ifdef DEBUG_FULL
2054 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2055#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002056
willy tarreau0f7af912005-12-17 12:21:26 +01002057 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002058#ifdef FILL_BUFFERS
2059 while (1)
2060#else
2061 do
2062#endif
2063 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002064 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2065 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002066 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002067 }
2068 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002069 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 }
2071 else {
2072 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002073 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2074 * since it means that the rewrite protection has been removed. This
2075 * implies that the if statement can be removed.
2076 */
2077 if (max > b->rlim - b->data)
2078 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002079 }
2080
2081 if (max == 0) { /* not anymore room to store data */
2082 FD_CLR(fd, StaticReadEvent);
2083 break;
2084 }
2085
willy tarreau3242e862005-12-17 12:27:53 +01002086#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002087 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002088 int skerr;
2089 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002090
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2092 if (skerr)
2093 ret = -1;
2094 else
2095 ret = recv(fd, b->r, max, 0);
2096 }
willy tarreau3242e862005-12-17 12:27:53 +01002097#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002098 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002099#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 if (ret > 0) {
2101 b->r += ret;
2102 b->l += ret;
2103 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002104
willy tarreau5cbea6f2005-12-17 12:48:26 +01002105 if (b->r == b->data + BUFSIZE) {
2106 b->r = b->data; /* wrap around the buffer */
2107 }
willy tarreaua1598082005-12-17 13:08:06 +01002108
2109 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002110 /* we hope to read more data or to get a close on next round */
2111 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002112 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002113 else if (ret == 0) {
2114 s->res_sr = RES_NULL;
2115 break;
2116 }
2117 else if (errno == EAGAIN) {/* ignore EAGAIN */
2118 break;
2119 }
2120 else {
2121 s->res_sr = RES_ERROR;
2122 fdtab[fd].state = FD_STERROR;
2123 break;
2124 }
2125 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002126#ifndef FILL_BUFFERS
2127 while (0);
2128#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002129 }
2130 else {
2131 s->res_sr = RES_ERROR;
2132 fdtab[fd].state = FD_STERROR;
2133 }
2134
willy tarreau5cbea6f2005-12-17 12:48:26 +01002135 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002136 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002137 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2138 else
2139 tv_eternity(&s->srexpire);
2140
2141 task_wakeup(&rq, t);
2142 }
willy tarreau0f7af912005-12-17 12:21:26 +01002143
willy tarreau0f7af912005-12-17 12:21:26 +01002144 return 0;
2145}
2146
2147/*
2148 * this function is called on a write event from a client socket.
2149 * It returns 0.
2150 */
2151int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002152 struct task *t = fdtab[fd].owner;
2153 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002154 struct buffer *b = s->rep;
2155 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002156
willy tarreau12350152005-12-18 01:03:27 +01002157#ifdef DEBUG_FULL
2158 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2159#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002160
2161 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002162 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002163 // max = BUFSIZE; BUG !!!!
2164 max = 0;
2165 }
2166 else if (b->r > b->w) {
2167 max = b->r - b->w;
2168 }
2169 else
2170 max = b->data + BUFSIZE - b->w;
2171
willy tarreau0f7af912005-12-17 12:21:26 +01002172 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002173 if (max == 0) {
2174 s->res_cw = RES_NULL;
2175 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002176 tv_eternity(&s->cwexpire);
2177 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002178 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002179 }
2180
willy tarreau3242e862005-12-17 12:27:53 +01002181#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002182 {
2183 int skerr;
2184 socklen_t lskerr = sizeof(skerr);
2185
2186 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2187 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002188 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002189 else
willy tarreau3242e862005-12-17 12:27:53 +01002190 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002191 }
willy tarreau3242e862005-12-17 12:27:53 +01002192#else
willy tarreau0f7af912005-12-17 12:21:26 +01002193 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002194#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002195
2196 if (ret > 0) {
2197 b->l -= ret;
2198 b->w += ret;
2199
2200 s->res_cw = RES_DATA;
2201
2202 if (b->w == b->data + BUFSIZE) {
2203 b->w = b->data; /* wrap around the buffer */
2204 }
2205 }
2206 else if (ret == 0) {
2207 /* nothing written, just make as if we were never called */
2208// s->res_cw = RES_NULL;
2209 return 0;
2210 }
2211 else if (errno == EAGAIN) /* ignore EAGAIN */
2212 return 0;
2213 else {
2214 s->res_cw = RES_ERROR;
2215 fdtab[fd].state = FD_STERROR;
2216 }
2217 }
2218 else {
2219 s->res_cw = RES_ERROR;
2220 fdtab[fd].state = FD_STERROR;
2221 }
2222
willy tarreaub1ff9db2005-12-17 13:51:03 +01002223 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002224 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002225 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2226 s->crexpire = s->cwexpire;
2227 }
willy tarreau0f7af912005-12-17 12:21:26 +01002228 else
2229 tv_eternity(&s->cwexpire);
2230
willy tarreau5cbea6f2005-12-17 12:48:26 +01002231 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002232 return 0;
2233}
2234
2235
2236/*
2237 * this function is called on a write event from a server socket.
2238 * It returns 0.
2239 */
2240int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002241 struct task *t = fdtab[fd].owner;
2242 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002243 struct buffer *b = s->req;
2244 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002245
willy tarreau12350152005-12-18 01:03:27 +01002246#ifdef DEBUG_FULL
2247 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2248#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002249
2250 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002251 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002252 // max = BUFSIZE; BUG !!!!
2253 max = 0;
2254 }
2255 else if (b->r > b->w) {
2256 max = b->r - b->w;
2257 }
2258 else
2259 max = b->data + BUFSIZE - b->w;
2260
willy tarreau0f7af912005-12-17 12:21:26 +01002261 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002262 if (max == 0) {
2263 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002264 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002265 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002266 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002267 tv_eternity(&s->swexpire);
2268 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002269 return 0;
2270 }
2271
willy tarreau3242e862005-12-17 12:27:53 +01002272#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002273 {
2274 int skerr;
2275 socklen_t lskerr = sizeof(skerr);
2276 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2277 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002278 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002279 else
willy tarreau3242e862005-12-17 12:27:53 +01002280 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002281 }
willy tarreau3242e862005-12-17 12:27:53 +01002282#else
willy tarreau0f7af912005-12-17 12:21:26 +01002283 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002284#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002285 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002286 if (ret > 0) {
2287 b->l -= ret;
2288 b->w += ret;
2289
2290 s->res_sw = RES_DATA;
2291
2292 if (b->w == b->data + BUFSIZE) {
2293 b->w = b->data; /* wrap around the buffer */
2294 }
2295 }
2296 else if (ret == 0) {
2297 /* nothing written, just make as if we were never called */
2298 // s->res_sw = RES_NULL;
2299 return 0;
2300 }
2301 else if (errno == EAGAIN) /* ignore EAGAIN */
2302 return 0;
2303 else {
2304 s->res_sw = RES_ERROR;
2305 fdtab[fd].state = FD_STERROR;
2306 }
2307 }
2308 else {
2309 s->res_sw = RES_ERROR;
2310 fdtab[fd].state = FD_STERROR;
2311 }
2312
willy tarreaub1ff9db2005-12-17 13:51:03 +01002313 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002314 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002315 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2316 s->srexpire = s->swexpire;
2317 }
willy tarreau0f7af912005-12-17 12:21:26 +01002318 else
2319 tv_eternity(&s->swexpire);
2320
willy tarreau5cbea6f2005-12-17 12:48:26 +01002321 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002322 return 0;
2323}
2324
2325
2326/*
willy tarreaue39cd132005-12-17 13:00:18 +01002327 * returns a message to the client ; the connection is shut down for read,
2328 * and the request is cleared so that no server connection can be initiated.
2329 * The client must be in a valid state for this (HEADER, DATA ...).
2330 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002331 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002332 */
2333void client_retnclose(struct session *s, int len, const char *msg) {
2334 FD_CLR(s->cli_fd, StaticReadEvent);
2335 FD_SET(s->cli_fd, StaticWriteEvent);
2336 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002337 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002338 shutdown(s->cli_fd, SHUT_RD);
2339 s->cli_state = CL_STSHUTR;
2340 strcpy(s->rep->data, msg);
2341 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002342 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002343 s->rep->r += len;
2344 s->req->l = 0;
2345}
2346
2347
2348/*
2349 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002350 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002351 */
2352void client_return(struct session *s, int len, const char *msg) {
2353 strcpy(s->rep->data, msg);
2354 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002355 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002356 s->rep->r += len;
2357 s->req->l = 0;
2358}
2359
willy tarreau9fe663a2005-12-17 13:02:59 +01002360/*
2361 * send a log for the session when we have enough info about it
2362 */
2363void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002364 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002365 struct proxy *p = s->proxy;
2366 int log;
2367 char *uri;
2368 char *pxid;
2369 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002370 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002371
2372 /* This is a first attempt at a better logging system.
2373 * For now, we rely on send_log() to provide the date, although it obviously
2374 * is the date of the log and not of the request, and most fields are not
2375 * computed.
2376 */
2377
willy tarreaua1598082005-12-17 13:08:06 +01002378 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002379
willy tarreau8a86dbf2005-12-18 00:45:59 +01002380 if (s->cli_addr.ss_family == AF_INET)
2381 inet_ntop(AF_INET,
2382 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2383 pn, sizeof(pn));
2384 else
2385 inet_ntop(AF_INET6,
2386 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2387 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002388
willy tarreauc1cae632005-12-17 14:12:23 +01002389 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002390 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002391 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002392
willy tarreauc1cae632005-12-17 14:12:23 +01002393 tm = localtime(&s->logs.tv_accept.tv_sec);
2394 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002395 char tmpline[MAX_SYSLOG_LEN], *h;
2396 int hdr;
2397
2398 h = tmpline;
2399 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2400 *(h++) = ' ';
2401 *(h++) = '{';
2402 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2403 if (hdr)
2404 *(h++) = '|';
2405 if (s->req_cap[hdr] != NULL)
2406 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2407 }
2408 *(h++) = '}';
2409 }
2410
2411 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2412 *(h++) = ' ';
2413 *(h++) = '{';
2414 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2415 if (hdr)
2416 *(h++) = '|';
2417 if (s->rsp_cap[hdr] != NULL)
2418 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2419 }
2420 *(h++) = '}';
2421 }
2422
2423 if (h < tmpline + sizeof(tmpline) - 4) {
2424 *(h++) = ' ';
2425 *(h++) = '"';
2426 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2427 *(h++) = '"';
2428 }
2429 *h = '\0';
2430
willy tarreau0fe39652005-12-18 01:25:24 +01002431 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 +01002432 pn,
2433 (s->cli_addr.ss_family == AF_INET) ?
2434 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2435 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002436 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2437 tm->tm_hour, tm->tm_min, tm->tm_sec,
2438 pxid, srv,
2439 s->logs.t_request,
2440 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2441 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002442 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2443 s->logs.status,
2444 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002445 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2446 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002447 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2448 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2449 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2450 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002451 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002452 }
2453 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002454 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 +01002455 pn,
2456 (s->cli_addr.ss_family == AF_INET) ?
2457 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2458 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002459 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2460 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002461 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002462 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002463 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2464 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002465 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002466 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2467 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002468 }
2469
2470 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002471}
2472
willy tarreaue39cd132005-12-17 13:00:18 +01002473
2474/*
willy tarreau0f7af912005-12-17 12:21:26 +01002475 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002476 * to an accept. It tries to accept as many connections as possible.
2477 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002478 */
2479int event_accept(int fd) {
2480 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002481 struct session *s;
2482 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002483 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002484
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002486 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002487 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002488
willy tarreaub1285d52005-12-18 01:20:14 +01002489 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2490 switch (errno) {
2491 case EAGAIN:
2492 case EINTR:
2493 case ECONNABORTED:
2494 return 0; /* nothing more to accept */
2495 case ENFILE:
2496 send_log(p, LOG_EMERG,
2497 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2498 p->id, maxfd);
2499 return 0;
2500 case EMFILE:
2501 send_log(p, LOG_EMERG,
2502 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2503 p->id, maxfd);
2504 return 0;
2505 case ENOBUFS:
2506 case ENOMEM:
2507 send_log(p, LOG_EMERG,
2508 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2509 p->id, maxfd);
2510 return 0;
2511 default:
2512 return 0;
2513 }
2514 }
willy tarreau0f7af912005-12-17 12:21:26 +01002515
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2517 Alert("out of memory in event_accept().\n");
2518 FD_CLR(fd, StaticReadEvent);
2519 p->state = PR_STIDLE;
2520 close(cfd);
2521 return 0;
2522 }
willy tarreau0f7af912005-12-17 12:21:26 +01002523
willy tarreaub1285d52005-12-18 01:20:14 +01002524 /* if this session comes from a known monitoring system, we want to ignore
2525 * it as soon as possible, which means closing it immediately for TCP.
2526 */
2527 s->flags = 0;
2528 if (addr.ss_family == AF_INET &&
2529 p->mon_mask.s_addr &&
2530 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2531 if (p->mode == PR_MODE_TCP) {
2532 close(cfd);
2533 pool_free(session, s);
2534 continue;
2535 }
2536 s->flags |= SN_MONITOR;
2537 }
2538
willy tarreau5cbea6f2005-12-17 12:48:26 +01002539 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2540 Alert("out of memory in event_accept().\n");
2541 FD_CLR(fd, StaticReadEvent);
2542 p->state = PR_STIDLE;
2543 close(cfd);
2544 pool_free(session, s);
2545 return 0;
2546 }
willy tarreau0f7af912005-12-17 12:21:26 +01002547
willy tarreau5cbea6f2005-12-17 12:48:26 +01002548 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002549 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002550 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2551 close(cfd);
2552 pool_free(task, t);
2553 pool_free(session, s);
2554 return 0;
2555 }
willy tarreau0f7af912005-12-17 12:21:26 +01002556
willy tarreau5cbea6f2005-12-17 12:48:26 +01002557 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2558 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2559 (char *) &one, sizeof(one)) == -1)) {
2560 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2561 close(cfd);
2562 pool_free(task, t);
2563 pool_free(session, s);
2564 return 0;
2565 }
willy tarreau0f7af912005-12-17 12:21:26 +01002566
willy tarreaub952e1d2005-12-18 01:31:20 +01002567 if (p->options & PR_O_TCP_CLI_KA)
2568 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2569
willy tarreau9fe663a2005-12-17 13:02:59 +01002570 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2571 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2572 t->state = TASK_IDLE;
2573 t->process = process_session;
2574 t->context = s;
2575
2576 s->task = t;
2577 s->proxy = p;
2578 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2579 s->srv_state = SV_STIDLE;
2580 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002581
willy tarreau9fe663a2005-12-17 13:02:59 +01002582 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2583 s->cli_fd = cfd;
2584 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002585 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002586 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002587
willy tarreaub1285d52005-12-18 01:20:14 +01002588 if (s->flags & SN_MONITOR)
2589 s->logs.logwait = 0;
2590 else
2591 s->logs.logwait = p->to_log;
2592
willy tarreaua1598082005-12-17 13:08:06 +01002593 s->logs.tv_accept = now;
2594 s->logs.t_request = -1;
2595 s->logs.t_connect = -1;
2596 s->logs.t_data = -1;
2597 s->logs.t_close = 0;
2598 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002599 s->logs.cli_cookie = NULL;
2600 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002601 s->logs.status = -1;
2602 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002603
willy tarreau2f6ba652005-12-17 13:57:42 +01002604 s->uniq_id = totalconn;
2605
willy tarreau4302f492005-12-18 01:00:37 +01002606 if (p->nb_req_cap > 0) {
2607 if ((s->req_cap =
2608 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2609 == NULL) { /* no memory */
2610 close(cfd); /* nothing can be done for this fd without memory */
2611 pool_free(task, t);
2612 pool_free(session, s);
2613 return 0;
2614 }
2615 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2616 }
2617 else
2618 s->req_cap = NULL;
2619
2620 if (p->nb_rsp_cap > 0) {
2621 if ((s->rsp_cap =
2622 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2623 == NULL) { /* no memory */
2624 if (s->req_cap != NULL)
2625 pool_free_to(p->req_cap_pool, s->req_cap);
2626 close(cfd); /* nothing can be done for this fd without memory */
2627 pool_free(task, t);
2628 pool_free(session, s);
2629 return 0;
2630 }
2631 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2632 }
2633 else
2634 s->rsp_cap = NULL;
2635
willy tarreau5cbea6f2005-12-17 12:48:26 +01002636 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2637 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002638 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002639 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002640
willy tarreau8a86dbf2005-12-18 00:45:59 +01002641 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002642 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002643 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002644 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002645
willy tarreau9fe663a2005-12-17 13:02:59 +01002646 if (p->to_log) {
2647 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002648 if (s->logs.logwait & LW_CLIP)
2649 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002650 sess_log(s);
2651 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002652 else if (s->cli_addr.ss_family == AF_INET) {
2653 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2654 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2655 sn, sizeof(sn)) &&
2656 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2657 pn, sizeof(pn))) {
2658 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2659 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2660 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2661 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2662 }
2663 }
2664 else {
2665 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2666 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2667 sn, sizeof(sn)) &&
2668 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2669 pn, sizeof(pn))) {
2670 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2671 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2672 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2673 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2674 }
2675 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002676 }
willy tarreau0f7af912005-12-17 12:21:26 +01002677
willy tarreau982249e2005-12-18 00:57:06 +01002678 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002679 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002680 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002681 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002682 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002683 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002684 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002685 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002686
willy tarreau8a86dbf2005-12-18 00:45:59 +01002687 if (s->cli_addr.ss_family == AF_INET) {
2688 char pn[INET_ADDRSTRLEN];
2689 inet_ntop(AF_INET,
2690 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2691 pn, sizeof(pn));
2692
2693 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2694 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2695 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2696 }
2697 else {
2698 char pn[INET6_ADDRSTRLEN];
2699 inet_ntop(AF_INET6,
2700 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2701 pn, sizeof(pn));
2702
2703 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2704 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2705 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2706 }
2707
willy tarreauef900ab2005-12-17 12:52:52 +01002708 write(1, trash, len);
2709 }
willy tarreau0f7af912005-12-17 12:21:26 +01002710
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002712 if (s->rsp_cap != NULL)
2713 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2714 if (s->req_cap != NULL)
2715 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002716 close(cfd); /* nothing can be done for this fd without memory */
2717 pool_free(task, t);
2718 pool_free(session, s);
2719 return 0;
2720 }
willy tarreau4302f492005-12-18 01:00:37 +01002721
willy tarreau5cbea6f2005-12-17 12:48:26 +01002722 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002723 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002724 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2725 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002726 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002727 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002728
willy tarreau5cbea6f2005-12-17 12:48:26 +01002729 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2730 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002731 if (s->rsp_cap != NULL)
2732 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2733 if (s->req_cap != NULL)
2734 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002735 close(cfd); /* nothing can be done for this fd without memory */
2736 pool_free(task, t);
2737 pool_free(session, s);
2738 return 0;
2739 }
2740 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002741 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002742 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 +01002743
willy tarreau5cbea6f2005-12-17 12:48:26 +01002744 fdtab[cfd].read = &event_cli_read;
2745 fdtab[cfd].write = &event_cli_write;
2746 fdtab[cfd].owner = t;
2747 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002748
willy tarreaub1285d52005-12-18 01:20:14 +01002749 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2750 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2751 /* Either we got a request from a monitoring system on an HTTP instance,
2752 * or we're in health check mode with the 'httpchk' option enabled. In
2753 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2754 */
2755 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2756 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2757 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002758 }
2759 else {
2760 FD_SET(cfd, StaticReadEvent);
2761 }
2762
willy tarreaub952e1d2005-12-18 01:31:20 +01002763#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2764 if (PrevReadEvent) {
2765 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2766 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2767 }
2768#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 fd_insert(cfd);
2770
2771 tv_eternity(&s->cnexpire);
2772 tv_eternity(&s->srexpire);
2773 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002774 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 tv_eternity(&s->cwexpire);
2776
willy tarreaub1285d52005-12-18 01:20:14 +01002777 if (s->proxy->clitimeout) {
2778 if (FD_ISSET(cfd, StaticReadEvent))
2779 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2780 if (FD_ISSET(cfd, StaticWriteEvent))
2781 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2782 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002783
willy tarreaub1285d52005-12-18 01:20:14 +01002784 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002785
2786 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002787
2788 if (p->mode != PR_MODE_HEALTH)
2789 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002790
2791 p->nbconn++;
2792 actconn++;
2793 totalconn++;
2794
willy tarreaub952e1d2005-12-18 01:31:20 +01002795 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002796 } /* end of while (p->nbconn < p->maxconn) */
2797 return 0;
2798}
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreau0f7af912005-12-17 12:21:26 +01002800
willy tarreau5cbea6f2005-12-17 12:48:26 +01002801/*
2802 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002803 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2804 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805 * or -1 if an error occured.
2806 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002807int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 struct task *t = fdtab[fd].owner;
2809 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002810
willy tarreauc5f73ed2005-12-18 01:26:38 +01002811 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002812 socklen_t lskerr = sizeof(skerr);
2813
willy tarreau5cbea6f2005-12-17 12:48:26 +01002814 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002815 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002816 if (skerr)
2817 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002818 else {
2819 if (s->proxy->options & PR_O_HTTP_CHK) {
2820 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002821 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002822 * so we'll send the request, and won't wake the checker up now.
2823 */
2824#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002825 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002826#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002827 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002828#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002829 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002830 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2831 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2832 return 0;
2833 }
2834 else
2835 s->result = -1;
2836 }
2837 else {
2838 /* good TCP connection is enough */
2839 s->result = 1;
2840 }
2841 }
2842
2843 task_wakeup(&rq, t);
2844 return 0;
2845}
2846
willy tarreau0f7af912005-12-17 12:21:26 +01002847
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002848/*
2849 * This function is used only for server health-checks. It handles
2850 * the server's reply to an HTTP request. It returns 1 if the server replies
2851 * 2xx or 3xx (valid responses), or -1 in other cases.
2852 */
2853int event_srv_chk_r(int fd) {
2854 char reply[64];
2855 int len;
2856 struct task *t = fdtab[fd].owner;
2857 struct server *s = t->context;
2858
willy tarreau197e8ec2005-12-17 14:10:59 +01002859 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002860#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002861 {
2862 int skerr;
2863 socklen_t lskerr = sizeof(skerr);
2864
2865 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2866 if (!skerr)
2867 len = recv(fd, reply, sizeof(reply), 0);
2868 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002869#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002870 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2871 * but the connection was closed on the remote end. Fortunately, recv still
2872 * works correctly and we don't need to do the getsockopt() on linux.
2873 */
2874 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002875#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002876 if ((len >= sizeof("HTTP/1.0 000")) &&
2877 !memcmp(reply, "HTTP/1.", 7) &&
2878 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2879 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002880
2881 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002883 return 0;
2884}
2885
2886
2887/*
2888 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2889 * and moves <end> just after the end of <str>.
2890 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2891 * the shift value (positive or negative) is returned.
2892 * If there's no space left, the move is not done.
2893 *
2894 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002895int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002896 int delta;
2897 int len;
2898
2899 len = strlen(str);
2900 delta = len - (end - pos);
2901
2902 if (delta + b->r >= b->data + BUFSIZE)
2903 return 0; /* no space left */
2904
2905 /* first, protect the end of the buffer */
2906 memmove(end + delta, end, b->data + b->l - end);
2907
2908 /* now, copy str over pos */
2909 memcpy(pos, str,len);
2910
willy tarreau5cbea6f2005-12-17 12:48:26 +01002911 /* we only move data after the displaced zone */
2912 if (b->r > pos) b->r += delta;
2913 if (b->w > pos) b->w += delta;
2914 if (b->h > pos) b->h += delta;
2915 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002916 b->l += delta;
2917
2918 return delta;
2919}
2920
willy tarreau8337c6b2005-12-17 13:41:01 +01002921/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002922 * len is 0.
2923 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002924int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002925 int delta;
2926
2927 delta = len - (end - pos);
2928
2929 if (delta + b->r >= b->data + BUFSIZE)
2930 return 0; /* no space left */
2931
2932 /* first, protect the end of the buffer */
2933 memmove(end + delta, end, b->data + b->l - end);
2934
2935 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002936 if (len)
2937 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002938
willy tarreau5cbea6f2005-12-17 12:48:26 +01002939 /* we only move data after the displaced zone */
2940 if (b->r > pos) b->r += delta;
2941 if (b->w > pos) b->w += delta;
2942 if (b->h > pos) b->h += delta;
2943 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002944 b->l += delta;
2945
2946 return delta;
2947}
2948
2949
2950int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2951 char *old_dst = dst;
2952
2953 while (*str) {
2954 if (*str == '\\') {
2955 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002956 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002957 int len, num;
2958
2959 num = *str - '0';
2960 str++;
2961
willy tarreau8a86dbf2005-12-18 00:45:59 +01002962 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002963 len = matches[num].rm_eo - matches[num].rm_so;
2964 memcpy(dst, src + matches[num].rm_so, len);
2965 dst += len;
2966 }
2967
2968 }
2969 else if (*str == 'x') {
2970 unsigned char hex1, hex2;
2971 str++;
2972
willy tarreauc1f47532005-12-18 01:08:26 +01002973 hex1 = toupper(*str++) - '0';
2974 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002975
2976 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2977 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2978 *dst++ = (hex1<<4) + hex2;
2979 }
2980 else
2981 *dst++ = *str++;
2982 }
2983 else
2984 *dst++ = *str++;
2985 }
2986 *dst = 0;
2987 return dst - old_dst;
2988}
2989
willy tarreauc1f47532005-12-18 01:08:26 +01002990static int ishex(char s)
2991{
2992 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
2993}
2994
2995/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
2996char *check_replace_string(char *str)
2997{
2998 char *err = NULL;
2999 while (*str) {
3000 if (*str == '\\') {
3001 err = str; /* in case of a backslash, we return the pointer to it */
3002 str++;
3003 if (!*str)
3004 return err;
3005 else if (isdigit((int)*str))
3006 err = NULL;
3007 else if (*str == 'x') {
3008 str++;
3009 if (!ishex(*str))
3010 return err;
3011 str++;
3012 if (!ishex(*str))
3013 return err;
3014 err = NULL;
3015 }
3016 else {
3017 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3018 err = NULL;
3019 }
3020 }
3021 str++;
3022 }
3023 return err;
3024}
3025
3026
willy tarreau9fe663a2005-12-17 13:02:59 +01003027
willy tarreau0f7af912005-12-17 12:21:26 +01003028/*
3029 * manages the client FSM and its socket. BTW, it also tries to handle the
3030 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3031 * 0 else.
3032 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003033int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003034 int s = t->srv_state;
3035 int c = t->cli_state;
3036 struct buffer *req = t->req;
3037 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003038 int method_checked = 0;
3039 appsess *asession_temp = NULL;
3040 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003041
willy tarreau750a4722005-12-17 13:21:24 +01003042#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003043 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3044 cli_stnames[c], srv_stnames[s],
3045 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3046 t->crexpire.tv_sec, t->crexpire.tv_usec,
3047 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003048#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003049 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3050 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3051 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3052 //);
3053 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003054 /* now parse the partial (or complete) headers */
3055 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3056 char *ptr;
3057 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003058 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003059
willy tarreau5cbea6f2005-12-17 12:48:26 +01003060 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003061
willy tarreau0f7af912005-12-17 12:21:26 +01003062 /* look for the end of the current header */
3063 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3064 ptr++;
3065
willy tarreau5cbea6f2005-12-17 12:48:26 +01003066 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003067 int line, len;
3068 /* we can only get here after an end of headers */
3069 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003070
willy tarreaue39cd132005-12-17 13:00:18 +01003071 if (t->flags & SN_CLDENY) {
3072 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003073 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003074 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003075 if (!(t->flags & SN_ERR_MASK))
3076 t->flags |= SN_ERR_PRXCOND;
3077 if (!(t->flags & SN_FINST_MASK))
3078 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003079 return 1;
3080 }
3081
willy tarreau5cbea6f2005-12-17 12:48:26 +01003082 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003083 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3084 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003085 }
willy tarreau0f7af912005-12-17 12:21:26 +01003086
willy tarreau9fe663a2005-12-17 13:02:59 +01003087 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003088 if (t->cli_addr.ss_family == AF_INET) {
3089 unsigned char *pn;
3090 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3091 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3092 pn[0], pn[1], pn[2], pn[3]);
3093 buffer_replace2(req, req->h, req->h, trash, len);
3094 }
3095 else if (t->cli_addr.ss_family == AF_INET6) {
3096 char pn[INET6_ADDRSTRLEN];
3097 inet_ntop(AF_INET6,
3098 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3099 pn, sizeof(pn));
3100 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3101 buffer_replace2(req, req->h, req->h, trash, len);
3102 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003103 }
3104
willy tarreau25c4ea52005-12-18 00:49:49 +01003105 /* add a "connection: close" line if needed */
3106 if (t->proxy->options & PR_O_HTTP_CLOSE)
3107 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3108
willy tarreau982249e2005-12-18 00:57:06 +01003109 if (!memcmp(req->data, "POST ", 5)) {
3110 /* this is a POST request, which is not cacheable by default */
3111 t->flags |= SN_POST;
3112 }
willy tarreaucd878942005-12-17 13:27:43 +01003113
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003115 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003116
willy tarreau750a4722005-12-17 13:21:24 +01003117 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003118 /* FIXME: we'll set the client in a wait state while we try to
3119 * connect to the server. Is this really needed ? wouldn't it be
3120 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003121 //FD_CLR(t->cli_fd, StaticReadEvent);
3122 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003123
3124 /* FIXME: if we break here (as up to 1.1.23), having the client
3125 * shutdown its connection can lead to an abort further.
3126 * it's better to either return 1 or even jump directly to the
3127 * data state which will save one schedule.
3128 */
3129 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003130
3131 if (!t->proxy->clitimeout ||
3132 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3133 /* If the client has no timeout, or if the server is not ready yet,
3134 * and we know for sure that it can expire, then it's cleaner to
3135 * disable the timeout on the client side so that too low values
3136 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003137 *
3138 * FIXME-20050705: the server needs a way to re-enable this time-out
3139 * when it switches its state, otherwise a client can stay connected
3140 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003141 */
3142 tv_eternity(&t->crexpire);
3143
willy tarreau197e8ec2005-12-17 14:10:59 +01003144 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003145 }
willy tarreau0f7af912005-12-17 12:21:26 +01003146
willy tarreau5cbea6f2005-12-17 12:48:26 +01003147 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3148 if (ptr > req->r - 2) {
3149 /* this is a partial header, let's wait for more to come */
3150 req->lr = ptr;
3151 break;
3152 }
willy tarreau0f7af912005-12-17 12:21:26 +01003153
willy tarreau5cbea6f2005-12-17 12:48:26 +01003154 /* now we know that *ptr is either \r or \n,
3155 * and that there are at least 1 char after it.
3156 */
3157 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3158 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3159 else
3160 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003161
willy tarreau5cbea6f2005-12-17 12:48:26 +01003162 /*
3163 * now we know that we have a full header ; we can do whatever
3164 * we want with these pointers :
3165 * req->h = beginning of header
3166 * ptr = end of header (first \r or \n)
3167 * req->lr = beginning of next line (next rep->h)
3168 * req->r = end of data (not used at this stage)
3169 */
willy tarreau0f7af912005-12-17 12:21:26 +01003170
willy tarreau12350152005-12-18 01:03:27 +01003171 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3172 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3173 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3174
3175 /* skip ; */
3176 request_line++;
3177
3178 /* look if we have a jsessionid */
3179
3180 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3181
3182 /* skip jsessionid= */
3183 request_line += t->proxy->appsession_name_len + 1;
3184
3185 /* First try if we allready have an appsession */
3186 asession_temp = &local_asession;
3187
3188 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3189 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3190 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3191 return 0;
3192 }
3193
3194 /* Copy the sessionid */
3195 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3196 asession_temp->sessid[t->proxy->appsession_len] = 0;
3197 asession_temp->serverid = NULL;
3198
3199 /* only do insert, if lookup fails */
3200 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3201 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3202 Alert("Not enough memory process_cli():asession:calloc().\n");
3203 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3204 return 0;
3205 }
3206 asession_temp->sessid = local_asession.sessid;
3207 asession_temp->serverid = local_asession.serverid;
3208 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003209 } /* end if (chtbl_lookup()) */
3210 else {
willy tarreau12350152005-12-18 01:03:27 +01003211 /*free wasted memory;*/
3212 pool_free_to(apools.sessid, local_asession.sessid);
3213 }
3214
3215 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3216 asession_temp->request_count++;
3217
3218#if defined(DEBUG_HASH)
3219 print_table(&(t->proxy->htbl_proxy));
3220#endif
3221
3222 if (asession_temp->serverid == NULL) {
3223 Alert("Found Application Session without matching server.\n");
3224 } else {
3225 struct server *srv = t->proxy->srv;
3226 while (srv) {
3227 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3228 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3229 /* we found the server and it's usable */
3230 t->flags &= ~SN_CK_MASK;
3231 t->flags |= SN_CK_VALID | SN_DIRECT;
3232 t->srv = srv;
3233 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003234 } else {
willy tarreau12350152005-12-18 01:03:27 +01003235 t->flags &= ~SN_CK_MASK;
3236 t->flags |= SN_CK_DOWN;
3237 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003238 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003239 srv = srv->next;
3240 }/* end while(srv) */
3241 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003242 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003243 else {
3244 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3245 }
willy tarreau598da412005-12-18 01:07:29 +01003246 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003247 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003248 else{
3249 //printf("No Methode-Header with Session-String\n");
3250 }
3251
willy tarreau8337c6b2005-12-17 13:41:01 +01003252 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003253 /* we have a complete HTTP request that we must log */
3254 int urilen;
3255
willy tarreaua1598082005-12-17 13:08:06 +01003256 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003257 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003258 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003259 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003260 if (!(t->flags & SN_ERR_MASK))
3261 t->flags |= SN_ERR_PRXCOND;
3262 if (!(t->flags & SN_FINST_MASK))
3263 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003264 return 1;
3265 }
3266
3267 urilen = ptr - req->h;
3268 if (urilen >= REQURI_LEN)
3269 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003270 memcpy(t->logs.uri, req->h, urilen);
3271 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003272
willy tarreaua1598082005-12-17 13:08:06 +01003273 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003274 sess_log(t);
3275 }
willy tarreau4302f492005-12-18 01:00:37 +01003276 else if (t->logs.logwait & LW_REQHDR) {
3277 struct cap_hdr *h;
3278 int len;
3279 for (h = t->proxy->req_cap; h; h = h->next) {
3280 if ((h->namelen + 2 <= ptr - req->h) &&
3281 (req->h[h->namelen] == ':') &&
3282 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3283
3284 if (t->req_cap[h->index] == NULL)
3285 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3286
3287 len = ptr - (req->h + h->namelen + 2);
3288 if (len > h->len)
3289 len = h->len;
3290
3291 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3292 t->req_cap[h->index][len]=0;
3293 }
3294 }
3295
3296 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003297
willy tarreau5cbea6f2005-12-17 12:48:26 +01003298 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003299
willy tarreau982249e2005-12-18 00:57:06 +01003300 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003301 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003302 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 +01003303 max = ptr - req->h;
3304 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003305 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003306 trash[len++] = '\n';
3307 write(1, trash, len);
3308 }
willy tarreau0f7af912005-12-17 12:21:26 +01003309
willy tarreau25c4ea52005-12-18 00:49:49 +01003310
3311 /* remove "connection: " if needed */
3312 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3313 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3314 delete_header = 1;
3315 }
3316
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003318 if (!delete_header && t->proxy->req_exp != NULL
3319 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003320 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003321 char term;
3322
3323 term = *ptr;
3324 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003325 exp = t->proxy->req_exp;
3326 do {
3327 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3328 switch (exp->action) {
3329 case ACT_ALLOW:
3330 if (!(t->flags & SN_CLDENY))
3331 t->flags |= SN_CLALLOW;
3332 break;
3333 case ACT_REPLACE:
3334 if (!(t->flags & SN_CLDENY)) {
3335 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3336 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3337 }
3338 break;
3339 case ACT_REMOVE:
3340 if (!(t->flags & SN_CLDENY))
3341 delete_header = 1;
3342 break;
3343 case ACT_DENY:
3344 if (!(t->flags & SN_CLALLOW))
3345 t->flags |= SN_CLDENY;
3346 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003347 case ACT_PASS: /* we simply don't deny this one */
3348 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003349 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003350 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003351 }
willy tarreaue39cd132005-12-17 13:00:18 +01003352 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003354 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355
willy tarreau240afa62005-12-17 13:14:35 +01003356 /* Now look for cookies. Conforming to RFC2109, we have to support
3357 * attributes whose name begin with a '$', and associate them with
3358 * the right cookie, if we want to delete this cookie.
3359 * So there are 3 cases for each cookie read :
3360 * 1) it's a special attribute, beginning with a '$' : ignore it.
3361 * 2) it's a server id cookie that we *MAY* want to delete : save
3362 * some pointers on it (last semi-colon, beginning of cookie...)
3363 * 3) it's an application cookie : we *MAY* have to delete a previous
3364 * "special" cookie.
3365 * At the end of loop, if a "special" cookie remains, we may have to
3366 * remove it. If no application cookie persists in the header, we
3367 * *MUST* delete it
3368 */
willy tarreau12350152005-12-18 01:03:27 +01003369 if (!delete_header &&
3370 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003371 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003372 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003373 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003374 char *del_colon, *del_cookie, *colon;
3375 int app_cookies;
3376
willy tarreau5cbea6f2005-12-17 12:48:26 +01003377 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003378 colon = p1;
3379 /* del_cookie == NULL => nothing to be deleted */
3380 del_colon = del_cookie = NULL;
3381 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003382
3383 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003384 /* skip spaces and colons, but keep an eye on these ones */
3385 while (p1 < ptr) {
3386 if (*p1 == ';' || *p1 == ',')
3387 colon = p1;
3388 else if (!isspace((int)*p1))
3389 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003390 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003391 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392
3393 if (p1 == ptr)
3394 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395
3396 /* p1 is at the beginning of the cookie name */
3397 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003398 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003399 p2++;
3400
3401 if (p2 == ptr)
3402 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003403
3404 p3 = p2 + 1; /* skips the '=' sign */
3405 if (p3 == ptr)
3406 break;
3407
willy tarreau240afa62005-12-17 13:14:35 +01003408 p4 = p3;
3409 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003410 p4++;
3411
3412 /* here, we have the cookie name between p1 and p2,
3413 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003414 * we can process it :
3415 *
3416 * Cookie: NAME=VALUE;
3417 * | || || |
3418 * | || || +--> p4
3419 * | || |+-------> p3
3420 * | || +--------> p2
3421 * | |+------------> p1
3422 * | +-------------> colon
3423 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003424 */
3425
willy tarreau240afa62005-12-17 13:14:35 +01003426 if (*p1 == '$') {
3427 /* skip this one */
3428 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003429 else {
3430 /* first, let's see if we want to capture it */
3431 if (t->proxy->capture_name != NULL &&
3432 t->logs.cli_cookie == NULL &&
3433 (p4 - p1 >= t->proxy->capture_namelen) &&
3434 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3435 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003436
willy tarreau8337c6b2005-12-17 13:41:01 +01003437 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3438 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003439 } else {
3440 if (log_len > t->proxy->capture_len)
3441 log_len = t->proxy->capture_len;
3442 memcpy(t->logs.cli_cookie, p1, log_len);
3443 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003444 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003446
3447 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3448 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3449 /* Cool... it's the right one */
3450 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003451 char *delim;
3452
3453 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3454 * have the server ID betweek p3 and delim, and the original cookie between
3455 * delim+1 and p4. Otherwise, delim==p4 :
3456 *
3457 * Cookie: NAME=SRV~VALUE;
3458 * | || || | |
3459 * | || || | +--> p4
3460 * | || || +--------> delim
3461 * | || |+-----------> p3
3462 * | || +------------> p2
3463 * | |+----------------> p1
3464 * | +-----------------> colon
3465 * +------------------------> req->h
3466 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003467
willy tarreau0174f312005-12-18 01:02:42 +01003468 if (t->proxy->options & PR_O_COOK_PFX) {
3469 for (delim = p3; delim < p4; delim++)
3470 if (*delim == COOKIE_DELIM)
3471 break;
3472 }
3473 else
3474 delim = p4;
3475
3476
3477 /* Here, we'll look for the first running server which supports the cookie.
3478 * This allows to share a same cookie between several servers, for example
3479 * to dedicate backup servers to specific servers only.
3480 */
3481 while (srv) {
3482 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3483 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3484 /* we found the server and it's usable */
3485 t->flags &= ~SN_CK_MASK;
3486 t->flags |= SN_CK_VALID | SN_DIRECT;
3487 t->srv = srv;
3488 break;
willy tarreau12350152005-12-18 01:03:27 +01003489 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003490 /* we found a server, but it's down */
3491 t->flags &= ~SN_CK_MASK;
3492 t->flags |= SN_CK_DOWN;
3493 }
3494 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003495 srv = srv->next;
3496 }
3497
willy tarreau0174f312005-12-18 01:02:42 +01003498 if (!srv && !(t->flags & SN_CK_DOWN)) {
3499 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003500 t->flags &= ~SN_CK_MASK;
3501 t->flags |= SN_CK_INVALID;
3502 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003503
willy tarreau0174f312005-12-18 01:02:42 +01003504 /* depending on the cookie mode, we may have to either :
3505 * - delete the complete cookie if we're in insert+indirect mode, so that
3506 * the server never sees it ;
3507 * - remove the server id from the cookie value, and tag the cookie as an
3508 * application cookie so that it does not get accidentely removed later,
3509 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003510 */
willy tarreau0174f312005-12-18 01:02:42 +01003511 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3512 buffer_replace2(req, p3, delim + 1, NULL, 0);
3513 p4 -= (delim + 1 - p3);
3514 ptr -= (delim + 1 - p3);
3515 del_cookie = del_colon = NULL;
3516 app_cookies++; /* protect the header from deletion */
3517 }
3518 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003519 (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 +01003520 del_cookie = p1;
3521 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003522 }
willy tarreau12350152005-12-18 01:03:27 +01003523 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003524 /* now we know that we must keep this cookie since it's
3525 * not ours. But if we wanted to delete our cookie
3526 * earlier, we cannot remove the complete header, but we
3527 * can remove the previous block itself.
3528 */
3529 app_cookies++;
3530
3531 if (del_cookie != NULL) {
3532 buffer_replace2(req, del_cookie, p1, NULL, 0);
3533 p4 -= (p1 - del_cookie);
3534 ptr -= (p1 - del_cookie);
3535 del_cookie = del_colon = NULL;
3536 }
willy tarreau240afa62005-12-17 13:14:35 +01003537 }
willy tarreau12350152005-12-18 01:03:27 +01003538
3539 if ((t->proxy->appsession_name != NULL) &&
3540 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3541 /* first, let's see if the cookie is our appcookie*/
3542
3543 /* Cool... it's the right one */
3544
3545 asession_temp = &local_asession;
3546
3547 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3548 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3549 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3550 return 0;
3551 }
3552
3553 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3554 asession_temp->sessid[t->proxy->appsession_len] = 0;
3555 asession_temp->serverid = NULL;
3556
3557 /* only do insert, if lookup fails */
3558 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3559 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3560 Alert("Not enough memory process_cli():asession:calloc().\n");
3561 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3562 return 0;
3563 }
3564
3565 asession_temp->sessid = local_asession.sessid;
3566 asession_temp->serverid = local_asession.serverid;
3567 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3568 }
3569 else{
3570 /* free wasted memory */
3571 pool_free_to(apools.sessid, local_asession.sessid);
3572 }
3573
3574 if (asession_temp->serverid == NULL) {
3575 Alert("Found Application Session without matching server.\n");
3576 } else {
3577 struct server *srv = t->proxy->srv;
3578 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003579 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003580 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3581 /* we found the server and it's usable */
3582 t->flags &= ~SN_CK_MASK;
3583 t->flags |= SN_CK_VALID | SN_DIRECT;
3584 t->srv = srv;
3585 break;
3586 } else {
3587 t->flags &= ~SN_CK_MASK;
3588 t->flags |= SN_CK_DOWN;
3589 }
3590 }
3591 srv = srv->next;
3592 }/* end while(srv) */
3593 }/* end else if server == NULL */
3594
3595 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003596 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003597 }
willy tarreau240afa62005-12-17 13:14:35 +01003598
willy tarreau5cbea6f2005-12-17 12:48:26 +01003599 /* we'll have to look for another cookie ... */
3600 p1 = p4;
3601 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003602
3603 /* There's no more cookie on this line.
3604 * We may have marked the last one(s) for deletion.
3605 * We must do this now in two ways :
3606 * - if there is no app cookie, we simply delete the header ;
3607 * - if there are app cookies, we must delete the end of the
3608 * string properly, including the colon/semi-colon before
3609 * the cookie name.
3610 */
3611 if (del_cookie != NULL) {
3612 if (app_cookies) {
3613 buffer_replace2(req, del_colon, ptr, NULL, 0);
3614 /* WARNING! <ptr> becomes invalid for now. If some code
3615 * below needs to rely on it before the end of the global
3616 * header loop, we need to correct it with this code :
3617 * ptr = del_colon;
3618 */
3619 }
3620 else
3621 delete_header = 1;
3622 }
3623 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003624
3625 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003626 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003627 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003628 }
willy tarreau240afa62005-12-17 13:14:35 +01003629 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3630
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 req->h = req->lr;
3632 } /* while (req->lr < req->r) */
3633
3634 /* end of header processing (even if incomplete) */
3635
willy tarreauef900ab2005-12-17 12:52:52 +01003636 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3637 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3638 * full. We cannot loop here since event_cli_read will disable it only if
3639 * req->l == rlim-data
3640 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 FD_SET(t->cli_fd, StaticReadEvent);
3642 if (t->proxy->clitimeout)
3643 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3644 else
3645 tv_eternity(&t->crexpire);
3646 }
3647
willy tarreaue39cd132005-12-17 13:00:18 +01003648 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003649 * won't be able to free more later, so the session will never terminate.
3650 */
willy tarreaue39cd132005-12-17 13:00:18 +01003651 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003652 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003653 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003654 if (!(t->flags & SN_ERR_MASK))
3655 t->flags |= SN_ERR_PRXCOND;
3656 if (!(t->flags & SN_FINST_MASK))
3657 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003658 return 1;
3659 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003660 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003661 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003662 tv_eternity(&t->crexpire);
3663 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003664 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003665 if (!(t->flags & SN_ERR_MASK))
3666 t->flags |= SN_ERR_CLICL;
3667 if (!(t->flags & SN_FINST_MASK))
3668 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003670 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003671 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3672
3673 /* read timeout : give up with an error message.
3674 */
3675 t->logs.status = 408;
3676 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003677 if (!(t->flags & SN_ERR_MASK))
3678 t->flags |= SN_ERR_CLITO;
3679 if (!(t->flags & SN_FINST_MASK))
3680 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003681 return 1;
3682 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683
3684 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003685 }
3686 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003687 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003688 /* FIXME: this error handling is partly buggy because we always report
3689 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3690 * or HEADER phase. BTW, it's not logical to expire the client while
3691 * we're waiting for the server to connect.
3692 */
willy tarreau0f7af912005-12-17 12:21:26 +01003693 /* read or write error */
3694 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003695 tv_eternity(&t->crexpire);
3696 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003697 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003698 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003699 if (!(t->flags & SN_ERR_MASK))
3700 t->flags |= SN_ERR_CLICL;
3701 if (!(t->flags & SN_FINST_MASK))
3702 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003703 return 1;
3704 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003705 /* last read, or end of server write */
3706 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003707 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003708 tv_eternity(&t->crexpire);
3709 shutdown(t->cli_fd, SHUT_RD);
3710 t->cli_state = CL_STSHUTR;
3711 return 1;
3712 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003713 /* last server read and buffer empty */
3714 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003715 FD_CLR(t->cli_fd, StaticWriteEvent);
3716 tv_eternity(&t->cwexpire);
3717 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003718 /* We must ensure that the read part is still alive when switching
3719 * to shutw */
3720 FD_SET(t->cli_fd, StaticReadEvent);
3721 if (t->proxy->clitimeout)
3722 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003723 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003724 //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 +01003725 return 1;
3726 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003727 /* read timeout */
3728 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3729 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003730 tv_eternity(&t->crexpire);
3731 shutdown(t->cli_fd, SHUT_RD);
3732 t->cli_state = CL_STSHUTR;
3733 if (!(t->flags & SN_ERR_MASK))
3734 t->flags |= SN_ERR_CLITO;
3735 if (!(t->flags & SN_FINST_MASK))
3736 t->flags |= SN_FINST_D;
3737 return 1;
3738 }
3739 /* write timeout */
3740 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3741 FD_CLR(t->cli_fd, StaticWriteEvent);
3742 tv_eternity(&t->cwexpire);
3743 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003744 /* We must ensure that the read part is still alive when switching
3745 * to shutw */
3746 FD_SET(t->cli_fd, StaticReadEvent);
3747 if (t->proxy->clitimeout)
3748 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3749
willy tarreau036e1ce2005-12-17 13:46:33 +01003750 t->cli_state = CL_STSHUTW;
3751 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003752 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003753 if (!(t->flags & SN_FINST_MASK))
3754 t->flags |= SN_FINST_D;
3755 return 1;
3756 }
willy tarreau0f7af912005-12-17 12:21:26 +01003757
willy tarreauc58fc692005-12-17 14:13:08 +01003758 if (req->l >= req->rlim - req->data) {
3759 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003760 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003761 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003762 FD_CLR(t->cli_fd, StaticReadEvent);
3763 tv_eternity(&t->crexpire);
3764 }
3765 }
3766 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003767 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003768 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3769 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003770 if (!t->proxy->clitimeout ||
3771 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3772 /* If the client has no timeout, or if the server not ready yet, and we
3773 * know for sure that it can expire, then it's cleaner to disable the
3774 * timeout on the client side so that too low values cannot make the
3775 * sessions abort too early.
3776 */
willy tarreau0f7af912005-12-17 12:21:26 +01003777 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003778 else
3779 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003780 }
3781 }
3782
3783 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003784 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003785 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3786 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3787 tv_eternity(&t->cwexpire);
3788 }
3789 }
3790 else { /* buffer not empty */
3791 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3792 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003793 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003794 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003795 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3796 t->crexpire = t->cwexpire;
3797 }
willy tarreau0f7af912005-12-17 12:21:26 +01003798 else
3799 tv_eternity(&t->cwexpire);
3800 }
3801 }
3802 return 0; /* other cases change nothing */
3803 }
3804 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003805 if (t->res_cw == RES_ERROR) {
3806 tv_eternity(&t->cwexpire);
3807 fd_delete(t->cli_fd);
3808 t->cli_state = CL_STCLOSE;
3809 if (!(t->flags & SN_ERR_MASK))
3810 t->flags |= SN_ERR_CLICL;
3811 if (!(t->flags & SN_FINST_MASK))
3812 t->flags |= SN_FINST_D;
3813 return 1;
3814 }
3815 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003816 tv_eternity(&t->cwexpire);
3817 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003818 t->cli_state = CL_STCLOSE;
3819 return 1;
3820 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003821 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3822 tv_eternity(&t->cwexpire);
3823 fd_delete(t->cli_fd);
3824 t->cli_state = CL_STCLOSE;
3825 if (!(t->flags & SN_ERR_MASK))
3826 t->flags |= SN_ERR_CLITO;
3827 if (!(t->flags & SN_FINST_MASK))
3828 t->flags |= SN_FINST_D;
3829 return 1;
3830 }
willy tarreau0f7af912005-12-17 12:21:26 +01003831 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003832 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003833 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3834 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3835 tv_eternity(&t->cwexpire);
3836 }
3837 }
3838 else { /* buffer not empty */
3839 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3840 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003841 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003842 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003843 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3844 t->crexpire = t->cwexpire;
3845 }
willy tarreau0f7af912005-12-17 12:21:26 +01003846 else
3847 tv_eternity(&t->cwexpire);
3848 }
3849 }
3850 return 0;
3851 }
3852 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003853 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003854 tv_eternity(&t->crexpire);
3855 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003856 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003857 if (!(t->flags & SN_ERR_MASK))
3858 t->flags |= SN_ERR_CLICL;
3859 if (!(t->flags & SN_FINST_MASK))
3860 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003861 return 1;
3862 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003863 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3864 tv_eternity(&t->crexpire);
3865 fd_delete(t->cli_fd);
3866 t->cli_state = CL_STCLOSE;
3867 return 1;
3868 }
3869 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3870 tv_eternity(&t->crexpire);
3871 fd_delete(t->cli_fd);
3872 t->cli_state = CL_STCLOSE;
3873 if (!(t->flags & SN_ERR_MASK))
3874 t->flags |= SN_ERR_CLITO;
3875 if (!(t->flags & SN_FINST_MASK))
3876 t->flags |= SN_FINST_D;
3877 return 1;
3878 }
willy tarreauef900ab2005-12-17 12:52:52 +01003879 else if (req->l >= req->rlim - req->data) {
3880 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003881
3882 /* FIXME-20050705: is it possible for a client to maintain a session
3883 * after the timeout by sending more data after it receives a close ?
3884 */
3885
willy tarreau0f7af912005-12-17 12:21:26 +01003886 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003887 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003888 FD_CLR(t->cli_fd, StaticReadEvent);
3889 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003890 //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 +01003891 }
3892 }
3893 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003894 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003895 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3896 FD_SET(t->cli_fd, StaticReadEvent);
3897 if (t->proxy->clitimeout)
3898 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3899 else
3900 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003901 //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 +01003902 }
3903 }
3904 return 0;
3905 }
3906 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003907 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003908 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003909 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 +01003910 write(1, trash, len);
3911 }
3912 return 0;
3913 }
3914 return 0;
3915}
3916
3917
3918/*
3919 * manages the server FSM and its socket. It returns 1 if a state has changed
3920 * (and a resync may be needed), 0 else.
3921 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003922int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003923 int s = t->srv_state;
3924 int c = t->cli_state;
3925 struct buffer *req = t->req;
3926 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003927 appsess *asession_temp = NULL;
3928 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003929 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003930
willy tarreau750a4722005-12-17 13:21:24 +01003931#ifdef DEBUG_FULL
3932 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3933#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003934 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3935 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3936 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3937 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003938 if (s == SV_STIDLE) {
3939 if (c == CL_STHEADERS)
3940 return 0; /* stay in idle, waiting for data to reach the client side */
3941 else if (c == CL_STCLOSE ||
3942 c == CL_STSHUTW ||
3943 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3944 tv_eternity(&t->cnexpire);
3945 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003946 if (!(t->flags & SN_ERR_MASK))
3947 t->flags |= SN_ERR_CLICL;
3948 if (!(t->flags & SN_FINST_MASK))
3949 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003950 return 1;
3951 }
3952 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003953 /* initiate a connection to the server */
3954 conn_err = connect_server(t);
3955 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003956 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3957 t->srv_state = SV_STCONN;
3958 }
3959 else { /* try again */
3960 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003961 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003962 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003963 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003964 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3965 t->flags &= ~SN_CK_MASK;
3966 t->flags |= SN_CK_DOWN;
3967 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003968 }
3969
willy tarreaub1285d52005-12-18 01:20:14 +01003970 conn_err = connect_server(t);
3971 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003972 t->srv_state = SV_STCONN;
3973 break;
3974 }
3975 }
3976 if (t->conn_retries < 0) {
3977 /* if conn_retries < 0 or other error, let's abort */
3978 tv_eternity(&t->cnexpire);
3979 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003980 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003981 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003982 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003983 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01003984 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01003985 if (!(t->flags & SN_FINST_MASK))
3986 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003987 }
3988 }
3989 return 1;
3990 }
3991 }
3992 else if (s == SV_STCONN) { /* connection in progress */
3993 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3994 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3995 return 0; /* nothing changed */
3996 }
3997 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3998 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3999 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004000 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004001 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004002 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004003 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 if (t->conn_retries >= 0) {
4005 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004006 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004007 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004008 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4009 t->flags &= ~SN_CK_MASK;
4010 t->flags |= SN_CK_DOWN;
4011 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012 }
willy tarreaub1285d52005-12-18 01:20:14 +01004013 conn_err = connect_server(t);
4014 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004015 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004016 }
willy tarreaub1285d52005-12-18 01:20:14 +01004017 else if (t->res_sw == RES_SILENT)
4018 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4019 else
4020 conn_err = SN_ERR_SRVCL; // it was a connect error.
4021
willy tarreau0f7af912005-12-17 12:21:26 +01004022 /* if conn_retries < 0 or other error, let's abort */
4023 tv_eternity(&t->cnexpire);
4024 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004025 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004026 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004027 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004028 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004029 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004030 if (!(t->flags & SN_FINST_MASK))
4031 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004032 return 1;
4033 }
4034 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004035 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004036
willy tarreau0f7af912005-12-17 12:21:26 +01004037 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004038 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004039 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004040 tv_eternity(&t->swexpire);
4041 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004042 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004043 if (t->proxy->srvtimeout) {
4044 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4045 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4046 t->srexpire = t->swexpire;
4047 }
4048 else
4049 tv_eternity(&t->swexpire);
4050 }
willy tarreau0f7af912005-12-17 12:21:26 +01004051
4052 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4053 FD_SET(t->srv_fd, StaticReadEvent);
4054 if (t->proxy->srvtimeout)
4055 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4056 else
4057 tv_eternity(&t->srexpire);
4058
4059 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004060 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004061
4062 /* if the user wants to log as soon as possible, without counting
4063 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004064 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004065 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4066 sess_log(t);
4067 }
willy tarreau0f7af912005-12-17 12:21:26 +01004068 }
willy tarreauef900ab2005-12-17 12:52:52 +01004069 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004070 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004071 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4072 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004073 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004074 return 1;
4075 }
4076 }
4077 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 /* now parse the partial (or complete) headers */
4079 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4080 char *ptr;
4081 int delete_header;
4082
4083 ptr = rep->lr;
4084
4085 /* look for the end of the current header */
4086 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4087 ptr++;
4088
4089 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090 int line, len;
4091
4092 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004093
4094 /* first, we'll block if security checks have caught nasty things */
4095 if (t->flags & SN_CACHEABLE) {
4096 if ((t->flags & SN_CACHE_COOK) &&
4097 (t->flags & SN_SCK_ANY) &&
4098 (t->proxy->options & PR_O_CHK_CACHE)) {
4099
4100 /* we're in presence of a cacheable response containing
4101 * a set-cookie header. We'll block it as requested by
4102 * the 'checkcache' option, and send an alert.
4103 */
4104 tv_eternity(&t->srexpire);
4105 tv_eternity(&t->swexpire);
4106 fd_delete(t->srv_fd);
4107 t->srv_state = SV_STCLOSE;
4108 t->logs.status = 502;
4109 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4110 if (!(t->flags & SN_ERR_MASK))
4111 t->flags |= SN_ERR_PRXCOND;
4112 if (!(t->flags & SN_FINST_MASK))
4113 t->flags |= SN_FINST_H;
4114
4115 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4116 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4117
4118 return 1;
4119 }
4120 }
4121
willy tarreau982249e2005-12-18 00:57:06 +01004122 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4123 if (t->flags & SN_SVDENY) {
4124 tv_eternity(&t->srexpire);
4125 tv_eternity(&t->swexpire);
4126 fd_delete(t->srv_fd);
4127 t->srv_state = SV_STCLOSE;
4128 t->logs.status = 502;
4129 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4130 if (!(t->flags & SN_ERR_MASK))
4131 t->flags |= SN_ERR_PRXCOND;
4132 if (!(t->flags & SN_FINST_MASK))
4133 t->flags |= SN_FINST_H;
4134 return 1;
4135 }
4136
willy tarreau5cbea6f2005-12-17 12:48:26 +01004137 /* we'll have something else to do here : add new headers ... */
4138
willy tarreaucd878942005-12-17 13:27:43 +01004139 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4140 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004141 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004142 * insert a set-cookie here, except if we want to insert only on POST
4143 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 */
willy tarreau750a4722005-12-17 13:21:24 +01004145 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004146 t->proxy->cookie_name,
4147 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004148
willy tarreau036e1ce2005-12-17 13:46:33 +01004149 t->flags |= SN_SCK_INSERTED;
4150
willy tarreau750a4722005-12-17 13:21:24 +01004151 /* Here, we will tell an eventual cache on the client side that we don't
4152 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4153 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4154 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4155 */
willy tarreau240afa62005-12-17 13:14:35 +01004156 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004157 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4158 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01004159
willy tarreau750a4722005-12-17 13:21:24 +01004160 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 }
4162
4163 /* headers to be added */
4164 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004165 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4166 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004167 }
4168
willy tarreau25c4ea52005-12-18 00:49:49 +01004169 /* add a "connection: close" line if needed */
4170 if (t->proxy->options & PR_O_HTTP_CLOSE)
4171 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4172
willy tarreau5cbea6f2005-12-17 12:48:26 +01004173 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004174 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004175 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004176
4177 /* if the user wants to log as soon as possible, without counting
4178 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004179 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004180 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4181 t->logs.bytes = rep->h - rep->data;
4182 sess_log(t);
4183 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004184 break;
4185 }
4186
4187 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4188 if (ptr > rep->r - 2) {
4189 /* this is a partial header, let's wait for more to come */
4190 rep->lr = ptr;
4191 break;
4192 }
4193
4194 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4195 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4196
4197 /* now we know that *ptr is either \r or \n,
4198 * and that there are at least 1 char after it.
4199 */
4200 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4201 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4202 else
4203 rep->lr = ptr + 2; /* \r\n or \n\r */
4204
4205 /*
4206 * now we know that we have a full header ; we can do whatever
4207 * we want with these pointers :
4208 * rep->h = beginning of header
4209 * ptr = end of header (first \r or \n)
4210 * rep->lr = beginning of next line (next rep->h)
4211 * rep->r = end of data (not used at this stage)
4212 */
4213
willy tarreaua1598082005-12-17 13:08:06 +01004214
willy tarreau982249e2005-12-18 00:57:06 +01004215 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004216 t->logs.logwait &= ~LW_RESP;
4217 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004218 switch (t->logs.status) {
4219 case 200:
4220 case 203:
4221 case 206:
4222 case 300:
4223 case 301:
4224 case 410:
4225 /* RFC2616 @13.4:
4226 * "A response received with a status code of
4227 * 200, 203, 206, 300, 301 or 410 MAY be stored
4228 * by a cache (...) unless a cache-control
4229 * directive prohibits caching."
4230 *
4231 * RFC2616 @9.5: POST method :
4232 * "Responses to this method are not cacheable,
4233 * unless the response includes appropriate
4234 * Cache-Control or Expires header fields."
4235 */
4236 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4237 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4238 break;
4239 default:
4240 break;
4241 }
willy tarreau4302f492005-12-18 01:00:37 +01004242 }
4243 else if (t->logs.logwait & LW_RSPHDR) {
4244 struct cap_hdr *h;
4245 int len;
4246 for (h = t->proxy->rsp_cap; h; h = h->next) {
4247 if ((h->namelen + 2 <= ptr - rep->h) &&
4248 (rep->h[h->namelen] == ':') &&
4249 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4250
4251 if (t->rsp_cap[h->index] == NULL)
4252 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4253
4254 len = ptr - (rep->h + h->namelen + 2);
4255 if (len > h->len)
4256 len = h->len;
4257
4258 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4259 t->rsp_cap[h->index][len]=0;
4260 }
4261 }
4262
willy tarreaua1598082005-12-17 13:08:06 +01004263 }
4264
willy tarreau5cbea6f2005-12-17 12:48:26 +01004265 delete_header = 0;
4266
willy tarreau982249e2005-12-18 00:57:06 +01004267 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004268 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004269 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 +01004270 max = ptr - rep->h;
4271 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004272 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004273 trash[len++] = '\n';
4274 write(1, trash, len);
4275 }
4276
willy tarreau25c4ea52005-12-18 00:49:49 +01004277 /* remove "connection: " if needed */
4278 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4279 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4280 delete_header = 1;
4281 }
4282
willy tarreau5cbea6f2005-12-17 12:48:26 +01004283 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004284 if (!delete_header && t->proxy->rsp_exp != NULL
4285 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004286 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004287 char term;
4288
4289 term = *ptr;
4290 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004291 exp = t->proxy->rsp_exp;
4292 do {
4293 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4294 switch (exp->action) {
4295 case ACT_ALLOW:
4296 if (!(t->flags & SN_SVDENY))
4297 t->flags |= SN_SVALLOW;
4298 break;
4299 case ACT_REPLACE:
4300 if (!(t->flags & SN_SVDENY)) {
4301 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4302 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4303 }
4304 break;
4305 case ACT_REMOVE:
4306 if (!(t->flags & SN_SVDENY))
4307 delete_header = 1;
4308 break;
4309 case ACT_DENY:
4310 if (!(t->flags & SN_SVALLOW))
4311 t->flags |= SN_SVDENY;
4312 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004313 case ACT_PASS: /* we simply don't deny this one */
4314 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004315 }
4316 break;
4317 }
willy tarreaue39cd132005-12-17 13:00:18 +01004318 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004319 *ptr = term; /* restore the string terminator */
4320 }
4321
willy tarreau97f58572005-12-18 00:53:44 +01004322 /* check for cache-control: or pragma: headers */
4323 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4324 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4325 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4326 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4327 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004328 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004329 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4330 else {
4331 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004332 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004333 t->flags &= ~SN_CACHE_COOK;
4334 }
4335 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004336 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004337 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004338 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004339 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4340 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004341 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004342 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004343 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4344 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4345 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4346 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4347 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4348 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004349 }
4350 }
4351 }
4352
willy tarreau5cbea6f2005-12-17 12:48:26 +01004353 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004354 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004355 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004356 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004357 char *p1, *p2, *p3, *p4;
4358
willy tarreau97f58572005-12-18 00:53:44 +01004359 t->flags |= SN_SCK_ANY;
4360
willy tarreau5cbea6f2005-12-17 12:48:26 +01004361 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4362
4363 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004364 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004365 p1++;
4366
4367 if (p1 == ptr || *p1 == ';') /* end of cookie */
4368 break;
4369
4370 /* p1 is at the beginning of the cookie name */
4371 p2 = p1;
4372
4373 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4374 p2++;
4375
4376 if (p2 == ptr || *p2 == ';') /* next cookie */
4377 break;
4378
4379 p3 = p2 + 1; /* skips the '=' sign */
4380 if (p3 == ptr)
4381 break;
4382
4383 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004384 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004385 p4++;
4386
4387 /* here, we have the cookie name between p1 and p2,
4388 * and its value between p3 and p4.
4389 * we can process it.
4390 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004391
4392 /* first, let's see if we want to capture it */
4393 if (t->proxy->capture_name != NULL &&
4394 t->logs.srv_cookie == NULL &&
4395 (p4 - p1 >= t->proxy->capture_namelen) &&
4396 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4397 int log_len = p4 - p1;
4398
4399 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4400 Alert("HTTP logging : out of memory.\n");
4401 }
4402
4403 if (log_len > t->proxy->capture_len)
4404 log_len = t->proxy->capture_len;
4405 memcpy(t->logs.srv_cookie, p1, log_len);
4406 t->logs.srv_cookie[log_len] = 0;
4407 }
4408
4409 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4410 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004411 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004412 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004413
4414 /* If the cookie is in insert mode on a known server, we'll delete
4415 * this occurrence because we'll insert another one later.
4416 * We'll delete it too if the "indirect" option is set and we're in
4417 * a direct access. */
4418 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004419 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004420 /* this header must be deleted */
4421 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004422 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004423 }
4424 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4425 /* replace bytes p3->p4 with the cookie name associated
4426 * with this server since we know it.
4427 */
4428 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004429 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004430 }
willy tarreau0174f312005-12-18 01:02:42 +01004431 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4432 /* insert the cookie name associated with this server
4433 * before existing cookie, and insert a delimitor between them..
4434 */
4435 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4436 p3[t->srv->cklen] = COOKIE_DELIM;
4437 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4438 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004439 break;
4440 }
willy tarreau12350152005-12-18 01:03:27 +01004441
4442 /* first, let's see if the cookie is our appcookie*/
4443 if ((t->proxy->appsession_name != NULL) &&
4444 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4445
4446 /* Cool... it's the right one */
4447
willy tarreaub952e1d2005-12-18 01:31:20 +01004448 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004449 asession_temp = &local_asession;
4450
willy tarreaub952e1d2005-12-18 01:31:20 +01004451 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004452 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4453 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4454 }
4455 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4456 asession_temp->sessid[t->proxy->appsession_len] = 0;
4457 asession_temp->serverid = NULL;
4458
4459 /* only do insert, if lookup fails */
4460 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4461 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4462 Alert("Not enought Memory process_srv():asession:calloc().\n");
4463 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4464 return 0;
4465 }
4466 asession_temp->sessid = local_asession.sessid;
4467 asession_temp->serverid = local_asession.serverid;
4468 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004469 }/* end if (chtbl_lookup()) */
4470 else {
willy tarreau12350152005-12-18 01:03:27 +01004471 /* free wasted memory */
4472 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004473 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004474
willy tarreaub952e1d2005-12-18 01:31:20 +01004475 if (asession_temp->serverid == NULL) {
4476 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004477 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4478 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4479 }
4480 asession_temp->serverid[0] = '\0';
4481 }
4482
willy tarreaub952e1d2005-12-18 01:31:20 +01004483 if (asession_temp->serverid[0] == '\0')
4484 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004485
4486 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4487
4488#if defined(DEBUG_HASH)
4489 print_table(&(t->proxy->htbl_proxy));
4490#endif
4491 break;
4492 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004493 else {
4494 // fprintf(stderr,"Ignoring unknown cookie : ");
4495 // write(2, p1, p2-p1);
4496 // fprintf(stderr," = ");
4497 // write(2, p3, p4-p3);
4498 // fprintf(stderr,"\n");
4499 }
4500 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4501 } /* we're now at the end of the cookie value */
4502 } /* end of cookie processing */
4503
willy tarreau97f58572005-12-18 00:53:44 +01004504 /* check for any set-cookie in case we check for cacheability */
4505 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4506 (t->proxy->options & PR_O_CHK_CACHE) &&
4507 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4508 t->flags |= SN_SCK_ANY;
4509 }
4510
willy tarreau5cbea6f2005-12-17 12:48:26 +01004511 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004512 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004513 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004514
willy tarreau5cbea6f2005-12-17 12:48:26 +01004515 rep->h = rep->lr;
4516 } /* while (rep->lr < rep->r) */
4517
4518 /* end of header processing (even if incomplete) */
4519
willy tarreauef900ab2005-12-17 12:52:52 +01004520 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4521 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4522 * full. We cannot loop here since event_srv_read will disable it only if
4523 * rep->l == rlim-data
4524 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004525 FD_SET(t->srv_fd, StaticReadEvent);
4526 if (t->proxy->srvtimeout)
4527 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4528 else
4529 tv_eternity(&t->srexpire);
4530 }
willy tarreau0f7af912005-12-17 12:21:26 +01004531
willy tarreau8337c6b2005-12-17 13:41:01 +01004532 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004533 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004534 tv_eternity(&t->srexpire);
4535 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004536 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004537 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004538 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004539 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004540 if (!(t->flags & SN_ERR_MASK))
4541 t->flags |= SN_ERR_SRVCL;
4542 if (!(t->flags & SN_FINST_MASK))
4543 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004544 return 1;
4545 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004546 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004547 * since we are in header mode, if there's no space left for headers, we
4548 * won't be able to free more later, so the session will never terminate.
4549 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004550 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 +01004551 FD_CLR(t->srv_fd, StaticReadEvent);
4552 tv_eternity(&t->srexpire);
4553 shutdown(t->srv_fd, SHUT_RD);
4554 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004555 //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 +01004556 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004557 }
4558 /* read timeout : return a 504 to the client.
4559 */
4560 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4561 tv_eternity(&t->srexpire);
4562 tv_eternity(&t->swexpire);
4563 fd_delete(t->srv_fd);
4564 t->srv_state = SV_STCLOSE;
4565 t->logs.status = 504;
4566 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004567 if (!(t->flags & SN_ERR_MASK))
4568 t->flags |= SN_ERR_SRVTO;
4569 if (!(t->flags & SN_FINST_MASK))
4570 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004571 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004572
4573 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004574 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004575 /* FIXME!!! here, we don't want to switch to SHUTW if the
4576 * client shuts read too early, because we may still have
4577 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004578 * The side-effect is that if the client completely closes its
4579 * connection during SV_STHEADER, the connection to the server
4580 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004581 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004582 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004583 FD_CLR(t->srv_fd, StaticWriteEvent);
4584 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004585
4586 /* We must ensure that the read part is still alive when switching
4587 * to shutw */
4588 FD_SET(t->srv_fd, StaticReadEvent);
4589 if (t->proxy->srvtimeout)
4590 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4591
willy tarreau0f7af912005-12-17 12:21:26 +01004592 shutdown(t->srv_fd, SHUT_WR);
4593 t->srv_state = SV_STSHUTW;
4594 return 1;
4595 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004596 /* write timeout */
4597 /* FIXME!!! here, we don't want to switch to SHUTW if the
4598 * client shuts read too early, because we may still have
4599 * some work to do on the headers.
4600 */
4601 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4602 FD_CLR(t->srv_fd, StaticWriteEvent);
4603 tv_eternity(&t->swexpire);
4604 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004605 /* We must ensure that the read part is still alive when switching
4606 * to shutw */
4607 FD_SET(t->srv_fd, StaticReadEvent);
4608 if (t->proxy->srvtimeout)
4609 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4610
4611 /* We must ensure that the read part is still alive when switching
4612 * to shutw */
4613 FD_SET(t->srv_fd, StaticReadEvent);
4614 if (t->proxy->srvtimeout)
4615 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4616
willy tarreau036e1ce2005-12-17 13:46:33 +01004617 t->srv_state = SV_STSHUTW;
4618 if (!(t->flags & SN_ERR_MASK))
4619 t->flags |= SN_ERR_SRVTO;
4620 if (!(t->flags & SN_FINST_MASK))
4621 t->flags |= SN_FINST_H;
4622 return 1;
4623 }
willy tarreau0f7af912005-12-17 12:21:26 +01004624
4625 if (req->l == 0) {
4626 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4627 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4628 tv_eternity(&t->swexpire);
4629 }
4630 }
4631 else { /* client buffer not empty */
4632 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4633 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004634 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004635 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004636 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4637 t->srexpire = t->swexpire;
4638 }
willy tarreau0f7af912005-12-17 12:21:26 +01004639 else
4640 tv_eternity(&t->swexpire);
4641 }
4642 }
4643
willy tarreau5cbea6f2005-12-17 12:48:26 +01004644 /* be nice with the client side which would like to send a complete header
4645 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4646 * would read all remaining data at once ! The client should not write past rep->lr
4647 * when the server is in header state.
4648 */
4649 //return header_processed;
4650 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004651 }
4652 else if (s == SV_STDATA) {
4653 /* read or write error */
4654 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004655 tv_eternity(&t->srexpire);
4656 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004657 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004658 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004659 if (!(t->flags & SN_ERR_MASK))
4660 t->flags |= SN_ERR_SRVCL;
4661 if (!(t->flags & SN_FINST_MASK))
4662 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004663 return 1;
4664 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004665 /* last read, or end of client write */
4666 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004667 FD_CLR(t->srv_fd, StaticReadEvent);
4668 tv_eternity(&t->srexpire);
4669 shutdown(t->srv_fd, SHUT_RD);
4670 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004671 //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 +01004672 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004673 }
4674 /* end of client read and no more data to send */
4675 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4676 FD_CLR(t->srv_fd, StaticWriteEvent);
4677 tv_eternity(&t->swexpire);
4678 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004679 /* We must ensure that the read part is still alive when switching
4680 * to shutw */
4681 FD_SET(t->srv_fd, StaticReadEvent);
4682 if (t->proxy->srvtimeout)
4683 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4684
willy tarreaua41a8b42005-12-17 14:02:24 +01004685 t->srv_state = SV_STSHUTW;
4686 return 1;
4687 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004688 /* read timeout */
4689 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4690 FD_CLR(t->srv_fd, StaticReadEvent);
4691 tv_eternity(&t->srexpire);
4692 shutdown(t->srv_fd, SHUT_RD);
4693 t->srv_state = SV_STSHUTR;
4694 if (!(t->flags & SN_ERR_MASK))
4695 t->flags |= SN_ERR_SRVTO;
4696 if (!(t->flags & SN_FINST_MASK))
4697 t->flags |= SN_FINST_D;
4698 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004699 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004700 /* write timeout */
4701 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004702 FD_CLR(t->srv_fd, StaticWriteEvent);
4703 tv_eternity(&t->swexpire);
4704 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004705 /* We must ensure that the read part is still alive when switching
4706 * to shutw */
4707 FD_SET(t->srv_fd, StaticReadEvent);
4708 if (t->proxy->srvtimeout)
4709 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004710 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004711 if (!(t->flags & SN_ERR_MASK))
4712 t->flags |= SN_ERR_SRVTO;
4713 if (!(t->flags & SN_FINST_MASK))
4714 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004715 return 1;
4716 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004717
4718 /* recompute request time-outs */
4719 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004720 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4721 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4722 tv_eternity(&t->swexpire);
4723 }
4724 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004725 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004726 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4727 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004728 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004729 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004730 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4731 t->srexpire = t->swexpire;
4732 }
willy tarreau0f7af912005-12-17 12:21:26 +01004733 else
4734 tv_eternity(&t->swexpire);
4735 }
4736 }
4737
willy tarreaub1ff9db2005-12-17 13:51:03 +01004738 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004739 if (rep->l == BUFSIZE) { /* no room to read more data */
4740 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4741 FD_CLR(t->srv_fd, StaticReadEvent);
4742 tv_eternity(&t->srexpire);
4743 }
4744 }
4745 else {
4746 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4747 FD_SET(t->srv_fd, StaticReadEvent);
4748 if (t->proxy->srvtimeout)
4749 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4750 else
4751 tv_eternity(&t->srexpire);
4752 }
4753 }
4754
4755 return 0; /* other cases change nothing */
4756 }
4757 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004758 if (t->res_sw == RES_ERROR) {
4759 //FD_CLR(t->srv_fd, StaticWriteEvent);
4760 tv_eternity(&t->swexpire);
4761 fd_delete(t->srv_fd);
4762 //close(t->srv_fd);
4763 t->srv_state = SV_STCLOSE;
4764 if (!(t->flags & SN_ERR_MASK))
4765 t->flags |= SN_ERR_SRVCL;
4766 if (!(t->flags & SN_FINST_MASK))
4767 t->flags |= SN_FINST_D;
4768 return 1;
4769 }
4770 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004771 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004772 tv_eternity(&t->swexpire);
4773 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004774 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004775 t->srv_state = SV_STCLOSE;
4776 return 1;
4777 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004778 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4779 //FD_CLR(t->srv_fd, StaticWriteEvent);
4780 tv_eternity(&t->swexpire);
4781 fd_delete(t->srv_fd);
4782 //close(t->srv_fd);
4783 t->srv_state = SV_STCLOSE;
4784 if (!(t->flags & SN_ERR_MASK))
4785 t->flags |= SN_ERR_SRVTO;
4786 if (!(t->flags & SN_FINST_MASK))
4787 t->flags |= SN_FINST_D;
4788 return 1;
4789 }
willy tarreau0f7af912005-12-17 12:21:26 +01004790 else if (req->l == 0) {
4791 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4792 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4793 tv_eternity(&t->swexpire);
4794 }
4795 }
4796 else { /* buffer not empty */
4797 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4798 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004799 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004800 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004801 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4802 t->srexpire = t->swexpire;
4803 }
willy tarreau0f7af912005-12-17 12:21:26 +01004804 else
4805 tv_eternity(&t->swexpire);
4806 }
4807 }
4808 return 0;
4809 }
4810 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004811 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004812 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004813 tv_eternity(&t->srexpire);
4814 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004815 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004816 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004817 if (!(t->flags & SN_ERR_MASK))
4818 t->flags |= SN_ERR_SRVCL;
4819 if (!(t->flags & SN_FINST_MASK))
4820 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004821 return 1;
4822 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004823 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4824 //FD_CLR(t->srv_fd, StaticReadEvent);
4825 tv_eternity(&t->srexpire);
4826 fd_delete(t->srv_fd);
4827 //close(t->srv_fd);
4828 t->srv_state = SV_STCLOSE;
4829 return 1;
4830 }
4831 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4832 //FD_CLR(t->srv_fd, StaticReadEvent);
4833 tv_eternity(&t->srexpire);
4834 fd_delete(t->srv_fd);
4835 //close(t->srv_fd);
4836 t->srv_state = SV_STCLOSE;
4837 if (!(t->flags & SN_ERR_MASK))
4838 t->flags |= SN_ERR_SRVTO;
4839 if (!(t->flags & SN_FINST_MASK))
4840 t->flags |= SN_FINST_D;
4841 return 1;
4842 }
willy tarreau0f7af912005-12-17 12:21:26 +01004843 else if (rep->l == BUFSIZE) { /* no room to read more data */
4844 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4845 FD_CLR(t->srv_fd, StaticReadEvent);
4846 tv_eternity(&t->srexpire);
4847 }
4848 }
4849 else {
4850 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4851 FD_SET(t->srv_fd, StaticReadEvent);
4852 if (t->proxy->srvtimeout)
4853 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4854 else
4855 tv_eternity(&t->srexpire);
4856 }
4857 }
4858 return 0;
4859 }
4860 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004861 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004862 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004863 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 +01004864 write(1, trash, len);
4865 }
4866 return 0;
4867 }
4868 return 0;
4869}
4870
4871
willy tarreau5cbea6f2005-12-17 12:48:26 +01004872/* Processes the client and server jobs of a session task, then
4873 * puts it back to the wait queue in a clean state, or
4874 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004875 * the time the task accepts to wait, or TIME_ETERNITY for
4876 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004877 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004878int process_session(struct task *t) {
4879 struct session *s = t->context;
4880 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004881
willy tarreau5cbea6f2005-12-17 12:48:26 +01004882 do {
4883 fsm_resync = 0;
4884 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4885 fsm_resync |= process_cli(s);
4886 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4887 fsm_resync |= process_srv(s);
4888 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4889 } while (fsm_resync);
4890
4891 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004892 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004893 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004894
willy tarreau5cbea6f2005-12-17 12:48:26 +01004895 tv_min(&min1, &s->crexpire, &s->cwexpire);
4896 tv_min(&min2, &s->srexpire, &s->swexpire);
4897 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004898 tv_min(&t->expire, &min1, &min2);
4899
4900 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004901 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004902
willy tarreaub952e1d2005-12-18 01:31:20 +01004903 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004904 }
4905
willy tarreau5cbea6f2005-12-17 12:48:26 +01004906 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004907 actconn--;
4908
willy tarreau982249e2005-12-18 00:57:06 +01004909 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004910 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004911 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 +01004912 write(1, trash, len);
4913 }
4914
willy tarreau750a4722005-12-17 13:21:24 +01004915 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004916 if (s->rep != NULL)
4917 s->logs.bytes = s->rep->total;
4918
willy tarreau9fe663a2005-12-17 13:02:59 +01004919 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004920 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004921 sess_log(s);
4922
willy tarreau0f7af912005-12-17 12:21:26 +01004923 /* the task MUST not be in the run queue anymore */
4924 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004925 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004926 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01004927 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004928}
4929
4930
4931
4932/*
4933 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004934 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004935 */
4936int process_chk(struct task *t) {
4937 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004938 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004939 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004940
willy tarreauef900ab2005-12-17 12:52:52 +01004941 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004942
4943 if (fd < 0) { /* no check currently running */
4944 //fprintf(stderr, "process_chk: 2\n");
4945 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4946 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01004947 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004948 }
4949
4950 /* we'll initiate a new check */
4951 s->result = 0; /* no result yet */
4952 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004953 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004954 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4955 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4956 //fprintf(stderr, "process_chk: 3\n");
4957
willy tarreaua41a8b42005-12-17 14:02:24 +01004958 /* we'll connect to the check port on the server */
4959 sa = s->addr;
4960 sa.sin_port = htons(s->check_port);
4961
willy tarreau0174f312005-12-18 01:02:42 +01004962 /* allow specific binding :
4963 * - server-specific at first
4964 * - proxy-specific next
4965 */
4966 if (s->state & SRV_BIND_SRC) {
4967 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4968 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4969 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4970 s->proxy->id, s->id);
4971 s->result = -1;
4972 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004973 }
willy tarreau0174f312005-12-18 01:02:42 +01004974 else if (s->proxy->options & PR_O_BIND_SRC) {
4975 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4976 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4977 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4978 s->proxy->id);
4979 s->result = -1;
4980 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004981 }
willy tarreau0174f312005-12-18 01:02:42 +01004982
4983 if (!s->result) {
4984 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4985 /* OK, connection in progress or established */
4986
4987 //fprintf(stderr, "process_chk: 4\n");
4988
4989 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4990 fdtab[fd].owner = t;
4991 fdtab[fd].read = &event_srv_chk_r;
4992 fdtab[fd].write = &event_srv_chk_w;
4993 fdtab[fd].state = FD_STCONN; /* connection in progress */
4994 FD_SET(fd, StaticWriteEvent); /* for connect status */
4995 fd_insert(fd);
4996 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4997 tv_delayfrom(&t->expire, &now, s->inter);
4998 task_queue(t); /* restore t to its place in the task list */
4999 return tv_remain(&now, &t->expire);
5000 }
5001 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5002 s->result = -1; /* a real error */
5003 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005004 }
5005 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005006 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005007 }
5008
5009 if (!s->result) { /* nothing done */
5010 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005011 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005012 task_queue(t); /* restore t to its place in the task list */
5013 return tv_remain(&now, &t->expire);
5014 }
5015
5016 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005017 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005018 s->health--; /* still good */
5019 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005020 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005021 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005022 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005023 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005024
willy tarreaudd07e972005-12-18 00:48:48 +01005025 if (find_server(s->proxy) == NULL) {
5026 Alert("Proxy %s has no server available !\n", s->proxy->id);
5027 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5028 }
5029 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005030 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005031 }
5032
5033 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005034 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5035 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005036 }
5037 else {
5038 //fprintf(stderr, "process_chk: 8\n");
5039 /* there was a test running */
5040 if (s->result > 0) { /* good server detected */
5041 //fprintf(stderr, "process_chk: 9\n");
5042 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005043 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005044 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005045 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005046 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005047 }
willy tarreauef900ab2005-12-17 12:52:52 +01005048
willy tarreaue47c8d72005-12-17 12:55:52 +01005049 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005050 s->state |= SRV_RUNNING;
5051 }
willy tarreauef900ab2005-12-17 12:52:52 +01005052 s->curfd = -1; /* no check running anymore */
5053 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005054 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005055 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 }
5057 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5058 //fprintf(stderr, "process_chk: 10\n");
5059 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005060 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005061 s->health--; /* still good */
5062 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005063 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005064
willy tarreaudd07e972005-12-18 00:48:48 +01005065 if (s->health == s->rise) {
5066 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005067 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005068
5069 if (find_server(s->proxy) == NULL) {
5070 Alert("Proxy %s has no server available !\n", s->proxy->id);
5071 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5072 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005073 }
willy tarreauef900ab2005-12-17 12:52:52 +01005074
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 }
5077 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005078 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005079 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005080 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005081 }
5082 /* if result is 0 and there's no timeout, we have to wait again */
5083 }
5084 //fprintf(stderr, "process_chk: 11\n");
5085 s->result = 0;
5086 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005087 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005088}
5089
5090
willy tarreau5cbea6f2005-12-17 12:48:26 +01005091
willy tarreau0f7af912005-12-17 12:21:26 +01005092#if STATTIME > 0
5093int stats(void);
5094#endif
5095
5096/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005097 * This does 4 things :
5098 * - wake up all expired tasks
5099 * - call all runnable tasks
5100 * - call maintain_proxies() to enable/disable the listeners
5101 * - return the delay till next event in ms, -1 = wait indefinitely
5102 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5103 *
willy tarreau0f7af912005-12-17 12:21:26 +01005104 */
5105
willy tarreau1c2ad212005-12-18 01:11:29 +01005106int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005107 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005108 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005109 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005110
willy tarreaub952e1d2005-12-18 01:31:20 +01005111 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005112
willy tarreau1c2ad212005-12-18 01:11:29 +01005113 /* look for expired tasks and add them to the run queue.
5114 */
5115 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5116 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5117 tnext = t->next;
5118 if (t->state & TASK_RUNNING)
5119 continue;
5120
willy tarreaub952e1d2005-12-18 01:31:20 +01005121 if (tv_iseternity(&t->expire))
5122 continue;
5123
willy tarreau1c2ad212005-12-18 01:11:29 +01005124 /* wakeup expired entries. It doesn't matter if they are
5125 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005126 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005127 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005128 task_wakeup(&rq, t);
5129 }
5130 else {
5131 /* first non-runnable task. Use its expiration date as an upper bound */
5132 int temp_time = tv_remain(&now, &t->expire);
5133 if (temp_time)
5134 next_time = temp_time;
5135 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005136 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005137 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005138
willy tarreau1c2ad212005-12-18 01:11:29 +01005139 /* process each task in the run queue now. Each task may be deleted
5140 * since we only use tnext.
5141 */
5142 tnext = rq;
5143 while ((t = tnext) != NULL) {
5144 int temp_time;
5145
5146 tnext = t->rqnext;
5147 task_sleep(&rq, t);
5148 temp_time = t->process(t);
5149 next_time = MINTIME(temp_time, next_time);
5150 }
5151
5152 /* maintain all proxies in a consistent state. This should quickly become a task */
5153 time2 = maintain_proxies();
5154 return MINTIME(time2, next_time);
5155}
5156
5157
5158#if defined(ENABLE_EPOLL)
5159
5160/*
5161 * Main epoll() loop.
5162 */
5163
5164/* does 3 actions :
5165 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5166 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5167 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5168 *
5169 * returns 0 if initialization failed, !0 otherwise.
5170 */
5171
5172int epoll_loop(int action) {
5173 int next_time;
5174 int status;
5175 int fd;
5176
5177 int fds, count;
5178 int pr, pw, sr, sw;
5179 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5180 struct epoll_event ev;
5181
5182 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005183 static struct epoll_event *epoll_events = NULL;
5184 static int epoll_fd;
5185
5186 if (action == POLL_LOOP_ACTION_INIT) {
5187 epoll_fd = epoll_create(global.maxsock + 1);
5188 if (epoll_fd < 0)
5189 return 0;
5190 else {
5191 epoll_events = (struct epoll_event*)
5192 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5193 PrevReadEvent = (fd_set *)
5194 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5195 PrevWriteEvent = (fd_set *)
5196 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005197 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005198 return 1;
5199 }
5200 else if (action == POLL_LOOP_ACTION_CLEAN) {
5201 if (PrevWriteEvent) free(PrevWriteEvent);
5202 if (PrevReadEvent) free(PrevReadEvent);
5203 if (epoll_events) free(epoll_events);
5204 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005205 epoll_fd = 0;
5206 return 1;
5207 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005208
willy tarreau1c2ad212005-12-18 01:11:29 +01005209 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005210
willy tarreau1c2ad212005-12-18 01:11:29 +01005211 tv_now(&now);
5212
5213 while (1) {
5214 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005215
5216 /* stop when there's no connection left and we don't allow them anymore */
5217 if (!actconn && listeners == 0)
5218 break;
5219
willy tarreau0f7af912005-12-17 12:21:26 +01005220#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005221 {
5222 int time2;
5223 time2 = stats();
5224 next_time = MINTIME(time2, next_time);
5225 }
willy tarreau0f7af912005-12-17 12:21:26 +01005226#endif
5227
willy tarreau1c2ad212005-12-18 01:11:29 +01005228 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5229
5230 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5231 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5232
5233 if ((ro^rn) | (wo^wn)) {
5234 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5235#define FDSETS_ARE_INT_ALIGNED
5236#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005237
willy tarreauad90a0c2005-12-18 01:09:15 +01005238#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5239#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005240 pr = (ro >> count) & 1;
5241 pw = (wo >> count) & 1;
5242 sr = (rn >> count) & 1;
5243 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005244#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005245 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5246 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5247 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5248 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005249#endif
5250#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005251 pr = FD_ISSET(fd, PrevReadEvent);
5252 pw = FD_ISSET(fd, PrevWriteEvent);
5253 sr = FD_ISSET(fd, StaticReadEvent);
5254 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005255#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005256 if (!((sr^pr) | (sw^pw)))
5257 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005258
willy tarreau1c2ad212005-12-18 01:11:29 +01005259 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5260 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005261
willy tarreaub952e1d2005-12-18 01:31:20 +01005262#ifdef EPOLL_CTL_MOD_WORKAROUND
5263 /* I encountered a rarely reproducible problem with
5264 * EPOLL_CTL_MOD where a modified FD (systematically
5265 * the one in epoll_events[0], fd#7) would sometimes
5266 * be set EPOLL_OUT while asked for a read ! This is
5267 * with the 2.4 epoll patch. The workaround is to
5268 * delete then recreate in case of modification.
5269 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5270 * nor RHEL kernels.
5271 */
5272
5273 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5274 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5275
5276 if ((sr | sw))
5277 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5278#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005279 if ((pr | pw)) {
5280 /* the file-descriptor already exists... */
5281 if ((sr | sw)) {
5282 /* ...and it will still exist */
5283 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5284 // perror("epoll_ctl(MOD)");
5285 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005286 }
5287 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005288 /* ...and it will be removed */
5289 if (fdtab[fd].state != FD_STCLOSE &&
5290 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5291 // perror("epoll_ctl(DEL)");
5292 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005293 }
5294 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005295 } else {
5296 /* the file-descriptor did not exist, let's add it */
5297 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5298 // perror("epoll_ctl(ADD)");
5299 // exit(1);
5300 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005301 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005302#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005303 }
5304 ((int*)PrevReadEvent)[fds] = rn;
5305 ((int*)PrevWriteEvent)[fds] = wn;
5306 }
5307 }
5308
5309 /* now let's wait for events */
5310 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5311 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005312
willy tarreau1c2ad212005-12-18 01:11:29 +01005313 for (count = 0; count < status; count++) {
5314 fd = epoll_events[count].data.fd;
5315
5316 if (fdtab[fd].state == FD_STCLOSE)
5317 continue;
5318
5319 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5320 fdtab[fd].read(fd);
5321
5322 if (fdtab[fd].state == FD_STCLOSE)
5323 continue;
5324
5325 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5326 fdtab[fd].write(fd);
5327 }
5328 }
5329 return 1;
5330}
5331#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005332
willy tarreauad90a0c2005-12-18 01:09:15 +01005333
willy tarreau5cbea6f2005-12-17 12:48:26 +01005334
willy tarreau1c2ad212005-12-18 01:11:29 +01005335#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005336
willy tarreau1c2ad212005-12-18 01:11:29 +01005337/*
5338 * Main poll() loop.
5339 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005340
willy tarreau1c2ad212005-12-18 01:11:29 +01005341/* does 3 actions :
5342 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5343 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5344 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5345 *
5346 * returns 0 if initialization failed, !0 otherwise.
5347 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005348
willy tarreau1c2ad212005-12-18 01:11:29 +01005349int poll_loop(int action) {
5350 int next_time;
5351 int status;
5352 int fd, nbfd;
5353
5354 int fds, count;
5355 int sr, sw;
5356 unsigned rn, wn; /* read new, write new */
5357
5358 /* private data */
5359 static struct pollfd *poll_events = NULL;
5360
5361 if (action == POLL_LOOP_ACTION_INIT) {
5362 poll_events = (struct pollfd*)
5363 calloc(1, sizeof(struct pollfd) * global.maxsock);
5364 return 1;
5365 }
5366 else if (action == POLL_LOOP_ACTION_CLEAN) {
5367 if (poll_events)
5368 free(poll_events);
5369 return 1;
5370 }
5371
5372 /* OK, it's POLL_LOOP_ACTION_RUN */
5373
5374 tv_now(&now);
5375
5376 while (1) {
5377 next_time = process_runnable_tasks();
5378
5379 /* stop when there's no connection left and we don't allow them anymore */
5380 if (!actconn && listeners == 0)
5381 break;
5382
5383#if STATTIME > 0
5384 {
5385 int time2;
5386 time2 = stats();
5387 next_time = MINTIME(time2, next_time);
5388 }
5389#endif
5390
5391
5392 nbfd = 0;
5393 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5394
5395 rn = ((int*)StaticReadEvent)[fds];
5396 wn = ((int*)StaticWriteEvent)[fds];
5397
5398 if ((rn|wn)) {
5399 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5400#define FDSETS_ARE_INT_ALIGNED
5401#ifdef FDSETS_ARE_INT_ALIGNED
5402
5403#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5404#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5405 sr = (rn >> count) & 1;
5406 sw = (wn >> count) & 1;
5407#else
5408 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5409 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5410#endif
5411#else
5412 sr = FD_ISSET(fd, StaticReadEvent);
5413 sw = FD_ISSET(fd, StaticWriteEvent);
5414#endif
5415 if ((sr|sw)) {
5416 poll_events[nbfd].fd = fd;
5417 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5418 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005419 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005420 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005421 }
5422 }
5423
5424 /* now let's wait for events */
5425 status = poll(poll_events, nbfd, next_time);
5426 tv_now(&now);
5427
5428 for (count = 0; status > 0 && count < nbfd; count++) {
5429 fd = poll_events[count].fd;
5430
5431 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5432 continue;
5433
5434 /* ok, we found one active fd */
5435 status--;
5436
5437 if (fdtab[fd].state == FD_STCLOSE)
5438 continue;
5439
5440 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5441 fdtab[fd].read(fd);
5442
5443 if (fdtab[fd].state == FD_STCLOSE)
5444 continue;
5445
5446 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5447 fdtab[fd].write(fd);
5448 }
5449 }
5450 return 1;
5451}
willy tarreauad90a0c2005-12-18 01:09:15 +01005452#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005453
willy tarreauad90a0c2005-12-18 01:09:15 +01005454
willy tarreauad90a0c2005-12-18 01:09:15 +01005455
willy tarreau1c2ad212005-12-18 01:11:29 +01005456/*
5457 * Main select() loop.
5458 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005459
willy tarreau1c2ad212005-12-18 01:11:29 +01005460/* does 3 actions :
5461 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5462 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5463 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5464 *
5465 * returns 0 if initialization failed, !0 otherwise.
5466 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005467
willy tarreauad90a0c2005-12-18 01:09:15 +01005468
willy tarreau1c2ad212005-12-18 01:11:29 +01005469int select_loop(int action) {
5470 int next_time;
5471 int status;
5472 int fd,i;
5473 struct timeval delta;
5474 int readnotnull, writenotnull;
5475 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005476
willy tarreau1c2ad212005-12-18 01:11:29 +01005477 if (action == POLL_LOOP_ACTION_INIT) {
5478 ReadEvent = (fd_set *)
5479 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5480 WriteEvent = (fd_set *)
5481 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5482 return 1;
5483 }
5484 else if (action == POLL_LOOP_ACTION_CLEAN) {
5485 if (WriteEvent) free(WriteEvent);
5486 if (ReadEvent) free(ReadEvent);
5487 return 1;
5488 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005489
willy tarreau1c2ad212005-12-18 01:11:29 +01005490 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005491
willy tarreau1c2ad212005-12-18 01:11:29 +01005492 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005493
willy tarreau1c2ad212005-12-18 01:11:29 +01005494 while (1) {
5495 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005496
willy tarreau1c2ad212005-12-18 01:11:29 +01005497 /* stop when there's no connection left and we don't allow them anymore */
5498 if (!actconn && listeners == 0)
5499 break;
5500
5501#if STATTIME > 0
5502 {
5503 int time2;
5504 time2 = stats();
5505 next_time = MINTIME(time2, next_time);
5506 }
5507#endif
5508
willy tarreau1c2ad212005-12-18 01:11:29 +01005509 if (next_time > 0) { /* FIXME */
5510 /* Convert to timeval */
5511 /* to avoid eventual select loops due to timer precision */
5512 next_time += SCHEDULER_RESOLUTION;
5513 delta.tv_sec = next_time / 1000;
5514 delta.tv_usec = (next_time % 1000) * 1000;
5515 }
5516 else if (next_time == 0) { /* allow select to return immediately when needed */
5517 delta.tv_sec = delta.tv_usec = 0;
5518 }
5519
5520
5521 /* let's restore fdset state */
5522
5523 readnotnull = 0; writenotnull = 0;
5524 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5525 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5526 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5527 }
5528
5529 // /* just a verification code, needs to be removed for performance */
5530 // for (i=0; i<maxfd; i++) {
5531 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5532 // abort();
5533 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5534 // abort();
5535 //
5536 // }
5537
5538 status = select(maxfd,
5539 readnotnull ? ReadEvent : NULL,
5540 writenotnull ? WriteEvent : NULL,
5541 NULL,
5542 (next_time >= 0) ? &delta : NULL);
5543
5544 /* this is an experiment on the separation of the select work */
5545 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5546 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5547
5548 tv_now(&now);
5549
5550 if (status > 0) { /* must proceed with events */
5551
5552 int fds;
5553 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005554
willy tarreau1c2ad212005-12-18 01:11:29 +01005555 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5556 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5557 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5558
5559 /* if we specify read first, the accepts and zero reads will be
5560 * seen first. Moreover, system buffers will be flushed faster.
5561 */
5562 if (fdtab[fd].state == FD_STCLOSE)
5563 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005564
willy tarreau1c2ad212005-12-18 01:11:29 +01005565 if (FD_ISSET(fd, ReadEvent))
5566 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005567
willy tarreau1c2ad212005-12-18 01:11:29 +01005568 if (FD_ISSET(fd, WriteEvent))
5569 fdtab[fd].write(fd);
5570 }
5571 }
5572 else {
5573 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005574 }
willy tarreau0f7af912005-12-17 12:21:26 +01005575 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005576 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005577}
5578
5579
5580#if STATTIME > 0
5581/*
5582 * Display proxy statistics regularly. It is designed to be called from the
5583 * select_loop().
5584 */
5585int stats(void) {
5586 static int lines;
5587 static struct timeval nextevt;
5588 static struct timeval lastevt;
5589 static struct timeval starttime = {0,0};
5590 unsigned long totaltime, deltatime;
5591 int ret;
5592
willy tarreau750a4722005-12-17 13:21:24 +01005593 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005594 deltatime = (tv_diff(&lastevt, &now)?:1);
5595 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005596
willy tarreau9fe663a2005-12-17 13:02:59 +01005597 if (global.mode & MODE_STATS) {
5598 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005599 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005600 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5601 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005602 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005603 actconn, totalconn,
5604 stats_tsk_new, stats_tsk_good,
5605 stats_tsk_left, stats_tsk_right,
5606 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5607 }
5608 }
5609
5610 tv_delayfrom(&nextevt, &now, STATTIME);
5611
5612 lastevt=now;
5613 }
5614 ret = tv_remain(&now, &nextevt);
5615 return ret;
5616}
5617#endif
5618
5619
5620/*
5621 * this function enables proxies when there are enough free sessions,
5622 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005623 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005624 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005625 */
5626static int maintain_proxies(void) {
5627 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005628 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005629 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005630
5631 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005632 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005633
5634 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005635 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005636 while (p) {
5637 if (p->nbconn < p->maxconn) {
5638 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005639 for (l = p->listen; l != NULL; l = l->next) {
5640 FD_SET(l->fd, StaticReadEvent);
5641 }
willy tarreau0f7af912005-12-17 12:21:26 +01005642 p->state = PR_STRUN;
5643 }
5644 }
5645 else {
5646 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005647 for (l = p->listen; l != NULL; l = l->next) {
5648 FD_CLR(l->fd, StaticReadEvent);
5649 }
willy tarreau0f7af912005-12-17 12:21:26 +01005650 p->state = PR_STIDLE;
5651 }
5652 }
5653 p = p->next;
5654 }
5655 }
5656 else { /* block all proxies */
5657 while (p) {
5658 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005659 for (l = p->listen; l != NULL; l = l->next) {
5660 FD_CLR(l->fd, StaticReadEvent);
5661 }
willy tarreau0f7af912005-12-17 12:21:26 +01005662 p->state = PR_STIDLE;
5663 }
5664 p = p->next;
5665 }
5666 }
5667
willy tarreau5cbea6f2005-12-17 12:48:26 +01005668 if (stopping) {
5669 p = proxy;
5670 while (p) {
5671 if (p->state != PR_STDISABLED) {
5672 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005673 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005674 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005675 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005676 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005677
willy tarreaua41a8b42005-12-17 14:02:24 +01005678 for (l = p->listen; l != NULL; l = l->next) {
5679 fd_delete(l->fd);
5680 listeners--;
5681 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005682 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005683 }
5684 else {
5685 tleft = MINTIME(t, tleft);
5686 }
5687 }
5688 p = p->next;
5689 }
5690 }
5691 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005692}
5693
5694/*
5695 * this function disables health-check servers so that the process will quickly be ignored
5696 * by load balancers.
5697 */
5698static void soft_stop(void) {
5699 struct proxy *p;
5700
5701 stopping = 1;
5702 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005703 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005704 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005705 if (p->state != PR_STDISABLED) {
5706 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005707 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005708 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005709 }
willy tarreau0f7af912005-12-17 12:21:26 +01005710 p = p->next;
5711 }
5712}
5713
5714/*
5715 * upon SIGUSR1, let's have a soft stop.
5716 */
5717void sig_soft_stop(int sig) {
5718 soft_stop();
5719 signal(sig, SIG_IGN);
5720}
5721
5722
willy tarreau8337c6b2005-12-17 13:41:01 +01005723/*
5724 * this function dumps every server's state when the process receives SIGHUP.
5725 */
5726void sig_dump_state(int sig) {
5727 struct proxy *p = proxy;
5728
5729 Warning("SIGHUP received, dumping servers states.\n");
5730 while (p) {
5731 struct server *s = p->srv;
5732
5733 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5734 while (s) {
5735 if (s->state & SRV_RUNNING) {
5736 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5737 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5738 }
5739 else {
5740 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5741 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5742 }
5743 s = s->next;
5744 }
willy tarreaudd07e972005-12-18 00:48:48 +01005745
5746 if (find_server(p) == NULL) {
5747 Warning("SIGHUP: proxy %s has no server available !\n", p);
5748 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5749 }
5750
willy tarreau8337c6b2005-12-17 13:41:01 +01005751 p = p->next;
5752 }
5753 signal(sig, sig_dump_state);
5754}
5755
willy tarreau0f7af912005-12-17 12:21:26 +01005756void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005757 struct task *t, *tnext;
5758 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005759
willy tarreau5cbea6f2005-12-17 12:48:26 +01005760 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5761 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5762 tnext = t->next;
5763 s = t->context;
5764 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5765 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5766 "req=%d, rep=%d, clifd=%d\n",
5767 s, tv_remain(&now, &t->expire),
5768 s->cli_state,
5769 s->srv_state,
5770 FD_ISSET(s->cli_fd, StaticReadEvent),
5771 FD_ISSET(s->cli_fd, StaticWriteEvent),
5772 FD_ISSET(s->srv_fd, StaticReadEvent),
5773 FD_ISSET(s->srv_fd, StaticWriteEvent),
5774 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5775 );
willy tarreau0f7af912005-12-17 12:21:26 +01005776 }
willy tarreau12350152005-12-18 01:03:27 +01005777}
5778
willy tarreau64a3cc32005-12-18 01:13:11 +01005779#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005780static void fast_stop(void)
5781{
5782 struct proxy *p;
5783 p = proxy;
5784 while (p) {
5785 p->grace = 0;
5786 p = p->next;
5787 }
5788 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005789}
5790
willy tarreau12350152005-12-18 01:03:27 +01005791void sig_int(int sig) {
5792 /* This would normally be a hard stop,
5793 but we want to be sure about deallocation,
5794 and so on, so we do a soft stop with
5795 0 GRACE time
5796 */
5797 fast_stop();
5798 /* If we are killed twice, we decide to die*/
5799 signal(sig, SIG_DFL);
5800}
5801
5802void sig_term(int sig) {
5803 /* This would normally be a hard stop,
5804 but we want to be sure about deallocation,
5805 and so on, so we do a soft stop with
5806 0 GRACE time
5807 */
5808 fast_stop();
5809 /* If we are killed twice, we decide to die*/
5810 signal(sig, SIG_DFL);
5811}
willy tarreau64a3cc32005-12-18 01:13:11 +01005812#endif
willy tarreau12350152005-12-18 01:03:27 +01005813
willy tarreauc1f47532005-12-18 01:08:26 +01005814/* returns the pointer to an error in the replacement string, or NULL if OK */
5815char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005816 struct hdr_exp *exp;
5817
willy tarreauc1f47532005-12-18 01:08:26 +01005818 if (replace != NULL) {
5819 char *err;
5820 err = check_replace_string(replace);
5821 if (err)
5822 return err;
5823 }
5824
willy tarreaue39cd132005-12-17 13:00:18 +01005825 while (*head != NULL)
5826 head = &(*head)->next;
5827
5828 exp = calloc(1, sizeof(struct hdr_exp));
5829
5830 exp->preg = preg;
5831 exp->replace = replace;
5832 exp->action = action;
5833 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005834
5835 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005836}
5837
willy tarreau9fe663a2005-12-17 13:02:59 +01005838
willy tarreau0f7af912005-12-17 12:21:26 +01005839/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005841 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005842int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005843
willy tarreau9fe663a2005-12-17 13:02:59 +01005844 if (!strcmp(args[0], "global")) { /* new section */
5845 /* no option, nothing special to do */
5846 return 0;
5847 }
5848 else if (!strcmp(args[0], "daemon")) {
5849 global.mode |= MODE_DAEMON;
5850 }
5851 else if (!strcmp(args[0], "debug")) {
5852 global.mode |= MODE_DEBUG;
5853 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005854 else if (!strcmp(args[0], "noepoll")) {
5855 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5856 }
5857 else if (!strcmp(args[0], "nopoll")) {
5858 cfg_polling_mechanism &= ~POLL_USE_POLL;
5859 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005860 else if (!strcmp(args[0], "quiet")) {
5861 global.mode |= MODE_QUIET;
5862 }
5863 else if (!strcmp(args[0], "stats")) {
5864 global.mode |= MODE_STATS;
5865 }
5866 else if (!strcmp(args[0], "uid")) {
5867 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005868 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005869 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005870 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005871 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005872 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005873 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005874 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005875 global.uid = atol(args[1]);
5876 }
5877 else if (!strcmp(args[0], "gid")) {
5878 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005879 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005880 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005881 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005882 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005883 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005884 return -1;
5885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005886 global.gid = atol(args[1]);
5887 }
5888 else if (!strcmp(args[0], "nbproc")) {
5889 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005890 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005891 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005893 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005894 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005895 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005896 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005897 global.nbproc = atol(args[1]);
5898 }
5899 else if (!strcmp(args[0], "maxconn")) {
5900 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005901 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005902 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005904 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005905 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005906 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005907 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005908 global.maxconn = atol(args[1]);
5909 }
willy tarreaub1285d52005-12-18 01:20:14 +01005910 else if (!strcmp(args[0], "ulimit-n")) {
5911 if (global.rlimit_nofile != 0) {
5912 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5913 return 0;
5914 }
5915 if (*(args[1]) == 0) {
5916 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5917 return -1;
5918 }
5919 global.rlimit_nofile = atol(args[1]);
5920 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005921 else if (!strcmp(args[0], "chroot")) {
5922 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005923 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005924 return 0;
5925 }
5926 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005927 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005928 return -1;
5929 }
5930 global.chroot = strdup(args[1]);
5931 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005932 else if (!strcmp(args[0], "pidfile")) {
5933 if (global.pidfile != NULL) {
5934 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5935 return 0;
5936 }
5937 if (*(args[1]) == 0) {
5938 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5939 return -1;
5940 }
5941 global.pidfile = strdup(args[1]);
5942 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005943 else if (!strcmp(args[0], "log")) { /* syslog server address */
5944 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005945 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005946
5947 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005948 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005949 return -1;
5950 }
5951
5952 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5953 if (!strcmp(log_facilities[facility], args[2]))
5954 break;
5955
5956 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005957 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005958 exit(1);
5959 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005960
5961 level = 7; /* max syslog level = debug */
5962 if (*(args[3])) {
5963 while (level >= 0 && strcmp(log_levels[level], args[3]))
5964 level--;
5965 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005966 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005967 exit(1);
5968 }
5969 }
5970
willy tarreau9fe663a2005-12-17 13:02:59 +01005971 sa = str2sa(args[1]);
5972 if (!sa->sin_port)
5973 sa->sin_port = htons(SYSLOG_PORT);
5974
5975 if (global.logfac1 == -1) {
5976 global.logsrv1 = *sa;
5977 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005978 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005979 }
5980 else if (global.logfac2 == -1) {
5981 global.logsrv2 = *sa;
5982 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005983 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005984 }
5985 else {
5986 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5987 return -1;
5988 }
5989
5990 }
5991 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005992 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005993 return -1;
5994 }
5995 return 0;
5996}
5997
5998
willy tarreaua41a8b42005-12-17 14:02:24 +01005999void init_default_instance() {
6000 memset(&defproxy, 0, sizeof(defproxy));
6001 defproxy.mode = PR_MODE_TCP;
6002 defproxy.state = PR_STNEW;
6003 defproxy.maxconn = cfg_maxpconn;
6004 defproxy.conn_retries = CONN_RETRIES;
6005 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6006}
6007
willy tarreau9fe663a2005-12-17 13:02:59 +01006008/*
6009 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6010 */
6011int cfg_parse_listen(char *file, int linenum, char **args) {
6012 static struct proxy *curproxy = NULL;
6013 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006014 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006015 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006016
6017 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006018 if (!*args[1]) {
6019 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6020 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006021 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006022 return -1;
6023 }
6024
6025 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006026 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006027 return -1;
6028 }
6029 curproxy->next = proxy;
6030 proxy = curproxy;
6031 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01006032 if (strchr(args[2], ':') != NULL)
6033 curproxy->listen = str2listener(args[2], curproxy->listen);
6034
willy tarreau9fe663a2005-12-17 13:02:59 +01006035 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006036 curproxy->state = defproxy.state;
6037 curproxy->maxconn = defproxy.maxconn;
6038 curproxy->conn_retries = defproxy.conn_retries;
6039 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006040
6041 if (defproxy.check_req)
6042 curproxy->check_req = strdup(defproxy.check_req);
6043 curproxy->check_len = defproxy.check_len;
6044
6045 if (defproxy.cookie_name)
6046 curproxy->cookie_name = strdup(defproxy.cookie_name);
6047 curproxy->cookie_len = defproxy.cookie_len;
6048
6049 if (defproxy.capture_name)
6050 curproxy->capture_name = strdup(defproxy.capture_name);
6051 curproxy->capture_namelen = defproxy.capture_namelen;
6052 curproxy->capture_len = defproxy.capture_len;
6053
6054 if (defproxy.errmsg.msg400)
6055 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6056 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6057
6058 if (defproxy.errmsg.msg403)
6059 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6060 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6061
6062 if (defproxy.errmsg.msg408)
6063 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6064 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6065
6066 if (defproxy.errmsg.msg500)
6067 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6068 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6069
6070 if (defproxy.errmsg.msg502)
6071 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6072 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6073
6074 if (defproxy.errmsg.msg503)
6075 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6076 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6077
6078 if (defproxy.errmsg.msg504)
6079 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6080 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6081
willy tarreaua41a8b42005-12-17 14:02:24 +01006082 curproxy->clitimeout = defproxy.clitimeout;
6083 curproxy->contimeout = defproxy.contimeout;
6084 curproxy->srvtimeout = defproxy.srvtimeout;
6085 curproxy->mode = defproxy.mode;
6086 curproxy->logfac1 = defproxy.logfac1;
6087 curproxy->logsrv1 = defproxy.logsrv1;
6088 curproxy->loglev1 = defproxy.loglev1;
6089 curproxy->logfac2 = defproxy.logfac2;
6090 curproxy->logsrv2 = defproxy.logsrv2;
6091 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006092 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006093 curproxy->grace = defproxy.grace;
6094 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006095 curproxy->mon_net = defproxy.mon_net;
6096 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006097 return 0;
6098 }
6099 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006100 /* some variables may have already been initialized earlier */
6101 if (defproxy.check_req) free(defproxy.check_req);
6102 if (defproxy.cookie_name) free(defproxy.cookie_name);
6103 if (defproxy.capture_name) free(defproxy.capture_name);
6104 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6105 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6106 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6107 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6108 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6109 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6110 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6111
6112 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006113 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006114 return 0;
6115 }
6116 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006117 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006118 return -1;
6119 }
6120
willy tarreaua41a8b42005-12-17 14:02:24 +01006121 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6122 if (curproxy == &defproxy) {
6123 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6124 return -1;
6125 }
6126
6127 if (strchr(args[1], ':') == NULL) {
6128 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6129 file, linenum, args[0]);
6130 return -1;
6131 }
6132 curproxy->listen = str2listener(args[1], curproxy->listen);
6133 return 0;
6134 }
willy tarreaub1285d52005-12-18 01:20:14 +01006135 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6136 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6137 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6138 file, linenum, args[0]);
6139 return -1;
6140 }
6141 /* flush useless bits */
6142 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6143 return 0;
6144 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006145 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006146 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6147 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6148 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6149 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006150 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006151 return -1;
6152 }
6153 }
6154 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6155 curproxy->state = PR_STDISABLED;
6156 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006157 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6158 curproxy->state = PR_STNEW;
6159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006160 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6161 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006162// if (curproxy == &defproxy) {
6163// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6164// return -1;
6165// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006166
willy tarreau9fe663a2005-12-17 13:02:59 +01006167 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006168// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6169// file, linenum);
6170// return 0;
6171 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006172 }
6173
6174 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006175 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6176 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006177 return -1;
6178 }
6179 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006180 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006181
6182 cur_arg = 2;
6183 while (*(args[cur_arg])) {
6184 if (!strcmp(args[cur_arg], "rewrite")) {
6185 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006186 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006187 else if (!strcmp(args[cur_arg], "indirect")) {
6188 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006189 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006190 else if (!strcmp(args[cur_arg], "insert")) {
6191 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006192 }
willy tarreau240afa62005-12-17 13:14:35 +01006193 else if (!strcmp(args[cur_arg], "nocache")) {
6194 curproxy->options |= PR_O_COOK_NOC;
6195 }
willy tarreaucd878942005-12-17 13:27:43 +01006196 else if (!strcmp(args[cur_arg], "postonly")) {
6197 curproxy->options |= PR_O_COOK_POST;
6198 }
willy tarreau0174f312005-12-18 01:02:42 +01006199 else if (!strcmp(args[cur_arg], "prefix")) {
6200 curproxy->options |= PR_O_COOK_PFX;
6201 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006202 else {
willy tarreau0174f312005-12-18 01:02:42 +01006203 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006204 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006205 return -1;
6206 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006207 cur_arg++;
6208 }
willy tarreau0174f312005-12-18 01:02:42 +01006209 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6210 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6211 file, linenum);
6212 return -1;
6213 }
6214
6215 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6216 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006217 file, linenum);
6218 return -1;
6219 }
willy tarreau12350152005-12-18 01:03:27 +01006220 }/* end else if (!strcmp(args[0], "cookie")) */
6221 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6222// if (curproxy == &defproxy) {
6223// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6224// return -1;
6225// }
6226
6227 if (curproxy->appsession_name != NULL) {
6228// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6229// file, linenum);
6230// return 0;
6231 free(curproxy->appsession_name);
6232 }
6233
6234 if (*(args[5]) == 0) {
6235 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6236 file, linenum, args[0]);
6237 return -1;
6238 }
6239 have_appsession = 1;
6240 curproxy->appsession_name = strdup(args[1]);
6241 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6242 curproxy->appsession_len = atoi(args[3]);
6243 curproxy->appsession_timeout = atoi(args[5]);
6244 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6245 if (rc) {
6246 Alert("Error Init Appsession Hashtable.\n");
6247 return -1;
6248 }
6249 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006250 else if (!strcmp(args[0], "capture")) {
6251 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6252 // if (curproxy == &defproxy) {
6253 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6254 // return -1;
6255 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006256
willy tarreau4302f492005-12-18 01:00:37 +01006257 if (curproxy->capture_name != NULL) {
6258 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6259 // file, linenum, args[0]);
6260 // return 0;
6261 free(curproxy->capture_name);
6262 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006263
willy tarreau4302f492005-12-18 01:00:37 +01006264 if (*(args[4]) == 0) {
6265 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6266 file, linenum, args[0]);
6267 return -1;
6268 }
6269 curproxy->capture_name = strdup(args[2]);
6270 curproxy->capture_namelen = strlen(curproxy->capture_name);
6271 curproxy->capture_len = atol(args[4]);
6272 if (curproxy->capture_len >= CAPTURE_LEN) {
6273 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6274 file, linenum, CAPTURE_LEN - 1);
6275 curproxy->capture_len = CAPTURE_LEN - 1;
6276 }
6277 curproxy->to_log |= LW_COOKIE;
6278 }
6279 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6280 struct cap_hdr *hdr;
6281
6282 if (curproxy == &defproxy) {
6283 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6284 return -1;
6285 }
6286
6287 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6288 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6289 file, linenum, args[0], args[1]);
6290 return -1;
6291 }
6292
6293 hdr = calloc(sizeof(struct cap_hdr), 1);
6294 hdr->next = curproxy->req_cap;
6295 hdr->name = strdup(args[3]);
6296 hdr->namelen = strlen(args[3]);
6297 hdr->len = atol(args[5]);
6298 hdr->index = curproxy->nb_req_cap++;
6299 curproxy->req_cap = hdr;
6300 curproxy->to_log |= LW_REQHDR;
6301 }
6302 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6303 struct cap_hdr *hdr;
6304
6305 if (curproxy == &defproxy) {
6306 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6307 return -1;
6308 }
6309
6310 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6311 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6312 file, linenum, args[0], args[1]);
6313 return -1;
6314 }
6315 hdr = calloc(sizeof(struct cap_hdr), 1);
6316 hdr->next = curproxy->rsp_cap;
6317 hdr->name = strdup(args[3]);
6318 hdr->namelen = strlen(args[3]);
6319 hdr->len = atol(args[5]);
6320 hdr->index = curproxy->nb_rsp_cap++;
6321 curproxy->rsp_cap = hdr;
6322 curproxy->to_log |= LW_RSPHDR;
6323 }
6324 else {
6325 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006326 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006327 return -1;
6328 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006329 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006330 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006331 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006332 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006333 return 0;
6334 }
6335 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006336 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6337 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006338 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006339 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006340 curproxy->contimeout = atol(args[1]);
6341 }
6342 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006343 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006344 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6345 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006346 return 0;
6347 }
6348 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006349 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6350 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006351 return -1;
6352 }
6353 curproxy->clitimeout = atol(args[1]);
6354 }
6355 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006356 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006357 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006358 return 0;
6359 }
6360 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006361 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6362 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006363 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006364 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006365 curproxy->srvtimeout = atol(args[1]);
6366 }
6367 else if (!strcmp(args[0], "retries")) { /* connection retries */
6368 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006369 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6370 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006371 return -1;
6372 }
6373 curproxy->conn_retries = atol(args[1]);
6374 }
6375 else if (!strcmp(args[0], "option")) {
6376 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006377 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return -1;
6379 }
6380 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006381 /* enable reconnections to dispatch */
6382 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006383#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006384 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006385 /* enable transparent proxy connections */
6386 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006387#endif
6388 else if (!strcmp(args[1], "keepalive"))
6389 /* enable keep-alive */
6390 curproxy->options |= PR_O_KEEPALIVE;
6391 else if (!strcmp(args[1], "forwardfor"))
6392 /* insert x-forwarded-for field */
6393 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006394 else if (!strcmp(args[1], "logasap"))
6395 /* log as soon as possible, without waiting for the session to complete */
6396 curproxy->options |= PR_O_LOGASAP;
6397 else if (!strcmp(args[1], "httpclose"))
6398 /* force connection: close in both directions in HTTP mode */
6399 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006400 else if (!strcmp(args[1], "checkcache"))
6401 /* require examination of cacheability of the 'set-cookie' field */
6402 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006403 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006405 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006406 else if (!strcmp(args[1], "tcplog"))
6407 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006408 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006409 else if (!strcmp(args[1], "dontlognull")) {
6410 /* don't log empty requests */
6411 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006412 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006413 else if (!strcmp(args[1], "tcpka")) {
6414 /* enable TCP keep-alives on client and server sessions */
6415 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6416 }
6417 else if (!strcmp(args[1], "clitcpka")) {
6418 /* enable TCP keep-alives on client sessions */
6419 curproxy->options |= PR_O_TCP_CLI_KA;
6420 }
6421 else if (!strcmp(args[1], "srvtcpka")) {
6422 /* enable TCP keep-alives on server sessions */
6423 curproxy->options |= PR_O_TCP_SRV_KA;
6424 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006425 else if (!strcmp(args[1], "httpchk")) {
6426 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006427 if (curproxy->check_req != NULL) {
6428 free(curproxy->check_req);
6429 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006430 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006431 if (!*args[2]) { /* no argument */
6432 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6433 curproxy->check_len = strlen(DEF_CHECK_REQ);
6434 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006435 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6436 curproxy->check_req = (char *)malloc(reqlen);
6437 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6438 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006439 } else { /* more arguments : METHOD URI [HTTP_VER] */
6440 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6441 if (*args[4])
6442 reqlen += strlen(args[4]);
6443 else
6444 reqlen += strlen("HTTP/1.0");
6445
6446 curproxy->check_req = (char *)malloc(reqlen);
6447 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6448 "%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 +01006449 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006450 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006451 else if (!strcmp(args[1], "persist")) {
6452 /* persist on using the server specified by the cookie, even when it's down */
6453 curproxy->options |= PR_O_PERSIST;
6454 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006455 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006456 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006457 return -1;
6458 }
6459 return 0;
6460 }
6461 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6462 /* enable reconnections to dispatch */
6463 curproxy->options |= PR_O_REDISP;
6464 }
willy tarreaua1598082005-12-17 13:08:06 +01006465#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006466 else if (!strcmp(args[0], "transparent")) {
6467 /* enable transparent proxy connections */
6468 curproxy->options |= PR_O_TRANSP;
6469 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006470#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006471 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6472 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006473 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006474 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006475 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006476 curproxy->maxconn = atol(args[1]);
6477 }
6478 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6479 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006480 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006481 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006482 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006483 curproxy->grace = atol(args[1]);
6484 }
6485 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006486 if (curproxy == &defproxy) {
6487 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6488 return -1;
6489 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006490 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006491 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006492 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006493 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006494 curproxy->dispatch_addr = *str2sa(args[1]);
6495 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006496 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006497 if (*(args[1])) {
6498 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006499 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006500 }
6501 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006502 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006503 return -1;
6504 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006505 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006506 else /* if no option is set, use round-robin by default */
6507 curproxy->options |= PR_O_BALANCE_RR;
6508 }
6509 else if (!strcmp(args[0], "server")) { /* server address */
6510 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006511 char *rport;
6512 char *raddr;
6513 short realport;
6514 int do_check;
6515
6516 if (curproxy == &defproxy) {
6517 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6518 return -1;
6519 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006520
willy tarreaua41a8b42005-12-17 14:02:24 +01006521 if (!*args[2]) {
6522 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006523 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006524 return -1;
6525 }
6526 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6527 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6528 return -1;
6529 }
willy tarreau0174f312005-12-18 01:02:42 +01006530
6531 if (curproxy->srv == NULL)
6532 curproxy->srv = newsrv;
6533 else
6534 curproxy->cursrv->next = newsrv;
6535 curproxy->cursrv = newsrv;
6536
6537 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006538 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006539
6540 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006541 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006542 newsrv->id = strdup(args[1]);
6543
6544 /* several ways to check the port component :
6545 * - IP => port=+0, relative
6546 * - IP: => port=+0, relative
6547 * - IP:N => port=N, absolute
6548 * - IP:+N => port=+N, relative
6549 * - IP:-N => port=-N, relative
6550 */
6551 raddr = strdup(args[2]);
6552 rport = strchr(raddr, ':');
6553 if (rport) {
6554 *rport++ = 0;
6555 realport = atol(rport);
6556 if (!isdigit((int)*rport))
6557 newsrv->state |= SRV_MAPPORTS;
6558 } else {
6559 realport = 0;
6560 newsrv->state |= SRV_MAPPORTS;
6561 }
6562
6563 newsrv->addr = *str2sa(raddr);
6564 newsrv->addr.sin_port = htons(realport);
6565 free(raddr);
6566
willy tarreau9fe663a2005-12-17 13:02:59 +01006567 newsrv->curfd = -1; /* no health-check in progress */
6568 newsrv->inter = DEF_CHKINTR;
6569 newsrv->rise = DEF_RISETIME;
6570 newsrv->fall = DEF_FALLTIME;
6571 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6572 cur_arg = 3;
6573 while (*args[cur_arg]) {
6574 if (!strcmp(args[cur_arg], "cookie")) {
6575 newsrv->cookie = strdup(args[cur_arg + 1]);
6576 newsrv->cklen = strlen(args[cur_arg + 1]);
6577 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006578 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006579 else if (!strcmp(args[cur_arg], "rise")) {
6580 newsrv->rise = atol(args[cur_arg + 1]);
6581 newsrv->health = newsrv->rise;
6582 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006583 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006584 else if (!strcmp(args[cur_arg], "fall")) {
6585 newsrv->fall = atol(args[cur_arg + 1]);
6586 cur_arg += 2;
6587 }
6588 else if (!strcmp(args[cur_arg], "inter")) {
6589 newsrv->inter = atol(args[cur_arg + 1]);
6590 cur_arg += 2;
6591 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006592 else if (!strcmp(args[cur_arg], "port")) {
6593 newsrv->check_port = atol(args[cur_arg + 1]);
6594 cur_arg += 2;
6595 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006596 else if (!strcmp(args[cur_arg], "backup")) {
6597 newsrv->state |= SRV_BACKUP;
6598 cur_arg ++;
6599 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006600 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006601 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006602 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006603 }
willy tarreau0174f312005-12-18 01:02:42 +01006604 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6605 if (!*args[cur_arg + 1]) {
6606 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6607 file, linenum, "source");
6608 return -1;
6609 }
6610 newsrv->state |= SRV_BIND_SRC;
6611 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6612 cur_arg += 2;
6613 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006614 else {
willy tarreau0174f312005-12-18 01:02:42 +01006615 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 +01006616 file, linenum, newsrv->id);
6617 return -1;
6618 }
6619 }
6620
6621 if (do_check) {
6622 struct task *t;
6623
6624 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6625 newsrv->check_port = realport; /* by default */
6626 if (!newsrv->check_port) {
6627 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 +01006628 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006629 return -1;
6630 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006631
6632 if ((t = pool_alloc(task)) == NULL) {
6633 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6634 return -1;
6635 }
6636
6637 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6638 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6639 t->state = TASK_IDLE;
6640 t->process = process_chk;
6641 t->context = newsrv;
6642
6643 if (curproxy->state != PR_STDISABLED) {
6644 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6645 task_queue(t);
6646 task_wakeup(&rq, t);
6647 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006648 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006649
willy tarreau9fe663a2005-12-17 13:02:59 +01006650 curproxy->nbservers++;
6651 }
6652 else if (!strcmp(args[0], "log")) { /* syslog server address */
6653 struct sockaddr_in *sa;
6654 int facility;
6655
6656 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6657 curproxy->logfac1 = global.logfac1;
6658 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006659 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006660 curproxy->logfac2 = global.logfac2;
6661 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006662 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006663 }
6664 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006665 int level;
6666
willy tarreau0f7af912005-12-17 12:21:26 +01006667 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6668 if (!strcmp(log_facilities[facility], args[2]))
6669 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006670
willy tarreau0f7af912005-12-17 12:21:26 +01006671 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006672 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006673 exit(1);
6674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006675
willy tarreau8337c6b2005-12-17 13:41:01 +01006676 level = 7; /* max syslog level = debug */
6677 if (*(args[3])) {
6678 while (level >= 0 && strcmp(log_levels[level], args[3]))
6679 level--;
6680 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006681 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006682 exit(1);
6683 }
6684 }
6685
willy tarreau0f7af912005-12-17 12:21:26 +01006686 sa = str2sa(args[1]);
6687 if (!sa->sin_port)
6688 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006689
willy tarreau0f7af912005-12-17 12:21:26 +01006690 if (curproxy->logfac1 == -1) {
6691 curproxy->logsrv1 = *sa;
6692 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006693 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006694 }
6695 else if (curproxy->logfac2 == -1) {
6696 curproxy->logsrv2 = *sa;
6697 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006698 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006699 }
6700 else {
6701 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006702 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006703 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006704 }
6705 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006706 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006707 file, linenum);
6708 return -1;
6709 }
6710 }
willy tarreaua1598082005-12-17 13:08:06 +01006711 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006712 if (!*args[1]) {
6713 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006714 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006715 return -1;
6716 }
6717
6718 curproxy->source_addr = *str2sa(args[1]);
6719 curproxy->options |= PR_O_BIND_SRC;
6720 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006721 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6722 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006723 if (curproxy == &defproxy) {
6724 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6725 return -1;
6726 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006727
6728 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006729 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6730 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006731 return -1;
6732 }
6733
6734 preg = calloc(1, sizeof(regex_t));
6735 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006736 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006737 return -1;
6738 }
6739
willy tarreauc1f47532005-12-18 01:08:26 +01006740 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6741 if (err) {
6742 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6743 file, linenum, *err);
6744 return -1;
6745 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006746 }
6747 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6748 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006749 if (curproxy == &defproxy) {
6750 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6751 return -1;
6752 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006753
6754 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006755 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006756 return -1;
6757 }
6758
6759 preg = calloc(1, sizeof(regex_t));
6760 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006761 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006762 return -1;
6763 }
6764
6765 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6766 }
6767 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6768 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006769 if (curproxy == &defproxy) {
6770 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6771 return -1;
6772 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006773
6774 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006775 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006776 return -1;
6777 }
6778
6779 preg = calloc(1, sizeof(regex_t));
6780 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006781 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006782 return -1;
6783 }
6784
6785 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6786 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006787 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6788 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006789 if (curproxy == &defproxy) {
6790 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6791 return -1;
6792 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006793
6794 if (*(args[1]) == 0) {
6795 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6796 return -1;
6797 }
6798
6799 preg = calloc(1, sizeof(regex_t));
6800 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6801 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6802 return -1;
6803 }
6804
6805 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6806 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006807 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6808 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006809 if (curproxy == &defproxy) {
6810 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6811 return -1;
6812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813
6814 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006815 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006816 return -1;
6817 }
6818
6819 preg = calloc(1, sizeof(regex_t));
6820 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006821 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006822 return -1;
6823 }
6824
6825 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6826 }
6827 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6828 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006829 if (curproxy == &defproxy) {
6830 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6831 return -1;
6832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006833
6834 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006835 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6836 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006837 return -1;
6838 }
6839
6840 preg = calloc(1, sizeof(regex_t));
6841 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006842 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006843 return -1;
6844 }
6845
willy tarreauc1f47532005-12-18 01:08:26 +01006846 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6847 if (err) {
6848 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6849 file, linenum, *err);
6850 return -1;
6851 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006852 }
6853 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6854 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006855 if (curproxy == &defproxy) {
6856 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6857 return -1;
6858 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006859
6860 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006861 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006862 return -1;
6863 }
6864
6865 preg = calloc(1, sizeof(regex_t));
6866 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006867 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006868 return -1;
6869 }
6870
6871 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6872 }
6873 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6874 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006875 if (curproxy == &defproxy) {
6876 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6877 return -1;
6878 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006879
6880 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006881 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006882 return -1;
6883 }
6884
6885 preg = calloc(1, sizeof(regex_t));
6886 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006887 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 return -1;
6889 }
6890
6891 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6892 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006893 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6894 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006895 if (curproxy == &defproxy) {
6896 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6897 return -1;
6898 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006899
6900 if (*(args[1]) == 0) {
6901 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6902 return -1;
6903 }
6904
6905 preg = calloc(1, sizeof(regex_t));
6906 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6907 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6908 return -1;
6909 }
6910
6911 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006913 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6914 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006915 if (curproxy == &defproxy) {
6916 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6917 return -1;
6918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919
6920 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006921 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006922 return -1;
6923 }
6924
6925 preg = calloc(1, sizeof(regex_t));
6926 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006927 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006928 return -1;
6929 }
6930
6931 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6932 }
6933 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006934 if (curproxy == &defproxy) {
6935 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6936 return -1;
6937 }
6938
willy tarreau9fe663a2005-12-17 13:02:59 +01006939 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006940 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006941 return 0;
6942 }
6943
6944 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006945 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006946 return -1;
6947 }
6948
willy tarreau4302f492005-12-18 01:00:37 +01006949 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6950 }
6951 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6952 regex_t *preg;
6953
6954 if (*(args[1]) == 0 || *(args[2]) == 0) {
6955 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6956 file, linenum, args[0]);
6957 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006958 }
willy tarreau4302f492005-12-18 01:00:37 +01006959
6960 preg = calloc(1, sizeof(regex_t));
6961 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6962 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6963 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 }
willy tarreau4302f492005-12-18 01:00:37 +01006965
willy tarreauc1f47532005-12-18 01:08:26 +01006966 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6967 if (err) {
6968 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6969 file, linenum, *err);
6970 return -1;
6971 }
willy tarreau4302f492005-12-18 01:00:37 +01006972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6974 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006975 if (curproxy == &defproxy) {
6976 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6977 return -1;
6978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979
6980 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006981 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 return -1;
6983 }
willy tarreaue39cd132005-12-17 13:00:18 +01006984
willy tarreau9fe663a2005-12-17 13:02:59 +01006985 preg = calloc(1, sizeof(regex_t));
6986 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006987 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006988 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006989 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006990
willy tarreauc1f47532005-12-18 01:08:26 +01006991 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6992 if (err) {
6993 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6994 file, linenum, *err);
6995 return -1;
6996 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006997 }
willy tarreau982249e2005-12-18 00:57:06 +01006998 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6999 regex_t *preg;
7000 if (curproxy == &defproxy) {
7001 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7002 return -1;
7003 }
7004
7005 if (*(args[1]) == 0) {
7006 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7007 return -1;
7008 }
7009
7010 preg = calloc(1, sizeof(regex_t));
7011 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7012 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7013 return -1;
7014 }
7015
willy tarreauc1f47532005-12-18 01:08:26 +01007016 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7017 if (err) {
7018 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7019 file, linenum, *err);
7020 return -1;
7021 }
willy tarreau982249e2005-12-18 00:57:06 +01007022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007024 regex_t *preg;
7025 if (curproxy == &defproxy) {
7026 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7027 return -1;
7028 }
willy tarreaue39cd132005-12-17 13:00:18 +01007029
willy tarreaua41a8b42005-12-17 14:02:24 +01007030 if (*(args[1]) == 0 || *(args[2]) == 0) {
7031 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7032 file, linenum, args[0]);
7033 return -1;
7034 }
willy tarreaue39cd132005-12-17 13:00:18 +01007035
willy tarreaua41a8b42005-12-17 14:02:24 +01007036 preg = calloc(1, sizeof(regex_t));
7037 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7038 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7039 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007040 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007041
willy tarreauc1f47532005-12-18 01:08:26 +01007042 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7043 if (err) {
7044 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7045 file, linenum, *err);
7046 return -1;
7047 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007048 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007049 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7050 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007051 if (curproxy == &defproxy) {
7052 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7053 return -1;
7054 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007055
7056 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007057 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007058 return -1;
7059 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007060
willy tarreau9fe663a2005-12-17 13:02:59 +01007061 preg = calloc(1, sizeof(regex_t));
7062 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007063 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007064 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007065 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007066
willy tarreauc1f47532005-12-18 01:08:26 +01007067 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7068 if (err) {
7069 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7070 file, linenum, *err);
7071 return -1;
7072 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007073 }
willy tarreau982249e2005-12-18 00:57:06 +01007074 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7075 regex_t *preg;
7076 if (curproxy == &defproxy) {
7077 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7078 return -1;
7079 }
7080
7081 if (*(args[1]) == 0) {
7082 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7083 return -1;
7084 }
7085
7086 preg = calloc(1, sizeof(regex_t));
7087 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7088 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7089 return -1;
7090 }
7091
willy tarreauc1f47532005-12-18 01:08:26 +01007092 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7093 if (err) {
7094 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7095 file, linenum, *err);
7096 return -1;
7097 }
willy tarreau982249e2005-12-18 00:57:06 +01007098 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007099 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007100 if (curproxy == &defproxy) {
7101 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7102 return -1;
7103 }
7104
willy tarreau9fe663a2005-12-17 13:02:59 +01007105 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007106 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007107 return 0;
7108 }
7109
7110 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007111 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007112 return -1;
7113 }
7114
7115 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7116 }
willy tarreauc1f47532005-12-18 01:08:26 +01007117 else if (!strcmp(args[0], "errorloc") ||
7118 !strcmp(args[0], "errorloc302") ||
7119 !strcmp(args[0], "errorloc303")) { /* error location */
7120 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007121 char *err;
7122
willy tarreaueedaa9f2005-12-17 14:08:03 +01007123 // if (curproxy == &defproxy) {
7124 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7125 // return -1;
7126 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007127
willy tarreau8337c6b2005-12-17 13:41:01 +01007128 if (*(args[2]) == 0) {
7129 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7130 return -1;
7131 }
7132
7133 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007134 if (!strcmp(args[0], "errorloc303")) {
7135 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7136 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7137 } else {
7138 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7139 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7140 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007141
7142 if (errnum == 400) {
7143 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007144 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007145 free(curproxy->errmsg.msg400);
7146 }
7147 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007148 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007149 }
7150 else if (errnum == 403) {
7151 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007152 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007153 free(curproxy->errmsg.msg403);
7154 }
7155 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007156 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007157 }
7158 else if (errnum == 408) {
7159 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007160 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007161 free(curproxy->errmsg.msg408);
7162 }
7163 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007164 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007165 }
7166 else if (errnum == 500) {
7167 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007168 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007169 free(curproxy->errmsg.msg500);
7170 }
7171 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007172 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007173 }
7174 else if (errnum == 502) {
7175 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007176 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007177 free(curproxy->errmsg.msg502);
7178 }
7179 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007180 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007181 }
7182 else if (errnum == 503) {
7183 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007184 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007185 free(curproxy->errmsg.msg503);
7186 }
7187 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007188 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007189 }
7190 else if (errnum == 504) {
7191 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007192 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007193 free(curproxy->errmsg.msg504);
7194 }
7195 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007196 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007197 }
7198 else {
7199 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7200 free(err);
7201 }
7202 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007203 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007204 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007205 return -1;
7206 }
7207 return 0;
7208}
willy tarreaue39cd132005-12-17 13:00:18 +01007209
willy tarreau5cbea6f2005-12-17 12:48:26 +01007210
willy tarreau9fe663a2005-12-17 13:02:59 +01007211/*
7212 * This function reads and parses the configuration file given in the argument.
7213 * returns 0 if OK, -1 if error.
7214 */
7215int readcfgfile(char *file) {
7216 char thisline[256];
7217 char *line;
7218 FILE *f;
7219 int linenum = 0;
7220 char *end;
7221 char *args[MAX_LINE_ARGS];
7222 int arg;
7223 int cfgerr = 0;
7224 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007225
willy tarreau9fe663a2005-12-17 13:02:59 +01007226 struct proxy *curproxy = NULL;
7227 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007228
willy tarreau9fe663a2005-12-17 13:02:59 +01007229 if ((f=fopen(file,"r")) == NULL)
7230 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007231
willy tarreaueedaa9f2005-12-17 14:08:03 +01007232 init_default_instance();
7233
willy tarreau9fe663a2005-12-17 13:02:59 +01007234 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7235 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007236
willy tarreau9fe663a2005-12-17 13:02:59 +01007237 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007238
willy tarreau9fe663a2005-12-17 13:02:59 +01007239 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007240 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007241 line++;
7242
7243 arg = 0;
7244 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007245
willy tarreau9fe663a2005-12-17 13:02:59 +01007246 while (*line && arg < MAX_LINE_ARGS) {
7247 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7248 * C equivalent value. Other combinations left unchanged (eg: \1).
7249 */
7250 if (*line == '\\') {
7251 int skip = 0;
7252 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7253 *line = line[1];
7254 skip = 1;
7255 }
7256 else if (line[1] == 'r') {
7257 *line = '\r';
7258 skip = 1;
7259 }
7260 else if (line[1] == 'n') {
7261 *line = '\n';
7262 skip = 1;
7263 }
7264 else if (line[1] == 't') {
7265 *line = '\t';
7266 skip = 1;
7267 }
willy tarreauc1f47532005-12-18 01:08:26 +01007268 else if (line[1] == 'x') {
7269 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7270 unsigned char hex1, hex2;
7271 hex1 = toupper(line[2]) - '0';
7272 hex2 = toupper(line[3]) - '0';
7273 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7274 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7275 *line = (hex1<<4) + hex2;
7276 skip = 3;
7277 }
7278 else {
7279 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7280 return -1;
7281 }
7282 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007283 if (skip) {
7284 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7285 end -= skip;
7286 }
7287 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007288 }
willy tarreaua1598082005-12-17 13:08:06 +01007289 else if (*line == '#' || *line == '\n' || *line == '\r') {
7290 /* end of string, end of loop */
7291 *line = 0;
7292 break;
7293 }
willy tarreauc29948c2005-12-17 13:10:27 +01007294 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007295 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007296 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007297 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007298 line++;
7299 args[++arg] = line;
7300 }
7301 else {
7302 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007303 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007304 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007305
willy tarreau9fe663a2005-12-17 13:02:59 +01007306 /* empty line */
7307 if (!**args)
7308 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007309
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 /* zero out remaining args */
7311 while (++arg < MAX_LINE_ARGS) {
7312 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007313 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007314
willy tarreaua41a8b42005-12-17 14:02:24 +01007315 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007316 confsect = CFG_LISTEN;
7317 else if (!strcmp(args[0], "global")) /* global config */
7318 confsect = CFG_GLOBAL;
7319 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007320
willy tarreau9fe663a2005-12-17 13:02:59 +01007321 switch (confsect) {
7322 case CFG_LISTEN:
7323 if (cfg_parse_listen(file, linenum, args) < 0)
7324 return -1;
7325 break;
7326 case CFG_GLOBAL:
7327 if (cfg_parse_global(file, linenum, args) < 0)
7328 return -1;
7329 break;
7330 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007331 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007332 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007333 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007334
7335
willy tarreau0f7af912005-12-17 12:21:26 +01007336 }
7337 fclose(f);
7338
7339 /*
7340 * Now, check for the integrity of all that we have collected.
7341 */
7342
7343 if ((curproxy = proxy) == NULL) {
7344 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7345 file);
7346 return -1;
7347 }
7348
7349 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007350 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007351 if (curproxy->state == PR_STDISABLED) {
7352 curproxy = curproxy->next;
7353 continue;
7354 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007355 if ((curproxy->mode != PR_MODE_HEALTH) &&
7356 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007357 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007358 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7359 file, curproxy->id);
7360 cfgerr++;
7361 }
7362 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7363 if (curproxy->options & PR_O_TRANSP) {
7364 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7365 file, curproxy->id);
7366 cfgerr++;
7367 }
7368 else if (curproxy->srv == NULL) {
7369 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7370 file, curproxy->id);
7371 cfgerr++;
7372 }
willy tarreaua1598082005-12-17 13:08:06 +01007373 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007374 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7375 file, curproxy->id);
7376 }
7377 }
7378 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007379 if (curproxy->cookie_name != NULL) {
7380 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7381 file, curproxy->id);
7382 }
7383 if ((newsrv = curproxy->srv) != NULL) {
7384 Warning("parsing %s : servers will be ignored for listener %s.\n",
7385 file, curproxy->id);
7386 }
willy tarreaue39cd132005-12-17 13:00:18 +01007387 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007388 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7389 file, curproxy->id);
7390 }
willy tarreaue39cd132005-12-17 13:00:18 +01007391 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007392 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7393 file, curproxy->id);
7394 }
7395 }
7396 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7397 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7398 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7399 file, curproxy->id);
7400 cfgerr++;
7401 }
7402 else {
7403 while (newsrv != NULL) {
7404 /* nothing to check for now */
7405 newsrv = newsrv->next;
7406 }
7407 }
7408 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007409
7410 if (curproxy->options & PR_O_LOGASAP)
7411 curproxy->to_log &= ~LW_BYTES;
7412
willy tarreau8337c6b2005-12-17 13:41:01 +01007413 if (curproxy->errmsg.msg400 == NULL) {
7414 curproxy->errmsg.msg400 = (char *)HTTP_400;
7415 curproxy->errmsg.len400 = strlen(HTTP_400);
7416 }
7417 if (curproxy->errmsg.msg403 == NULL) {
7418 curproxy->errmsg.msg403 = (char *)HTTP_403;
7419 curproxy->errmsg.len403 = strlen(HTTP_403);
7420 }
7421 if (curproxy->errmsg.msg408 == NULL) {
7422 curproxy->errmsg.msg408 = (char *)HTTP_408;
7423 curproxy->errmsg.len408 = strlen(HTTP_408);
7424 }
7425 if (curproxy->errmsg.msg500 == NULL) {
7426 curproxy->errmsg.msg500 = (char *)HTTP_500;
7427 curproxy->errmsg.len500 = strlen(HTTP_500);
7428 }
7429 if (curproxy->errmsg.msg502 == NULL) {
7430 curproxy->errmsg.msg502 = (char *)HTTP_502;
7431 curproxy->errmsg.len502 = strlen(HTTP_502);
7432 }
7433 if (curproxy->errmsg.msg503 == NULL) {
7434 curproxy->errmsg.msg503 = (char *)HTTP_503;
7435 curproxy->errmsg.len503 = strlen(HTTP_503);
7436 }
7437 if (curproxy->errmsg.msg504 == NULL) {
7438 curproxy->errmsg.msg504 = (char *)HTTP_504;
7439 curproxy->errmsg.len504 = strlen(HTTP_504);
7440 }
willy tarreau0f7af912005-12-17 12:21:26 +01007441 curproxy = curproxy->next;
7442 }
7443 if (cfgerr > 0) {
7444 Alert("Errors found in configuration file, aborting.\n");
7445 return -1;
7446 }
7447 else
7448 return 0;
7449}
7450
7451
7452/*
7453 * This function initializes all the necessary variables. It only returns
7454 * if everything is OK. If something fails, it exits.
7455 */
7456void init(int argc, char **argv) {
7457 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007458 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007459 char *old_argv = *argv;
7460 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007461 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007462 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007463
7464 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007465 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007466 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007467 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007468 exit(1);
7469 }
7470
willy tarreau4302f492005-12-18 01:00:37 +01007471 /* initialize the log header encoding map : '{|}"#' should be encoded with
7472 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7473 * URL encoding only requires '"', '#' to be encoded as well as non-
7474 * printable characters above.
7475 */
7476 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7477 memset(url_encode_map, 0, sizeof(url_encode_map));
7478 for (i = 0; i < 32; i++) {
7479 FD_SET(i, hdr_encode_map);
7480 FD_SET(i, url_encode_map);
7481 }
7482 for (i = 127; i < 256; i++) {
7483 FD_SET(i, hdr_encode_map);
7484 FD_SET(i, url_encode_map);
7485 }
7486
7487 tmp = "\"#{|}";
7488 while (*tmp) {
7489 FD_SET(*tmp, hdr_encode_map);
7490 tmp++;
7491 }
7492
7493 tmp = "\"#";
7494 while (*tmp) {
7495 FD_SET(*tmp, url_encode_map);
7496 tmp++;
7497 }
7498
willy tarreau64a3cc32005-12-18 01:13:11 +01007499 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7500#if defined(ENABLE_POLL)
7501 cfg_polling_mechanism |= POLL_USE_POLL;
7502#endif
7503#if defined(ENABLE_EPOLL)
7504 cfg_polling_mechanism |= POLL_USE_EPOLL;
7505#endif
7506
willy tarreau0f7af912005-12-17 12:21:26 +01007507 pid = getpid();
7508 progname = *argv;
7509 while ((tmp = strchr(progname, '/')) != NULL)
7510 progname = tmp + 1;
7511
7512 argc--; argv++;
7513 while (argc > 0) {
7514 char *flag;
7515
7516 if (**argv == '-') {
7517 flag = *argv+1;
7518
7519 /* 1 arg */
7520 if (*flag == 'v') {
7521 display_version();
7522 exit(0);
7523 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007524#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007525 else if (*flag == 'd' && flag[1] == 'e')
7526 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007527#endif
7528#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007529 else if (*flag == 'd' && flag[1] == 'p')
7530 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007531#endif
willy tarreau982249e2005-12-18 00:57:06 +01007532 else if (*flag == 'V')
7533 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007534 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007535 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007536 else if (*flag == 'c')
7537 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007538 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007539 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007540 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007541 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007542#if STATTIME > 0
7543 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007544 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007545 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007546 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007547#endif
7548 else { /* >=2 args */
7549 argv++; argc--;
7550 if (argc == 0)
7551 usage(old_argv);
7552
7553 switch (*flag) {
7554 case 'n' : cfg_maxconn = atol(*argv); break;
7555 case 'N' : cfg_maxpconn = atol(*argv); break;
7556 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007557 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007558 default: usage(old_argv);
7559 }
7560 }
7561 }
7562 else
7563 usage(old_argv);
7564 argv++; argc--;
7565 }
7566
willy tarreau982249e2005-12-18 00:57:06 +01007567 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007568
willy tarreau0f7af912005-12-17 12:21:26 +01007569 if (!cfg_cfgfile)
7570 usage(old_argv);
7571
7572 gethostname(hostname, MAX_HOSTNAME_LEN);
7573
willy tarreau12350152005-12-18 01:03:27 +01007574 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007575 if (readcfgfile(cfg_cfgfile) < 0) {
7576 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7577 exit(1);
7578 }
willy tarreau12350152005-12-18 01:03:27 +01007579 if (have_appsession)
7580 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007581
willy tarreau982249e2005-12-18 00:57:06 +01007582 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007583 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7584 exit(0);
7585 }
7586
willy tarreau9fe663a2005-12-17 13:02:59 +01007587 if (cfg_maxconn > 0)
7588 global.maxconn = cfg_maxconn;
7589
willy tarreaufe2c5c12005-12-17 14:14:34 +01007590 if (cfg_pidfile) {
7591 if (global.pidfile)
7592 free(global.pidfile);
7593 global.pidfile = strdup(cfg_pidfile);
7594 }
7595
willy tarreau9fe663a2005-12-17 13:02:59 +01007596 if (global.maxconn == 0)
7597 global.maxconn = DEFAULT_MAXCONN;
7598
7599 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7600
7601 if (arg_mode & MODE_DEBUG) {
7602 /* command line debug mode inhibits configuration mode */
7603 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7604 }
willy tarreau982249e2005-12-18 00:57:06 +01007605 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7606 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007607
7608 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7609 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7610 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7611 }
7612
7613 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7614 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7615 global.nbproc = 1;
7616 }
7617
7618 if (global.nbproc < 1)
7619 global.nbproc = 1;
7620
willy tarreau0f7af912005-12-17 12:21:26 +01007621 StaticReadEvent = (fd_set *)calloc(1,
7622 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007623 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007624 StaticWriteEvent = (fd_set *)calloc(1,
7625 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007626 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007627
7628 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007629 sizeof(struct fdtab) * (global.maxsock));
7630 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007631 fdtab[i].state = FD_STCLOSE;
7632 }
7633}
7634
7635/*
7636 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7637 */
7638int start_proxies() {
7639 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007640 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007641 int fd;
7642
7643 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007644 if (curproxy->state == PR_STDISABLED)
7645 continue;
7646
willy tarreaua41a8b42005-12-17 14:02:24 +01007647 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7648 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007649 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007650 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7651 curproxy->id);
7652 return -1;
7653 }
willy tarreau0f7af912005-12-17 12:21:26 +01007654
willy tarreaua41a8b42005-12-17 14:02:24 +01007655 if (fd >= global.maxsock) {
7656 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7657 curproxy->id);
7658 close(fd);
7659 return -1;
7660 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007661
willy tarreaua41a8b42005-12-17 14:02:24 +01007662 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7663 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7664 (char *) &one, sizeof(one)) == -1)) {
7665 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7666 curproxy->id);
7667 close(fd);
7668 return -1;
7669 }
willy tarreau0f7af912005-12-17 12:21:26 +01007670
willy tarreaua41a8b42005-12-17 14:02:24 +01007671 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7672 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7673 curproxy->id);
7674 }
willy tarreau0f7af912005-12-17 12:21:26 +01007675
willy tarreaua41a8b42005-12-17 14:02:24 +01007676 if (bind(fd,
7677 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007678 listener->addr.ss_family == AF_INET6 ?
7679 sizeof(struct sockaddr_in6) :
7680 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007681 Alert("cannot bind socket for proxy %s. Aborting.\n",
7682 curproxy->id);
7683 close(fd);
7684 return -1;
7685 }
willy tarreau0f7af912005-12-17 12:21:26 +01007686
willy tarreaua41a8b42005-12-17 14:02:24 +01007687 if (listen(fd, curproxy->maxconn) == -1) {
7688 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7689 curproxy->id);
7690 close(fd);
7691 return -1;
7692 }
willy tarreau0f7af912005-12-17 12:21:26 +01007693
willy tarreaua41a8b42005-12-17 14:02:24 +01007694 /* the function for the accept() event */
7695 fdtab[fd].read = &event_accept;
7696 fdtab[fd].write = NULL; /* never called */
7697 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7698 curproxy->state = PR_STRUN;
7699 fdtab[fd].state = FD_STLISTEN;
7700 FD_SET(fd, StaticReadEvent);
7701 fd_insert(fd);
7702 listeners++;
7703 }
willy tarreaua1598082005-12-17 13:08:06 +01007704 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007705 }
7706 return 0;
7707}
7708
willy tarreaub952e1d2005-12-18 01:31:20 +01007709int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007710
7711 appsess *temp1,*temp2;
7712 temp1 = (appsess *)key1;
7713 temp2 = (appsess *)key2;
7714
7715 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7716 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7717
7718 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7719}/* end match_str */
7720
willy tarreaub952e1d2005-12-18 01:31:20 +01007721void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007722 appsess *temp1;
7723
7724 //printf("destroy called\n");
7725 temp1 = (appsess *)data;
7726
7727 if (temp1->sessid)
7728 pool_free_to(apools.sessid, temp1->sessid);
7729
7730 if (temp1->serverid)
7731 pool_free_to(apools.serverid, temp1->serverid);
7732
7733 pool_free(appsess, temp1);
7734} /* end destroy */
7735
7736void appsession_cleanup( void )
7737{
7738 struct proxy *p = proxy;
7739
7740 while(p) {
7741 chtbl_destroy(&(p->htbl_proxy));
7742 p = p->next;
7743 }
7744}/* end appsession_cleanup() */
7745
7746void pool_destroy(void **pool)
7747{
7748 void *temp, *next;
7749 next = pool;
7750 while (next) {
7751 temp = next;
7752 next = *(void **)temp;
7753 free(temp);
7754 }
7755}/* end pool_destroy() */
7756
willy tarreaub952e1d2005-12-18 01:31:20 +01007757void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01007758 struct proxy *p = proxy;
7759 struct cap_hdr *h,*h_next;
7760 struct server *s,*s_next;
7761 struct listener *l,*l_next;
7762
7763 while (p) {
7764 if (p->id)
7765 free(p->id);
7766
7767 if (p->check_req)
7768 free(p->check_req);
7769
7770 if (p->cookie_name)
7771 free(p->cookie_name);
7772
7773 if (p->capture_name)
7774 free(p->capture_name);
7775
7776 /* only strup if the user have set in config.
7777 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01007778 if (p->errmsg.msg400) free(p->errmsg.msg400);
7779 if (p->errmsg.msg403) free(p->errmsg.msg403);
7780 if (p->errmsg.msg408) free(p->errmsg.msg408);
7781 if (p->errmsg.msg500) free(p->errmsg.msg500);
7782 if (p->errmsg.msg502) free(p->errmsg.msg502);
7783 if (p->errmsg.msg503) free(p->errmsg.msg503);
7784 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01007785 */
7786 if (p->appsession_name)
7787 free(p->appsession_name);
7788
7789 h = p->req_cap;
7790 while (h) {
7791 h_next = h->next;
7792 if (h->name)
7793 free(h->name);
7794 pool_destroy(h->pool);
7795 free(h);
7796 h = h_next;
7797 }/* end while(h) */
7798
7799 h = p->rsp_cap;
7800 while (h) {
7801 h_next = h->next;
7802 if (h->name)
7803 free(h->name);
7804
7805 pool_destroy(h->pool);
7806 free(h);
7807 h = h_next;
7808 }/* end while(h) */
7809
7810 s = p->srv;
7811 while (s) {
7812 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01007813 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01007814 free(s->id);
7815
willy tarreaub952e1d2005-12-18 01:31:20 +01007816 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01007817 free(s->cookie);
7818
7819 free(s);
7820 s = s_next;
7821 }/* end while(s) */
7822
7823 l = p->listen;
7824 while (l) {
7825 l_next = l->next;
7826 free(l);
7827 l = l_next;
7828 }/* end while(l) */
7829
7830 pool_destroy((void **) p->req_cap_pool);
7831 pool_destroy((void **) p->rsp_cap_pool);
7832 p = p->next;
7833 }/* end while(p) */
7834
7835 if (global.chroot) free(global.chroot);
7836 if (global.pidfile) free(global.pidfile);
7837
willy tarreau12350152005-12-18 01:03:27 +01007838 if (StaticReadEvent) free(StaticReadEvent);
7839 if (StaticWriteEvent) free(StaticWriteEvent);
7840 if (fdtab) free(fdtab);
7841
7842 pool_destroy(pool_session);
7843 pool_destroy(pool_buffer);
7844 pool_destroy(pool_fdtab);
7845 pool_destroy(pool_requri);
7846 pool_destroy(pool_task);
7847 pool_destroy(pool_capture);
7848 pool_destroy(pool_appsess);
7849
7850 if (have_appsession) {
7851 pool_destroy(apools.serverid);
7852 pool_destroy(apools.sessid);
7853 }
7854} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007855
7856int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007857 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007858 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007859 init(argc, argv);
7860
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007862 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007863 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007864 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007865 }
7866
7867 signal(SIGQUIT, dump);
7868 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007869 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007870#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007871 signal(SIGINT, sig_int);
7872 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007873#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007874
7875 /* on very high loads, a sigpipe sometimes happen just between the
7876 * getsockopt() which tells "it's OK to write", and the following write :-(
7877 */
willy tarreau3242e862005-12-17 12:27:53 +01007878#ifndef MSG_NOSIGNAL
7879 signal(SIGPIPE, SIG_IGN);
7880#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007881
7882 if (start_proxies() < 0)
7883 exit(1);
7884
willy tarreaufe2c5c12005-12-17 14:14:34 +01007885 /* open log & pid files before the chroot */
7886 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7887 int pidfd;
7888 unlink(global.pidfile);
7889 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7890 if (pidfd < 0) {
7891 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7892 exit(1);
7893 }
7894 pidfile = fdopen(pidfd, "w");
7895 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007896
7897 /* chroot if needed */
7898 if (global.chroot != NULL) {
7899 if (chroot(global.chroot) == -1) {
7900 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7901 exit(1);
7902 }
7903 chdir("/");
7904 }
7905
willy tarreaub1285d52005-12-18 01:20:14 +01007906 /* ulimits */
7907 if (global.rlimit_nofile) {
7908 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7909 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7910 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7911 }
7912 }
7913
willy tarreau9fe663a2005-12-17 13:02:59 +01007914 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007915 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007916 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7917 exit(1);
7918 }
7919
willy tarreau036e1ce2005-12-17 13:46:33 +01007920 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007921 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7922 exit(1);
7923 }
7924
willy tarreaub1285d52005-12-18 01:20:14 +01007925 /* check ulimits */
7926 limit.rlim_cur = limit.rlim_max = 0;
7927 getrlimit(RLIMIT_NOFILE, &limit);
7928 if (limit.rlim_cur < global.maxsock) {
7929 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",
7930 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
7931 }
7932
willy tarreau9fe663a2005-12-17 13:02:59 +01007933 if (global.mode & MODE_DAEMON) {
7934 int ret = 0;
7935 int proc;
7936
7937 /* the father launches the required number of processes */
7938 for (proc = 0; proc < global.nbproc; proc++) {
7939 ret = fork();
7940 if (ret < 0) {
7941 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7942 exit(1); /* there has been an error */
7943 }
7944 else if (ret == 0) /* child breaks here */
7945 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007946 if (pidfile != NULL) {
7947 fprintf(pidfile, "%d\n", ret);
7948 fflush(pidfile);
7949 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007950 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007951 /* close the pidfile both in children and father */
7952 if (pidfile != NULL)
7953 fclose(pidfile);
7954 free(global.pidfile);
7955
willy tarreau9fe663a2005-12-17 13:02:59 +01007956 if (proc == global.nbproc)
7957 exit(0); /* parent must leave */
7958
willy tarreau750a4722005-12-17 13:21:24 +01007959 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7960 * that we can detach from the TTY. We MUST NOT do it in other cases since
7961 * it would have already be done, and 0-2 would have been affected to listening
7962 * sockets
7963 */
7964 if (!(global.mode & MODE_QUIET)) {
7965 /* detach from the tty */
7966 fclose(stdin); fclose(stdout); fclose(stderr);
7967 close(0); close(1); close(2); /* close all fd's */
7968 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7969 }
willy tarreaua1598082005-12-17 13:08:06 +01007970 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007971 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007972 }
7973
willy tarreau1c2ad212005-12-18 01:11:29 +01007974#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007975 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007976 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
7977 epoll_loop(POLL_LOOP_ACTION_RUN);
7978 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007979 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007980 }
7981 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01007982 Warning("epoll() is not available. Using poll()/select() instead.\n");
7983 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007984 }
7985 }
7986#endif
7987
7988#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007989 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007990 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
7991 poll_loop(POLL_LOOP_ACTION_RUN);
7992 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007993 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007994 }
7995 else {
7996 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01007997 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007998 }
7999 }
8000#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008001 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008002 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8003 select_loop(POLL_LOOP_ACTION_RUN);
8004 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008005 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008006 }
8007 }
8008
willy tarreau0f7af912005-12-17 12:21:26 +01008009
willy tarreau12350152005-12-18 01:03:27 +01008010 /* Free all Hash Keys and all Hash elements */
8011 appsession_cleanup();
8012 /* Do some cleanup */
8013 deinit();
8014
willy tarreau0f7af912005-12-17 12:21:26 +01008015 exit(0);
8016}
willy tarreau12350152005-12-18 01:03:27 +01008017
8018#if defined(DEBUG_HASH)
8019static void print_table(const CHTbl *htbl) {
8020
8021 ListElmt *element;
8022 int i;
8023 appsess *asession;
8024
8025 /*****************************************************************************
8026 * *
8027 * Display the chained hash table. *
8028 * *
8029 *****************************************************************************/
8030
8031 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8032
8033 for (i = 0; i < TBLSIZ; i++) {
8034 fprintf(stdout, "Bucket[%03d]\n", i);
8035
8036 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8037 //fprintf(stdout, "%c", *(char *)list_data(element));
8038 asession = (appsess *)list_data(element);
8039 fprintf(stdout, "ELEM :%s:", asession->sessid);
8040 fprintf(stdout, " Server :%s: \n", asession->serverid);
8041 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8042 }
8043
8044 fprintf(stdout, "\n");
8045 }
8046 return;
8047} /* end print_table */
8048#endif
8049
8050static int appsession_init(void)
8051{
8052 static int initialized = 0;
8053 int idlen;
8054 struct server *s;
8055 struct proxy *p = proxy;
8056
8057 if (!initialized) {
8058 if (!appsession_task_init()) {
8059 apools.sessid = NULL;
8060 apools.serverid = NULL;
8061 apools.ser_waste = 0;
8062 apools.ser_use = 0;
8063 apools.ser_msize = sizeof(void *);
8064 apools.ses_waste = 0;
8065 apools.ses_use = 0;
8066 apools.ses_msize = sizeof(void *);
8067 while (p) {
8068 s = p->srv;
8069 if (apools.ses_msize < p->appsession_len)
8070 apools.ses_msize = p->appsession_len;
8071 while (s) {
8072 idlen = strlen(s->id);
8073 if (apools.ser_msize < idlen)
8074 apools.ser_msize = idlen;
8075 s = s->next;
8076 }
8077 p = p->next;
8078 }
8079 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8080 apools.ses_msize ++;
8081 }
8082 else {
8083 fprintf(stderr, "appsession_task_init failed\n");
8084 return -1;
8085 }
8086 initialized ++;
8087 }
8088 return 0;
8089}
8090
8091static int appsession_task_init(void)
8092{
8093 static int initialized = 0;
8094 struct task *t;
8095 if (!initialized) {
8096 if ((t = pool_alloc(task)) == NULL)
8097 return -1;
8098 t->next = t->prev = t->rqnext = NULL;
8099 t->wq = LIST_HEAD(wait_queue);
8100 t->state = TASK_IDLE;
8101 t->context = NULL;
8102 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8103 task_queue(t);
8104 t->process = appsession_refresh;
8105 initialized ++;
8106 }
8107 return 0;
8108}
8109
8110static int appsession_refresh(struct task *t) {
8111 struct proxy *p = proxy;
8112 CHTbl *htbl;
8113 ListElmt *element, *last;
8114 int i;
8115 appsess *asession;
8116 void *data;
8117
8118 while (p) {
8119 if (p->appsession_name != NULL) {
8120 htbl = &p->htbl_proxy;
8121 /* if we ever give up the use of TBLSIZ, we need to change this */
8122 for (i = 0; i < TBLSIZ; i++) {
8123 last = NULL;
8124 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8125 asession = (appsess *)list_data(element);
8126 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8127 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8128 int len;
8129 /*
8130 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8131 */
8132 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8133 asession->sessid, asession->serverid?asession->serverid:"(null)");
8134 write(1, trash, len);
8135 }
8136 /* delete the expired element from within the hash table */
8137 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8138 && (htbl->table[i].destroy != NULL)) {
8139 htbl->table[i].destroy(data);
8140 }
8141 if (last == NULL) {/* patient lost his head, get a new one */
8142 element = list_head(&htbl->table[i]);
8143 if (element == NULL) break; /* no heads left, go to next patient */
8144 }
8145 else
8146 element = last;
8147 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8148 else
8149 last = element;
8150 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8151 }
8152 }
8153 p = p->next;
8154 }
8155 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8156 return TBLCHKINT;
8157} /* end appsession_refresh */
8158