blob: 41c9820c406b835a9a16063c570a5ea226598ce3 [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 tarreaua56eca72005-12-18 01:34:42 +010086#define HAPROXY_VERSION "1.2.7"
87#define HAPROXY_DATE "2005/11/13"
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 tarreaud0fb4652005-12-18 01:32:04 +0100405#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406
407/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100408#define SRV_RUNNING 1 /* the server is UP */
409#define SRV_BACKUP 2 /* this server is a backup server */
410#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100411#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100412
willy tarreaue39cd132005-12-17 13:00:18 +0100413/* what to do when a header matches a regex */
414#define ACT_ALLOW 0 /* allow the request */
415#define ACT_REPLACE 1 /* replace the matching header */
416#define ACT_REMOVE 2 /* remove the matching header */
417#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100418#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100419
willy tarreau9fe663a2005-12-17 13:02:59 +0100420/* configuration sections */
421#define CFG_NONE 0
422#define CFG_GLOBAL 1
423#define CFG_LISTEN 2
424
willy tarreaua1598082005-12-17 13:08:06 +0100425/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100426#define LW_DATE 1 /* date */
427#define LW_CLIP 2 /* CLient IP */
428#define LW_SVIP 4 /* SerVer IP */
429#define LW_SVID 8 /* server ID */
430#define LW_REQ 16 /* http REQuest */
431#define LW_RESP 32 /* http RESPonse */
432#define LW_PXIP 64 /* proxy IP */
433#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100434#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100435#define LW_COOKIE 512 /* captured cookie */
436#define LW_REQHDR 1024 /* request header(s) */
437#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100438
willy tarreau0f7af912005-12-17 12:21:26 +0100439/*********************************************************************/
440
441#define LIST_HEAD(a) ((void *)(&(a)))
442
443/*********************************************************************/
444
willy tarreau4302f492005-12-18 01:00:37 +0100445struct cap_hdr {
446 struct cap_hdr *next;
447 char *name; /* header name, case insensitive */
448 int namelen; /* length of the header name, to speed-up lookups */
449 int len; /* capture length, not including terminal zero */
450 int index; /* index in the output array */
451 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
452};
453
willy tarreau0f7af912005-12-17 12:21:26 +0100454struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100455 struct hdr_exp *next;
456 regex_t *preg; /* expression to look for */
457 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
458 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100459};
460
461struct buffer {
462 unsigned int l; /* data length */
463 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100464 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100465 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100466 char data[BUFSIZE];
467};
468
469struct server {
470 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100471 int state; /* server state (SRV_*) */
472 int cklen; /* the len of the cookie, to speed up checks */
473 char *cookie; /* the id set in the cookie */
474 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100476 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100477 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100478 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100479 int rise, fall; /* time in iterations */
480 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100481 int result; /* 0 = connect OK, -1 = connect KO */
482 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100483 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100484};
485
willy tarreau5cbea6f2005-12-17 12:48:26 +0100486/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100487struct task {
488 struct task *next, *prev; /* chaining ... */
489 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100490 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100491 int state; /* task state : IDLE or RUNNING */
492 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100493 int (*process)(struct task *t); /* the function which processes the task */
494 void *context; /* the task's context */
495};
496
497/* WARNING: if new fields are added, they must be initialized in event_accept() */
498struct session {
499 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100500 /* application specific below */
501 struct timeval crexpire; /* expiration date for a client read */
502 struct timeval cwexpire; /* expiration date for a client write */
503 struct timeval srexpire; /* expiration date for a server read */
504 struct timeval swexpire; /* expiration date for a server write */
505 struct timeval cnexpire; /* expiration date for a connect */
506 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
507 struct proxy *proxy; /* the proxy this socket belongs to */
508 int cli_fd; /* the client side fd */
509 int srv_fd; /* the server side fd */
510 int cli_state; /* state of the client side */
511 int srv_state; /* state of the server side */
512 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100513 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100514 struct buffer *req; /* request buffer */
515 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100516 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100517 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100518 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100519 char **req_cap; /* array of captured request headers (may be NULL) */
520 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100521 struct {
522 int logwait; /* log fields waiting to be collected : LW_* */
523 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
524 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
525 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
526 long t_data; /* delay before the first data byte from the server ... */
527 unsigned long t_close; /* total session duration */
528 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100529 char *cli_cookie; /* cookie presented by the client, in capture mode */
530 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100531 int status; /* HTTP status from the server, negative if from proxy */
532 long long bytes; /* number of bytes transferred from the server */
533 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100534 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100535};
536
willy tarreaua41a8b42005-12-17 14:02:24 +0100537struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100538 int fd; /* the listen socket */
539 struct sockaddr_storage addr; /* the address we listen to */
540 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100541};
542
543
willy tarreau0f7af912005-12-17 12:21:26 +0100544struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100545 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100546 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 +0100547 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100548 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100549 struct server *srv, *cursrv; /* known servers, current server */
550 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100551 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100552 int cookie_len; /* strlen(cookie_name), computed only once */
553 char *appsession_name; /* name of the cookie to look for */
554 int appsession_name_len; /* strlen(appsession_name), computed only once */
555 int appsession_len; /* length of the appsession cookie value to be used */
556 int appsession_timeout;
557 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100558 char *capture_name; /* beginning of the name of the cookie to capture */
559 int capture_namelen; /* length of the cookie name to match */
560 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100561 int clitimeout; /* client I/O timeout (in milliseconds) */
562 int srvtimeout; /* server I/O timeout (in milliseconds) */
563 int contimeout; /* connect timeout (in milliseconds) */
564 char *id; /* proxy id */
565 int nbconn; /* # of active sessions */
566 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100567 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100568 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100569 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100570 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100571 struct proxy *next;
572 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100573 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100574 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100575 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100576 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100577 int nb_reqadd, nb_rspadd;
578 struct hdr_exp *req_exp; /* regular expressions for request headers */
579 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100580 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
581 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
582 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
583 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100584 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100585 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100586 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
587 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100588 struct {
589 char *msg400; /* message for error 400 */
590 int len400; /* message length for error 400 */
591 char *msg403; /* message for error 403 */
592 int len403; /* message length for error 403 */
593 char *msg408; /* message for error 408 */
594 int len408; /* message length for error 408 */
595 char *msg500; /* message for error 500 */
596 int len500; /* message length for error 500 */
597 char *msg502; /* message for error 502 */
598 int len502; /* message length for error 502 */
599 char *msg503; /* message for error 503 */
600 int len503; /* message length for error 503 */
601 char *msg504; /* message for error 504 */
602 int len504; /* message length for error 504 */
603 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100604};
605
606/* info about one given fd */
607struct fdtab {
608 int (*read)(int fd); /* read function */
609 int (*write)(int fd); /* write function */
610 struct task *owner; /* the session (or proxy) associated with this fd */
611 int state; /* the state of this fd */
612};
613
614/*********************************************************************/
615
willy tarreaub952e1d2005-12-18 01:31:20 +0100616int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100617char *cfg_cfgfile = NULL; /* configuration file */
618char *progname = NULL; /* program name */
619int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100620
621/* global options */
622static struct {
623 int uid;
624 int gid;
625 int nbproc;
626 int maxconn;
627 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100628 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100629 int mode;
630 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100631 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100632 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100633 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100634 struct sockaddr_in logsrv1, logsrv2;
635} global = {
636 logfac1 : -1,
637 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100638 loglev1 : 7, /* max syslog level : debug */
639 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100640 /* others NULL OK */
641};
642
willy tarreau0f7af912005-12-17 12:21:26 +0100643/*********************************************************************/
644
willy tarreau1c2ad212005-12-18 01:11:29 +0100645fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100646 *StaticWriteEvent;
647
willy tarreau64a3cc32005-12-18 01:13:11 +0100648int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100649
willy tarreau0f7af912005-12-17 12:21:26 +0100650void **pool_session = NULL,
651 **pool_buffer = NULL,
652 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100653 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100654 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100655 **pool_capture = NULL,
656 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100657
658struct proxy *proxy = NULL; /* list of all existing proxies */
659struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100660struct task *rq = NULL; /* global run queue */
661struct task wait_queue = { /* global wait queue */
662 prev:LIST_HEAD(wait_queue),
663 next:LIST_HEAD(wait_queue)
664};
willy tarreau0f7af912005-12-17 12:21:26 +0100665
willy tarreau0f7af912005-12-17 12:21:26 +0100666static int totalconn = 0; /* total # of terminated sessions */
667static int actconn = 0; /* # of active sessions */
668static int maxfd = 0; /* # of the highest fd + 1 */
669static int listeners = 0; /* # of listeners */
670static int stopping = 0; /* non zero means stopping in progress */
671static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100672static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100673
willy tarreau08dedbe2005-12-18 01:13:48 +0100674#if defined(ENABLE_EPOLL)
675/* FIXME: this is dirty, but at the moment, there's no other solution to remove
676 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
677 * structure with pointers to functions such as init_fd() and close_fd(), plus
678 * a private structure with several pointers to places such as below.
679 */
680
681static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
682#endif
683
willy tarreau0f7af912005-12-17 12:21:26 +0100684static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100685/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100686static char trash[BUFSIZE];
687
willy tarreaudd07e972005-12-18 00:48:48 +0100688const int zero = 0;
689const int one = 1;
690
willy tarreau0f7af912005-12-17 12:21:26 +0100691/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100692 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100693 */
694
695#define MAX_SYSLOG_LEN 1024
696#define NB_LOG_FACILITIES 24
697const char *log_facilities[NB_LOG_FACILITIES] = {
698 "kern", "user", "mail", "daemon",
699 "auth", "syslog", "lpr", "news",
700 "uucp", "cron", "auth2", "ftp",
701 "ntp", "audit", "alert", "cron2",
702 "local0", "local1", "local2", "local3",
703 "local4", "local5", "local6", "local7"
704};
705
706
707#define NB_LOG_LEVELS 8
708const char *log_levels[NB_LOG_LEVELS] = {
709 "emerg", "alert", "crit", "err",
710 "warning", "notice", "info", "debug"
711};
712
713#define SYSLOG_PORT 514
714
715const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
716 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100717
willy tarreaub1285d52005-12-18 01:20:14 +0100718const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100719const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
720const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
721const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
722 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
723 unknown, Set-cookie Rewritten */
724
willy tarreau0f7af912005-12-17 12:21:26 +0100725#define MAX_HOSTNAME_LEN 32
726static char hostname[MAX_HOSTNAME_LEN] = "";
727
willy tarreau8337c6b2005-12-17 13:41:01 +0100728const char *HTTP_302 =
729 "HTTP/1.0 302 Found\r\n"
730 "Cache-Control: no-cache\r\n"
731 "Connection: close\r\n"
732 "Location: "; /* not terminated since it will be concatenated with the URL */
733
willy tarreauc1f47532005-12-18 01:08:26 +0100734/* same as 302 except that the browser MUST retry with the GET method */
735const char *HTTP_303 =
736 "HTTP/1.0 303 See Other\r\n"
737 "Cache-Control: no-cache\r\n"
738 "Connection: close\r\n"
739 "Location: "; /* not terminated since it will be concatenated with the URL */
740
willy tarreaua1598082005-12-17 13:08:06 +0100741const char *HTTP_400 =
742 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100743 "Cache-Control: no-cache\r\n"
744 "Connection: close\r\n"
745 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100746 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100747
willy tarreaua1598082005-12-17 13:08:06 +0100748const char *HTTP_403 =
749 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100750 "Cache-Control: no-cache\r\n"
751 "Connection: close\r\n"
752 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100753 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
754
willy tarreau8337c6b2005-12-17 13:41:01 +0100755const char *HTTP_408 =
756 "HTTP/1.0 408 Request Time-out\r\n"
757 "Cache-Control: no-cache\r\n"
758 "Connection: close\r\n"
759 "\r\n"
760 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
761
willy tarreau750a4722005-12-17 13:21:24 +0100762const char *HTTP_500 =
763 "HTTP/1.0 500 Server Error\r\n"
764 "Cache-Control: no-cache\r\n"
765 "Connection: close\r\n"
766 "\r\n"
767 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100768
769const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100770 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100771 "Cache-Control: no-cache\r\n"
772 "Connection: close\r\n"
773 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100774 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
775
776const char *HTTP_503 =
777 "HTTP/1.0 503 Service Unavailable\r\n"
778 "Cache-Control: no-cache\r\n"
779 "Connection: close\r\n"
780 "\r\n"
781 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
782
783const char *HTTP_504 =
784 "HTTP/1.0 504 Gateway Time-out\r\n"
785 "Cache-Control: no-cache\r\n"
786 "Connection: close\r\n"
787 "\r\n"
788 "<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 +0100789
willy tarreau0f7af912005-12-17 12:21:26 +0100790/*********************************************************************/
791/* statistics ******************************************************/
792/*********************************************************************/
793
willy tarreau750a4722005-12-17 13:21:24 +0100794#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100795static int stats_tsk_lsrch, stats_tsk_rsrch,
796 stats_tsk_good, stats_tsk_right, stats_tsk_left,
797 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100798#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100799
800
801/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100802/* debugging *******************************************************/
803/*********************************************************************/
804#ifdef DEBUG_FULL
805static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
806static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
807#endif
808
809/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100810/* function prototypes *********************************************/
811/*********************************************************************/
812
813int event_accept(int fd);
814int event_cli_read(int fd);
815int event_cli_write(int fd);
816int event_srv_read(int fd);
817int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100818int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100819
willy tarreau12350152005-12-18 01:03:27 +0100820static int appsession_task_init(void);
821static int appsession_init(void);
822static int appsession_refresh(struct task *t);
823
willy tarreau0f7af912005-12-17 12:21:26 +0100824/*********************************************************************/
825/* general purpose functions ***************************************/
826/*********************************************************************/
827
828void display_version() {
829 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100830 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100831}
832
833/*
834 * This function prints the command line usage and exits
835 */
836void usage(char *name) {
837 display_version();
838 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100839 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100840#if STATTIME > 0
841 "sl"
842#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100843 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100844 " -v displays version\n"
845 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100846 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100847#if STATTIME > 0
848 " -s enables statistics output\n"
849 " -l enables long statistics format\n"
850#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100851 " -D goes daemon ; implies -q\n"
852 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100853 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100854 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100855 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100856 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100857#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100858 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100859#endif
860#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100861 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100862#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100863 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100864 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100865 exit(1);
866}
867
868
869/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100870 * Displays the message on stderr with the date and pid. Overrides the quiet
871 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100872 */
873void Alert(char *fmt, ...) {
874 va_list argp;
875 struct timeval tv;
876 struct tm *tm;
877
willy tarreaud0fb4652005-12-18 01:32:04 +0100878 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100879 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100880
willy tarreau5cbea6f2005-12-17 12:48:26 +0100881 gettimeofday(&tv, NULL);
882 tm=localtime(&tv.tv_sec);
883 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100884 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100885 vfprintf(stderr, fmt, argp);
886 fflush(stderr);
887 va_end(argp);
888 }
willy tarreau0f7af912005-12-17 12:21:26 +0100889}
890
891
892/*
893 * Displays the message on stderr with the date and pid.
894 */
895void Warning(char *fmt, ...) {
896 va_list argp;
897 struct timeval tv;
898 struct tm *tm;
899
willy tarreau982249e2005-12-18 00:57:06 +0100900 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100901 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100902
willy tarreau5cbea6f2005-12-17 12:48:26 +0100903 gettimeofday(&tv, NULL);
904 tm=localtime(&tv.tv_sec);
905 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100906 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100907 vfprintf(stderr, fmt, argp);
908 fflush(stderr);
909 va_end(argp);
910 }
911}
912
913/*
914 * Displays the message on <out> only if quiet mode is not set.
915 */
916void qfprintf(FILE *out, char *fmt, ...) {
917 va_list argp;
918
willy tarreau982249e2005-12-18 00:57:06 +0100919 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100920 va_start(argp, fmt);
921 vfprintf(out, fmt, argp);
922 fflush(out);
923 va_end(argp);
924 }
willy tarreau0f7af912005-12-17 12:21:26 +0100925}
926
927
928/*
929 * converts <str> to a struct sockaddr_in* which is locally allocated.
930 * The format is "addr:port", where "addr" can be empty or "*" to indicate
931 * INADDR_ANY.
932 */
933struct sockaddr_in *str2sa(char *str) {
934 static struct sockaddr_in sa;
935 char *c;
936 int port;
937
willy tarreaua1598082005-12-17 13:08:06 +0100938 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100939 str=strdup(str);
940
941 if ((c=strrchr(str,':')) != NULL) {
942 *c++=0;
943 port=atol(c);
944 }
945 else
946 port=0;
947
948 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
949 sa.sin_addr.s_addr = INADDR_ANY;
950 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100951 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100952 struct hostent *he;
953
954 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100955 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100956 }
957 else
958 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
959 }
960 sa.sin_port=htons(port);
961 sa.sin_family=AF_INET;
962
963 free(str);
964 return &sa;
965}
966
willy tarreaub1285d52005-12-18 01:20:14 +0100967/*
968 * converts <str> to a two struct in_addr* which are locally allocated.
969 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
970 * is optionnal and either in the dotted or CIDR notation.
971 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
972 */
973int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
974 char *c;
975 unsigned long len;
976
977 memset(mask, 0, sizeof(*mask));
978 memset(addr, 0, sizeof(*addr));
979 str=strdup(str);
980
981 if ((c = strrchr(str, '/')) != NULL) {
982 *c++ = 0;
983 /* c points to the mask */
984 if (strchr(c, '.') != NULL) { /* dotted notation */
985 if (!inet_pton(AF_INET, c, mask))
986 return 0;
987 }
988 else { /* mask length */
989 char *err;
990 len = strtol(c, &err, 10);
991 if (!*c || (err && *err) || (unsigned)len > 32)
992 return 0;
993 if (len)
994 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
995 else
996 mask->s_addr = 0;
997 }
998 }
999 else {
1000 mask->s_addr = 0xFFFFFFFF;
1001 }
1002 if (!inet_pton(AF_INET, str, addr)) {
1003 struct hostent *he;
1004
1005 if ((he = gethostbyname(str)) == NULL) {
1006 return 0;
1007 }
1008 else
1009 *addr = *(struct in_addr *) *(he->h_addr_list);
1010 }
1011 free(str);
1012 return 1;
1013}
1014
willy tarreau9fe663a2005-12-17 13:02:59 +01001015
1016/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001017 * converts <str> to a list of listeners which are dynamically allocated.
1018 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1019 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1020 * - <port> is a numerical port from 1 to 65535 ;
1021 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1022 * This can be repeated as many times as necessary, separated by a coma.
1023 * The <tail> argument is a pointer to a current list which should be appended
1024 * to the tail of the new list. The pointer to the new list is returned.
1025 */
1026struct listener *str2listener(char *str, struct listener *tail) {
1027 struct listener *l;
1028 char *c, *next, *range, *dupstr;
1029 int port, end;
1030
1031 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001032
willy tarreaua41a8b42005-12-17 14:02:24 +01001033 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001034 struct sockaddr_storage ss;
1035
willy tarreaua41a8b42005-12-17 14:02:24 +01001036 str = next;
1037 /* 1) look for the end of the first address */
1038 if ((next = strrchr(str, ',')) != NULL) {
1039 *next++ = 0;
1040 }
1041
willy tarreau8a86dbf2005-12-18 00:45:59 +01001042 /* 2) look for the addr/port delimiter, it's the last colon. */
1043 if ((range = strrchr(str, ':')) == NULL) {
1044 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001045 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001046 }
1047
1048 *range++ = 0;
1049
1050 if (strrchr(str, ':') != NULL) {
1051 /* IPv6 address contains ':' */
1052 memset(&ss, 0, sizeof(ss));
1053 ss.ss_family = AF_INET6;
1054
1055 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1056 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001057 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001058 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001059 }
1060 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001061 memset(&ss, 0, sizeof(ss));
1062 ss.ss_family = AF_INET;
1063
1064 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1065 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1066 }
1067 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1068 struct hostent *he;
1069
1070 if ((he = gethostbyname(str)) == NULL) {
1071 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001072 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001073 }
1074 else
1075 ((struct sockaddr_in *)&ss)->sin_addr =
1076 *(struct in_addr *) *(he->h_addr_list);
1077 }
1078 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001079
1080 /* 3) look for the port-end delimiter */
1081 if ((c = strchr(range, '-')) != NULL) {
1082 *c++ = 0;
1083 end = atol(c);
1084 }
1085 else {
1086 end = atol(range);
1087 }
1088
willy tarreaud0fb4652005-12-18 01:32:04 +01001089 port = atol(range);
1090
1091 if (port < 1 || port > 65535) {
1092 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1093 goto fail;
1094 }
1095
1096 if (end < 1 || end > 65535) {
1097 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1098 goto fail;
1099 }
1100
1101 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001102 l = (struct listener *)calloc(1, sizeof(struct listener));
1103 l->next = tail;
1104 tail = l;
1105
willy tarreau8a86dbf2005-12-18 00:45:59 +01001106 l->addr = ss;
1107 if (ss.ss_family == AF_INET6)
1108 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1109 else
1110 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1111
willy tarreaua41a8b42005-12-17 14:02:24 +01001112 } /* end for(port) */
1113 } /* end while(next) */
1114 free(dupstr);
1115 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001116 fail:
1117 free(dupstr);
1118 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001119}
1120
willy tarreau4302f492005-12-18 01:00:37 +01001121
1122#define FD_SETS_ARE_BITFIELDS
1123#ifdef FD_SETS_ARE_BITFIELDS
1124/*
1125 * This map is used with all the FD_* macros to check whether a particular bit
1126 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1127 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1128 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1129 * exclusively to the macros.
1130 */
1131fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1132fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1133
1134#else
1135#error "Check if your OS uses bitfields for fd_sets"
1136#endif
1137
1138/* will try to encode the string <string> replacing all characters tagged in
1139 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1140 * prefixed by <escape>, and will store the result between <start> (included
1141 *) and <stop> (excluded), and will always terminate the string with a '\0'
1142 * before <stop>. The position of the '\0' is returned if the conversion
1143 * completes. If bytes are missing between <start> and <stop>, then the
1144 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1145 * cannot even be stored so we return <start> without writing the 0.
1146 * The input string must also be zero-terminated.
1147 */
1148char hextab[16] = "0123456789ABCDEF";
1149char *encode_string(char *start, char *stop,
1150 const char escape, const fd_set *map,
1151 const char *string)
1152{
1153 if (start < stop) {
1154 stop--; /* reserve one byte for the final '\0' */
1155 while (start < stop && *string != 0) {
1156 if (!FD_ISSET((unsigned char)(*string), map))
1157 *start++ = *string;
1158 else {
1159 if (start + 3 >= stop)
1160 break;
1161 *start++ = escape;
1162 *start++ = hextab[(*string >> 4) & 15];
1163 *start++ = hextab[*string & 15];
1164 }
1165 string++;
1166 }
1167 *start = '\0';
1168 }
1169 return start;
1170}
willy tarreaua41a8b42005-12-17 14:02:24 +01001171
1172/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001173 * This function sends a syslog message to both log servers of a proxy,
1174 * or to global log servers if the proxy is NULL.
1175 * It also tries not to waste too much time computing the message header.
1176 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001177 */
1178void send_log(struct proxy *p, int level, char *message, ...) {
1179 static int logfd = -1; /* syslog UDP socket */
1180 static long tvsec = -1; /* to force the string to be initialized */
1181 struct timeval tv;
1182 va_list argp;
1183 static char logmsg[MAX_SYSLOG_LEN];
1184 static char *dataptr = NULL;
1185 int fac_level;
1186 int hdr_len, data_len;
1187 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001188 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001189 int nbloggers = 0;
1190 char *log_ptr;
1191
1192 if (logfd < 0) {
1193 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1194 return;
1195 }
1196
1197 if (level < 0 || progname == NULL || message == NULL)
1198 return;
1199
1200 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001201 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001202 /* this string is rebuild only once a second */
1203 struct tm *tm = localtime(&tv.tv_sec);
1204 tvsec = tv.tv_sec;
1205
willy tarreauc29948c2005-12-17 13:10:27 +01001206 hdr_len = snprintf(logmsg, sizeof(logmsg),
1207 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1208 monthname[tm->tm_mon],
1209 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1210 progname, pid);
1211 /* WARNING: depending upon implementations, snprintf may return
1212 * either -1 or the number of bytes that would be needed to store
1213 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001214 */
willy tarreauc29948c2005-12-17 13:10:27 +01001215 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1216 hdr_len = sizeof(logmsg);
1217
1218 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001219 }
1220
1221 va_start(argp, message);
1222 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001223 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1224 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001225 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001226 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001227
1228 if (p == NULL) {
1229 if (global.logfac1 >= 0) {
1230 sa[nbloggers] = &global.logsrv1;
1231 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001232 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001233 nbloggers++;
1234 }
1235 if (global.logfac2 >= 0) {
1236 sa[nbloggers] = &global.logsrv2;
1237 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001238 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001239 nbloggers++;
1240 }
1241 } else {
1242 if (p->logfac1 >= 0) {
1243 sa[nbloggers] = &p->logsrv1;
1244 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001245 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001246 nbloggers++;
1247 }
1248 if (p->logfac2 >= 0) {
1249 sa[nbloggers] = &p->logsrv2;
1250 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001251 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001252 nbloggers++;
1253 }
1254 }
1255
1256 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001257 /* we can filter the level of the messages that are sent to each logger */
1258 if (level > loglevel[nbloggers])
1259 continue;
1260
willy tarreauc29948c2005-12-17 13:10:27 +01001261 /* For each target, we may have a different facility.
1262 * We can also have a different log level for each message.
1263 * This induces variations in the message header length.
1264 * Since we don't want to recompute it each time, nor copy it every
1265 * time, we only change the facility in the pre-computed header,
1266 * and we change the pointer to the header accordingly.
1267 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001268 fac_level = (facilities[nbloggers] << 3) + level;
1269 log_ptr = logmsg + 3; /* last digit of the log level */
1270 do {
1271 *log_ptr = '0' + fac_level % 10;
1272 fac_level /= 10;
1273 log_ptr--;
1274 } while (fac_level && log_ptr > logmsg);
1275 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001276
willy tarreauc29948c2005-12-17 13:10:27 +01001277 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001278
1279#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001280 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001281 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1282#else
willy tarreauc29948c2005-12-17 13:10:27 +01001283 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001284 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1285#endif
1286 }
willy tarreau0f7af912005-12-17 12:21:26 +01001287}
1288
1289
1290/* sets <tv> to the current time */
1291static inline struct timeval *tv_now(struct timeval *tv) {
1292 if (tv)
1293 gettimeofday(tv, NULL);
1294 return tv;
1295}
1296
1297/*
1298 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1299 */
1300static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1301 if (!tv || !from)
1302 return NULL;
1303 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1304 tv->tv_sec = from->tv_sec + (ms/1000);
1305 while (tv->tv_usec >= 1000000) {
1306 tv->tv_usec -= 1000000;
1307 tv->tv_sec++;
1308 }
1309 return tv;
1310}
1311
1312/*
1313 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001314 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001315 */
1316static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001317 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001318 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001319 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001320 return 1;
1321 else if (tv1->tv_usec < tv2->tv_usec)
1322 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001323 else if (tv1->tv_usec > tv2->tv_usec)
1324 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001325 else
1326 return 0;
1327}
1328
1329/*
1330 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001331 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001332 */
1333unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1334 int cmp;
1335 unsigned long ret;
1336
1337
willy tarreauef900ab2005-12-17 12:52:52 +01001338 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001339 if (!cmp)
1340 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001341 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001342 struct timeval *tmp = tv1;
1343 tv1 = tv2;
1344 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001345 }
willy tarreauef900ab2005-12-17 12:52:52 +01001346 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001347 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001348 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001349 else
willy tarreauef900ab2005-12-17 12:52:52 +01001350 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001351 return (unsigned long) ret;
1352}
1353
1354/*
willy tarreau750a4722005-12-17 13:21:24 +01001355 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001356 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001357 */
1358static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1359 unsigned long ret;
1360
willy tarreau6e682ce2005-12-17 13:26:49 +01001361 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1362 if (tv2->tv_usec > tv1->tv_usec)
1363 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001364 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001365 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001366 return (unsigned long) ret;
1367}
1368
1369/*
willy tarreau0f7af912005-12-17 12:21:26 +01001370 * 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 +01001371 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001372 */
1373static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001374 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001375 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001376 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001377 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1378 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001379 else
1380 return 0;
1381 }
willy tarreau0f7af912005-12-17 12:21:26 +01001382 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001383 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001384 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001385 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1386 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1387 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001388 else
1389 return 0;
1390}
1391
1392/*
1393 * returns the remaining time between tv1=now and event=tv2
1394 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001395 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001396 */
1397static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1398 unsigned long ret;
1399
willy tarreau0f7af912005-12-17 12:21:26 +01001400 if (tv_cmp_ms(tv1, tv2) >= 0)
1401 return 0; /* event elapsed */
1402
willy tarreauef900ab2005-12-17 12:52:52 +01001403 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001404 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001405 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001406 else
willy tarreauef900ab2005-12-17 12:52:52 +01001407 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001408 return (unsigned long) ret;
1409}
1410
1411
1412/*
1413 * zeroes a struct timeval
1414 */
1415
1416static inline struct timeval *tv_eternity(struct timeval *tv) {
1417 tv->tv_sec = tv->tv_usec = 0;
1418 return tv;
1419}
1420
1421/*
1422 * returns 1 if tv is null, else 0
1423 */
1424static inline int tv_iseternity(struct timeval *tv) {
1425 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1426 return 1;
1427 else
1428 return 0;
1429}
1430
1431/*
1432 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1433 * considering that 0 is the eternity.
1434 */
1435static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1436 if (tv_iseternity(tv1))
1437 if (tv_iseternity(tv2))
1438 return 0; /* same */
1439 else
1440 return 1; /* tv1 later than tv2 */
1441 else if (tv_iseternity(tv2))
1442 return -1; /* tv2 later than tv1 */
1443
1444 if (tv1->tv_sec > tv2->tv_sec)
1445 return 1;
1446 else if (tv1->tv_sec < tv2->tv_sec)
1447 return -1;
1448 else if (tv1->tv_usec > tv2->tv_usec)
1449 return 1;
1450 else if (tv1->tv_usec < tv2->tv_usec)
1451 return -1;
1452 else
1453 return 0;
1454}
1455
1456/*
1457 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1458 * considering that 0 is the eternity.
1459 */
1460static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1461 if (tv_iseternity(tv1))
1462 if (tv_iseternity(tv2))
1463 return 0; /* same */
1464 else
1465 return 1; /* tv1 later than tv2 */
1466 else if (tv_iseternity(tv2))
1467 return -1; /* tv2 later than tv1 */
1468
willy tarreauefae1842005-12-17 12:51:03 +01001469 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001470 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001471 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001472 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001473 return -1;
1474 else
1475 return 0;
1476 }
1477 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001478 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001479 return 1;
1480 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001481 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001482 return -1;
1483 else
1484 return 0;
1485}
1486
1487/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001488 * returns the remaining time between tv1=now and event=tv2
1489 * if tv2 is passed, 0 is returned.
1490 * Returns TIME_ETERNITY if tv2 is eternity.
1491 */
1492static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1493 unsigned long ret;
1494
1495 if (tv_iseternity(tv2))
1496 return TIME_ETERNITY;
1497
1498 if (tv_cmp_ms(tv1, tv2) >= 0)
1499 return 0; /* event elapsed */
1500
1501 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1502 if (tv2->tv_usec > tv1->tv_usec)
1503 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1504 else
1505 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1506 return (unsigned long) ret;
1507}
1508
1509/*
willy tarreau0f7af912005-12-17 12:21:26 +01001510 * returns the first event between tv1 and tv2 into tvmin.
1511 * a zero tv is ignored. tvmin is returned.
1512 */
1513static inline struct timeval *tv_min(struct timeval *tvmin,
1514 struct timeval *tv1, struct timeval *tv2) {
1515
1516 if (tv_cmp2(tv1, tv2) <= 0)
1517 *tvmin = *tv1;
1518 else
1519 *tvmin = *tv2;
1520
1521 return tvmin;
1522}
1523
1524
1525
1526/***********************************************************/
1527/* fd management ***************************************/
1528/***********************************************************/
1529
1530
1531
willy tarreau5cbea6f2005-12-17 12:48:26 +01001532/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1533 * The file descriptor is also closed.
1534 */
willy tarreau0f7af912005-12-17 12:21:26 +01001535static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001536 FD_CLR(fd, StaticReadEvent);
1537 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001538#if defined(ENABLE_EPOLL)
1539 if (PrevReadEvent) {
1540 FD_CLR(fd, PrevReadEvent);
1541 FD_CLR(fd, PrevWriteEvent);
1542 }
1543#endif
1544
willy tarreau5cbea6f2005-12-17 12:48:26 +01001545 close(fd);
1546 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001547
1548 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1549 maxfd--;
1550}
1551
1552/* recomputes the maxfd limit from the fd */
1553static inline void fd_insert(int fd) {
1554 if (fd+1 > maxfd)
1555 maxfd = fd+1;
1556}
1557
1558/*************************************************************/
1559/* task management ***************************************/
1560/*************************************************************/
1561
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562/* puts the task <t> in run queue <q>, and returns <t> */
1563static inline struct task *task_wakeup(struct task **q, struct task *t) {
1564 if (t->state == TASK_RUNNING)
1565 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001566 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001567 t->rqnext = *q;
1568 t->state = TASK_RUNNING;
1569 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001570 }
1571}
1572
willy tarreau5cbea6f2005-12-17 12:48:26 +01001573/* removes the task <t> from the queue <q>
1574 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001575 * set the run queue to point to the next one, and return it
1576 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577static inline struct task *task_sleep(struct task **q, struct task *t) {
1578 if (t->state == TASK_RUNNING) {
1579 *q = t->rqnext;
1580 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001581 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001583}
1584
1585/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001586 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001587 * from the run queue. A pointer to the task itself is returned.
1588 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589static inline struct task *task_delete(struct task *t) {
1590 t->prev->next = t->next;
1591 t->next->prev = t->prev;
1592 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001593}
1594
1595/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001597 */
1598static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001599 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001600}
1601
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001603 * may be only moved or left where it was, depending on its timing requirements.
1604 * <task> is returned.
1605 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001606struct task *task_queue(struct task *task) {
1607 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001608 struct task *start_from;
1609
1610 /* first, test if the task was already in a list */
1611 if (task->prev == NULL) {
1612 // start_from = list;
1613 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001614#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001615 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001616#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001617 /* insert the unlinked <task> into the list, searching back from the last entry */
1618 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1619 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001620#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001621 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001622#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001623 }
1624
1625 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1626 // start_from = start_from->next;
1627 // stats_tsk_nsrch++;
1628 // }
1629 }
1630 else if (task->prev == list ||
1631 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1632 start_from = task->next;
1633 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001634#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001635 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001636#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001637 return task; /* it's already in the right place */
1638 }
1639
willy tarreau750a4722005-12-17 13:21:24 +01001640#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001641 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001642#endif
1643
1644 /* if the task is not at the right place, there's little chance that
1645 * it has only shifted a bit, and it will nearly always be queued
1646 * at the end of the list because of constant timeouts
1647 * (observed in real case).
1648 */
1649#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1650 start_from = list->prev; /* assume we'll queue to the end of the list */
1651 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1652 start_from = start_from->prev;
1653#if STATTIME > 0
1654 stats_tsk_lsrch++;
1655#endif
1656 }
1657#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001658 /* insert the unlinked <task> into the list, searching after position <start_from> */
1659 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1660 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001661#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001662 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001663#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001664 }
willy tarreau750a4722005-12-17 13:21:24 +01001665#endif /* WE_REALLY_... */
1666
willy tarreau0f7af912005-12-17 12:21:26 +01001667 /* we need to unlink it now */
1668 task_delete(task);
1669 }
1670 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001671#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001672 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001673#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001674#ifdef LEFT_TO_TOP /* not very good */
1675 start_from = list;
1676 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1677 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001678#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001679 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001680#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001681 }
1682#else
1683 start_from = task->prev->prev; /* valid because of the previous test above */
1684 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1685 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001686#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001687 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001688#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001689 }
1690#endif
1691 /* we need to unlink it now */
1692 task_delete(task);
1693 }
1694 task->prev = start_from;
1695 task->next = start_from->next;
1696 task->next->prev = task;
1697 start_from->next = task;
1698 return task;
1699}
1700
1701
1702/*********************************************************************/
1703/* more specific functions ***************************************/
1704/*********************************************************************/
1705
1706/* some prototypes */
1707static int maintain_proxies(void);
1708
willy tarreaub952e1d2005-12-18 01:31:20 +01001709/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001710 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1711 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001712static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001713#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001714 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1715#else
willy tarreaua1598082005-12-17 13:08:06 +01001716#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001717 return getsockname(fd, (struct sockaddr *)sa, salen);
1718#else
1719 return -1;
1720#endif
1721#endif
1722}
1723
1724/*
1725 * frees the context associated to a session. It must have been removed first.
1726 */
1727static inline void session_free(struct session *s) {
1728 if (s->req)
1729 pool_free(buffer, s->req);
1730 if (s->rep)
1731 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001732
1733 if (s->rsp_cap != NULL) {
1734 struct cap_hdr *h;
1735 for (h = s->proxy->rsp_cap; h; h = h->next) {
1736 if (s->rsp_cap[h->index] != NULL)
1737 pool_free_to(h->pool, s->rsp_cap[h->index]);
1738 }
1739 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1740 }
1741 if (s->req_cap != NULL) {
1742 struct cap_hdr *h;
1743 for (h = s->proxy->req_cap; h; h = h->next) {
1744 if (s->req_cap[h->index] != NULL)
1745 pool_free_to(h->pool, s->req_cap[h->index]);
1746 }
1747 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1748 }
1749
willy tarreaua1598082005-12-17 13:08:06 +01001750 if (s->logs.uri)
1751 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001752 if (s->logs.cli_cookie)
1753 pool_free(capture, s->logs.cli_cookie);
1754 if (s->logs.srv_cookie)
1755 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001756
willy tarreau5cbea6f2005-12-17 12:48:26 +01001757 pool_free(session, s);
1758}
1759
willy tarreau0f7af912005-12-17 12:21:26 +01001760
1761/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001762 * This function tries to find a running server for the proxy <px>. A first
1763 * pass looks for active servers, and if none is found, a second pass also
1764 * looks for backup servers.
1765 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1766 */
1767static inline struct server *find_server(struct proxy *px) {
1768 struct server *srv = px->cursrv;
1769 int ignore_backup = 1;
1770
1771 do {
1772 do {
1773 if (srv == NULL)
1774 srv = px->srv;
1775 if (srv->state & SRV_RUNNING
1776 && !((srv->state & SRV_BACKUP) && ignore_backup))
1777 return srv;
1778 srv = srv->next;
1779 } while (srv != px->cursrv);
1780 } while (ignore_backup--);
1781 return NULL;
1782}
1783
1784/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001785 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001786 * is set, or to the dispatch server if (s->direct) is 0.
1787 * It can return one of :
1788 * - SN_ERR_NONE if everything's OK
1789 * - SN_ERR_SRVTO if there are no more servers
1790 * - SN_ERR_SRVCL if the connection was refused by the server
1791 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1792 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1793 * - SN_ERR_INTERNAL for any other purely internal errors
1794 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001795 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001796int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001797 int fd;
1798
willy tarreau12350152005-12-18 01:03:27 +01001799#ifdef DEBUG_FULL
1800 fprintf(stderr,"connect_server : s=%p\n",s);
1801#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001802
willy tarreaue39cd132005-12-17 13:00:18 +01001803 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001804 s->srv_addr = s->srv->addr;
1805 }
1806 else if (s->proxy->options & PR_O_BALANCE) {
1807 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001808 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001809
willy tarreau8337c6b2005-12-17 13:41:01 +01001810 srv = find_server(s->proxy);
1811
1812 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001813 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001814
willy tarreau8337c6b2005-12-17 13:41:01 +01001815 s->srv_addr = srv->addr;
1816 s->srv = srv;
1817 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001818 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001820 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001821 }
willy tarreaua1598082005-12-17 13:08:06 +01001822 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001823 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001824 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825 }
1826 else if (s->proxy->options & PR_O_TRANSP) {
1827 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001828 socklen_t salen = sizeof(s->srv_addr);
1829
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1831 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001832 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001833 }
1834 }
willy tarreau0f7af912005-12-17 12:21:26 +01001835
willy tarreaua41a8b42005-12-17 14:02:24 +01001836 /* if this server remaps proxied ports, we'll use
1837 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001838 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001839 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001840 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001841
willy tarreaub952e1d2005-12-18 01:31:20 +01001842 if (!(s->proxy->options & PR_O_TRANSP) ||
1843 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001844 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1845 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1846 }
1847
willy tarreau0f7af912005-12-17 12:21:26 +01001848 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001849 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001850
1851 if (errno == ENFILE)
1852 send_log(s->proxy, LOG_EMERG,
1853 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1854 s->proxy->id, maxfd);
1855 else if (errno == EMFILE)
1856 send_log(s->proxy, LOG_EMERG,
1857 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1858 s->proxy->id, maxfd);
1859 else if (errno == ENOBUFS || errno == ENOMEM)
1860 send_log(s->proxy, LOG_EMERG,
1861 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1862 s->proxy->id, maxfd);
1863 /* this is a resource error */
1864 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001865 }
1866
willy tarreau9fe663a2005-12-17 13:02:59 +01001867 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001868 /* do not log anything there, it's a normal condition when this option
1869 * is used to serialize connections to a server !
1870 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001871 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1872 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001873 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001874 }
1875
willy tarreau0f7af912005-12-17 12:21:26 +01001876 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1877 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001879 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001880 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001881 }
1882
willy tarreaub952e1d2005-12-18 01:31:20 +01001883 if (s->proxy->options & PR_O_TCP_SRV_KA)
1884 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1885
willy tarreau0174f312005-12-18 01:02:42 +01001886 /* allow specific binding :
1887 * - server-specific at first
1888 * - proxy-specific next
1889 */
1890 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1891 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1892 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1893 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1894 s->proxy->id, s->srv->id);
1895 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001896 send_log(s->proxy, LOG_EMERG,
1897 "Cannot bind to source address before connect() for server %s/%s.\n",
1898 s->proxy->id, s->srv->id);
1899 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001900 }
1901 }
1902 else if (s->proxy->options & PR_O_BIND_SRC) {
1903 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1904 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1905 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1906 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001907 send_log(s->proxy, LOG_EMERG,
1908 "Cannot bind to source address before connect() for server %s/%s.\n",
1909 s->proxy->id, s->srv->id);
1910 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001911 }
willy tarreaua1598082005-12-17 13:08:06 +01001912 }
1913
willy tarreaub1285d52005-12-18 01:20:14 +01001914 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1915 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1916
1917 if (errno == EAGAIN || errno == EADDRINUSE) {
1918 char *msg;
1919 if (errno == EAGAIN) /* no free ports left, try again later */
1920 msg = "no free ports";
1921 else
1922 msg = "local address already in use";
1923
1924 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001925 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001926 send_log(s->proxy, LOG_EMERG,
1927 "Connect() failed for server %s/%s: %s.\n",
1928 s->proxy->id, s->srv->id, msg);
1929 return SN_ERR_RESOURCE;
1930 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001931 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001932 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001933 return SN_ERR_SRVTO;
1934 } else {
1935 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001936 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001937 close(fd);
1938 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001939 }
1940 }
1941
willy tarreau5cbea6f2005-12-17 12:48:26 +01001942 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001943 fdtab[fd].read = &event_srv_read;
1944 fdtab[fd].write = &event_srv_write;
1945 fdtab[fd].state = FD_STCONN; /* connection in progress */
1946
1947 FD_SET(fd, StaticWriteEvent); /* for connect status */
1948
1949 fd_insert(fd);
1950
1951 if (s->proxy->contimeout)
1952 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1953 else
1954 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001955 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001956}
1957
1958/*
1959 * this function is called on a read event from a client socket.
1960 * It returns 0.
1961 */
1962int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001963 struct task *t = fdtab[fd].owner;
1964 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001965 struct buffer *b = s->req;
1966 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001967
willy tarreau12350152005-12-18 01:03:27 +01001968#ifdef DEBUG_FULL
1969 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1970#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001971
willy tarreau0f7af912005-12-17 12:21:26 +01001972 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001973#ifdef FILL_BUFFERS
1974 while (1)
1975#else
1976 do
1977#endif
1978 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1980 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001981 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001982 }
1983 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001984 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001985 }
1986 else {
1987 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001988 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1989 * since it means that the rewrite protection has been removed. This
1990 * implies that the if statement can be removed.
1991 */
1992 if (max > b->rlim - b->data)
1993 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994 }
1995
1996 if (max == 0) { /* not anymore room to store data */
1997 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001998 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 }
2000
willy tarreau3242e862005-12-17 12:27:53 +01002001#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002002 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002003 int skerr;
2004 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002005
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2007 if (skerr)
2008 ret = -1;
2009 else
2010 ret = recv(fd, b->r, max, 0);
2011 }
willy tarreau3242e862005-12-17 12:27:53 +01002012#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002013 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002014#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002015 if (ret > 0) {
2016 b->r += ret;
2017 b->l += ret;
2018 s->res_cr = RES_DATA;
2019
2020 if (b->r == b->data + BUFSIZE) {
2021 b->r = b->data; /* wrap around the buffer */
2022 }
willy tarreaua1598082005-12-17 13:08:06 +01002023
2024 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025 /* we hope to read more data or to get a close on next round */
2026 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002027 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002028 else if (ret == 0) {
2029 s->res_cr = RES_NULL;
2030 break;
2031 }
2032 else if (errno == EAGAIN) {/* ignore EAGAIN */
2033 break;
2034 }
2035 else {
2036 s->res_cr = RES_ERROR;
2037 fdtab[fd].state = FD_STERROR;
2038 break;
2039 }
2040 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002041#ifndef FILL_BUFFERS
2042 while (0);
2043#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002044 }
2045 else {
2046 s->res_cr = RES_ERROR;
2047 fdtab[fd].state = FD_STERROR;
2048 }
2049
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002051 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2053 else
2054 tv_eternity(&s->crexpire);
2055
2056 task_wakeup(&rq, t);
2057 }
willy tarreau0f7af912005-12-17 12:21:26 +01002058
willy tarreau0f7af912005-12-17 12:21:26 +01002059 return 0;
2060}
2061
2062
2063/*
2064 * this function is called on a read event from a server socket.
2065 * It returns 0.
2066 */
2067int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002068 struct task *t = fdtab[fd].owner;
2069 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002070 struct buffer *b = s->rep;
2071 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002072
willy tarreau12350152005-12-18 01:03:27 +01002073#ifdef DEBUG_FULL
2074 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2075#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002076
willy tarreau0f7af912005-12-17 12:21:26 +01002077 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002078#ifdef FILL_BUFFERS
2079 while (1)
2080#else
2081 do
2082#endif
2083 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002084 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2085 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002086 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002087 }
2088 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002089 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002090 }
2091 else {
2092 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002093 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2094 * since it means that the rewrite protection has been removed. This
2095 * implies that the if statement can be removed.
2096 */
2097 if (max > b->rlim - b->data)
2098 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002099 }
2100
2101 if (max == 0) { /* not anymore room to store data */
2102 FD_CLR(fd, StaticReadEvent);
2103 break;
2104 }
2105
willy tarreau3242e862005-12-17 12:27:53 +01002106#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002107 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002108 int skerr;
2109 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002110
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2112 if (skerr)
2113 ret = -1;
2114 else
2115 ret = recv(fd, b->r, max, 0);
2116 }
willy tarreau3242e862005-12-17 12:27:53 +01002117#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002118 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002119#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002120 if (ret > 0) {
2121 b->r += ret;
2122 b->l += ret;
2123 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002124
willy tarreau5cbea6f2005-12-17 12:48:26 +01002125 if (b->r == b->data + BUFSIZE) {
2126 b->r = b->data; /* wrap around the buffer */
2127 }
willy tarreaua1598082005-12-17 13:08:06 +01002128
2129 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002130 /* we hope to read more data or to get a close on next round */
2131 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002132 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002133 else if (ret == 0) {
2134 s->res_sr = RES_NULL;
2135 break;
2136 }
2137 else if (errno == EAGAIN) {/* ignore EAGAIN */
2138 break;
2139 }
2140 else {
2141 s->res_sr = RES_ERROR;
2142 fdtab[fd].state = FD_STERROR;
2143 break;
2144 }
2145 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002146#ifndef FILL_BUFFERS
2147 while (0);
2148#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002149 }
2150 else {
2151 s->res_sr = RES_ERROR;
2152 fdtab[fd].state = FD_STERROR;
2153 }
2154
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002156 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002157 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2158 else
2159 tv_eternity(&s->srexpire);
2160
2161 task_wakeup(&rq, t);
2162 }
willy tarreau0f7af912005-12-17 12:21:26 +01002163
willy tarreau0f7af912005-12-17 12:21:26 +01002164 return 0;
2165}
2166
2167/*
2168 * this function is called on a write event from a client socket.
2169 * It returns 0.
2170 */
2171int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002172 struct task *t = fdtab[fd].owner;
2173 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002174 struct buffer *b = s->rep;
2175 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002176
willy tarreau12350152005-12-18 01:03:27 +01002177#ifdef DEBUG_FULL
2178 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2179#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002180
2181 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002182 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002183 // max = BUFSIZE; BUG !!!!
2184 max = 0;
2185 }
2186 else if (b->r > b->w) {
2187 max = b->r - b->w;
2188 }
2189 else
2190 max = b->data + BUFSIZE - b->w;
2191
willy tarreau0f7af912005-12-17 12:21:26 +01002192 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002193 if (max == 0) {
2194 s->res_cw = RES_NULL;
2195 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002196 tv_eternity(&s->cwexpire);
2197 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002198 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002199 }
2200
willy tarreau3242e862005-12-17 12:27:53 +01002201#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002202 {
2203 int skerr;
2204 socklen_t lskerr = sizeof(skerr);
2205
2206 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2207 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002208 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002209 else
willy tarreau3242e862005-12-17 12:27:53 +01002210 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002211 }
willy tarreau3242e862005-12-17 12:27:53 +01002212#else
willy tarreau0f7af912005-12-17 12:21:26 +01002213 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002214#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002215
2216 if (ret > 0) {
2217 b->l -= ret;
2218 b->w += ret;
2219
2220 s->res_cw = RES_DATA;
2221
2222 if (b->w == b->data + BUFSIZE) {
2223 b->w = b->data; /* wrap around the buffer */
2224 }
2225 }
2226 else if (ret == 0) {
2227 /* nothing written, just make as if we were never called */
2228// s->res_cw = RES_NULL;
2229 return 0;
2230 }
2231 else if (errno == EAGAIN) /* ignore EAGAIN */
2232 return 0;
2233 else {
2234 s->res_cw = RES_ERROR;
2235 fdtab[fd].state = FD_STERROR;
2236 }
2237 }
2238 else {
2239 s->res_cw = RES_ERROR;
2240 fdtab[fd].state = FD_STERROR;
2241 }
2242
willy tarreaub1ff9db2005-12-17 13:51:03 +01002243 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002244 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002245 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2246 s->crexpire = s->cwexpire;
2247 }
willy tarreau0f7af912005-12-17 12:21:26 +01002248 else
2249 tv_eternity(&s->cwexpire);
2250
willy tarreau5cbea6f2005-12-17 12:48:26 +01002251 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002252 return 0;
2253}
2254
2255
2256/*
2257 * this function is called on a write event from a server socket.
2258 * It returns 0.
2259 */
2260int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002261 struct task *t = fdtab[fd].owner;
2262 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002263 struct buffer *b = s->req;
2264 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002265
willy tarreau12350152005-12-18 01:03:27 +01002266#ifdef DEBUG_FULL
2267 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2268#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002269
2270 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002271 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002272 // max = BUFSIZE; BUG !!!!
2273 max = 0;
2274 }
2275 else if (b->r > b->w) {
2276 max = b->r - b->w;
2277 }
2278 else
2279 max = b->data + BUFSIZE - b->w;
2280
willy tarreau0f7af912005-12-17 12:21:26 +01002281 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002282 if (max == 0) {
2283 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002284 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002285 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002286 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002287 tv_eternity(&s->swexpire);
2288 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002289 return 0;
2290 }
2291
willy tarreau3242e862005-12-17 12:27:53 +01002292#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002293 {
2294 int skerr;
2295 socklen_t lskerr = sizeof(skerr);
2296 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2297 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002298 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002299 else
willy tarreau3242e862005-12-17 12:27:53 +01002300 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002301 }
willy tarreau3242e862005-12-17 12:27:53 +01002302#else
willy tarreau0f7af912005-12-17 12:21:26 +01002303 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002304#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002305 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002306 if (ret > 0) {
2307 b->l -= ret;
2308 b->w += ret;
2309
2310 s->res_sw = RES_DATA;
2311
2312 if (b->w == b->data + BUFSIZE) {
2313 b->w = b->data; /* wrap around the buffer */
2314 }
2315 }
2316 else if (ret == 0) {
2317 /* nothing written, just make as if we were never called */
2318 // s->res_sw = RES_NULL;
2319 return 0;
2320 }
2321 else if (errno == EAGAIN) /* ignore EAGAIN */
2322 return 0;
2323 else {
2324 s->res_sw = RES_ERROR;
2325 fdtab[fd].state = FD_STERROR;
2326 }
2327 }
2328 else {
2329 s->res_sw = RES_ERROR;
2330 fdtab[fd].state = FD_STERROR;
2331 }
2332
willy tarreaub1ff9db2005-12-17 13:51:03 +01002333 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002334 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002335 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2336 s->srexpire = s->swexpire;
2337 }
willy tarreau0f7af912005-12-17 12:21:26 +01002338 else
2339 tv_eternity(&s->swexpire);
2340
willy tarreau5cbea6f2005-12-17 12:48:26 +01002341 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002342 return 0;
2343}
2344
2345
2346/*
willy tarreaue39cd132005-12-17 13:00:18 +01002347 * returns a message to the client ; the connection is shut down for read,
2348 * and the request is cleared so that no server connection can be initiated.
2349 * The client must be in a valid state for this (HEADER, DATA ...).
2350 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002351 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002352 */
2353void client_retnclose(struct session *s, int len, const char *msg) {
2354 FD_CLR(s->cli_fd, StaticReadEvent);
2355 FD_SET(s->cli_fd, StaticWriteEvent);
2356 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002357 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002358 shutdown(s->cli_fd, SHUT_RD);
2359 s->cli_state = CL_STSHUTR;
2360 strcpy(s->rep->data, msg);
2361 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002362 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002363 s->rep->r += len;
2364 s->req->l = 0;
2365}
2366
2367
2368/*
2369 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002370 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002371 */
2372void client_return(struct session *s, int len, const char *msg) {
2373 strcpy(s->rep->data, msg);
2374 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002375 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002376 s->rep->r += len;
2377 s->req->l = 0;
2378}
2379
willy tarreau9fe663a2005-12-17 13:02:59 +01002380/*
2381 * send a log for the session when we have enough info about it
2382 */
2383void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002384 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002385 struct proxy *p = s->proxy;
2386 int log;
2387 char *uri;
2388 char *pxid;
2389 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002390 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002391
2392 /* This is a first attempt at a better logging system.
2393 * For now, we rely on send_log() to provide the date, although it obviously
2394 * is the date of the log and not of the request, and most fields are not
2395 * computed.
2396 */
2397
willy tarreaua1598082005-12-17 13:08:06 +01002398 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002399
willy tarreau8a86dbf2005-12-18 00:45:59 +01002400 if (s->cli_addr.ss_family == AF_INET)
2401 inet_ntop(AF_INET,
2402 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2403 pn, sizeof(pn));
2404 else
2405 inet_ntop(AF_INET6,
2406 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2407 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002408
willy tarreauc1cae632005-12-17 14:12:23 +01002409 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002410 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002411 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002412
willy tarreauc1cae632005-12-17 14:12:23 +01002413 tm = localtime(&s->logs.tv_accept.tv_sec);
2414 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002415 char tmpline[MAX_SYSLOG_LEN], *h;
2416 int hdr;
2417
2418 h = tmpline;
2419 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2420 *(h++) = ' ';
2421 *(h++) = '{';
2422 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2423 if (hdr)
2424 *(h++) = '|';
2425 if (s->req_cap[hdr] != NULL)
2426 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2427 }
2428 *(h++) = '}';
2429 }
2430
2431 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2432 *(h++) = ' ';
2433 *(h++) = '{';
2434 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2435 if (hdr)
2436 *(h++) = '|';
2437 if (s->rsp_cap[hdr] != NULL)
2438 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2439 }
2440 *(h++) = '}';
2441 }
2442
2443 if (h < tmpline + sizeof(tmpline) - 4) {
2444 *(h++) = ' ';
2445 *(h++) = '"';
2446 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2447 *(h++) = '"';
2448 }
2449 *h = '\0';
2450
willy tarreau0fe39652005-12-18 01:25:24 +01002451 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 +01002452 pn,
2453 (s->cli_addr.ss_family == AF_INET) ?
2454 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2455 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002456 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2457 tm->tm_hour, tm->tm_min, tm->tm_sec,
2458 pxid, srv,
2459 s->logs.t_request,
2460 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2461 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002462 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2463 s->logs.status,
2464 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002465 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2466 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002467 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2468 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2469 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2470 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002471 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002472 }
2473 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002474 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 +01002475 pn,
2476 (s->cli_addr.ss_family == AF_INET) ?
2477 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2478 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002479 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2480 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002481 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002482 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002483 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2484 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002485 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002486 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2487 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002488 }
2489
2490 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002491}
2492
willy tarreaue39cd132005-12-17 13:00:18 +01002493
2494/*
willy tarreau0f7af912005-12-17 12:21:26 +01002495 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002496 * to an accept. It tries to accept as many connections as possible.
2497 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002498 */
2499int event_accept(int fd) {
2500 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501 struct session *s;
2502 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002503 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002504
willy tarreau5cbea6f2005-12-17 12:48:26 +01002505 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002506 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002507 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002508
willy tarreaub1285d52005-12-18 01:20:14 +01002509 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2510 switch (errno) {
2511 case EAGAIN:
2512 case EINTR:
2513 case ECONNABORTED:
2514 return 0; /* nothing more to accept */
2515 case ENFILE:
2516 send_log(p, LOG_EMERG,
2517 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2518 p->id, maxfd);
2519 return 0;
2520 case EMFILE:
2521 send_log(p, LOG_EMERG,
2522 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2523 p->id, maxfd);
2524 return 0;
2525 case ENOBUFS:
2526 case ENOMEM:
2527 send_log(p, LOG_EMERG,
2528 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2529 p->id, maxfd);
2530 return 0;
2531 default:
2532 return 0;
2533 }
2534 }
willy tarreau0f7af912005-12-17 12:21:26 +01002535
willy tarreau5cbea6f2005-12-17 12:48:26 +01002536 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2537 Alert("out of memory in event_accept().\n");
2538 FD_CLR(fd, StaticReadEvent);
2539 p->state = PR_STIDLE;
2540 close(cfd);
2541 return 0;
2542 }
willy tarreau0f7af912005-12-17 12:21:26 +01002543
willy tarreaub1285d52005-12-18 01:20:14 +01002544 /* if this session comes from a known monitoring system, we want to ignore
2545 * it as soon as possible, which means closing it immediately for TCP.
2546 */
2547 s->flags = 0;
2548 if (addr.ss_family == AF_INET &&
2549 p->mon_mask.s_addr &&
2550 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2551 if (p->mode == PR_MODE_TCP) {
2552 close(cfd);
2553 pool_free(session, s);
2554 continue;
2555 }
2556 s->flags |= SN_MONITOR;
2557 }
2558
willy tarreau5cbea6f2005-12-17 12:48:26 +01002559 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2560 Alert("out of memory in event_accept().\n");
2561 FD_CLR(fd, StaticReadEvent);
2562 p->state = PR_STIDLE;
2563 close(cfd);
2564 pool_free(session, s);
2565 return 0;
2566 }
willy tarreau0f7af912005-12-17 12:21:26 +01002567
willy tarreau5cbea6f2005-12-17 12:48:26 +01002568 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002569 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2571 close(cfd);
2572 pool_free(task, t);
2573 pool_free(session, s);
2574 return 0;
2575 }
willy tarreau0f7af912005-12-17 12:21:26 +01002576
willy tarreau5cbea6f2005-12-17 12:48:26 +01002577 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2578 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2579 (char *) &one, sizeof(one)) == -1)) {
2580 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2581 close(cfd);
2582 pool_free(task, t);
2583 pool_free(session, s);
2584 return 0;
2585 }
willy tarreau0f7af912005-12-17 12:21:26 +01002586
willy tarreaub952e1d2005-12-18 01:31:20 +01002587 if (p->options & PR_O_TCP_CLI_KA)
2588 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2589
willy tarreau9fe663a2005-12-17 13:02:59 +01002590 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2591 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2592 t->state = TASK_IDLE;
2593 t->process = process_session;
2594 t->context = s;
2595
2596 s->task = t;
2597 s->proxy = p;
2598 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2599 s->srv_state = SV_STIDLE;
2600 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002601
willy tarreau9fe663a2005-12-17 13:02:59 +01002602 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2603 s->cli_fd = cfd;
2604 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002605 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002606 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002607
willy tarreaub1285d52005-12-18 01:20:14 +01002608 if (s->flags & SN_MONITOR)
2609 s->logs.logwait = 0;
2610 else
2611 s->logs.logwait = p->to_log;
2612
willy tarreaua1598082005-12-17 13:08:06 +01002613 s->logs.tv_accept = now;
2614 s->logs.t_request = -1;
2615 s->logs.t_connect = -1;
2616 s->logs.t_data = -1;
2617 s->logs.t_close = 0;
2618 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002619 s->logs.cli_cookie = NULL;
2620 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002621 s->logs.status = -1;
2622 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002623
willy tarreau2f6ba652005-12-17 13:57:42 +01002624 s->uniq_id = totalconn;
2625
willy tarreau4302f492005-12-18 01:00:37 +01002626 if (p->nb_req_cap > 0) {
2627 if ((s->req_cap =
2628 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2629 == NULL) { /* no memory */
2630 close(cfd); /* nothing can be done for this fd without memory */
2631 pool_free(task, t);
2632 pool_free(session, s);
2633 return 0;
2634 }
2635 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2636 }
2637 else
2638 s->req_cap = NULL;
2639
2640 if (p->nb_rsp_cap > 0) {
2641 if ((s->rsp_cap =
2642 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2643 == NULL) { /* no memory */
2644 if (s->req_cap != NULL)
2645 pool_free_to(p->req_cap_pool, s->req_cap);
2646 close(cfd); /* nothing can be done for this fd without memory */
2647 pool_free(task, t);
2648 pool_free(session, s);
2649 return 0;
2650 }
2651 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2652 }
2653 else
2654 s->rsp_cap = NULL;
2655
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2657 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002658 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002659 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau8a86dbf2005-12-18 00:45:59 +01002661 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002662 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002663 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002665
willy tarreau9fe663a2005-12-17 13:02:59 +01002666 if (p->to_log) {
2667 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002668 if (s->logs.logwait & LW_CLIP)
2669 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002670 sess_log(s);
2671 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002672 else if (s->cli_addr.ss_family == AF_INET) {
2673 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2674 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2675 sn, sizeof(sn)) &&
2676 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2677 pn, sizeof(pn))) {
2678 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2679 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2680 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2681 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2682 }
2683 }
2684 else {
2685 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2686 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2687 sn, sizeof(sn)) &&
2688 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2689 pn, sizeof(pn))) {
2690 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2691 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2692 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2693 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2694 }
2695 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002696 }
willy tarreau0f7af912005-12-17 12:21:26 +01002697
willy tarreau982249e2005-12-18 00:57:06 +01002698 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002699 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002700 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002701 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002702 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002703 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002704 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002705 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002706
willy tarreau8a86dbf2005-12-18 00:45:59 +01002707 if (s->cli_addr.ss_family == AF_INET) {
2708 char pn[INET_ADDRSTRLEN];
2709 inet_ntop(AF_INET,
2710 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2711 pn, sizeof(pn));
2712
2713 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2714 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2715 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2716 }
2717 else {
2718 char pn[INET6_ADDRSTRLEN];
2719 inet_ntop(AF_INET6,
2720 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2721 pn, sizeof(pn));
2722
2723 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2724 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2725 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2726 }
2727
willy tarreauef900ab2005-12-17 12:52:52 +01002728 write(1, trash, len);
2729 }
willy tarreau0f7af912005-12-17 12:21:26 +01002730
willy tarreau5cbea6f2005-12-17 12:48:26 +01002731 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002732 if (s->rsp_cap != NULL)
2733 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2734 if (s->req_cap != NULL)
2735 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002736 close(cfd); /* nothing can be done for this fd without memory */
2737 pool_free(task, t);
2738 pool_free(session, s);
2739 return 0;
2740 }
willy tarreau4302f492005-12-18 01:00:37 +01002741
willy tarreau5cbea6f2005-12-17 12:48:26 +01002742 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002743 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002744 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2745 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002746 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002747 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002748
willy tarreau5cbea6f2005-12-17 12:48:26 +01002749 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2750 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002751 if (s->rsp_cap != NULL)
2752 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2753 if (s->req_cap != NULL)
2754 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002755 close(cfd); /* nothing can be done for this fd without memory */
2756 pool_free(task, t);
2757 pool_free(session, s);
2758 return 0;
2759 }
2760 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002761 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002762 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 +01002763
willy tarreau5cbea6f2005-12-17 12:48:26 +01002764 fdtab[cfd].read = &event_cli_read;
2765 fdtab[cfd].write = &event_cli_write;
2766 fdtab[cfd].owner = t;
2767 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002768
willy tarreaub1285d52005-12-18 01:20:14 +01002769 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2770 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2771 /* Either we got a request from a monitoring system on an HTTP instance,
2772 * or we're in health check mode with the 'httpchk' option enabled. In
2773 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2774 */
2775 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2776 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2777 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002778 }
2779 else {
2780 FD_SET(cfd, StaticReadEvent);
2781 }
2782
willy tarreaub952e1d2005-12-18 01:31:20 +01002783#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2784 if (PrevReadEvent) {
2785 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2786 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2787 }
2788#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002789 fd_insert(cfd);
2790
2791 tv_eternity(&s->cnexpire);
2792 tv_eternity(&s->srexpire);
2793 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002794 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795 tv_eternity(&s->cwexpire);
2796
willy tarreaub1285d52005-12-18 01:20:14 +01002797 if (s->proxy->clitimeout) {
2798 if (FD_ISSET(cfd, StaticReadEvent))
2799 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2800 if (FD_ISSET(cfd, StaticWriteEvent))
2801 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2802 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803
willy tarreaub1285d52005-12-18 01:20:14 +01002804 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002805
2806 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002807
2808 if (p->mode != PR_MODE_HEALTH)
2809 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002810
2811 p->nbconn++;
2812 actconn++;
2813 totalconn++;
2814
willy tarreaub952e1d2005-12-18 01:31:20 +01002815 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002816 } /* end of while (p->nbconn < p->maxconn) */
2817 return 0;
2818}
willy tarreau0f7af912005-12-17 12:21:26 +01002819
willy tarreau0f7af912005-12-17 12:21:26 +01002820
willy tarreau5cbea6f2005-12-17 12:48:26 +01002821/*
2822 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002823 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2824 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002825 * or -1 if an error occured.
2826 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002827int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002828 struct task *t = fdtab[fd].owner;
2829 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002830
willy tarreauc5f73ed2005-12-18 01:26:38 +01002831 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002832 socklen_t lskerr = sizeof(skerr);
2833
willy tarreau5cbea6f2005-12-17 12:48:26 +01002834 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002835 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836 if (skerr)
2837 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002838 else {
2839 if (s->proxy->options & PR_O_HTTP_CHK) {
2840 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002841 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002842 * so we'll send the request, and won't wake the checker up now.
2843 */
2844#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002845 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002846#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002847 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002848#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002849 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002850 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2851 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2852 return 0;
2853 }
2854 else
2855 s->result = -1;
2856 }
2857 else {
2858 /* good TCP connection is enough */
2859 s->result = 1;
2860 }
2861 }
2862
2863 task_wakeup(&rq, t);
2864 return 0;
2865}
2866
willy tarreau0f7af912005-12-17 12:21:26 +01002867
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002868/*
2869 * This function is used only for server health-checks. It handles
2870 * the server's reply to an HTTP request. It returns 1 if the server replies
2871 * 2xx or 3xx (valid responses), or -1 in other cases.
2872 */
2873int event_srv_chk_r(int fd) {
2874 char reply[64];
2875 int len;
2876 struct task *t = fdtab[fd].owner;
2877 struct server *s = t->context;
2878
willy tarreau197e8ec2005-12-17 14:10:59 +01002879 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002880#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002881 {
2882 int skerr;
2883 socklen_t lskerr = sizeof(skerr);
2884
2885 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2886 if (!skerr)
2887 len = recv(fd, reply, sizeof(reply), 0);
2888 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002889#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002890 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2891 * but the connection was closed on the remote end. Fortunately, recv still
2892 * works correctly and we don't need to do the getsockopt() on linux.
2893 */
2894 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002895#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002896 if ((len >= sizeof("HTTP/1.0 000")) &&
2897 !memcmp(reply, "HTTP/1.", 7) &&
2898 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2899 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002900
2901 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002902 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002903 return 0;
2904}
2905
2906
2907/*
2908 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2909 * and moves <end> just after the end of <str>.
2910 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2911 * the shift value (positive or negative) is returned.
2912 * If there's no space left, the move is not done.
2913 *
2914 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002915int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002916 int delta;
2917 int len;
2918
2919 len = strlen(str);
2920 delta = len - (end - pos);
2921
2922 if (delta + b->r >= b->data + BUFSIZE)
2923 return 0; /* no space left */
2924
2925 /* first, protect the end of the buffer */
2926 memmove(end + delta, end, b->data + b->l - end);
2927
2928 /* now, copy str over pos */
2929 memcpy(pos, str,len);
2930
willy tarreau5cbea6f2005-12-17 12:48:26 +01002931 /* we only move data after the displaced zone */
2932 if (b->r > pos) b->r += delta;
2933 if (b->w > pos) b->w += delta;
2934 if (b->h > pos) b->h += delta;
2935 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002936 b->l += delta;
2937
2938 return delta;
2939}
2940
willy tarreau8337c6b2005-12-17 13:41:01 +01002941/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002942 * len is 0.
2943 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002944int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002945 int delta;
2946
2947 delta = len - (end - pos);
2948
2949 if (delta + b->r >= b->data + BUFSIZE)
2950 return 0; /* no space left */
2951
2952 /* first, protect the end of the buffer */
2953 memmove(end + delta, end, b->data + b->l - end);
2954
2955 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002956 if (len)
2957 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002958
willy tarreau5cbea6f2005-12-17 12:48:26 +01002959 /* we only move data after the displaced zone */
2960 if (b->r > pos) b->r += delta;
2961 if (b->w > pos) b->w += delta;
2962 if (b->h > pos) b->h += delta;
2963 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002964 b->l += delta;
2965
2966 return delta;
2967}
2968
2969
2970int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2971 char *old_dst = dst;
2972
2973 while (*str) {
2974 if (*str == '\\') {
2975 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002976 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002977 int len, num;
2978
2979 num = *str - '0';
2980 str++;
2981
willy tarreau8a86dbf2005-12-18 00:45:59 +01002982 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002983 len = matches[num].rm_eo - matches[num].rm_so;
2984 memcpy(dst, src + matches[num].rm_so, len);
2985 dst += len;
2986 }
2987
2988 }
2989 else if (*str == 'x') {
2990 unsigned char hex1, hex2;
2991 str++;
2992
willy tarreauc1f47532005-12-18 01:08:26 +01002993 hex1 = toupper(*str++) - '0';
2994 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002995
2996 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2997 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2998 *dst++ = (hex1<<4) + hex2;
2999 }
3000 else
3001 *dst++ = *str++;
3002 }
3003 else
3004 *dst++ = *str++;
3005 }
3006 *dst = 0;
3007 return dst - old_dst;
3008}
3009
willy tarreauc1f47532005-12-18 01:08:26 +01003010static int ishex(char s)
3011{
3012 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3013}
3014
3015/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3016char *check_replace_string(char *str)
3017{
3018 char *err = NULL;
3019 while (*str) {
3020 if (*str == '\\') {
3021 err = str; /* in case of a backslash, we return the pointer to it */
3022 str++;
3023 if (!*str)
3024 return err;
3025 else if (isdigit((int)*str))
3026 err = NULL;
3027 else if (*str == 'x') {
3028 str++;
3029 if (!ishex(*str))
3030 return err;
3031 str++;
3032 if (!ishex(*str))
3033 return err;
3034 err = NULL;
3035 }
3036 else {
3037 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3038 err = NULL;
3039 }
3040 }
3041 str++;
3042 }
3043 return err;
3044}
3045
3046
willy tarreau9fe663a2005-12-17 13:02:59 +01003047
willy tarreau0f7af912005-12-17 12:21:26 +01003048/*
3049 * manages the client FSM and its socket. BTW, it also tries to handle the
3050 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3051 * 0 else.
3052 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003053int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003054 int s = t->srv_state;
3055 int c = t->cli_state;
3056 struct buffer *req = t->req;
3057 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003058 int method_checked = 0;
3059 appsess *asession_temp = NULL;
3060 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003061
willy tarreau750a4722005-12-17 13:21:24 +01003062#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003063 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3064 cli_stnames[c], srv_stnames[s],
3065 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3066 t->crexpire.tv_sec, t->crexpire.tv_usec,
3067 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003068#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003069 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3070 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3071 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3072 //);
3073 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003074 /* now parse the partial (or complete) headers */
3075 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3076 char *ptr;
3077 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003078 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003079
willy tarreau5cbea6f2005-12-17 12:48:26 +01003080 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003081
willy tarreau0f7af912005-12-17 12:21:26 +01003082 /* look for the end of the current header */
3083 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3084 ptr++;
3085
willy tarreau5cbea6f2005-12-17 12:48:26 +01003086 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003087 int line, len;
3088 /* we can only get here after an end of headers */
3089 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003090
willy tarreaue39cd132005-12-17 13:00:18 +01003091 if (t->flags & SN_CLDENY) {
3092 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003093 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003094 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003095 if (!(t->flags & SN_ERR_MASK))
3096 t->flags |= SN_ERR_PRXCOND;
3097 if (!(t->flags & SN_FINST_MASK))
3098 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003099 return 1;
3100 }
3101
willy tarreau5cbea6f2005-12-17 12:48:26 +01003102 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003103 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3104 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 }
willy tarreau0f7af912005-12-17 12:21:26 +01003106
willy tarreau9fe663a2005-12-17 13:02:59 +01003107 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003108 if (t->cli_addr.ss_family == AF_INET) {
3109 unsigned char *pn;
3110 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3111 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3112 pn[0], pn[1], pn[2], pn[3]);
3113 buffer_replace2(req, req->h, req->h, trash, len);
3114 }
3115 else if (t->cli_addr.ss_family == AF_INET6) {
3116 char pn[INET6_ADDRSTRLEN];
3117 inet_ntop(AF_INET6,
3118 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3119 pn, sizeof(pn));
3120 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3121 buffer_replace2(req, req->h, req->h, trash, len);
3122 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003123 }
3124
willy tarreau25c4ea52005-12-18 00:49:49 +01003125 /* add a "connection: close" line if needed */
3126 if (t->proxy->options & PR_O_HTTP_CLOSE)
3127 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3128
willy tarreau982249e2005-12-18 00:57:06 +01003129 if (!memcmp(req->data, "POST ", 5)) {
3130 /* this is a POST request, which is not cacheable by default */
3131 t->flags |= SN_POST;
3132 }
willy tarreaucd878942005-12-17 13:27:43 +01003133
willy tarreau5cbea6f2005-12-17 12:48:26 +01003134 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003135 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003136
willy tarreau750a4722005-12-17 13:21:24 +01003137 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003138 /* FIXME: we'll set the client in a wait state while we try to
3139 * connect to the server. Is this really needed ? wouldn't it be
3140 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003141 //FD_CLR(t->cli_fd, StaticReadEvent);
3142 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003143
3144 /* FIXME: if we break here (as up to 1.1.23), having the client
3145 * shutdown its connection can lead to an abort further.
3146 * it's better to either return 1 or even jump directly to the
3147 * data state which will save one schedule.
3148 */
3149 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003150
3151 if (!t->proxy->clitimeout ||
3152 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3153 /* If the client has no timeout, or if the server is not ready yet,
3154 * and we know for sure that it can expire, then it's cleaner to
3155 * disable the timeout on the client side so that too low values
3156 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003157 *
3158 * FIXME-20050705: the server needs a way to re-enable this time-out
3159 * when it switches its state, otherwise a client can stay connected
3160 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003161 */
3162 tv_eternity(&t->crexpire);
3163
willy tarreau197e8ec2005-12-17 14:10:59 +01003164 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003165 }
willy tarreau0f7af912005-12-17 12:21:26 +01003166
willy tarreau5cbea6f2005-12-17 12:48:26 +01003167 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3168 if (ptr > req->r - 2) {
3169 /* this is a partial header, let's wait for more to come */
3170 req->lr = ptr;
3171 break;
3172 }
willy tarreau0f7af912005-12-17 12:21:26 +01003173
willy tarreau5cbea6f2005-12-17 12:48:26 +01003174 /* now we know that *ptr is either \r or \n,
3175 * and that there are at least 1 char after it.
3176 */
3177 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3178 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3179 else
3180 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003181
willy tarreau5cbea6f2005-12-17 12:48:26 +01003182 /*
3183 * now we know that we have a full header ; we can do whatever
3184 * we want with these pointers :
3185 * req->h = beginning of header
3186 * ptr = end of header (first \r or \n)
3187 * req->lr = beginning of next line (next rep->h)
3188 * req->r = end of data (not used at this stage)
3189 */
willy tarreau0f7af912005-12-17 12:21:26 +01003190
willy tarreau12350152005-12-18 01:03:27 +01003191 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3192 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3193 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3194
3195 /* skip ; */
3196 request_line++;
3197
3198 /* look if we have a jsessionid */
3199
3200 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3201
3202 /* skip jsessionid= */
3203 request_line += t->proxy->appsession_name_len + 1;
3204
3205 /* First try if we allready have an appsession */
3206 asession_temp = &local_asession;
3207
3208 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3209 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3210 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3211 return 0;
3212 }
3213
3214 /* Copy the sessionid */
3215 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3216 asession_temp->sessid[t->proxy->appsession_len] = 0;
3217 asession_temp->serverid = NULL;
3218
3219 /* only do insert, if lookup fails */
3220 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3221 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3222 Alert("Not enough memory process_cli():asession:calloc().\n");
3223 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3224 return 0;
3225 }
3226 asession_temp->sessid = local_asession.sessid;
3227 asession_temp->serverid = local_asession.serverid;
3228 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003229 } /* end if (chtbl_lookup()) */
3230 else {
willy tarreau12350152005-12-18 01:03:27 +01003231 /*free wasted memory;*/
3232 pool_free_to(apools.sessid, local_asession.sessid);
3233 }
3234
3235 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3236 asession_temp->request_count++;
3237
3238#if defined(DEBUG_HASH)
3239 print_table(&(t->proxy->htbl_proxy));
3240#endif
3241
3242 if (asession_temp->serverid == NULL) {
3243 Alert("Found Application Session without matching server.\n");
3244 } else {
3245 struct server *srv = t->proxy->srv;
3246 while (srv) {
3247 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3248 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3249 /* we found the server and it's usable */
3250 t->flags &= ~SN_CK_MASK;
3251 t->flags |= SN_CK_VALID | SN_DIRECT;
3252 t->srv = srv;
3253 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003254 } else {
willy tarreau12350152005-12-18 01:03:27 +01003255 t->flags &= ~SN_CK_MASK;
3256 t->flags |= SN_CK_DOWN;
3257 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003258 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003259 srv = srv->next;
3260 }/* end while(srv) */
3261 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003262 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003263 else {
3264 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3265 }
willy tarreau598da412005-12-18 01:07:29 +01003266 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003267 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003268 else{
3269 //printf("No Methode-Header with Session-String\n");
3270 }
3271
willy tarreau8337c6b2005-12-17 13:41:01 +01003272 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003273 /* we have a complete HTTP request that we must log */
3274 int urilen;
3275
willy tarreaua1598082005-12-17 13:08:06 +01003276 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003277 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003278 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003279 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003280 if (!(t->flags & SN_ERR_MASK))
3281 t->flags |= SN_ERR_PRXCOND;
3282 if (!(t->flags & SN_FINST_MASK))
3283 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003284 return 1;
3285 }
3286
3287 urilen = ptr - req->h;
3288 if (urilen >= REQURI_LEN)
3289 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003290 memcpy(t->logs.uri, req->h, urilen);
3291 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003292
willy tarreaua1598082005-12-17 13:08:06 +01003293 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003294 sess_log(t);
3295 }
willy tarreau4302f492005-12-18 01:00:37 +01003296 else if (t->logs.logwait & LW_REQHDR) {
3297 struct cap_hdr *h;
3298 int len;
3299 for (h = t->proxy->req_cap; h; h = h->next) {
3300 if ((h->namelen + 2 <= ptr - req->h) &&
3301 (req->h[h->namelen] == ':') &&
3302 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3303
3304 if (t->req_cap[h->index] == NULL)
3305 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3306
3307 len = ptr - (req->h + h->namelen + 2);
3308 if (len > h->len)
3309 len = h->len;
3310
3311 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3312 t->req_cap[h->index][len]=0;
3313 }
3314 }
3315
3316 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003317
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003319
willy tarreau982249e2005-12-18 00:57:06 +01003320 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003321 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003322 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 +01003323 max = ptr - req->h;
3324 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003325 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003326 trash[len++] = '\n';
3327 write(1, trash, len);
3328 }
willy tarreau0f7af912005-12-17 12:21:26 +01003329
willy tarreau25c4ea52005-12-18 00:49:49 +01003330
3331 /* remove "connection: " if needed */
3332 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3333 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3334 delete_header = 1;
3335 }
3336
willy tarreau5cbea6f2005-12-17 12:48:26 +01003337 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003338 if (!delete_header && t->proxy->req_exp != NULL
3339 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003340 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003341 char term;
3342
3343 term = *ptr;
3344 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003345 exp = t->proxy->req_exp;
3346 do {
3347 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3348 switch (exp->action) {
3349 case ACT_ALLOW:
3350 if (!(t->flags & SN_CLDENY))
3351 t->flags |= SN_CLALLOW;
3352 break;
3353 case ACT_REPLACE:
3354 if (!(t->flags & SN_CLDENY)) {
3355 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3356 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3357 }
3358 break;
3359 case ACT_REMOVE:
3360 if (!(t->flags & SN_CLDENY))
3361 delete_header = 1;
3362 break;
3363 case ACT_DENY:
3364 if (!(t->flags & SN_CLALLOW))
3365 t->flags |= SN_CLDENY;
3366 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003367 case ACT_PASS: /* we simply don't deny this one */
3368 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003369 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003370 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003371 }
willy tarreaue39cd132005-12-17 13:00:18 +01003372 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003373 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003374 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003375
willy tarreau240afa62005-12-17 13:14:35 +01003376 /* Now look for cookies. Conforming to RFC2109, we have to support
3377 * attributes whose name begin with a '$', and associate them with
3378 * the right cookie, if we want to delete this cookie.
3379 * So there are 3 cases for each cookie read :
3380 * 1) it's a special attribute, beginning with a '$' : ignore it.
3381 * 2) it's a server id cookie that we *MAY* want to delete : save
3382 * some pointers on it (last semi-colon, beginning of cookie...)
3383 * 3) it's an application cookie : we *MAY* have to delete a previous
3384 * "special" cookie.
3385 * At the end of loop, if a "special" cookie remains, we may have to
3386 * remove it. If no application cookie persists in the header, we
3387 * *MUST* delete it
3388 */
willy tarreau12350152005-12-18 01:03:27 +01003389 if (!delete_header &&
3390 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003391 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003392 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003393 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003394 char *del_colon, *del_cookie, *colon;
3395 int app_cookies;
3396
willy tarreau5cbea6f2005-12-17 12:48:26 +01003397 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003398 colon = p1;
3399 /* del_cookie == NULL => nothing to be deleted */
3400 del_colon = del_cookie = NULL;
3401 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003402
3403 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003404 /* skip spaces and colons, but keep an eye on these ones */
3405 while (p1 < ptr) {
3406 if (*p1 == ';' || *p1 == ',')
3407 colon = p1;
3408 else if (!isspace((int)*p1))
3409 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003410 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003411 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412
3413 if (p1 == ptr)
3414 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003415
3416 /* p1 is at the beginning of the cookie name */
3417 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003418 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 p2++;
3420
3421 if (p2 == ptr)
3422 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003423
3424 p3 = p2 + 1; /* skips the '=' sign */
3425 if (p3 == ptr)
3426 break;
3427
willy tarreau240afa62005-12-17 13:14:35 +01003428 p4 = p3;
3429 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003430 p4++;
3431
3432 /* here, we have the cookie name between p1 and p2,
3433 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003434 * we can process it :
3435 *
3436 * Cookie: NAME=VALUE;
3437 * | || || |
3438 * | || || +--> p4
3439 * | || |+-------> p3
3440 * | || +--------> p2
3441 * | |+------------> p1
3442 * | +-------------> colon
3443 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003444 */
3445
willy tarreau240afa62005-12-17 13:14:35 +01003446 if (*p1 == '$') {
3447 /* skip this one */
3448 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003449 else {
3450 /* first, let's see if we want to capture it */
3451 if (t->proxy->capture_name != NULL &&
3452 t->logs.cli_cookie == NULL &&
3453 (p4 - p1 >= t->proxy->capture_namelen) &&
3454 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3455 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003456
willy tarreau8337c6b2005-12-17 13:41:01 +01003457 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3458 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003459 } else {
3460 if (log_len > t->proxy->capture_len)
3461 log_len = t->proxy->capture_len;
3462 memcpy(t->logs.cli_cookie, p1, log_len);
3463 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003464 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003465 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003466
3467 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3468 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3469 /* Cool... it's the right one */
3470 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003471 char *delim;
3472
3473 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3474 * have the server ID betweek p3 and delim, and the original cookie between
3475 * delim+1 and p4. Otherwise, delim==p4 :
3476 *
3477 * Cookie: NAME=SRV~VALUE;
3478 * | || || | |
3479 * | || || | +--> p4
3480 * | || || +--------> delim
3481 * | || |+-----------> p3
3482 * | || +------------> p2
3483 * | |+----------------> p1
3484 * | +-----------------> colon
3485 * +------------------------> req->h
3486 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003487
willy tarreau0174f312005-12-18 01:02:42 +01003488 if (t->proxy->options & PR_O_COOK_PFX) {
3489 for (delim = p3; delim < p4; delim++)
3490 if (*delim == COOKIE_DELIM)
3491 break;
3492 }
3493 else
3494 delim = p4;
3495
3496
3497 /* Here, we'll look for the first running server which supports the cookie.
3498 * This allows to share a same cookie between several servers, for example
3499 * to dedicate backup servers to specific servers only.
3500 */
3501 while (srv) {
3502 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3503 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3504 /* we found the server and it's usable */
3505 t->flags &= ~SN_CK_MASK;
3506 t->flags |= SN_CK_VALID | SN_DIRECT;
3507 t->srv = srv;
3508 break;
willy tarreau12350152005-12-18 01:03:27 +01003509 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003510 /* we found a server, but it's down */
3511 t->flags &= ~SN_CK_MASK;
3512 t->flags |= SN_CK_DOWN;
3513 }
3514 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003515 srv = srv->next;
3516 }
3517
willy tarreau0174f312005-12-18 01:02:42 +01003518 if (!srv && !(t->flags & SN_CK_DOWN)) {
3519 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003520 t->flags &= ~SN_CK_MASK;
3521 t->flags |= SN_CK_INVALID;
3522 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003523
willy tarreau0174f312005-12-18 01:02:42 +01003524 /* depending on the cookie mode, we may have to either :
3525 * - delete the complete cookie if we're in insert+indirect mode, so that
3526 * the server never sees it ;
3527 * - remove the server id from the cookie value, and tag the cookie as an
3528 * application cookie so that it does not get accidentely removed later,
3529 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003530 */
willy tarreau0174f312005-12-18 01:02:42 +01003531 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3532 buffer_replace2(req, p3, delim + 1, NULL, 0);
3533 p4 -= (delim + 1 - p3);
3534 ptr -= (delim + 1 - p3);
3535 del_cookie = del_colon = NULL;
3536 app_cookies++; /* protect the header from deletion */
3537 }
3538 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003539 (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 +01003540 del_cookie = p1;
3541 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003542 }
willy tarreau12350152005-12-18 01:03:27 +01003543 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003544 /* now we know that we must keep this cookie since it's
3545 * not ours. But if we wanted to delete our cookie
3546 * earlier, we cannot remove the complete header, but we
3547 * can remove the previous block itself.
3548 */
3549 app_cookies++;
3550
3551 if (del_cookie != NULL) {
3552 buffer_replace2(req, del_cookie, p1, NULL, 0);
3553 p4 -= (p1 - del_cookie);
3554 ptr -= (p1 - del_cookie);
3555 del_cookie = del_colon = NULL;
3556 }
willy tarreau240afa62005-12-17 13:14:35 +01003557 }
willy tarreau12350152005-12-18 01:03:27 +01003558
3559 if ((t->proxy->appsession_name != NULL) &&
3560 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3561 /* first, let's see if the cookie is our appcookie*/
3562
3563 /* Cool... it's the right one */
3564
3565 asession_temp = &local_asession;
3566
3567 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3568 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3569 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3570 return 0;
3571 }
3572
3573 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3574 asession_temp->sessid[t->proxy->appsession_len] = 0;
3575 asession_temp->serverid = NULL;
3576
3577 /* only do insert, if lookup fails */
3578 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3579 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3580 Alert("Not enough memory process_cli():asession:calloc().\n");
3581 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3582 return 0;
3583 }
3584
3585 asession_temp->sessid = local_asession.sessid;
3586 asession_temp->serverid = local_asession.serverid;
3587 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3588 }
3589 else{
3590 /* free wasted memory */
3591 pool_free_to(apools.sessid, local_asession.sessid);
3592 }
3593
3594 if (asession_temp->serverid == NULL) {
3595 Alert("Found Application Session without matching server.\n");
3596 } else {
3597 struct server *srv = t->proxy->srv;
3598 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003599 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003600 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3601 /* we found the server and it's usable */
3602 t->flags &= ~SN_CK_MASK;
3603 t->flags |= SN_CK_VALID | SN_DIRECT;
3604 t->srv = srv;
3605 break;
3606 } else {
3607 t->flags &= ~SN_CK_MASK;
3608 t->flags |= SN_CK_DOWN;
3609 }
3610 }
3611 srv = srv->next;
3612 }/* end while(srv) */
3613 }/* end else if server == NULL */
3614
3615 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003616 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003617 }
willy tarreau240afa62005-12-17 13:14:35 +01003618
willy tarreau5cbea6f2005-12-17 12:48:26 +01003619 /* we'll have to look for another cookie ... */
3620 p1 = p4;
3621 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003622
3623 /* There's no more cookie on this line.
3624 * We may have marked the last one(s) for deletion.
3625 * We must do this now in two ways :
3626 * - if there is no app cookie, we simply delete the header ;
3627 * - if there are app cookies, we must delete the end of the
3628 * string properly, including the colon/semi-colon before
3629 * the cookie name.
3630 */
3631 if (del_cookie != NULL) {
3632 if (app_cookies) {
3633 buffer_replace2(req, del_colon, ptr, NULL, 0);
3634 /* WARNING! <ptr> becomes invalid for now. If some code
3635 * below needs to rely on it before the end of the global
3636 * header loop, we need to correct it with this code :
3637 * ptr = del_colon;
3638 */
3639 }
3640 else
3641 delete_header = 1;
3642 }
3643 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003644
3645 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003646 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003647 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003648 }
willy tarreau240afa62005-12-17 13:14:35 +01003649 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3650
willy tarreau5cbea6f2005-12-17 12:48:26 +01003651 req->h = req->lr;
3652 } /* while (req->lr < req->r) */
3653
3654 /* end of header processing (even if incomplete) */
3655
willy tarreauef900ab2005-12-17 12:52:52 +01003656 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3657 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3658 * full. We cannot loop here since event_cli_read will disable it only if
3659 * req->l == rlim-data
3660 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003661 FD_SET(t->cli_fd, StaticReadEvent);
3662 if (t->proxy->clitimeout)
3663 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3664 else
3665 tv_eternity(&t->crexpire);
3666 }
3667
willy tarreaue39cd132005-12-17 13:00:18 +01003668 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003669 * won't be able to free more later, so the session will never terminate.
3670 */
willy tarreaue39cd132005-12-17 13:00:18 +01003671 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003672 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003673 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003674 if (!(t->flags & SN_ERR_MASK))
3675 t->flags |= SN_ERR_PRXCOND;
3676 if (!(t->flags & SN_FINST_MASK))
3677 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003678 return 1;
3679 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003680 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003681 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003682 tv_eternity(&t->crexpire);
3683 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003684 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003685 if (!(t->flags & SN_ERR_MASK))
3686 t->flags |= SN_ERR_CLICL;
3687 if (!(t->flags & SN_FINST_MASK))
3688 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003689 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003690 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003691 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3692
3693 /* read timeout : give up with an error message.
3694 */
3695 t->logs.status = 408;
3696 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003697 if (!(t->flags & SN_ERR_MASK))
3698 t->flags |= SN_ERR_CLITO;
3699 if (!(t->flags & SN_FINST_MASK))
3700 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003701 return 1;
3702 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003703
3704 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003705 }
3706 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003707 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003708 /* FIXME: this error handling is partly buggy because we always report
3709 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3710 * or HEADER phase. BTW, it's not logical to expire the client while
3711 * we're waiting for the server to connect.
3712 */
willy tarreau0f7af912005-12-17 12:21:26 +01003713 /* read or write error */
3714 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003715 tv_eternity(&t->crexpire);
3716 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003717 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003718 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003719 if (!(t->flags & SN_ERR_MASK))
3720 t->flags |= SN_ERR_CLICL;
3721 if (!(t->flags & SN_FINST_MASK))
3722 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003723 return 1;
3724 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003725 /* last read, or end of server write */
3726 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003727 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003728 tv_eternity(&t->crexpire);
3729 shutdown(t->cli_fd, SHUT_RD);
3730 t->cli_state = CL_STSHUTR;
3731 return 1;
3732 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003733 /* last server read and buffer empty */
3734 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003735 FD_CLR(t->cli_fd, StaticWriteEvent);
3736 tv_eternity(&t->cwexpire);
3737 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003738 /* We must ensure that the read part is still alive when switching
3739 * to shutw */
3740 FD_SET(t->cli_fd, StaticReadEvent);
3741 if (t->proxy->clitimeout)
3742 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003743 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003744 //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 +01003745 return 1;
3746 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003747 /* read timeout */
3748 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3749 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003750 tv_eternity(&t->crexpire);
3751 shutdown(t->cli_fd, SHUT_RD);
3752 t->cli_state = CL_STSHUTR;
3753 if (!(t->flags & SN_ERR_MASK))
3754 t->flags |= SN_ERR_CLITO;
3755 if (!(t->flags & SN_FINST_MASK))
3756 t->flags |= SN_FINST_D;
3757 return 1;
3758 }
3759 /* write timeout */
3760 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3761 FD_CLR(t->cli_fd, StaticWriteEvent);
3762 tv_eternity(&t->cwexpire);
3763 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003764 /* We must ensure that the read part is still alive when switching
3765 * to shutw */
3766 FD_SET(t->cli_fd, StaticReadEvent);
3767 if (t->proxy->clitimeout)
3768 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3769
willy tarreau036e1ce2005-12-17 13:46:33 +01003770 t->cli_state = CL_STSHUTW;
3771 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003772 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003773 if (!(t->flags & SN_FINST_MASK))
3774 t->flags |= SN_FINST_D;
3775 return 1;
3776 }
willy tarreau0f7af912005-12-17 12:21:26 +01003777
willy tarreauc58fc692005-12-17 14:13:08 +01003778 if (req->l >= req->rlim - req->data) {
3779 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003780 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003781 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003782 FD_CLR(t->cli_fd, StaticReadEvent);
3783 tv_eternity(&t->crexpire);
3784 }
3785 }
3786 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003787 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003788 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3789 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003790 if (!t->proxy->clitimeout ||
3791 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3792 /* If the client has no timeout, or if the server not ready yet, and we
3793 * know for sure that it can expire, then it's cleaner to disable the
3794 * timeout on the client side so that too low values cannot make the
3795 * sessions abort too early.
3796 */
willy tarreau0f7af912005-12-17 12:21:26 +01003797 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003798 else
3799 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003800 }
3801 }
3802
3803 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003804 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003805 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3806 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3807 tv_eternity(&t->cwexpire);
3808 }
3809 }
3810 else { /* buffer not empty */
3811 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3812 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003813 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003814 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003815 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3816 t->crexpire = t->cwexpire;
3817 }
willy tarreau0f7af912005-12-17 12:21:26 +01003818 else
3819 tv_eternity(&t->cwexpire);
3820 }
3821 }
3822 return 0; /* other cases change nothing */
3823 }
3824 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003825 if (t->res_cw == RES_ERROR) {
3826 tv_eternity(&t->cwexpire);
3827 fd_delete(t->cli_fd);
3828 t->cli_state = CL_STCLOSE;
3829 if (!(t->flags & SN_ERR_MASK))
3830 t->flags |= SN_ERR_CLICL;
3831 if (!(t->flags & SN_FINST_MASK))
3832 t->flags |= SN_FINST_D;
3833 return 1;
3834 }
3835 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003836 tv_eternity(&t->cwexpire);
3837 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003838 t->cli_state = CL_STCLOSE;
3839 return 1;
3840 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003841 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3842 tv_eternity(&t->cwexpire);
3843 fd_delete(t->cli_fd);
3844 t->cli_state = CL_STCLOSE;
3845 if (!(t->flags & SN_ERR_MASK))
3846 t->flags |= SN_ERR_CLITO;
3847 if (!(t->flags & SN_FINST_MASK))
3848 t->flags |= SN_FINST_D;
3849 return 1;
3850 }
willy tarreau0f7af912005-12-17 12:21:26 +01003851 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003852 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003853 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3854 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3855 tv_eternity(&t->cwexpire);
3856 }
3857 }
3858 else { /* buffer not empty */
3859 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3860 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003861 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003862 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003863 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3864 t->crexpire = t->cwexpire;
3865 }
willy tarreau0f7af912005-12-17 12:21:26 +01003866 else
3867 tv_eternity(&t->cwexpire);
3868 }
3869 }
3870 return 0;
3871 }
3872 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003873 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003874 tv_eternity(&t->crexpire);
3875 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003876 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003877 if (!(t->flags & SN_ERR_MASK))
3878 t->flags |= SN_ERR_CLICL;
3879 if (!(t->flags & SN_FINST_MASK))
3880 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003881 return 1;
3882 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003883 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3884 tv_eternity(&t->crexpire);
3885 fd_delete(t->cli_fd);
3886 t->cli_state = CL_STCLOSE;
3887 return 1;
3888 }
3889 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3890 tv_eternity(&t->crexpire);
3891 fd_delete(t->cli_fd);
3892 t->cli_state = CL_STCLOSE;
3893 if (!(t->flags & SN_ERR_MASK))
3894 t->flags |= SN_ERR_CLITO;
3895 if (!(t->flags & SN_FINST_MASK))
3896 t->flags |= SN_FINST_D;
3897 return 1;
3898 }
willy tarreauef900ab2005-12-17 12:52:52 +01003899 else if (req->l >= req->rlim - req->data) {
3900 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003901
3902 /* FIXME-20050705: is it possible for a client to maintain a session
3903 * after the timeout by sending more data after it receives a close ?
3904 */
3905
willy tarreau0f7af912005-12-17 12:21:26 +01003906 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003907 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003908 FD_CLR(t->cli_fd, StaticReadEvent);
3909 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003910 //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 +01003911 }
3912 }
3913 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003914 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003915 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3916 FD_SET(t->cli_fd, StaticReadEvent);
3917 if (t->proxy->clitimeout)
3918 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3919 else
3920 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003921 //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 +01003922 }
3923 }
3924 return 0;
3925 }
3926 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003927 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003928 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003929 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 +01003930 write(1, trash, len);
3931 }
3932 return 0;
3933 }
3934 return 0;
3935}
3936
3937
3938/*
3939 * manages the server FSM and its socket. It returns 1 if a state has changed
3940 * (and a resync may be needed), 0 else.
3941 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003942int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003943 int s = t->srv_state;
3944 int c = t->cli_state;
3945 struct buffer *req = t->req;
3946 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003947 appsess *asession_temp = NULL;
3948 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003949 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003950
willy tarreau750a4722005-12-17 13:21:24 +01003951#ifdef DEBUG_FULL
3952 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3953#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003954 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3955 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3956 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3957 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003958 if (s == SV_STIDLE) {
3959 if (c == CL_STHEADERS)
3960 return 0; /* stay in idle, waiting for data to reach the client side */
3961 else if (c == CL_STCLOSE ||
3962 c == CL_STSHUTW ||
3963 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3964 tv_eternity(&t->cnexpire);
3965 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003966 if (!(t->flags & SN_ERR_MASK))
3967 t->flags |= SN_ERR_CLICL;
3968 if (!(t->flags & SN_FINST_MASK))
3969 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003970 return 1;
3971 }
3972 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003973 /* initiate a connection to the server */
3974 conn_err = connect_server(t);
3975 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003976 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3977 t->srv_state = SV_STCONN;
3978 }
3979 else { /* try again */
3980 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003981 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003982 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003983 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003984 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3985 t->flags &= ~SN_CK_MASK;
3986 t->flags |= SN_CK_DOWN;
3987 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003988 }
3989
willy tarreaub1285d52005-12-18 01:20:14 +01003990 conn_err = connect_server(t);
3991 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003992 t->srv_state = SV_STCONN;
3993 break;
3994 }
3995 }
3996 if (t->conn_retries < 0) {
3997 /* if conn_retries < 0 or other error, let's abort */
3998 tv_eternity(&t->cnexpire);
3999 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004000 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004001 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004002 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004003 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004004 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004005 if (!(t->flags & SN_FINST_MASK))
4006 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004007 }
4008 }
4009 return 1;
4010 }
4011 }
4012 else if (s == SV_STCONN) { /* connection in progress */
4013 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
4014 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
4015 return 0; /* nothing changed */
4016 }
4017 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4018 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4019 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004020 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004021 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004022 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004023 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004024 if (t->conn_retries >= 0) {
4025 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004026 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004027 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004028 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4029 t->flags &= ~SN_CK_MASK;
4030 t->flags |= SN_CK_DOWN;
4031 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004032 }
willy tarreaub1285d52005-12-18 01:20:14 +01004033 conn_err = connect_server(t);
4034 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004035 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004036 }
willy tarreaub1285d52005-12-18 01:20:14 +01004037 else if (t->res_sw == RES_SILENT)
4038 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4039 else
4040 conn_err = SN_ERR_SRVCL; // it was a connect error.
4041
willy tarreau0f7af912005-12-17 12:21:26 +01004042 /* if conn_retries < 0 or other error, let's abort */
4043 tv_eternity(&t->cnexpire);
4044 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004045 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004046 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004047 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004048 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004049 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004050 if (!(t->flags & SN_FINST_MASK))
4051 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004052 return 1;
4053 }
4054 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004055 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004056
willy tarreau0f7af912005-12-17 12:21:26 +01004057 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004058 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004059 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004060 tv_eternity(&t->swexpire);
4061 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004062 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004063 if (t->proxy->srvtimeout) {
4064 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4065 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4066 t->srexpire = t->swexpire;
4067 }
4068 else
4069 tv_eternity(&t->swexpire);
4070 }
willy tarreau0f7af912005-12-17 12:21:26 +01004071
4072 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4073 FD_SET(t->srv_fd, StaticReadEvent);
4074 if (t->proxy->srvtimeout)
4075 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4076 else
4077 tv_eternity(&t->srexpire);
4078
4079 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004080 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004081
4082 /* if the user wants to log as soon as possible, without counting
4083 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004084 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004085 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4086 sess_log(t);
4087 }
willy tarreau0f7af912005-12-17 12:21:26 +01004088 }
willy tarreauef900ab2005-12-17 12:52:52 +01004089 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004090 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004091 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4092 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004093 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004094 return 1;
4095 }
4096 }
4097 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004098 /* now parse the partial (or complete) headers */
4099 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4100 char *ptr;
4101 int delete_header;
4102
4103 ptr = rep->lr;
4104
4105 /* look for the end of the current header */
4106 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4107 ptr++;
4108
4109 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004110 int line, len;
4111
4112 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004113
4114 /* first, we'll block if security checks have caught nasty things */
4115 if (t->flags & SN_CACHEABLE) {
4116 if ((t->flags & SN_CACHE_COOK) &&
4117 (t->flags & SN_SCK_ANY) &&
4118 (t->proxy->options & PR_O_CHK_CACHE)) {
4119
4120 /* we're in presence of a cacheable response containing
4121 * a set-cookie header. We'll block it as requested by
4122 * the 'checkcache' option, and send an alert.
4123 */
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
4135 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4136 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4137
4138 return 1;
4139 }
4140 }
4141
willy tarreau982249e2005-12-18 00:57:06 +01004142 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4143 if (t->flags & SN_SVDENY) {
4144 tv_eternity(&t->srexpire);
4145 tv_eternity(&t->swexpire);
4146 fd_delete(t->srv_fd);
4147 t->srv_state = SV_STCLOSE;
4148 t->logs.status = 502;
4149 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4150 if (!(t->flags & SN_ERR_MASK))
4151 t->flags |= SN_ERR_PRXCOND;
4152 if (!(t->flags & SN_FINST_MASK))
4153 t->flags |= SN_FINST_H;
4154 return 1;
4155 }
4156
willy tarreau5cbea6f2005-12-17 12:48:26 +01004157 /* we'll have something else to do here : add new headers ... */
4158
willy tarreaucd878942005-12-17 13:27:43 +01004159 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4160 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004161 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004162 * insert a set-cookie here, except if we want to insert only on POST
4163 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004164 */
willy tarreau750a4722005-12-17 13:21:24 +01004165 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004166 t->proxy->cookie_name,
4167 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004168
willy tarreau036e1ce2005-12-17 13:46:33 +01004169 t->flags |= SN_SCK_INSERTED;
4170
willy tarreau750a4722005-12-17 13:21:24 +01004171 /* Here, we will tell an eventual cache on the client side that we don't
4172 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4173 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4174 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4175 */
willy tarreau240afa62005-12-17 13:14:35 +01004176 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004177 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4178 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01004179
willy tarreau750a4722005-12-17 13:21:24 +01004180 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004181 }
4182
4183 /* headers to be added */
4184 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004185 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4186 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004187 }
4188
willy tarreau25c4ea52005-12-18 00:49:49 +01004189 /* add a "connection: close" line if needed */
4190 if (t->proxy->options & PR_O_HTTP_CLOSE)
4191 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4192
willy tarreau5cbea6f2005-12-17 12:48:26 +01004193 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004194 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004195 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004196
4197 /* if the user wants to log as soon as possible, without counting
4198 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004199 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004200 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4201 t->logs.bytes = rep->h - rep->data;
4202 sess_log(t);
4203 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004204 break;
4205 }
4206
4207 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4208 if (ptr > rep->r - 2) {
4209 /* this is a partial header, let's wait for more to come */
4210 rep->lr = ptr;
4211 break;
4212 }
4213
4214 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4215 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4216
4217 /* now we know that *ptr is either \r or \n,
4218 * and that there are at least 1 char after it.
4219 */
4220 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4221 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4222 else
4223 rep->lr = ptr + 2; /* \r\n or \n\r */
4224
4225 /*
4226 * now we know that we have a full header ; we can do whatever
4227 * we want with these pointers :
4228 * rep->h = beginning of header
4229 * ptr = end of header (first \r or \n)
4230 * rep->lr = beginning of next line (next rep->h)
4231 * rep->r = end of data (not used at this stage)
4232 */
4233
willy tarreaua1598082005-12-17 13:08:06 +01004234
willy tarreau982249e2005-12-18 00:57:06 +01004235 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004236 t->logs.logwait &= ~LW_RESP;
4237 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004238 switch (t->logs.status) {
4239 case 200:
4240 case 203:
4241 case 206:
4242 case 300:
4243 case 301:
4244 case 410:
4245 /* RFC2616 @13.4:
4246 * "A response received with a status code of
4247 * 200, 203, 206, 300, 301 or 410 MAY be stored
4248 * by a cache (...) unless a cache-control
4249 * directive prohibits caching."
4250 *
4251 * RFC2616 @9.5: POST method :
4252 * "Responses to this method are not cacheable,
4253 * unless the response includes appropriate
4254 * Cache-Control or Expires header fields."
4255 */
4256 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4257 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4258 break;
4259 default:
4260 break;
4261 }
willy tarreau4302f492005-12-18 01:00:37 +01004262 }
4263 else if (t->logs.logwait & LW_RSPHDR) {
4264 struct cap_hdr *h;
4265 int len;
4266 for (h = t->proxy->rsp_cap; h; h = h->next) {
4267 if ((h->namelen + 2 <= ptr - rep->h) &&
4268 (rep->h[h->namelen] == ':') &&
4269 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4270
4271 if (t->rsp_cap[h->index] == NULL)
4272 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4273
4274 len = ptr - (rep->h + h->namelen + 2);
4275 if (len > h->len)
4276 len = h->len;
4277
4278 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4279 t->rsp_cap[h->index][len]=0;
4280 }
4281 }
4282
willy tarreaua1598082005-12-17 13:08:06 +01004283 }
4284
willy tarreau5cbea6f2005-12-17 12:48:26 +01004285 delete_header = 0;
4286
willy tarreau982249e2005-12-18 00:57:06 +01004287 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004288 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004289 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 +01004290 max = ptr - rep->h;
4291 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004292 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004293 trash[len++] = '\n';
4294 write(1, trash, len);
4295 }
4296
willy tarreau25c4ea52005-12-18 00:49:49 +01004297 /* remove "connection: " if needed */
4298 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4299 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4300 delete_header = 1;
4301 }
4302
willy tarreau5cbea6f2005-12-17 12:48:26 +01004303 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004304 if (!delete_header && t->proxy->rsp_exp != NULL
4305 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004306 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004307 char term;
4308
4309 term = *ptr;
4310 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004311 exp = t->proxy->rsp_exp;
4312 do {
4313 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4314 switch (exp->action) {
4315 case ACT_ALLOW:
4316 if (!(t->flags & SN_SVDENY))
4317 t->flags |= SN_SVALLOW;
4318 break;
4319 case ACT_REPLACE:
4320 if (!(t->flags & SN_SVDENY)) {
4321 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4322 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4323 }
4324 break;
4325 case ACT_REMOVE:
4326 if (!(t->flags & SN_SVDENY))
4327 delete_header = 1;
4328 break;
4329 case ACT_DENY:
4330 if (!(t->flags & SN_SVALLOW))
4331 t->flags |= SN_SVDENY;
4332 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004333 case ACT_PASS: /* we simply don't deny this one */
4334 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004335 }
4336 break;
4337 }
willy tarreaue39cd132005-12-17 13:00:18 +01004338 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004339 *ptr = term; /* restore the string terminator */
4340 }
4341
willy tarreau97f58572005-12-18 00:53:44 +01004342 /* check for cache-control: or pragma: headers */
4343 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4344 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4345 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4346 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4347 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004348 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004349 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4350 else {
4351 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004352 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004353 t->flags &= ~SN_CACHE_COOK;
4354 }
4355 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004356 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004357 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004358 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004359 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4360 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004361 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004362 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004363 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4364 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4365 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4366 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4367 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4368 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004369 }
4370 }
4371 }
4372
willy tarreau5cbea6f2005-12-17 12:48:26 +01004373 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004374 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004375 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004376 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004377 char *p1, *p2, *p3, *p4;
4378
willy tarreau97f58572005-12-18 00:53:44 +01004379 t->flags |= SN_SCK_ANY;
4380
willy tarreau5cbea6f2005-12-17 12:48:26 +01004381 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4382
4383 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004384 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004385 p1++;
4386
4387 if (p1 == ptr || *p1 == ';') /* end of cookie */
4388 break;
4389
4390 /* p1 is at the beginning of the cookie name */
4391 p2 = p1;
4392
4393 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4394 p2++;
4395
4396 if (p2 == ptr || *p2 == ';') /* next cookie */
4397 break;
4398
4399 p3 = p2 + 1; /* skips the '=' sign */
4400 if (p3 == ptr)
4401 break;
4402
4403 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004404 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004405 p4++;
4406
4407 /* here, we have the cookie name between p1 and p2,
4408 * and its value between p3 and p4.
4409 * we can process it.
4410 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004411
4412 /* first, let's see if we want to capture it */
4413 if (t->proxy->capture_name != NULL &&
4414 t->logs.srv_cookie == NULL &&
4415 (p4 - p1 >= t->proxy->capture_namelen) &&
4416 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4417 int log_len = p4 - p1;
4418
4419 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4420 Alert("HTTP logging : out of memory.\n");
4421 }
4422
4423 if (log_len > t->proxy->capture_len)
4424 log_len = t->proxy->capture_len;
4425 memcpy(t->logs.srv_cookie, p1, log_len);
4426 t->logs.srv_cookie[log_len] = 0;
4427 }
4428
4429 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4430 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004431 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004432 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004433
4434 /* If the cookie is in insert mode on a known server, we'll delete
4435 * this occurrence because we'll insert another one later.
4436 * We'll delete it too if the "indirect" option is set and we're in
4437 * a direct access. */
4438 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004439 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004440 /* this header must be deleted */
4441 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004442 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004443 }
4444 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4445 /* replace bytes p3->p4 with the cookie name associated
4446 * with this server since we know it.
4447 */
4448 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004449 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004450 }
willy tarreau0174f312005-12-18 01:02:42 +01004451 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4452 /* insert the cookie name associated with this server
4453 * before existing cookie, and insert a delimitor between them..
4454 */
4455 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4456 p3[t->srv->cklen] = COOKIE_DELIM;
4457 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4458 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004459 break;
4460 }
willy tarreau12350152005-12-18 01:03:27 +01004461
4462 /* first, let's see if the cookie is our appcookie*/
4463 if ((t->proxy->appsession_name != NULL) &&
4464 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4465
4466 /* Cool... it's the right one */
4467
willy tarreaub952e1d2005-12-18 01:31:20 +01004468 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004469 asession_temp = &local_asession;
4470
willy tarreaub952e1d2005-12-18 01:31:20 +01004471 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004472 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4473 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4474 }
4475 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4476 asession_temp->sessid[t->proxy->appsession_len] = 0;
4477 asession_temp->serverid = NULL;
4478
4479 /* only do insert, if lookup fails */
4480 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4481 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4482 Alert("Not enought Memory process_srv():asession:calloc().\n");
4483 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4484 return 0;
4485 }
4486 asession_temp->sessid = local_asession.sessid;
4487 asession_temp->serverid = local_asession.serverid;
4488 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004489 }/* end if (chtbl_lookup()) */
4490 else {
willy tarreau12350152005-12-18 01:03:27 +01004491 /* free wasted memory */
4492 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004493 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004494
willy tarreaub952e1d2005-12-18 01:31:20 +01004495 if (asession_temp->serverid == NULL) {
4496 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004497 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4498 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4499 }
4500 asession_temp->serverid[0] = '\0';
4501 }
4502
willy tarreaub952e1d2005-12-18 01:31:20 +01004503 if (asession_temp->serverid[0] == '\0')
4504 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004505
4506 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4507
4508#if defined(DEBUG_HASH)
4509 print_table(&(t->proxy->htbl_proxy));
4510#endif
4511 break;
4512 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004513 else {
4514 // fprintf(stderr,"Ignoring unknown cookie : ");
4515 // write(2, p1, p2-p1);
4516 // fprintf(stderr," = ");
4517 // write(2, p3, p4-p3);
4518 // fprintf(stderr,"\n");
4519 }
4520 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4521 } /* we're now at the end of the cookie value */
4522 } /* end of cookie processing */
4523
willy tarreau97f58572005-12-18 00:53:44 +01004524 /* check for any set-cookie in case we check for cacheability */
4525 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4526 (t->proxy->options & PR_O_CHK_CACHE) &&
4527 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4528 t->flags |= SN_SCK_ANY;
4529 }
4530
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004532 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004533 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004534
willy tarreau5cbea6f2005-12-17 12:48:26 +01004535 rep->h = rep->lr;
4536 } /* while (rep->lr < rep->r) */
4537
4538 /* end of header processing (even if incomplete) */
4539
willy tarreauef900ab2005-12-17 12:52:52 +01004540 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4541 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4542 * full. We cannot loop here since event_srv_read will disable it only if
4543 * rep->l == rlim-data
4544 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004545 FD_SET(t->srv_fd, StaticReadEvent);
4546 if (t->proxy->srvtimeout)
4547 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4548 else
4549 tv_eternity(&t->srexpire);
4550 }
willy tarreau0f7af912005-12-17 12:21:26 +01004551
willy tarreau8337c6b2005-12-17 13:41:01 +01004552 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004553 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004554 tv_eternity(&t->srexpire);
4555 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004557 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004558 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004559 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004560 if (!(t->flags & SN_ERR_MASK))
4561 t->flags |= SN_ERR_SRVCL;
4562 if (!(t->flags & SN_FINST_MASK))
4563 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004564 return 1;
4565 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004566 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004567 * since we are in header mode, if there's no space left for headers, we
4568 * won't be able to free more later, so the session will never terminate.
4569 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004570 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 +01004571 FD_CLR(t->srv_fd, StaticReadEvent);
4572 tv_eternity(&t->srexpire);
4573 shutdown(t->srv_fd, SHUT_RD);
4574 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004575 //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 +01004576 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004577 }
4578 /* read timeout : return a 504 to the client.
4579 */
4580 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4581 tv_eternity(&t->srexpire);
4582 tv_eternity(&t->swexpire);
4583 fd_delete(t->srv_fd);
4584 t->srv_state = SV_STCLOSE;
4585 t->logs.status = 504;
4586 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004587 if (!(t->flags & SN_ERR_MASK))
4588 t->flags |= SN_ERR_SRVTO;
4589 if (!(t->flags & SN_FINST_MASK))
4590 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004591 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004592
4593 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004594 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004595 /* FIXME!!! here, we don't want to switch to SHUTW if the
4596 * client shuts read too early, because we may still have
4597 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004598 * The side-effect is that if the client completely closes its
4599 * connection during SV_STHEADER, the connection to the server
4600 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004601 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004602 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004603 FD_CLR(t->srv_fd, StaticWriteEvent);
4604 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004605
4606 /* We must ensure that the read part is still alive when switching
4607 * to shutw */
4608 FD_SET(t->srv_fd, StaticReadEvent);
4609 if (t->proxy->srvtimeout)
4610 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4611
willy tarreau0f7af912005-12-17 12:21:26 +01004612 shutdown(t->srv_fd, SHUT_WR);
4613 t->srv_state = SV_STSHUTW;
4614 return 1;
4615 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004616 /* write timeout */
4617 /* FIXME!!! here, we don't want to switch to SHUTW if the
4618 * client shuts read too early, because we may still have
4619 * some work to do on the headers.
4620 */
4621 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4622 FD_CLR(t->srv_fd, StaticWriteEvent);
4623 tv_eternity(&t->swexpire);
4624 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004625 /* We must ensure that the read part is still alive when switching
4626 * to shutw */
4627 FD_SET(t->srv_fd, StaticReadEvent);
4628 if (t->proxy->srvtimeout)
4629 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4630
4631 /* We must ensure that the read part is still alive when switching
4632 * to shutw */
4633 FD_SET(t->srv_fd, StaticReadEvent);
4634 if (t->proxy->srvtimeout)
4635 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4636
willy tarreau036e1ce2005-12-17 13:46:33 +01004637 t->srv_state = SV_STSHUTW;
4638 if (!(t->flags & SN_ERR_MASK))
4639 t->flags |= SN_ERR_SRVTO;
4640 if (!(t->flags & SN_FINST_MASK))
4641 t->flags |= SN_FINST_H;
4642 return 1;
4643 }
willy tarreau0f7af912005-12-17 12:21:26 +01004644
4645 if (req->l == 0) {
4646 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4647 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4648 tv_eternity(&t->swexpire);
4649 }
4650 }
4651 else { /* client buffer not empty */
4652 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4653 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004654 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004655 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004656 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4657 t->srexpire = t->swexpire;
4658 }
willy tarreau0f7af912005-12-17 12:21:26 +01004659 else
4660 tv_eternity(&t->swexpire);
4661 }
4662 }
4663
willy tarreau5cbea6f2005-12-17 12:48:26 +01004664 /* be nice with the client side which would like to send a complete header
4665 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4666 * would read all remaining data at once ! The client should not write past rep->lr
4667 * when the server is in header state.
4668 */
4669 //return header_processed;
4670 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004671 }
4672 else if (s == SV_STDATA) {
4673 /* read or write error */
4674 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004675 tv_eternity(&t->srexpire);
4676 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004677 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004678 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004679 if (!(t->flags & SN_ERR_MASK))
4680 t->flags |= SN_ERR_SRVCL;
4681 if (!(t->flags & SN_FINST_MASK))
4682 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004683 return 1;
4684 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004685 /* last read, or end of client write */
4686 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004687 FD_CLR(t->srv_fd, StaticReadEvent);
4688 tv_eternity(&t->srexpire);
4689 shutdown(t->srv_fd, SHUT_RD);
4690 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004691 //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 +01004692 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004693 }
4694 /* end of client read and no more data to send */
4695 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4696 FD_CLR(t->srv_fd, StaticWriteEvent);
4697 tv_eternity(&t->swexpire);
4698 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004699 /* We must ensure that the read part is still alive when switching
4700 * to shutw */
4701 FD_SET(t->srv_fd, StaticReadEvent);
4702 if (t->proxy->srvtimeout)
4703 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4704
willy tarreaua41a8b42005-12-17 14:02:24 +01004705 t->srv_state = SV_STSHUTW;
4706 return 1;
4707 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004708 /* read timeout */
4709 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4710 FD_CLR(t->srv_fd, StaticReadEvent);
4711 tv_eternity(&t->srexpire);
4712 shutdown(t->srv_fd, SHUT_RD);
4713 t->srv_state = SV_STSHUTR;
4714 if (!(t->flags & SN_ERR_MASK))
4715 t->flags |= SN_ERR_SRVTO;
4716 if (!(t->flags & SN_FINST_MASK))
4717 t->flags |= SN_FINST_D;
4718 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004719 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004720 /* write timeout */
4721 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004722 FD_CLR(t->srv_fd, StaticWriteEvent);
4723 tv_eternity(&t->swexpire);
4724 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004725 /* We must ensure that the read part is still alive when switching
4726 * to shutw */
4727 FD_SET(t->srv_fd, StaticReadEvent);
4728 if (t->proxy->srvtimeout)
4729 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004730 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004731 if (!(t->flags & SN_ERR_MASK))
4732 t->flags |= SN_ERR_SRVTO;
4733 if (!(t->flags & SN_FINST_MASK))
4734 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004735 return 1;
4736 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004737
4738 /* recompute request time-outs */
4739 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004740 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4741 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4742 tv_eternity(&t->swexpire);
4743 }
4744 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004745 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004746 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4747 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004748 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004749 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004750 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4751 t->srexpire = t->swexpire;
4752 }
willy tarreau0f7af912005-12-17 12:21:26 +01004753 else
4754 tv_eternity(&t->swexpire);
4755 }
4756 }
4757
willy tarreaub1ff9db2005-12-17 13:51:03 +01004758 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004759 if (rep->l == BUFSIZE) { /* no room to read more data */
4760 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4761 FD_CLR(t->srv_fd, StaticReadEvent);
4762 tv_eternity(&t->srexpire);
4763 }
4764 }
4765 else {
4766 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4767 FD_SET(t->srv_fd, StaticReadEvent);
4768 if (t->proxy->srvtimeout)
4769 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4770 else
4771 tv_eternity(&t->srexpire);
4772 }
4773 }
4774
4775 return 0; /* other cases change nothing */
4776 }
4777 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004778 if (t->res_sw == RES_ERROR) {
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_SRVCL;
4786 if (!(t->flags & SN_FINST_MASK))
4787 t->flags |= SN_FINST_D;
4788 return 1;
4789 }
4790 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004791 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004792 tv_eternity(&t->swexpire);
4793 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004794 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004795 t->srv_state = SV_STCLOSE;
4796 return 1;
4797 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004798 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4799 //FD_CLR(t->srv_fd, StaticWriteEvent);
4800 tv_eternity(&t->swexpire);
4801 fd_delete(t->srv_fd);
4802 //close(t->srv_fd);
4803 t->srv_state = SV_STCLOSE;
4804 if (!(t->flags & SN_ERR_MASK))
4805 t->flags |= SN_ERR_SRVTO;
4806 if (!(t->flags & SN_FINST_MASK))
4807 t->flags |= SN_FINST_D;
4808 return 1;
4809 }
willy tarreau0f7af912005-12-17 12:21:26 +01004810 else if (req->l == 0) {
4811 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4812 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4813 tv_eternity(&t->swexpire);
4814 }
4815 }
4816 else { /* buffer not empty */
4817 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4818 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004819 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004820 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004821 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4822 t->srexpire = t->swexpire;
4823 }
willy tarreau0f7af912005-12-17 12:21:26 +01004824 else
4825 tv_eternity(&t->swexpire);
4826 }
4827 }
4828 return 0;
4829 }
4830 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004831 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004832 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004833 tv_eternity(&t->srexpire);
4834 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004835 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004836 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004837 if (!(t->flags & SN_ERR_MASK))
4838 t->flags |= SN_ERR_SRVCL;
4839 if (!(t->flags & SN_FINST_MASK))
4840 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004841 return 1;
4842 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004843 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4844 //FD_CLR(t->srv_fd, StaticReadEvent);
4845 tv_eternity(&t->srexpire);
4846 fd_delete(t->srv_fd);
4847 //close(t->srv_fd);
4848 t->srv_state = SV_STCLOSE;
4849 return 1;
4850 }
4851 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4852 //FD_CLR(t->srv_fd, StaticReadEvent);
4853 tv_eternity(&t->srexpire);
4854 fd_delete(t->srv_fd);
4855 //close(t->srv_fd);
4856 t->srv_state = SV_STCLOSE;
4857 if (!(t->flags & SN_ERR_MASK))
4858 t->flags |= SN_ERR_SRVTO;
4859 if (!(t->flags & SN_FINST_MASK))
4860 t->flags |= SN_FINST_D;
4861 return 1;
4862 }
willy tarreau0f7af912005-12-17 12:21:26 +01004863 else if (rep->l == BUFSIZE) { /* no room to read more data */
4864 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4865 FD_CLR(t->srv_fd, StaticReadEvent);
4866 tv_eternity(&t->srexpire);
4867 }
4868 }
4869 else {
4870 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4871 FD_SET(t->srv_fd, StaticReadEvent);
4872 if (t->proxy->srvtimeout)
4873 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4874 else
4875 tv_eternity(&t->srexpire);
4876 }
4877 }
4878 return 0;
4879 }
4880 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004881 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004882 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004883 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 +01004884 write(1, trash, len);
4885 }
4886 return 0;
4887 }
4888 return 0;
4889}
4890
4891
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892/* Processes the client and server jobs of a session task, then
4893 * puts it back to the wait queue in a clean state, or
4894 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004895 * the time the task accepts to wait, or TIME_ETERNITY for
4896 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004897 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004898int process_session(struct task *t) {
4899 struct session *s = t->context;
4900 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004901
willy tarreau5cbea6f2005-12-17 12:48:26 +01004902 do {
4903 fsm_resync = 0;
4904 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4905 fsm_resync |= process_cli(s);
4906 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4907 fsm_resync |= process_srv(s);
4908 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4909 } while (fsm_resync);
4910
4911 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004912 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004913 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004914
willy tarreau5cbea6f2005-12-17 12:48:26 +01004915 tv_min(&min1, &s->crexpire, &s->cwexpire);
4916 tv_min(&min2, &s->srexpire, &s->swexpire);
4917 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004918 tv_min(&t->expire, &min1, &min2);
4919
4920 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004921 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004922
willy tarreaub952e1d2005-12-18 01:31:20 +01004923 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004924 }
4925
willy tarreau5cbea6f2005-12-17 12:48:26 +01004926 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004927 actconn--;
4928
willy tarreau982249e2005-12-18 00:57:06 +01004929 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004930 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004931 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 +01004932 write(1, trash, len);
4933 }
4934
willy tarreau750a4722005-12-17 13:21:24 +01004935 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004936 if (s->rep != NULL)
4937 s->logs.bytes = s->rep->total;
4938
willy tarreau9fe663a2005-12-17 13:02:59 +01004939 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004940 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004941 sess_log(s);
4942
willy tarreau0f7af912005-12-17 12:21:26 +01004943 /* the task MUST not be in the run queue anymore */
4944 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004945 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004946 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01004947 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004948}
4949
4950
4951
4952/*
4953 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004954 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004955 */
4956int process_chk(struct task *t) {
4957 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004958 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004959 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004960
willy tarreauef900ab2005-12-17 12:52:52 +01004961 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004962
4963 if (fd < 0) { /* no check currently running */
4964 //fprintf(stderr, "process_chk: 2\n");
4965 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4966 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01004967 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004968 }
4969
4970 /* we'll initiate a new check */
4971 s->result = 0; /* no result yet */
4972 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004973 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004974 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4975 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4976 //fprintf(stderr, "process_chk: 3\n");
4977
willy tarreaua41a8b42005-12-17 14:02:24 +01004978 /* we'll connect to the check port on the server */
4979 sa = s->addr;
4980 sa.sin_port = htons(s->check_port);
4981
willy tarreau0174f312005-12-18 01:02:42 +01004982 /* allow specific binding :
4983 * - server-specific at first
4984 * - proxy-specific next
4985 */
4986 if (s->state & SRV_BIND_SRC) {
4987 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4988 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4989 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4990 s->proxy->id, s->id);
4991 s->result = -1;
4992 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004993 }
willy tarreau0174f312005-12-18 01:02:42 +01004994 else if (s->proxy->options & PR_O_BIND_SRC) {
4995 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4996 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4997 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4998 s->proxy->id);
4999 s->result = -1;
5000 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005001 }
willy tarreau0174f312005-12-18 01:02:42 +01005002
5003 if (!s->result) {
5004 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5005 /* OK, connection in progress or established */
5006
5007 //fprintf(stderr, "process_chk: 4\n");
5008
5009 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5010 fdtab[fd].owner = t;
5011 fdtab[fd].read = &event_srv_chk_r;
5012 fdtab[fd].write = &event_srv_chk_w;
5013 fdtab[fd].state = FD_STCONN; /* connection in progress */
5014 FD_SET(fd, StaticWriteEvent); /* for connect status */
5015 fd_insert(fd);
5016 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5017 tv_delayfrom(&t->expire, &now, s->inter);
5018 task_queue(t); /* restore t to its place in the task list */
5019 return tv_remain(&now, &t->expire);
5020 }
5021 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5022 s->result = -1; /* a real error */
5023 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005024 }
5025 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005026 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005027 }
5028
5029 if (!s->result) { /* nothing done */
5030 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005031 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005032 task_queue(t); /* restore t to its place in the task list */
5033 return tv_remain(&now, &t->expire);
5034 }
5035
5036 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005037 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005038 s->health--; /* still good */
5039 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005040 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005041 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005042 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005043 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005044
willy tarreaudd07e972005-12-18 00:48:48 +01005045 if (find_server(s->proxy) == NULL) {
5046 Alert("Proxy %s has no server available !\n", s->proxy->id);
5047 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5048 }
5049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005050 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005051 }
5052
5053 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005054 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5055 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 }
5057 else {
5058 //fprintf(stderr, "process_chk: 8\n");
5059 /* there was a test running */
5060 if (s->result > 0) { /* good server detected */
5061 //fprintf(stderr, "process_chk: 9\n");
5062 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005063 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005064 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005065 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005066 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005067 }
willy tarreauef900ab2005-12-17 12:52:52 +01005068
willy tarreaue47c8d72005-12-17 12:55:52 +01005069 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005070 s->state |= SRV_RUNNING;
5071 }
willy tarreauef900ab2005-12-17 12:52:52 +01005072 s->curfd = -1; /* no check running anymore */
5073 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005074 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005075 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 }
5077 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5078 //fprintf(stderr, "process_chk: 10\n");
5079 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005080 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005081 s->health--; /* still good */
5082 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005083 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005084
willy tarreaudd07e972005-12-18 00:48:48 +01005085 if (s->health == s->rise) {
5086 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005087 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005088
5089 if (find_server(s->proxy) == NULL) {
5090 Alert("Proxy %s has no server available !\n", s->proxy->id);
5091 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5092 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005093 }
willy tarreauef900ab2005-12-17 12:52:52 +01005094
willy tarreau5cbea6f2005-12-17 12:48:26 +01005095 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005096 }
5097 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005098 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005099 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005100 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005101 }
5102 /* if result is 0 and there's no timeout, we have to wait again */
5103 }
5104 //fprintf(stderr, "process_chk: 11\n");
5105 s->result = 0;
5106 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005107 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005108}
5109
5110
willy tarreau5cbea6f2005-12-17 12:48:26 +01005111
willy tarreau0f7af912005-12-17 12:21:26 +01005112#if STATTIME > 0
5113int stats(void);
5114#endif
5115
5116/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005117 * This does 4 things :
5118 * - wake up all expired tasks
5119 * - call all runnable tasks
5120 * - call maintain_proxies() to enable/disable the listeners
5121 * - return the delay till next event in ms, -1 = wait indefinitely
5122 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5123 *
willy tarreau0f7af912005-12-17 12:21:26 +01005124 */
5125
willy tarreau1c2ad212005-12-18 01:11:29 +01005126int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005127 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005128 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005129 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005130
willy tarreaub952e1d2005-12-18 01:31:20 +01005131 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005132
willy tarreau1c2ad212005-12-18 01:11:29 +01005133 /* look for expired tasks and add them to the run queue.
5134 */
5135 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5136 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5137 tnext = t->next;
5138 if (t->state & TASK_RUNNING)
5139 continue;
5140
willy tarreaub952e1d2005-12-18 01:31:20 +01005141 if (tv_iseternity(&t->expire))
5142 continue;
5143
willy tarreau1c2ad212005-12-18 01:11:29 +01005144 /* wakeup expired entries. It doesn't matter if they are
5145 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005146 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005147 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005148 task_wakeup(&rq, t);
5149 }
5150 else {
5151 /* first non-runnable task. Use its expiration date as an upper bound */
5152 int temp_time = tv_remain(&now, &t->expire);
5153 if (temp_time)
5154 next_time = temp_time;
5155 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005156 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005157 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005158
willy tarreau1c2ad212005-12-18 01:11:29 +01005159 /* process each task in the run queue now. Each task may be deleted
5160 * since we only use tnext.
5161 */
5162 tnext = rq;
5163 while ((t = tnext) != NULL) {
5164 int temp_time;
5165
5166 tnext = t->rqnext;
5167 task_sleep(&rq, t);
5168 temp_time = t->process(t);
5169 next_time = MINTIME(temp_time, next_time);
5170 }
5171
5172 /* maintain all proxies in a consistent state. This should quickly become a task */
5173 time2 = maintain_proxies();
5174 return MINTIME(time2, next_time);
5175}
5176
5177
5178#if defined(ENABLE_EPOLL)
5179
5180/*
5181 * Main epoll() loop.
5182 */
5183
5184/* does 3 actions :
5185 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5186 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5187 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5188 *
5189 * returns 0 if initialization failed, !0 otherwise.
5190 */
5191
5192int epoll_loop(int action) {
5193 int next_time;
5194 int status;
5195 int fd;
5196
5197 int fds, count;
5198 int pr, pw, sr, sw;
5199 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5200 struct epoll_event ev;
5201
5202 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005203 static struct epoll_event *epoll_events = NULL;
5204 static int epoll_fd;
5205
5206 if (action == POLL_LOOP_ACTION_INIT) {
5207 epoll_fd = epoll_create(global.maxsock + 1);
5208 if (epoll_fd < 0)
5209 return 0;
5210 else {
5211 epoll_events = (struct epoll_event*)
5212 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5213 PrevReadEvent = (fd_set *)
5214 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5215 PrevWriteEvent = (fd_set *)
5216 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005217 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005218 return 1;
5219 }
5220 else if (action == POLL_LOOP_ACTION_CLEAN) {
5221 if (PrevWriteEvent) free(PrevWriteEvent);
5222 if (PrevReadEvent) free(PrevReadEvent);
5223 if (epoll_events) free(epoll_events);
5224 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005225 epoll_fd = 0;
5226 return 1;
5227 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005228
willy tarreau1c2ad212005-12-18 01:11:29 +01005229 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005230
willy tarreau1c2ad212005-12-18 01:11:29 +01005231 tv_now(&now);
5232
5233 while (1) {
5234 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235
5236 /* stop when there's no connection left and we don't allow them anymore */
5237 if (!actconn && listeners == 0)
5238 break;
5239
willy tarreau0f7af912005-12-17 12:21:26 +01005240#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005241 {
5242 int time2;
5243 time2 = stats();
5244 next_time = MINTIME(time2, next_time);
5245 }
willy tarreau0f7af912005-12-17 12:21:26 +01005246#endif
5247
willy tarreau1c2ad212005-12-18 01:11:29 +01005248 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5249
5250 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5251 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5252
5253 if ((ro^rn) | (wo^wn)) {
5254 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5255#define FDSETS_ARE_INT_ALIGNED
5256#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005257
willy tarreauad90a0c2005-12-18 01:09:15 +01005258#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5259#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005260 pr = (ro >> count) & 1;
5261 pw = (wo >> count) & 1;
5262 sr = (rn >> count) & 1;
5263 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005264#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005265 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5266 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5267 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5268 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005269#endif
5270#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005271 pr = FD_ISSET(fd, PrevReadEvent);
5272 pw = FD_ISSET(fd, PrevWriteEvent);
5273 sr = FD_ISSET(fd, StaticReadEvent);
5274 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005275#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005276 if (!((sr^pr) | (sw^pw)))
5277 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005278
willy tarreau1c2ad212005-12-18 01:11:29 +01005279 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5280 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005281
willy tarreaub952e1d2005-12-18 01:31:20 +01005282#ifdef EPOLL_CTL_MOD_WORKAROUND
5283 /* I encountered a rarely reproducible problem with
5284 * EPOLL_CTL_MOD where a modified FD (systematically
5285 * the one in epoll_events[0], fd#7) would sometimes
5286 * be set EPOLL_OUT while asked for a read ! This is
5287 * with the 2.4 epoll patch. The workaround is to
5288 * delete then recreate in case of modification.
5289 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5290 * nor RHEL kernels.
5291 */
5292
5293 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5294 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5295
5296 if ((sr | sw))
5297 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5298#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005299 if ((pr | pw)) {
5300 /* the file-descriptor already exists... */
5301 if ((sr | sw)) {
5302 /* ...and it will still exist */
5303 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5304 // perror("epoll_ctl(MOD)");
5305 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005306 }
5307 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005308 /* ...and it will be removed */
5309 if (fdtab[fd].state != FD_STCLOSE &&
5310 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5311 // perror("epoll_ctl(DEL)");
5312 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005313 }
5314 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005315 } else {
5316 /* the file-descriptor did not exist, let's add it */
5317 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5318 // perror("epoll_ctl(ADD)");
5319 // exit(1);
5320 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005321 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005322#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005323 }
5324 ((int*)PrevReadEvent)[fds] = rn;
5325 ((int*)PrevWriteEvent)[fds] = wn;
5326 }
5327 }
5328
5329 /* now let's wait for events */
5330 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5331 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005332
willy tarreau1c2ad212005-12-18 01:11:29 +01005333 for (count = 0; count < status; count++) {
5334 fd = epoll_events[count].data.fd;
5335
5336 if (fdtab[fd].state == FD_STCLOSE)
5337 continue;
5338
5339 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5340 fdtab[fd].read(fd);
5341
5342 if (fdtab[fd].state == FD_STCLOSE)
5343 continue;
5344
5345 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5346 fdtab[fd].write(fd);
5347 }
5348 }
5349 return 1;
5350}
5351#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005352
willy tarreauad90a0c2005-12-18 01:09:15 +01005353
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354
willy tarreau1c2ad212005-12-18 01:11:29 +01005355#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005356
willy tarreau1c2ad212005-12-18 01:11:29 +01005357/*
5358 * Main poll() loop.
5359 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005360
willy tarreau1c2ad212005-12-18 01:11:29 +01005361/* does 3 actions :
5362 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5363 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5364 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5365 *
5366 * returns 0 if initialization failed, !0 otherwise.
5367 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005368
willy tarreau1c2ad212005-12-18 01:11:29 +01005369int poll_loop(int action) {
5370 int next_time;
5371 int status;
5372 int fd, nbfd;
5373
5374 int fds, count;
5375 int sr, sw;
5376 unsigned rn, wn; /* read new, write new */
5377
5378 /* private data */
5379 static struct pollfd *poll_events = NULL;
5380
5381 if (action == POLL_LOOP_ACTION_INIT) {
5382 poll_events = (struct pollfd*)
5383 calloc(1, sizeof(struct pollfd) * global.maxsock);
5384 return 1;
5385 }
5386 else if (action == POLL_LOOP_ACTION_CLEAN) {
5387 if (poll_events)
5388 free(poll_events);
5389 return 1;
5390 }
5391
5392 /* OK, it's POLL_LOOP_ACTION_RUN */
5393
5394 tv_now(&now);
5395
5396 while (1) {
5397 next_time = process_runnable_tasks();
5398
5399 /* stop when there's no connection left and we don't allow them anymore */
5400 if (!actconn && listeners == 0)
5401 break;
5402
5403#if STATTIME > 0
5404 {
5405 int time2;
5406 time2 = stats();
5407 next_time = MINTIME(time2, next_time);
5408 }
5409#endif
5410
5411
5412 nbfd = 0;
5413 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5414
5415 rn = ((int*)StaticReadEvent)[fds];
5416 wn = ((int*)StaticWriteEvent)[fds];
5417
5418 if ((rn|wn)) {
5419 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5420#define FDSETS_ARE_INT_ALIGNED
5421#ifdef FDSETS_ARE_INT_ALIGNED
5422
5423#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5424#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5425 sr = (rn >> count) & 1;
5426 sw = (wn >> count) & 1;
5427#else
5428 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5429 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5430#endif
5431#else
5432 sr = FD_ISSET(fd, StaticReadEvent);
5433 sw = FD_ISSET(fd, StaticWriteEvent);
5434#endif
5435 if ((sr|sw)) {
5436 poll_events[nbfd].fd = fd;
5437 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5438 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005439 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005440 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005441 }
5442 }
5443
5444 /* now let's wait for events */
5445 status = poll(poll_events, nbfd, next_time);
5446 tv_now(&now);
5447
5448 for (count = 0; status > 0 && count < nbfd; count++) {
5449 fd = poll_events[count].fd;
5450
5451 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5452 continue;
5453
5454 /* ok, we found one active fd */
5455 status--;
5456
5457 if (fdtab[fd].state == FD_STCLOSE)
5458 continue;
5459
5460 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5461 fdtab[fd].read(fd);
5462
5463 if (fdtab[fd].state == FD_STCLOSE)
5464 continue;
5465
5466 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5467 fdtab[fd].write(fd);
5468 }
5469 }
5470 return 1;
5471}
willy tarreauad90a0c2005-12-18 01:09:15 +01005472#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005473
willy tarreauad90a0c2005-12-18 01:09:15 +01005474
willy tarreauad90a0c2005-12-18 01:09:15 +01005475
willy tarreau1c2ad212005-12-18 01:11:29 +01005476/*
5477 * Main select() loop.
5478 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005479
willy tarreau1c2ad212005-12-18 01:11:29 +01005480/* does 3 actions :
5481 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5482 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5483 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5484 *
5485 * returns 0 if initialization failed, !0 otherwise.
5486 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005487
willy tarreauad90a0c2005-12-18 01:09:15 +01005488
willy tarreau1c2ad212005-12-18 01:11:29 +01005489int select_loop(int action) {
5490 int next_time;
5491 int status;
5492 int fd,i;
5493 struct timeval delta;
5494 int readnotnull, writenotnull;
5495 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005496
willy tarreau1c2ad212005-12-18 01:11:29 +01005497 if (action == POLL_LOOP_ACTION_INIT) {
5498 ReadEvent = (fd_set *)
5499 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5500 WriteEvent = (fd_set *)
5501 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5502 return 1;
5503 }
5504 else if (action == POLL_LOOP_ACTION_CLEAN) {
5505 if (WriteEvent) free(WriteEvent);
5506 if (ReadEvent) free(ReadEvent);
5507 return 1;
5508 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005509
willy tarreau1c2ad212005-12-18 01:11:29 +01005510 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005511
willy tarreau1c2ad212005-12-18 01:11:29 +01005512 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005513
willy tarreau1c2ad212005-12-18 01:11:29 +01005514 while (1) {
5515 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005516
willy tarreau1c2ad212005-12-18 01:11:29 +01005517 /* stop when there's no connection left and we don't allow them anymore */
5518 if (!actconn && listeners == 0)
5519 break;
5520
5521#if STATTIME > 0
5522 {
5523 int time2;
5524 time2 = stats();
5525 next_time = MINTIME(time2, next_time);
5526 }
5527#endif
5528
willy tarreau1c2ad212005-12-18 01:11:29 +01005529 if (next_time > 0) { /* FIXME */
5530 /* Convert to timeval */
5531 /* to avoid eventual select loops due to timer precision */
5532 next_time += SCHEDULER_RESOLUTION;
5533 delta.tv_sec = next_time / 1000;
5534 delta.tv_usec = (next_time % 1000) * 1000;
5535 }
5536 else if (next_time == 0) { /* allow select to return immediately when needed */
5537 delta.tv_sec = delta.tv_usec = 0;
5538 }
5539
5540
5541 /* let's restore fdset state */
5542
5543 readnotnull = 0; writenotnull = 0;
5544 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5545 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5546 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5547 }
5548
5549 // /* just a verification code, needs to be removed for performance */
5550 // for (i=0; i<maxfd; i++) {
5551 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5552 // abort();
5553 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5554 // abort();
5555 //
5556 // }
5557
5558 status = select(maxfd,
5559 readnotnull ? ReadEvent : NULL,
5560 writenotnull ? WriteEvent : NULL,
5561 NULL,
5562 (next_time >= 0) ? &delta : NULL);
5563
5564 /* this is an experiment on the separation of the select work */
5565 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5566 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5567
5568 tv_now(&now);
5569
5570 if (status > 0) { /* must proceed with events */
5571
5572 int fds;
5573 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005574
willy tarreau1c2ad212005-12-18 01:11:29 +01005575 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5576 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5577 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5578
5579 /* if we specify read first, the accepts and zero reads will be
5580 * seen first. Moreover, system buffers will be flushed faster.
5581 */
5582 if (fdtab[fd].state == FD_STCLOSE)
5583 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005584
willy tarreau1c2ad212005-12-18 01:11:29 +01005585 if (FD_ISSET(fd, ReadEvent))
5586 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005587
willy tarreau1c2ad212005-12-18 01:11:29 +01005588 if (FD_ISSET(fd, WriteEvent))
5589 fdtab[fd].write(fd);
5590 }
5591 }
5592 else {
5593 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005594 }
willy tarreau0f7af912005-12-17 12:21:26 +01005595 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005596 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005597}
5598
5599
5600#if STATTIME > 0
5601/*
5602 * Display proxy statistics regularly. It is designed to be called from the
5603 * select_loop().
5604 */
5605int stats(void) {
5606 static int lines;
5607 static struct timeval nextevt;
5608 static struct timeval lastevt;
5609 static struct timeval starttime = {0,0};
5610 unsigned long totaltime, deltatime;
5611 int ret;
5612
willy tarreau750a4722005-12-17 13:21:24 +01005613 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005614 deltatime = (tv_diff(&lastevt, &now)?:1);
5615 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005616
willy tarreau9fe663a2005-12-17 13:02:59 +01005617 if (global.mode & MODE_STATS) {
5618 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005619 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005620 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5621 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005622 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005623 actconn, totalconn,
5624 stats_tsk_new, stats_tsk_good,
5625 stats_tsk_left, stats_tsk_right,
5626 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5627 }
5628 }
5629
5630 tv_delayfrom(&nextevt, &now, STATTIME);
5631
5632 lastevt=now;
5633 }
5634 ret = tv_remain(&now, &nextevt);
5635 return ret;
5636}
5637#endif
5638
5639
5640/*
5641 * this function enables proxies when there are enough free sessions,
5642 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005643 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005644 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005645 */
5646static int maintain_proxies(void) {
5647 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005648 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005649 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005650
5651 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005652 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005653
5654 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005655 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005656 while (p) {
5657 if (p->nbconn < p->maxconn) {
5658 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005659 for (l = p->listen; l != NULL; l = l->next) {
5660 FD_SET(l->fd, StaticReadEvent);
5661 }
willy tarreau0f7af912005-12-17 12:21:26 +01005662 p->state = PR_STRUN;
5663 }
5664 }
5665 else {
5666 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005667 for (l = p->listen; l != NULL; l = l->next) {
5668 FD_CLR(l->fd, StaticReadEvent);
5669 }
willy tarreau0f7af912005-12-17 12:21:26 +01005670 p->state = PR_STIDLE;
5671 }
5672 }
5673 p = p->next;
5674 }
5675 }
5676 else { /* block all proxies */
5677 while (p) {
5678 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005679 for (l = p->listen; l != NULL; l = l->next) {
5680 FD_CLR(l->fd, StaticReadEvent);
5681 }
willy tarreau0f7af912005-12-17 12:21:26 +01005682 p->state = PR_STIDLE;
5683 }
5684 p = p->next;
5685 }
5686 }
5687
willy tarreau5cbea6f2005-12-17 12:48:26 +01005688 if (stopping) {
5689 p = proxy;
5690 while (p) {
5691 if (p->state != PR_STDISABLED) {
5692 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005693 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005694 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005695 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005696 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005697
willy tarreaua41a8b42005-12-17 14:02:24 +01005698 for (l = p->listen; l != NULL; l = l->next) {
5699 fd_delete(l->fd);
5700 listeners--;
5701 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005702 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005703 }
5704 else {
5705 tleft = MINTIME(t, tleft);
5706 }
5707 }
5708 p = p->next;
5709 }
5710 }
5711 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005712}
5713
5714/*
5715 * this function disables health-check servers so that the process will quickly be ignored
5716 * by load balancers.
5717 */
5718static void soft_stop(void) {
5719 struct proxy *p;
5720
5721 stopping = 1;
5722 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005723 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005724 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005725 if (p->state != PR_STDISABLED) {
5726 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005727 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005728 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005729 }
willy tarreau0f7af912005-12-17 12:21:26 +01005730 p = p->next;
5731 }
5732}
5733
5734/*
5735 * upon SIGUSR1, let's have a soft stop.
5736 */
5737void sig_soft_stop(int sig) {
5738 soft_stop();
5739 signal(sig, SIG_IGN);
5740}
5741
5742
willy tarreau8337c6b2005-12-17 13:41:01 +01005743/*
5744 * this function dumps every server's state when the process receives SIGHUP.
5745 */
5746void sig_dump_state(int sig) {
5747 struct proxy *p = proxy;
5748
5749 Warning("SIGHUP received, dumping servers states.\n");
5750 while (p) {
5751 struct server *s = p->srv;
5752
5753 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5754 while (s) {
5755 if (s->state & SRV_RUNNING) {
5756 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5757 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5758 }
5759 else {
5760 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5761 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5762 }
5763 s = s->next;
5764 }
willy tarreaudd07e972005-12-18 00:48:48 +01005765
5766 if (find_server(p) == NULL) {
5767 Warning("SIGHUP: proxy %s has no server available !\n", p);
5768 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5769 }
5770
willy tarreau8337c6b2005-12-17 13:41:01 +01005771 p = p->next;
5772 }
5773 signal(sig, sig_dump_state);
5774}
5775
willy tarreau0f7af912005-12-17 12:21:26 +01005776void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005777 struct task *t, *tnext;
5778 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005779
willy tarreau5cbea6f2005-12-17 12:48:26 +01005780 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5781 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5782 tnext = t->next;
5783 s = t->context;
5784 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5785 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5786 "req=%d, rep=%d, clifd=%d\n",
5787 s, tv_remain(&now, &t->expire),
5788 s->cli_state,
5789 s->srv_state,
5790 FD_ISSET(s->cli_fd, StaticReadEvent),
5791 FD_ISSET(s->cli_fd, StaticWriteEvent),
5792 FD_ISSET(s->srv_fd, StaticReadEvent),
5793 FD_ISSET(s->srv_fd, StaticWriteEvent),
5794 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5795 );
willy tarreau0f7af912005-12-17 12:21:26 +01005796 }
willy tarreau12350152005-12-18 01:03:27 +01005797}
5798
willy tarreau64a3cc32005-12-18 01:13:11 +01005799#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005800static void fast_stop(void)
5801{
5802 struct proxy *p;
5803 p = proxy;
5804 while (p) {
5805 p->grace = 0;
5806 p = p->next;
5807 }
5808 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005809}
5810
willy tarreau12350152005-12-18 01:03:27 +01005811void sig_int(int sig) {
5812 /* This would normally be a hard stop,
5813 but we want to be sure about deallocation,
5814 and so on, so we do a soft stop with
5815 0 GRACE time
5816 */
5817 fast_stop();
5818 /* If we are killed twice, we decide to die*/
5819 signal(sig, SIG_DFL);
5820}
5821
5822void sig_term(int sig) {
5823 /* This would normally be a hard stop,
5824 but we want to be sure about deallocation,
5825 and so on, so we do a soft stop with
5826 0 GRACE time
5827 */
5828 fast_stop();
5829 /* If we are killed twice, we decide to die*/
5830 signal(sig, SIG_DFL);
5831}
willy tarreau64a3cc32005-12-18 01:13:11 +01005832#endif
willy tarreau12350152005-12-18 01:03:27 +01005833
willy tarreauc1f47532005-12-18 01:08:26 +01005834/* returns the pointer to an error in the replacement string, or NULL if OK */
5835char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005836 struct hdr_exp *exp;
5837
willy tarreauc1f47532005-12-18 01:08:26 +01005838 if (replace != NULL) {
5839 char *err;
5840 err = check_replace_string(replace);
5841 if (err)
5842 return err;
5843 }
5844
willy tarreaue39cd132005-12-17 13:00:18 +01005845 while (*head != NULL)
5846 head = &(*head)->next;
5847
5848 exp = calloc(1, sizeof(struct hdr_exp));
5849
5850 exp->preg = preg;
5851 exp->replace = replace;
5852 exp->action = action;
5853 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005854
5855 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005856}
5857
willy tarreau9fe663a2005-12-17 13:02:59 +01005858
willy tarreau0f7af912005-12-17 12:21:26 +01005859/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005860 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005861 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005862int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005863
willy tarreau9fe663a2005-12-17 13:02:59 +01005864 if (!strcmp(args[0], "global")) { /* new section */
5865 /* no option, nothing special to do */
5866 return 0;
5867 }
5868 else if (!strcmp(args[0], "daemon")) {
5869 global.mode |= MODE_DAEMON;
5870 }
5871 else if (!strcmp(args[0], "debug")) {
5872 global.mode |= MODE_DEBUG;
5873 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005874 else if (!strcmp(args[0], "noepoll")) {
5875 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5876 }
5877 else if (!strcmp(args[0], "nopoll")) {
5878 cfg_polling_mechanism &= ~POLL_USE_POLL;
5879 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005880 else if (!strcmp(args[0], "quiet")) {
5881 global.mode |= MODE_QUIET;
5882 }
5883 else if (!strcmp(args[0], "stats")) {
5884 global.mode |= MODE_STATS;
5885 }
5886 else if (!strcmp(args[0], "uid")) {
5887 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005888 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005889 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005890 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005891 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005892 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005893 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005894 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005895 global.uid = atol(args[1]);
5896 }
5897 else if (!strcmp(args[0], "gid")) {
5898 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005899 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005900 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005901 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005902 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005903 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005904 return -1;
5905 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005906 global.gid = atol(args[1]);
5907 }
5908 else if (!strcmp(args[0], "nbproc")) {
5909 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005910 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005911 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005913 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005914 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005915 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005916 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005917 global.nbproc = atol(args[1]);
5918 }
5919 else if (!strcmp(args[0], "maxconn")) {
5920 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005921 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005922 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005923 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005924 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005925 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005926 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005928 global.maxconn = atol(args[1]);
5929 }
willy tarreaub1285d52005-12-18 01:20:14 +01005930 else if (!strcmp(args[0], "ulimit-n")) {
5931 if (global.rlimit_nofile != 0) {
5932 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5933 return 0;
5934 }
5935 if (*(args[1]) == 0) {
5936 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5937 return -1;
5938 }
5939 global.rlimit_nofile = atol(args[1]);
5940 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005941 else if (!strcmp(args[0], "chroot")) {
5942 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 return 0;
5945 }
5946 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005947 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005948 return -1;
5949 }
5950 global.chroot = strdup(args[1]);
5951 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005952 else if (!strcmp(args[0], "pidfile")) {
5953 if (global.pidfile != NULL) {
5954 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5955 return 0;
5956 }
5957 if (*(args[1]) == 0) {
5958 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5959 return -1;
5960 }
5961 global.pidfile = strdup(args[1]);
5962 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005963 else if (!strcmp(args[0], "log")) { /* syslog server address */
5964 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005965 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005966
5967 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005968 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005969 return -1;
5970 }
5971
5972 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5973 if (!strcmp(log_facilities[facility], args[2]))
5974 break;
5975
5976 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005977 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005978 exit(1);
5979 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005980
5981 level = 7; /* max syslog level = debug */
5982 if (*(args[3])) {
5983 while (level >= 0 && strcmp(log_levels[level], args[3]))
5984 level--;
5985 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005986 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005987 exit(1);
5988 }
5989 }
5990
willy tarreau9fe663a2005-12-17 13:02:59 +01005991 sa = str2sa(args[1]);
5992 if (!sa->sin_port)
5993 sa->sin_port = htons(SYSLOG_PORT);
5994
5995 if (global.logfac1 == -1) {
5996 global.logsrv1 = *sa;
5997 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005998 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005999 }
6000 else if (global.logfac2 == -1) {
6001 global.logsrv2 = *sa;
6002 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006003 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006004 }
6005 else {
6006 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6007 return -1;
6008 }
6009
6010 }
6011 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006012 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006013 return -1;
6014 }
6015 return 0;
6016}
6017
6018
willy tarreaua41a8b42005-12-17 14:02:24 +01006019void init_default_instance() {
6020 memset(&defproxy, 0, sizeof(defproxy));
6021 defproxy.mode = PR_MODE_TCP;
6022 defproxy.state = PR_STNEW;
6023 defproxy.maxconn = cfg_maxpconn;
6024 defproxy.conn_retries = CONN_RETRIES;
6025 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6026}
6027
willy tarreau9fe663a2005-12-17 13:02:59 +01006028/*
6029 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6030 */
6031int cfg_parse_listen(char *file, int linenum, char **args) {
6032 static struct proxy *curproxy = NULL;
6033 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006034 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006035 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006036
6037 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006038 if (!*args[1]) {
6039 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6040 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006041 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006042 return -1;
6043 }
6044
6045 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006046 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006047 return -1;
6048 }
6049 curproxy->next = proxy;
6050 proxy = curproxy;
6051 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006052
6053 /* parse the listener address if any */
6054 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006055 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006056 if (!curproxy->listen)
6057 return -1;
6058 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006059
willy tarreau9fe663a2005-12-17 13:02:59 +01006060 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006061 curproxy->state = defproxy.state;
6062 curproxy->maxconn = defproxy.maxconn;
6063 curproxy->conn_retries = defproxy.conn_retries;
6064 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006065
6066 if (defproxy.check_req)
6067 curproxy->check_req = strdup(defproxy.check_req);
6068 curproxy->check_len = defproxy.check_len;
6069
6070 if (defproxy.cookie_name)
6071 curproxy->cookie_name = strdup(defproxy.cookie_name);
6072 curproxy->cookie_len = defproxy.cookie_len;
6073
6074 if (defproxy.capture_name)
6075 curproxy->capture_name = strdup(defproxy.capture_name);
6076 curproxy->capture_namelen = defproxy.capture_namelen;
6077 curproxy->capture_len = defproxy.capture_len;
6078
6079 if (defproxy.errmsg.msg400)
6080 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6081 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6082
6083 if (defproxy.errmsg.msg403)
6084 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6085 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6086
6087 if (defproxy.errmsg.msg408)
6088 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6089 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6090
6091 if (defproxy.errmsg.msg500)
6092 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6093 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6094
6095 if (defproxy.errmsg.msg502)
6096 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6097 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6098
6099 if (defproxy.errmsg.msg503)
6100 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6101 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6102
6103 if (defproxy.errmsg.msg504)
6104 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6105 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6106
willy tarreaua41a8b42005-12-17 14:02:24 +01006107 curproxy->clitimeout = defproxy.clitimeout;
6108 curproxy->contimeout = defproxy.contimeout;
6109 curproxy->srvtimeout = defproxy.srvtimeout;
6110 curproxy->mode = defproxy.mode;
6111 curproxy->logfac1 = defproxy.logfac1;
6112 curproxy->logsrv1 = defproxy.logsrv1;
6113 curproxy->loglev1 = defproxy.loglev1;
6114 curproxy->logfac2 = defproxy.logfac2;
6115 curproxy->logsrv2 = defproxy.logsrv2;
6116 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006117 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006118 curproxy->grace = defproxy.grace;
6119 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006120 curproxy->mon_net = defproxy.mon_net;
6121 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006122 return 0;
6123 }
6124 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006125 /* some variables may have already been initialized earlier */
6126 if (defproxy.check_req) free(defproxy.check_req);
6127 if (defproxy.cookie_name) free(defproxy.cookie_name);
6128 if (defproxy.capture_name) free(defproxy.capture_name);
6129 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6130 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6131 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6132 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6133 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6134 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6135 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6136
6137 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006138 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006139 return 0;
6140 }
6141 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006142 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006143 return -1;
6144 }
6145
willy tarreaua41a8b42005-12-17 14:02:24 +01006146 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6147 if (curproxy == &defproxy) {
6148 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6149 return -1;
6150 }
6151
6152 if (strchr(args[1], ':') == NULL) {
6153 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6154 file, linenum, args[0]);
6155 return -1;
6156 }
6157 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006158 if (!curproxy->listen)
6159 return -1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006160 return 0;
6161 }
willy tarreaub1285d52005-12-18 01:20:14 +01006162 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6163 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6164 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6165 file, linenum, args[0]);
6166 return -1;
6167 }
6168 /* flush useless bits */
6169 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6170 return 0;
6171 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006172 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006173 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6174 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6175 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6176 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006177 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006178 return -1;
6179 }
6180 }
6181 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6182 curproxy->state = PR_STDISABLED;
6183 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006184 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6185 curproxy->state = PR_STNEW;
6186 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006187 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6188 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006189// if (curproxy == &defproxy) {
6190// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6191// return -1;
6192// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006193
willy tarreau9fe663a2005-12-17 13:02:59 +01006194 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006195// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6196// file, linenum);
6197// return 0;
6198 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006199 }
6200
6201 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006202 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6203 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006204 return -1;
6205 }
6206 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006207 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006208
6209 cur_arg = 2;
6210 while (*(args[cur_arg])) {
6211 if (!strcmp(args[cur_arg], "rewrite")) {
6212 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006213 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006214 else if (!strcmp(args[cur_arg], "indirect")) {
6215 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006216 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006217 else if (!strcmp(args[cur_arg], "insert")) {
6218 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006219 }
willy tarreau240afa62005-12-17 13:14:35 +01006220 else if (!strcmp(args[cur_arg], "nocache")) {
6221 curproxy->options |= PR_O_COOK_NOC;
6222 }
willy tarreaucd878942005-12-17 13:27:43 +01006223 else if (!strcmp(args[cur_arg], "postonly")) {
6224 curproxy->options |= PR_O_COOK_POST;
6225 }
willy tarreau0174f312005-12-18 01:02:42 +01006226 else if (!strcmp(args[cur_arg], "prefix")) {
6227 curproxy->options |= PR_O_COOK_PFX;
6228 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006229 else {
willy tarreau0174f312005-12-18 01:02:42 +01006230 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006231 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006232 return -1;
6233 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006234 cur_arg++;
6235 }
willy tarreau0174f312005-12-18 01:02:42 +01006236 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6237 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6238 file, linenum);
6239 return -1;
6240 }
6241
6242 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6243 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006244 file, linenum);
6245 return -1;
6246 }
willy tarreau12350152005-12-18 01:03:27 +01006247 }/* end else if (!strcmp(args[0], "cookie")) */
6248 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6249// if (curproxy == &defproxy) {
6250// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6251// return -1;
6252// }
6253
6254 if (curproxy->appsession_name != NULL) {
6255// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6256// file, linenum);
6257// return 0;
6258 free(curproxy->appsession_name);
6259 }
6260
6261 if (*(args[5]) == 0) {
6262 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6263 file, linenum, args[0]);
6264 return -1;
6265 }
6266 have_appsession = 1;
6267 curproxy->appsession_name = strdup(args[1]);
6268 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6269 curproxy->appsession_len = atoi(args[3]);
6270 curproxy->appsession_timeout = atoi(args[5]);
6271 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6272 if (rc) {
6273 Alert("Error Init Appsession Hashtable.\n");
6274 return -1;
6275 }
6276 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006277 else if (!strcmp(args[0], "capture")) {
6278 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6279 // if (curproxy == &defproxy) {
6280 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6281 // return -1;
6282 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006283
willy tarreau4302f492005-12-18 01:00:37 +01006284 if (curproxy->capture_name != NULL) {
6285 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6286 // file, linenum, args[0]);
6287 // return 0;
6288 free(curproxy->capture_name);
6289 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006290
willy tarreau4302f492005-12-18 01:00:37 +01006291 if (*(args[4]) == 0) {
6292 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6293 file, linenum, args[0]);
6294 return -1;
6295 }
6296 curproxy->capture_name = strdup(args[2]);
6297 curproxy->capture_namelen = strlen(curproxy->capture_name);
6298 curproxy->capture_len = atol(args[4]);
6299 if (curproxy->capture_len >= CAPTURE_LEN) {
6300 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6301 file, linenum, CAPTURE_LEN - 1);
6302 curproxy->capture_len = CAPTURE_LEN - 1;
6303 }
6304 curproxy->to_log |= LW_COOKIE;
6305 }
6306 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6307 struct cap_hdr *hdr;
6308
6309 if (curproxy == &defproxy) {
6310 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6311 return -1;
6312 }
6313
6314 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6315 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6316 file, linenum, args[0], args[1]);
6317 return -1;
6318 }
6319
6320 hdr = calloc(sizeof(struct cap_hdr), 1);
6321 hdr->next = curproxy->req_cap;
6322 hdr->name = strdup(args[3]);
6323 hdr->namelen = strlen(args[3]);
6324 hdr->len = atol(args[5]);
6325 hdr->index = curproxy->nb_req_cap++;
6326 curproxy->req_cap = hdr;
6327 curproxy->to_log |= LW_REQHDR;
6328 }
6329 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6330 struct cap_hdr *hdr;
6331
6332 if (curproxy == &defproxy) {
6333 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6334 return -1;
6335 }
6336
6337 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6338 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6339 file, linenum, args[0], args[1]);
6340 return -1;
6341 }
6342 hdr = calloc(sizeof(struct cap_hdr), 1);
6343 hdr->next = curproxy->rsp_cap;
6344 hdr->name = strdup(args[3]);
6345 hdr->namelen = strlen(args[3]);
6346 hdr->len = atol(args[5]);
6347 hdr->index = curproxy->nb_rsp_cap++;
6348 curproxy->rsp_cap = hdr;
6349 curproxy->to_log |= LW_RSPHDR;
6350 }
6351 else {
6352 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006353 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006354 return -1;
6355 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006358 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006359 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006360 return 0;
6361 }
6362 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006363 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6364 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006365 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006366 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006367 curproxy->contimeout = atol(args[1]);
6368 }
6369 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006370 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6372 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006373 return 0;
6374 }
6375 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006376 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6377 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return -1;
6379 }
6380 curproxy->clitimeout = atol(args[1]);
6381 }
6382 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006383 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006384 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006385 return 0;
6386 }
6387 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006388 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6389 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006390 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006391 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006392 curproxy->srvtimeout = atol(args[1]);
6393 }
6394 else if (!strcmp(args[0], "retries")) { /* connection retries */
6395 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006396 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6397 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006398 return -1;
6399 }
6400 curproxy->conn_retries = atol(args[1]);
6401 }
6402 else if (!strcmp(args[0], "option")) {
6403 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006404 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006405 return -1;
6406 }
6407 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006408 /* enable reconnections to dispatch */
6409 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006410#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006411 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006412 /* enable transparent proxy connections */
6413 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006414#endif
6415 else if (!strcmp(args[1], "keepalive"))
6416 /* enable keep-alive */
6417 curproxy->options |= PR_O_KEEPALIVE;
6418 else if (!strcmp(args[1], "forwardfor"))
6419 /* insert x-forwarded-for field */
6420 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006421 else if (!strcmp(args[1], "logasap"))
6422 /* log as soon as possible, without waiting for the session to complete */
6423 curproxy->options |= PR_O_LOGASAP;
6424 else if (!strcmp(args[1], "httpclose"))
6425 /* force connection: close in both directions in HTTP mode */
6426 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006427 else if (!strcmp(args[1], "checkcache"))
6428 /* require examination of cacheability of the 'set-cookie' field */
6429 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006430 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006431 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006432 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006433 else if (!strcmp(args[1], "tcplog"))
6434 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006435 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006436 else if (!strcmp(args[1], "dontlognull")) {
6437 /* don't log empty requests */
6438 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006439 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006440 else if (!strcmp(args[1], "tcpka")) {
6441 /* enable TCP keep-alives on client and server sessions */
6442 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6443 }
6444 else if (!strcmp(args[1], "clitcpka")) {
6445 /* enable TCP keep-alives on client sessions */
6446 curproxy->options |= PR_O_TCP_CLI_KA;
6447 }
6448 else if (!strcmp(args[1], "srvtcpka")) {
6449 /* enable TCP keep-alives on server sessions */
6450 curproxy->options |= PR_O_TCP_SRV_KA;
6451 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006452 else if (!strcmp(args[1], "httpchk")) {
6453 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006454 if (curproxy->check_req != NULL) {
6455 free(curproxy->check_req);
6456 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006457 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006458 if (!*args[2]) { /* no argument */
6459 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6460 curproxy->check_len = strlen(DEF_CHECK_REQ);
6461 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006462 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6463 curproxy->check_req = (char *)malloc(reqlen);
6464 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6465 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006466 } else { /* more arguments : METHOD URI [HTTP_VER] */
6467 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6468 if (*args[4])
6469 reqlen += strlen(args[4]);
6470 else
6471 reqlen += strlen("HTTP/1.0");
6472
6473 curproxy->check_req = (char *)malloc(reqlen);
6474 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6475 "%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 +01006476 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006477 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006478 else if (!strcmp(args[1], "persist")) {
6479 /* persist on using the server specified by the cookie, even when it's down */
6480 curproxy->options |= PR_O_PERSIST;
6481 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006482 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006483 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006484 return -1;
6485 }
6486 return 0;
6487 }
6488 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6489 /* enable reconnections to dispatch */
6490 curproxy->options |= PR_O_REDISP;
6491 }
willy tarreaua1598082005-12-17 13:08:06 +01006492#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006493 else if (!strcmp(args[0], "transparent")) {
6494 /* enable transparent proxy connections */
6495 curproxy->options |= PR_O_TRANSP;
6496 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006497#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006498 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6499 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006500 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006501 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006502 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006503 curproxy->maxconn = atol(args[1]);
6504 }
6505 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6506 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006507 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006508 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006509 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006510 curproxy->grace = atol(args[1]);
6511 }
6512 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006513 if (curproxy == &defproxy) {
6514 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6515 return -1;
6516 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006517 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006518 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006519 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006520 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006521 curproxy->dispatch_addr = *str2sa(args[1]);
6522 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006523 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006524 if (*(args[1])) {
6525 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006526 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006527 }
6528 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006529 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006530 return -1;
6531 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006532 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006533 else /* if no option is set, use round-robin by default */
6534 curproxy->options |= PR_O_BALANCE_RR;
6535 }
6536 else if (!strcmp(args[0], "server")) { /* server address */
6537 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006538 char *rport;
6539 char *raddr;
6540 short realport;
6541 int do_check;
6542
6543 if (curproxy == &defproxy) {
6544 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6545 return -1;
6546 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006547
willy tarreaua41a8b42005-12-17 14:02:24 +01006548 if (!*args[2]) {
6549 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006550 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006551 return -1;
6552 }
6553 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6554 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6555 return -1;
6556 }
willy tarreau0174f312005-12-18 01:02:42 +01006557
6558 if (curproxy->srv == NULL)
6559 curproxy->srv = newsrv;
6560 else
6561 curproxy->cursrv->next = newsrv;
6562 curproxy->cursrv = newsrv;
6563
6564 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006565 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006566
6567 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006568 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006569 newsrv->id = strdup(args[1]);
6570
6571 /* several ways to check the port component :
6572 * - IP => port=+0, relative
6573 * - IP: => port=+0, relative
6574 * - IP:N => port=N, absolute
6575 * - IP:+N => port=+N, relative
6576 * - IP:-N => port=-N, relative
6577 */
6578 raddr = strdup(args[2]);
6579 rport = strchr(raddr, ':');
6580 if (rport) {
6581 *rport++ = 0;
6582 realport = atol(rport);
6583 if (!isdigit((int)*rport))
6584 newsrv->state |= SRV_MAPPORTS;
6585 } else {
6586 realport = 0;
6587 newsrv->state |= SRV_MAPPORTS;
6588 }
6589
6590 newsrv->addr = *str2sa(raddr);
6591 newsrv->addr.sin_port = htons(realport);
6592 free(raddr);
6593
willy tarreau9fe663a2005-12-17 13:02:59 +01006594 newsrv->curfd = -1; /* no health-check in progress */
6595 newsrv->inter = DEF_CHKINTR;
6596 newsrv->rise = DEF_RISETIME;
6597 newsrv->fall = DEF_FALLTIME;
6598 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6599 cur_arg = 3;
6600 while (*args[cur_arg]) {
6601 if (!strcmp(args[cur_arg], "cookie")) {
6602 newsrv->cookie = strdup(args[cur_arg + 1]);
6603 newsrv->cklen = strlen(args[cur_arg + 1]);
6604 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006605 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006606 else if (!strcmp(args[cur_arg], "rise")) {
6607 newsrv->rise = atol(args[cur_arg + 1]);
6608 newsrv->health = newsrv->rise;
6609 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006610 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006611 else if (!strcmp(args[cur_arg], "fall")) {
6612 newsrv->fall = atol(args[cur_arg + 1]);
6613 cur_arg += 2;
6614 }
6615 else if (!strcmp(args[cur_arg], "inter")) {
6616 newsrv->inter = atol(args[cur_arg + 1]);
6617 cur_arg += 2;
6618 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006619 else if (!strcmp(args[cur_arg], "port")) {
6620 newsrv->check_port = atol(args[cur_arg + 1]);
6621 cur_arg += 2;
6622 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006623 else if (!strcmp(args[cur_arg], "backup")) {
6624 newsrv->state |= SRV_BACKUP;
6625 cur_arg ++;
6626 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006628 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006630 }
willy tarreau0174f312005-12-18 01:02:42 +01006631 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6632 if (!*args[cur_arg + 1]) {
6633 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6634 file, linenum, "source");
6635 return -1;
6636 }
6637 newsrv->state |= SRV_BIND_SRC;
6638 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6639 cur_arg += 2;
6640 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006641 else {
willy tarreau0174f312005-12-18 01:02:42 +01006642 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 +01006643 file, linenum, newsrv->id);
6644 return -1;
6645 }
6646 }
6647
6648 if (do_check) {
6649 struct task *t;
6650
6651 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6652 newsrv->check_port = realport; /* by default */
6653 if (!newsrv->check_port) {
6654 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 +01006655 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006656 return -1;
6657 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006658
6659 if ((t = pool_alloc(task)) == NULL) {
6660 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6661 return -1;
6662 }
6663
6664 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6665 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6666 t->state = TASK_IDLE;
6667 t->process = process_chk;
6668 t->context = newsrv;
6669
6670 if (curproxy->state != PR_STDISABLED) {
6671 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6672 task_queue(t);
6673 task_wakeup(&rq, t);
6674 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006675 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006676
willy tarreau9fe663a2005-12-17 13:02:59 +01006677 curproxy->nbservers++;
6678 }
6679 else if (!strcmp(args[0], "log")) { /* syslog server address */
6680 struct sockaddr_in *sa;
6681 int facility;
6682
6683 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6684 curproxy->logfac1 = global.logfac1;
6685 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006686 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006687 curproxy->logfac2 = global.logfac2;
6688 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006689 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006690 }
6691 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006692 int level;
6693
willy tarreau0f7af912005-12-17 12:21:26 +01006694 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6695 if (!strcmp(log_facilities[facility], args[2]))
6696 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006697
willy tarreau0f7af912005-12-17 12:21:26 +01006698 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006699 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006700 exit(1);
6701 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006702
willy tarreau8337c6b2005-12-17 13:41:01 +01006703 level = 7; /* max syslog level = debug */
6704 if (*(args[3])) {
6705 while (level >= 0 && strcmp(log_levels[level], args[3]))
6706 level--;
6707 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006708 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006709 exit(1);
6710 }
6711 }
6712
willy tarreau0f7af912005-12-17 12:21:26 +01006713 sa = str2sa(args[1]);
6714 if (!sa->sin_port)
6715 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006716
willy tarreau0f7af912005-12-17 12:21:26 +01006717 if (curproxy->logfac1 == -1) {
6718 curproxy->logsrv1 = *sa;
6719 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006720 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006721 }
6722 else if (curproxy->logfac2 == -1) {
6723 curproxy->logsrv2 = *sa;
6724 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006725 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006726 }
6727 else {
6728 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006729 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006730 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006731 }
6732 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006733 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006734 file, linenum);
6735 return -1;
6736 }
6737 }
willy tarreaua1598082005-12-17 13:08:06 +01006738 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006739 if (!*args[1]) {
6740 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006741 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006742 return -1;
6743 }
6744
6745 curproxy->source_addr = *str2sa(args[1]);
6746 curproxy->options |= PR_O_BIND_SRC;
6747 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006748 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6749 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006750 if (curproxy == &defproxy) {
6751 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6752 return -1;
6753 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006754
6755 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006756 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6757 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006758 return -1;
6759 }
6760
6761 preg = calloc(1, sizeof(regex_t));
6762 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006763 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006764 return -1;
6765 }
6766
willy tarreauc1f47532005-12-18 01:08:26 +01006767 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6768 if (err) {
6769 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6770 file, linenum, *err);
6771 return -1;
6772 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006773 }
6774 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6775 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006776 if (curproxy == &defproxy) {
6777 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6778 return -1;
6779 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006780
6781 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006782 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006783 return -1;
6784 }
6785
6786 preg = calloc(1, sizeof(regex_t));
6787 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006788 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006789 return -1;
6790 }
6791
6792 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6793 }
6794 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6795 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006796 if (curproxy == &defproxy) {
6797 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6798 return -1;
6799 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006800
6801 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006802 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006803 return -1;
6804 }
6805
6806 preg = calloc(1, sizeof(regex_t));
6807 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006808 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006809 return -1;
6810 }
6811
6812 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6813 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006814 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6815 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006816 if (curproxy == &defproxy) {
6817 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6818 return -1;
6819 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006820
6821 if (*(args[1]) == 0) {
6822 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6823 return -1;
6824 }
6825
6826 preg = calloc(1, sizeof(regex_t));
6827 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6828 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6829 return -1;
6830 }
6831
6832 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6833 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006834 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6835 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006836 if (curproxy == &defproxy) {
6837 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6838 return -1;
6839 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006840
6841 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006842 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006843 return -1;
6844 }
6845
6846 preg = calloc(1, sizeof(regex_t));
6847 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006848 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006849 return -1;
6850 }
6851
6852 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6853 }
6854 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6855 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006856 if (curproxy == &defproxy) {
6857 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6858 return -1;
6859 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006860
6861 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006862 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6863 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006864 return -1;
6865 }
6866
6867 preg = calloc(1, sizeof(regex_t));
6868 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006869 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006870 return -1;
6871 }
6872
willy tarreauc1f47532005-12-18 01:08:26 +01006873 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6874 if (err) {
6875 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6876 file, linenum, *err);
6877 return -1;
6878 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006879 }
6880 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6881 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006882 if (curproxy == &defproxy) {
6883 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6884 return -1;
6885 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006886
6887 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006888 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006889 return -1;
6890 }
6891
6892 preg = calloc(1, sizeof(regex_t));
6893 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006894 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006895 return -1;
6896 }
6897
6898 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6899 }
6900 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6901 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006902 if (curproxy == &defproxy) {
6903 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6904 return -1;
6905 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006906
6907 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006908 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006909 return -1;
6910 }
6911
6912 preg = calloc(1, sizeof(regex_t));
6913 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006914 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006915 return -1;
6916 }
6917
6918 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6919 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006920 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6921 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006922 if (curproxy == &defproxy) {
6923 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6924 return -1;
6925 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006926
6927 if (*(args[1]) == 0) {
6928 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6929 return -1;
6930 }
6931
6932 preg = calloc(1, sizeof(regex_t));
6933 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6934 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6935 return -1;
6936 }
6937
6938 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6939 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006940 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6941 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006942 if (curproxy == &defproxy) {
6943 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6944 return -1;
6945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006946
6947 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006948 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 return -1;
6950 }
6951
6952 preg = calloc(1, sizeof(regex_t));
6953 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006954 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006955 return -1;
6956 }
6957
6958 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6959 }
6960 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006961 if (curproxy == &defproxy) {
6962 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6963 return -1;
6964 }
6965
willy tarreau9fe663a2005-12-17 13:02:59 +01006966 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006967 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 return 0;
6969 }
6970
6971 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006972 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 return -1;
6974 }
6975
willy tarreau4302f492005-12-18 01:00:37 +01006976 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6977 }
6978 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6979 regex_t *preg;
6980
6981 if (*(args[1]) == 0 || *(args[2]) == 0) {
6982 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6983 file, linenum, args[0]);
6984 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006985 }
willy tarreau4302f492005-12-18 01:00:37 +01006986
6987 preg = calloc(1, sizeof(regex_t));
6988 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6989 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6990 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006991 }
willy tarreau4302f492005-12-18 01:00:37 +01006992
willy tarreauc1f47532005-12-18 01:08:26 +01006993 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6994 if (err) {
6995 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6996 file, linenum, *err);
6997 return -1;
6998 }
willy tarreau4302f492005-12-18 01:00:37 +01006999 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007000 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7001 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007002 if (curproxy == &defproxy) {
7003 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7004 return -1;
7005 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007006
7007 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007008 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007009 return -1;
7010 }
willy tarreaue39cd132005-12-17 13:00:18 +01007011
willy tarreau9fe663a2005-12-17 13:02:59 +01007012 preg = calloc(1, sizeof(regex_t));
7013 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007014 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007015 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007016 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007017
willy tarreauc1f47532005-12-18 01:08:26 +01007018 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7019 if (err) {
7020 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7021 file, linenum, *err);
7022 return -1;
7023 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 }
willy tarreau982249e2005-12-18 00:57:06 +01007025 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7026 regex_t *preg;
7027 if (curproxy == &defproxy) {
7028 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7029 return -1;
7030 }
7031
7032 if (*(args[1]) == 0) {
7033 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7034 return -1;
7035 }
7036
7037 preg = calloc(1, sizeof(regex_t));
7038 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7039 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7040 return -1;
7041 }
7042
willy tarreauc1f47532005-12-18 01:08:26 +01007043 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7044 if (err) {
7045 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7046 file, linenum, *err);
7047 return -1;
7048 }
willy tarreau982249e2005-12-18 00:57:06 +01007049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007050 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007051 regex_t *preg;
7052 if (curproxy == &defproxy) {
7053 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7054 return -1;
7055 }
willy tarreaue39cd132005-12-17 13:00:18 +01007056
willy tarreaua41a8b42005-12-17 14:02:24 +01007057 if (*(args[1]) == 0 || *(args[2]) == 0) {
7058 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7059 file, linenum, args[0]);
7060 return -1;
7061 }
willy tarreaue39cd132005-12-17 13:00:18 +01007062
willy tarreaua41a8b42005-12-17 14:02:24 +01007063 preg = calloc(1, sizeof(regex_t));
7064 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7065 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7066 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007067 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007068
willy tarreauc1f47532005-12-18 01:08:26 +01007069 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7070 if (err) {
7071 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7072 file, linenum, *err);
7073 return -1;
7074 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007076 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7077 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007078 if (curproxy == &defproxy) {
7079 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7080 return -1;
7081 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007082
7083 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007084 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007085 return -1;
7086 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007087
willy tarreau9fe663a2005-12-17 13:02:59 +01007088 preg = calloc(1, sizeof(regex_t));
7089 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007090 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007091 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007092 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007093
willy tarreauc1f47532005-12-18 01:08:26 +01007094 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7095 if (err) {
7096 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7097 file, linenum, *err);
7098 return -1;
7099 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007100 }
willy tarreau982249e2005-12-18 00:57:06 +01007101 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7102 regex_t *preg;
7103 if (curproxy == &defproxy) {
7104 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7105 return -1;
7106 }
7107
7108 if (*(args[1]) == 0) {
7109 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7110 return -1;
7111 }
7112
7113 preg = calloc(1, sizeof(regex_t));
7114 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7115 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7116 return -1;
7117 }
7118
willy tarreauc1f47532005-12-18 01:08:26 +01007119 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7120 if (err) {
7121 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7122 file, linenum, *err);
7123 return -1;
7124 }
willy tarreau982249e2005-12-18 00:57:06 +01007125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007126 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007127 if (curproxy == &defproxy) {
7128 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7129 return -1;
7130 }
7131
willy tarreau9fe663a2005-12-17 13:02:59 +01007132 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007133 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007134 return 0;
7135 }
7136
7137 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007138 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 return -1;
7140 }
7141
7142 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7143 }
willy tarreauc1f47532005-12-18 01:08:26 +01007144 else if (!strcmp(args[0], "errorloc") ||
7145 !strcmp(args[0], "errorloc302") ||
7146 !strcmp(args[0], "errorloc303")) { /* error location */
7147 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007148 char *err;
7149
willy tarreaueedaa9f2005-12-17 14:08:03 +01007150 // if (curproxy == &defproxy) {
7151 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7152 // return -1;
7153 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007154
willy tarreau8337c6b2005-12-17 13:41:01 +01007155 if (*(args[2]) == 0) {
7156 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7157 return -1;
7158 }
7159
7160 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007161 if (!strcmp(args[0], "errorloc303")) {
7162 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7163 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7164 } else {
7165 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7166 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7167 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007168
7169 if (errnum == 400) {
7170 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007171 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007172 free(curproxy->errmsg.msg400);
7173 }
7174 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007175 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007176 }
7177 else if (errnum == 403) {
7178 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007179 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007180 free(curproxy->errmsg.msg403);
7181 }
7182 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007183 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007184 }
7185 else if (errnum == 408) {
7186 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007187 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007188 free(curproxy->errmsg.msg408);
7189 }
7190 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007191 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007192 }
7193 else if (errnum == 500) {
7194 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007195 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007196 free(curproxy->errmsg.msg500);
7197 }
7198 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007199 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007200 }
7201 else if (errnum == 502) {
7202 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007203 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007204 free(curproxy->errmsg.msg502);
7205 }
7206 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007207 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007208 }
7209 else if (errnum == 503) {
7210 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007211 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007212 free(curproxy->errmsg.msg503);
7213 }
7214 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007215 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007216 }
7217 else if (errnum == 504) {
7218 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007219 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007220 free(curproxy->errmsg.msg504);
7221 }
7222 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007223 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007224 }
7225 else {
7226 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7227 free(err);
7228 }
7229 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007230 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007231 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007232 return -1;
7233 }
7234 return 0;
7235}
willy tarreaue39cd132005-12-17 13:00:18 +01007236
willy tarreau5cbea6f2005-12-17 12:48:26 +01007237
willy tarreau9fe663a2005-12-17 13:02:59 +01007238/*
7239 * This function reads and parses the configuration file given in the argument.
7240 * returns 0 if OK, -1 if error.
7241 */
7242int readcfgfile(char *file) {
7243 char thisline[256];
7244 char *line;
7245 FILE *f;
7246 int linenum = 0;
7247 char *end;
7248 char *args[MAX_LINE_ARGS];
7249 int arg;
7250 int cfgerr = 0;
7251 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007252
willy tarreau9fe663a2005-12-17 13:02:59 +01007253 struct proxy *curproxy = NULL;
7254 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007255
willy tarreau9fe663a2005-12-17 13:02:59 +01007256 if ((f=fopen(file,"r")) == NULL)
7257 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007258
willy tarreaueedaa9f2005-12-17 14:08:03 +01007259 init_default_instance();
7260
willy tarreau9fe663a2005-12-17 13:02:59 +01007261 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7262 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007263
willy tarreau9fe663a2005-12-17 13:02:59 +01007264 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007265
willy tarreau9fe663a2005-12-17 13:02:59 +01007266 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007267 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007268 line++;
7269
7270 arg = 0;
7271 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007272
willy tarreau9fe663a2005-12-17 13:02:59 +01007273 while (*line && arg < MAX_LINE_ARGS) {
7274 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7275 * C equivalent value. Other combinations left unchanged (eg: \1).
7276 */
7277 if (*line == '\\') {
7278 int skip = 0;
7279 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7280 *line = line[1];
7281 skip = 1;
7282 }
7283 else if (line[1] == 'r') {
7284 *line = '\r';
7285 skip = 1;
7286 }
7287 else if (line[1] == 'n') {
7288 *line = '\n';
7289 skip = 1;
7290 }
7291 else if (line[1] == 't') {
7292 *line = '\t';
7293 skip = 1;
7294 }
willy tarreauc1f47532005-12-18 01:08:26 +01007295 else if (line[1] == 'x') {
7296 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7297 unsigned char hex1, hex2;
7298 hex1 = toupper(line[2]) - '0';
7299 hex2 = toupper(line[3]) - '0';
7300 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7301 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7302 *line = (hex1<<4) + hex2;
7303 skip = 3;
7304 }
7305 else {
7306 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7307 return -1;
7308 }
7309 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007310 if (skip) {
7311 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7312 end -= skip;
7313 }
7314 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007315 }
willy tarreaua1598082005-12-17 13:08:06 +01007316 else if (*line == '#' || *line == '\n' || *line == '\r') {
7317 /* end of string, end of loop */
7318 *line = 0;
7319 break;
7320 }
willy tarreauc29948c2005-12-17 13:10:27 +01007321 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007322 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007323 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007324 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007325 line++;
7326 args[++arg] = line;
7327 }
7328 else {
7329 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007330 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007331 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007332
willy tarreau9fe663a2005-12-17 13:02:59 +01007333 /* empty line */
7334 if (!**args)
7335 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007336
willy tarreau9fe663a2005-12-17 13:02:59 +01007337 /* zero out remaining args */
7338 while (++arg < MAX_LINE_ARGS) {
7339 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007340 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007341
willy tarreaua41a8b42005-12-17 14:02:24 +01007342 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007343 confsect = CFG_LISTEN;
7344 else if (!strcmp(args[0], "global")) /* global config */
7345 confsect = CFG_GLOBAL;
7346 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007347
willy tarreau9fe663a2005-12-17 13:02:59 +01007348 switch (confsect) {
7349 case CFG_LISTEN:
7350 if (cfg_parse_listen(file, linenum, args) < 0)
7351 return -1;
7352 break;
7353 case CFG_GLOBAL:
7354 if (cfg_parse_global(file, linenum, args) < 0)
7355 return -1;
7356 break;
7357 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007358 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007359 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007360 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007361
7362
willy tarreau0f7af912005-12-17 12:21:26 +01007363 }
7364 fclose(f);
7365
7366 /*
7367 * Now, check for the integrity of all that we have collected.
7368 */
7369
7370 if ((curproxy = proxy) == NULL) {
7371 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7372 file);
7373 return -1;
7374 }
7375
7376 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007377 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007378 if (curproxy->state == PR_STDISABLED) {
7379 curproxy = curproxy->next;
7380 continue;
7381 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007382
7383 if (curproxy->listen == NULL) {
7384 Alert("parsing %s : listener %s has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", file, curproxy->id);
7385 cfgerr++;
7386 }
7387 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007388 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007389 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007390 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7391 file, curproxy->id);
7392 cfgerr++;
7393 }
7394 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7395 if (curproxy->options & PR_O_TRANSP) {
7396 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7397 file, curproxy->id);
7398 cfgerr++;
7399 }
7400 else if (curproxy->srv == NULL) {
7401 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7402 file, curproxy->id);
7403 cfgerr++;
7404 }
willy tarreaua1598082005-12-17 13:08:06 +01007405 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007406 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7407 file, curproxy->id);
7408 }
7409 }
7410 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007411 if (curproxy->cookie_name != NULL) {
7412 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7413 file, curproxy->id);
7414 }
7415 if ((newsrv = curproxy->srv) != NULL) {
7416 Warning("parsing %s : servers will be ignored for listener %s.\n",
7417 file, curproxy->id);
7418 }
willy tarreaue39cd132005-12-17 13:00:18 +01007419 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007420 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7421 file, curproxy->id);
7422 }
willy tarreaue39cd132005-12-17 13:00:18 +01007423 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007424 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7425 file, curproxy->id);
7426 }
7427 }
7428 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7429 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7430 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7431 file, curproxy->id);
7432 cfgerr++;
7433 }
7434 else {
7435 while (newsrv != NULL) {
7436 /* nothing to check for now */
7437 newsrv = newsrv->next;
7438 }
7439 }
7440 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007441
7442 if (curproxy->options & PR_O_LOGASAP)
7443 curproxy->to_log &= ~LW_BYTES;
7444
willy tarreau8337c6b2005-12-17 13:41:01 +01007445 if (curproxy->errmsg.msg400 == NULL) {
7446 curproxy->errmsg.msg400 = (char *)HTTP_400;
7447 curproxy->errmsg.len400 = strlen(HTTP_400);
7448 }
7449 if (curproxy->errmsg.msg403 == NULL) {
7450 curproxy->errmsg.msg403 = (char *)HTTP_403;
7451 curproxy->errmsg.len403 = strlen(HTTP_403);
7452 }
7453 if (curproxy->errmsg.msg408 == NULL) {
7454 curproxy->errmsg.msg408 = (char *)HTTP_408;
7455 curproxy->errmsg.len408 = strlen(HTTP_408);
7456 }
7457 if (curproxy->errmsg.msg500 == NULL) {
7458 curproxy->errmsg.msg500 = (char *)HTTP_500;
7459 curproxy->errmsg.len500 = strlen(HTTP_500);
7460 }
7461 if (curproxy->errmsg.msg502 == NULL) {
7462 curproxy->errmsg.msg502 = (char *)HTTP_502;
7463 curproxy->errmsg.len502 = strlen(HTTP_502);
7464 }
7465 if (curproxy->errmsg.msg503 == NULL) {
7466 curproxy->errmsg.msg503 = (char *)HTTP_503;
7467 curproxy->errmsg.len503 = strlen(HTTP_503);
7468 }
7469 if (curproxy->errmsg.msg504 == NULL) {
7470 curproxy->errmsg.msg504 = (char *)HTTP_504;
7471 curproxy->errmsg.len504 = strlen(HTTP_504);
7472 }
willy tarreau0f7af912005-12-17 12:21:26 +01007473 curproxy = curproxy->next;
7474 }
7475 if (cfgerr > 0) {
7476 Alert("Errors found in configuration file, aborting.\n");
7477 return -1;
7478 }
7479 else
7480 return 0;
7481}
7482
7483
7484/*
7485 * This function initializes all the necessary variables. It only returns
7486 * if everything is OK. If something fails, it exits.
7487 */
7488void init(int argc, char **argv) {
7489 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007490 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007491 char *old_argv = *argv;
7492 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007493 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007494 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007495
7496 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007497 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007498 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007499 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007500 exit(1);
7501 }
7502
willy tarreau4302f492005-12-18 01:00:37 +01007503 /* initialize the log header encoding map : '{|}"#' should be encoded with
7504 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7505 * URL encoding only requires '"', '#' to be encoded as well as non-
7506 * printable characters above.
7507 */
7508 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7509 memset(url_encode_map, 0, sizeof(url_encode_map));
7510 for (i = 0; i < 32; i++) {
7511 FD_SET(i, hdr_encode_map);
7512 FD_SET(i, url_encode_map);
7513 }
7514 for (i = 127; i < 256; i++) {
7515 FD_SET(i, hdr_encode_map);
7516 FD_SET(i, url_encode_map);
7517 }
7518
7519 tmp = "\"#{|}";
7520 while (*tmp) {
7521 FD_SET(*tmp, hdr_encode_map);
7522 tmp++;
7523 }
7524
7525 tmp = "\"#";
7526 while (*tmp) {
7527 FD_SET(*tmp, url_encode_map);
7528 tmp++;
7529 }
7530
willy tarreau64a3cc32005-12-18 01:13:11 +01007531 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7532#if defined(ENABLE_POLL)
7533 cfg_polling_mechanism |= POLL_USE_POLL;
7534#endif
7535#if defined(ENABLE_EPOLL)
7536 cfg_polling_mechanism |= POLL_USE_EPOLL;
7537#endif
7538
willy tarreau0f7af912005-12-17 12:21:26 +01007539 pid = getpid();
7540 progname = *argv;
7541 while ((tmp = strchr(progname, '/')) != NULL)
7542 progname = tmp + 1;
7543
7544 argc--; argv++;
7545 while (argc > 0) {
7546 char *flag;
7547
7548 if (**argv == '-') {
7549 flag = *argv+1;
7550
7551 /* 1 arg */
7552 if (*flag == 'v') {
7553 display_version();
7554 exit(0);
7555 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007556#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007557 else if (*flag == 'd' && flag[1] == 'e')
7558 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007559#endif
7560#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007561 else if (*flag == 'd' && flag[1] == 'p')
7562 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007563#endif
willy tarreau982249e2005-12-18 00:57:06 +01007564 else if (*flag == 'V')
7565 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007566 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007567 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007568 else if (*flag == 'c')
7569 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007570 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007571 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007572 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007573 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007574#if STATTIME > 0
7575 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007576 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007577 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007578 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007579#endif
7580 else { /* >=2 args */
7581 argv++; argc--;
7582 if (argc == 0)
7583 usage(old_argv);
7584
7585 switch (*flag) {
7586 case 'n' : cfg_maxconn = atol(*argv); break;
7587 case 'N' : cfg_maxpconn = atol(*argv); break;
7588 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007589 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007590 default: usage(old_argv);
7591 }
7592 }
7593 }
7594 else
7595 usage(old_argv);
7596 argv++; argc--;
7597 }
7598
willy tarreaud0fb4652005-12-18 01:32:04 +01007599 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7600 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007601
willy tarreau0f7af912005-12-17 12:21:26 +01007602 if (!cfg_cfgfile)
7603 usage(old_argv);
7604
7605 gethostname(hostname, MAX_HOSTNAME_LEN);
7606
willy tarreau12350152005-12-18 01:03:27 +01007607 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007608 if (readcfgfile(cfg_cfgfile) < 0) {
7609 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7610 exit(1);
7611 }
willy tarreau12350152005-12-18 01:03:27 +01007612 if (have_appsession)
7613 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007614
willy tarreau982249e2005-12-18 00:57:06 +01007615 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007616 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7617 exit(0);
7618 }
7619
willy tarreau9fe663a2005-12-17 13:02:59 +01007620 if (cfg_maxconn > 0)
7621 global.maxconn = cfg_maxconn;
7622
willy tarreaufe2c5c12005-12-17 14:14:34 +01007623 if (cfg_pidfile) {
7624 if (global.pidfile)
7625 free(global.pidfile);
7626 global.pidfile = strdup(cfg_pidfile);
7627 }
7628
willy tarreau9fe663a2005-12-17 13:02:59 +01007629 if (global.maxconn == 0)
7630 global.maxconn = DEFAULT_MAXCONN;
7631
7632 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7633
7634 if (arg_mode & MODE_DEBUG) {
7635 /* command line debug mode inhibits configuration mode */
7636 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7637 }
willy tarreau982249e2005-12-18 00:57:06 +01007638 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7639 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007640
7641 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7642 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7643 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7644 }
7645
7646 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7647 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7648 global.nbproc = 1;
7649 }
7650
7651 if (global.nbproc < 1)
7652 global.nbproc = 1;
7653
willy tarreau0f7af912005-12-17 12:21:26 +01007654 StaticReadEvent = (fd_set *)calloc(1,
7655 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007656 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007657 StaticWriteEvent = (fd_set *)calloc(1,
7658 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007659 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007660
7661 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007662 sizeof(struct fdtab) * (global.maxsock));
7663 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007664 fdtab[i].state = FD_STCLOSE;
7665 }
7666}
7667
7668/*
7669 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7670 */
7671int start_proxies() {
7672 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007673 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007674 int fd;
7675
7676 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007677 if (curproxy->state == PR_STDISABLED)
7678 continue;
7679
willy tarreaua41a8b42005-12-17 14:02:24 +01007680 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7681 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007682 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007683 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7684 curproxy->id);
7685 return -1;
7686 }
willy tarreau0f7af912005-12-17 12:21:26 +01007687
willy tarreaua41a8b42005-12-17 14:02:24 +01007688 if (fd >= global.maxsock) {
7689 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7690 curproxy->id);
7691 close(fd);
7692 return -1;
7693 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007694
willy tarreaua41a8b42005-12-17 14:02:24 +01007695 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7696 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7697 (char *) &one, sizeof(one)) == -1)) {
7698 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7699 curproxy->id);
7700 close(fd);
7701 return -1;
7702 }
willy tarreau0f7af912005-12-17 12:21:26 +01007703
willy tarreaua41a8b42005-12-17 14:02:24 +01007704 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7705 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7706 curproxy->id);
7707 }
willy tarreau0f7af912005-12-17 12:21:26 +01007708
willy tarreaua41a8b42005-12-17 14:02:24 +01007709 if (bind(fd,
7710 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007711 listener->addr.ss_family == AF_INET6 ?
7712 sizeof(struct sockaddr_in6) :
7713 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007714 Alert("cannot bind socket for proxy %s. Aborting.\n",
7715 curproxy->id);
7716 close(fd);
7717 return -1;
7718 }
willy tarreau0f7af912005-12-17 12:21:26 +01007719
willy tarreaua41a8b42005-12-17 14:02:24 +01007720 if (listen(fd, curproxy->maxconn) == -1) {
7721 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7722 curproxy->id);
7723 close(fd);
7724 return -1;
7725 }
willy tarreau0f7af912005-12-17 12:21:26 +01007726
willy tarreaua41a8b42005-12-17 14:02:24 +01007727 /* the function for the accept() event */
7728 fdtab[fd].read = &event_accept;
7729 fdtab[fd].write = NULL; /* never called */
7730 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7731 curproxy->state = PR_STRUN;
7732 fdtab[fd].state = FD_STLISTEN;
7733 FD_SET(fd, StaticReadEvent);
7734 fd_insert(fd);
7735 listeners++;
7736 }
willy tarreaua1598082005-12-17 13:08:06 +01007737 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007738 }
7739 return 0;
7740}
7741
willy tarreaub952e1d2005-12-18 01:31:20 +01007742int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007743
7744 appsess *temp1,*temp2;
7745 temp1 = (appsess *)key1;
7746 temp2 = (appsess *)key2;
7747
7748 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7749 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7750
7751 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7752}/* end match_str */
7753
willy tarreaub952e1d2005-12-18 01:31:20 +01007754void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007755 appsess *temp1;
7756
7757 //printf("destroy called\n");
7758 temp1 = (appsess *)data;
7759
7760 if (temp1->sessid)
7761 pool_free_to(apools.sessid, temp1->sessid);
7762
7763 if (temp1->serverid)
7764 pool_free_to(apools.serverid, temp1->serverid);
7765
7766 pool_free(appsess, temp1);
7767} /* end destroy */
7768
7769void appsession_cleanup( void )
7770{
7771 struct proxy *p = proxy;
7772
7773 while(p) {
7774 chtbl_destroy(&(p->htbl_proxy));
7775 p = p->next;
7776 }
7777}/* end appsession_cleanup() */
7778
7779void pool_destroy(void **pool)
7780{
7781 void *temp, *next;
7782 next = pool;
7783 while (next) {
7784 temp = next;
7785 next = *(void **)temp;
7786 free(temp);
7787 }
7788}/* end pool_destroy() */
7789
willy tarreaub952e1d2005-12-18 01:31:20 +01007790void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01007791 struct proxy *p = proxy;
7792 struct cap_hdr *h,*h_next;
7793 struct server *s,*s_next;
7794 struct listener *l,*l_next;
7795
7796 while (p) {
7797 if (p->id)
7798 free(p->id);
7799
7800 if (p->check_req)
7801 free(p->check_req);
7802
7803 if (p->cookie_name)
7804 free(p->cookie_name);
7805
7806 if (p->capture_name)
7807 free(p->capture_name);
7808
7809 /* only strup if the user have set in config.
7810 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01007811 if (p->errmsg.msg400) free(p->errmsg.msg400);
7812 if (p->errmsg.msg403) free(p->errmsg.msg403);
7813 if (p->errmsg.msg408) free(p->errmsg.msg408);
7814 if (p->errmsg.msg500) free(p->errmsg.msg500);
7815 if (p->errmsg.msg502) free(p->errmsg.msg502);
7816 if (p->errmsg.msg503) free(p->errmsg.msg503);
7817 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01007818 */
7819 if (p->appsession_name)
7820 free(p->appsession_name);
7821
7822 h = p->req_cap;
7823 while (h) {
7824 h_next = h->next;
7825 if (h->name)
7826 free(h->name);
7827 pool_destroy(h->pool);
7828 free(h);
7829 h = h_next;
7830 }/* end while(h) */
7831
7832 h = p->rsp_cap;
7833 while (h) {
7834 h_next = h->next;
7835 if (h->name)
7836 free(h->name);
7837
7838 pool_destroy(h->pool);
7839 free(h);
7840 h = h_next;
7841 }/* end while(h) */
7842
7843 s = p->srv;
7844 while (s) {
7845 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01007846 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01007847 free(s->id);
7848
willy tarreaub952e1d2005-12-18 01:31:20 +01007849 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01007850 free(s->cookie);
7851
7852 free(s);
7853 s = s_next;
7854 }/* end while(s) */
7855
7856 l = p->listen;
7857 while (l) {
7858 l_next = l->next;
7859 free(l);
7860 l = l_next;
7861 }/* end while(l) */
7862
7863 pool_destroy((void **) p->req_cap_pool);
7864 pool_destroy((void **) p->rsp_cap_pool);
7865 p = p->next;
7866 }/* end while(p) */
7867
7868 if (global.chroot) free(global.chroot);
7869 if (global.pidfile) free(global.pidfile);
7870
willy tarreau12350152005-12-18 01:03:27 +01007871 if (StaticReadEvent) free(StaticReadEvent);
7872 if (StaticWriteEvent) free(StaticWriteEvent);
7873 if (fdtab) free(fdtab);
7874
7875 pool_destroy(pool_session);
7876 pool_destroy(pool_buffer);
7877 pool_destroy(pool_fdtab);
7878 pool_destroy(pool_requri);
7879 pool_destroy(pool_task);
7880 pool_destroy(pool_capture);
7881 pool_destroy(pool_appsess);
7882
7883 if (have_appsession) {
7884 pool_destroy(apools.serverid);
7885 pool_destroy(apools.sessid);
7886 }
7887} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007888
7889int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007890 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007891 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007892 init(argc, argv);
7893
willy tarreau0f7af912005-12-17 12:21:26 +01007894 signal(SIGQUIT, dump);
7895 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007896 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007897#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007898 signal(SIGINT, sig_int);
7899 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007900#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007901
7902 /* on very high loads, a sigpipe sometimes happen just between the
7903 * getsockopt() which tells "it's OK to write", and the following write :-(
7904 */
willy tarreau3242e862005-12-17 12:27:53 +01007905#ifndef MSG_NOSIGNAL
7906 signal(SIGPIPE, SIG_IGN);
7907#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007908
willy tarreaud0fb4652005-12-18 01:32:04 +01007909 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01007910 if (start_proxies() < 0)
7911 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01007912
7913 if (listeners == 0) {
7914 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
7915 exit(1);
7916 }
7917
7918 /* MODE_QUIET can inhibit alerts and warnings below this line */
7919
7920 global.mode &= ~MODE_STARTING;
7921 if (global.mode & MODE_QUIET) {
7922 /* detach from the tty */
7923 fclose(stdin); fclose(stdout); fclose(stderr);
7924 close(0); close(1); close(2);
7925 }
willy tarreau0f7af912005-12-17 12:21:26 +01007926
willy tarreaufe2c5c12005-12-17 14:14:34 +01007927 /* open log & pid files before the chroot */
7928 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7929 int pidfd;
7930 unlink(global.pidfile);
7931 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7932 if (pidfd < 0) {
7933 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7934 exit(1);
7935 }
7936 pidfile = fdopen(pidfd, "w");
7937 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007938
7939 /* chroot if needed */
7940 if (global.chroot != NULL) {
7941 if (chroot(global.chroot) == -1) {
7942 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7943 exit(1);
7944 }
7945 chdir("/");
7946 }
7947
willy tarreaub1285d52005-12-18 01:20:14 +01007948 /* ulimits */
7949 if (global.rlimit_nofile) {
7950 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7951 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7952 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7953 }
7954 }
7955
willy tarreau9fe663a2005-12-17 13:02:59 +01007956 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007957 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007958 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7959 exit(1);
7960 }
7961
willy tarreau036e1ce2005-12-17 13:46:33 +01007962 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007963 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7964 exit(1);
7965 }
7966
willy tarreaub1285d52005-12-18 01:20:14 +01007967 /* check ulimits */
7968 limit.rlim_cur = limit.rlim_max = 0;
7969 getrlimit(RLIMIT_NOFILE, &limit);
7970 if (limit.rlim_cur < global.maxsock) {
7971 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",
7972 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
7973 }
7974
willy tarreau9fe663a2005-12-17 13:02:59 +01007975 if (global.mode & MODE_DAEMON) {
7976 int ret = 0;
7977 int proc;
7978
7979 /* the father launches the required number of processes */
7980 for (proc = 0; proc < global.nbproc; proc++) {
7981 ret = fork();
7982 if (ret < 0) {
7983 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7984 exit(1); /* there has been an error */
7985 }
7986 else if (ret == 0) /* child breaks here */
7987 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007988 if (pidfile != NULL) {
7989 fprintf(pidfile, "%d\n", ret);
7990 fflush(pidfile);
7991 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007992 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007993 /* close the pidfile both in children and father */
7994 if (pidfile != NULL)
7995 fclose(pidfile);
7996 free(global.pidfile);
7997
willy tarreau9fe663a2005-12-17 13:02:59 +01007998 if (proc == global.nbproc)
7999 exit(0); /* parent must leave */
8000
willy tarreau750a4722005-12-17 13:21:24 +01008001 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8002 * that we can detach from the TTY. We MUST NOT do it in other cases since
8003 * it would have already be done, and 0-2 would have been affected to listening
8004 * sockets
8005 */
8006 if (!(global.mode & MODE_QUIET)) {
8007 /* detach from the tty */
8008 fclose(stdin); fclose(stdout); fclose(stderr);
8009 close(0); close(1); close(2); /* close all fd's */
8010 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8011 }
willy tarreaua1598082005-12-17 13:08:06 +01008012 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008013 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008014 }
8015
willy tarreau1c2ad212005-12-18 01:11:29 +01008016#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008017 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008018 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8019 epoll_loop(POLL_LOOP_ACTION_RUN);
8020 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008021 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008022 }
8023 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008024 Warning("epoll() is not available. Using poll()/select() instead.\n");
8025 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008026 }
8027 }
8028#endif
8029
8030#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008031 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008032 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8033 poll_loop(POLL_LOOP_ACTION_RUN);
8034 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008035 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008036 }
8037 else {
8038 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008039 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008040 }
8041 }
8042#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008043 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008044 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8045 select_loop(POLL_LOOP_ACTION_RUN);
8046 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008047 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008048 }
8049 }
8050
willy tarreau0f7af912005-12-17 12:21:26 +01008051
willy tarreau12350152005-12-18 01:03:27 +01008052 /* Free all Hash Keys and all Hash elements */
8053 appsession_cleanup();
8054 /* Do some cleanup */
8055 deinit();
8056
willy tarreau0f7af912005-12-17 12:21:26 +01008057 exit(0);
8058}
willy tarreau12350152005-12-18 01:03:27 +01008059
8060#if defined(DEBUG_HASH)
8061static void print_table(const CHTbl *htbl) {
8062
8063 ListElmt *element;
8064 int i;
8065 appsess *asession;
8066
8067 /*****************************************************************************
8068 * *
8069 * Display the chained hash table. *
8070 * *
8071 *****************************************************************************/
8072
8073 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8074
8075 for (i = 0; i < TBLSIZ; i++) {
8076 fprintf(stdout, "Bucket[%03d]\n", i);
8077
8078 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8079 //fprintf(stdout, "%c", *(char *)list_data(element));
8080 asession = (appsess *)list_data(element);
8081 fprintf(stdout, "ELEM :%s:", asession->sessid);
8082 fprintf(stdout, " Server :%s: \n", asession->serverid);
8083 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8084 }
8085
8086 fprintf(stdout, "\n");
8087 }
8088 return;
8089} /* end print_table */
8090#endif
8091
8092static int appsession_init(void)
8093{
8094 static int initialized = 0;
8095 int idlen;
8096 struct server *s;
8097 struct proxy *p = proxy;
8098
8099 if (!initialized) {
8100 if (!appsession_task_init()) {
8101 apools.sessid = NULL;
8102 apools.serverid = NULL;
8103 apools.ser_waste = 0;
8104 apools.ser_use = 0;
8105 apools.ser_msize = sizeof(void *);
8106 apools.ses_waste = 0;
8107 apools.ses_use = 0;
8108 apools.ses_msize = sizeof(void *);
8109 while (p) {
8110 s = p->srv;
8111 if (apools.ses_msize < p->appsession_len)
8112 apools.ses_msize = p->appsession_len;
8113 while (s) {
8114 idlen = strlen(s->id);
8115 if (apools.ser_msize < idlen)
8116 apools.ser_msize = idlen;
8117 s = s->next;
8118 }
8119 p = p->next;
8120 }
8121 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8122 apools.ses_msize ++;
8123 }
8124 else {
8125 fprintf(stderr, "appsession_task_init failed\n");
8126 return -1;
8127 }
8128 initialized ++;
8129 }
8130 return 0;
8131}
8132
8133static int appsession_task_init(void)
8134{
8135 static int initialized = 0;
8136 struct task *t;
8137 if (!initialized) {
8138 if ((t = pool_alloc(task)) == NULL)
8139 return -1;
8140 t->next = t->prev = t->rqnext = NULL;
8141 t->wq = LIST_HEAD(wait_queue);
8142 t->state = TASK_IDLE;
8143 t->context = NULL;
8144 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8145 task_queue(t);
8146 t->process = appsession_refresh;
8147 initialized ++;
8148 }
8149 return 0;
8150}
8151
8152static int appsession_refresh(struct task *t) {
8153 struct proxy *p = proxy;
8154 CHTbl *htbl;
8155 ListElmt *element, *last;
8156 int i;
8157 appsess *asession;
8158 void *data;
8159
8160 while (p) {
8161 if (p->appsession_name != NULL) {
8162 htbl = &p->htbl_proxy;
8163 /* if we ever give up the use of TBLSIZ, we need to change this */
8164 for (i = 0; i < TBLSIZ; i++) {
8165 last = NULL;
8166 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8167 asession = (appsess *)list_data(element);
8168 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8169 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8170 int len;
8171 /*
8172 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8173 */
8174 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8175 asession->sessid, asession->serverid?asession->serverid:"(null)");
8176 write(1, trash, len);
8177 }
8178 /* delete the expired element from within the hash table */
8179 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8180 && (htbl->table[i].destroy != NULL)) {
8181 htbl->table[i].destroy(data);
8182 }
8183 if (last == NULL) {/* patient lost his head, get a new one */
8184 element = list_head(&htbl->table[i]);
8185 if (element == NULL) break; /* no heads left, go to next patient */
8186 }
8187 else
8188 element = last;
8189 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8190 else
8191 last = element;
8192 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8193 }
8194 }
8195 p = p->next;
8196 }
8197 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8198 return TBLCHKINT;
8199} /* end appsession_refresh */
8200