blob: cf9872e1137a1b4677c4dfe2cf2f610a5b7222ae [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 tarreau48b06592005-12-18 01:37:12 +01002284 if (s->srv_state == SV_STCONN) {
2285 int skerr;
2286 socklen_t lskerr = sizeof(skerr);
2287 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2288 if (skerr) {
2289 s->res_sw = RES_ERROR;
2290 fdtab[fd].state = FD_STERROR;
2291 task_wakeup(&rq, t);
2292 tv_eternity(&s->swexpire);
2293 FD_CLR(fd, StaticWriteEvent);
2294 return 0;
2295 }
2296 }
2297
willy tarreau0f7af912005-12-17 12:21:26 +01002298 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002299 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002300 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002301 tv_eternity(&s->swexpire);
2302 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002303 return 0;
2304 }
2305
willy tarreau3242e862005-12-17 12:27:53 +01002306#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002307 {
2308 int skerr;
2309 socklen_t lskerr = sizeof(skerr);
2310 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2311 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002312 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002313 else
willy tarreau3242e862005-12-17 12:27:53 +01002314 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002315 }
willy tarreau3242e862005-12-17 12:27:53 +01002316#else
willy tarreau0f7af912005-12-17 12:21:26 +01002317 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002318#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002319 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002320 if (ret > 0) {
2321 b->l -= ret;
2322 b->w += ret;
2323
2324 s->res_sw = RES_DATA;
2325
2326 if (b->w == b->data + BUFSIZE) {
2327 b->w = b->data; /* wrap around the buffer */
2328 }
2329 }
2330 else if (ret == 0) {
2331 /* nothing written, just make as if we were never called */
2332 // s->res_sw = RES_NULL;
2333 return 0;
2334 }
2335 else if (errno == EAGAIN) /* ignore EAGAIN */
2336 return 0;
2337 else {
2338 s->res_sw = RES_ERROR;
2339 fdtab[fd].state = FD_STERROR;
2340 }
2341 }
2342 else {
2343 s->res_sw = RES_ERROR;
2344 fdtab[fd].state = FD_STERROR;
2345 }
2346
willy tarreaub1ff9db2005-12-17 13:51:03 +01002347 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002348 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002349 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2350 s->srexpire = s->swexpire;
2351 }
willy tarreau0f7af912005-12-17 12:21:26 +01002352 else
2353 tv_eternity(&s->swexpire);
2354
willy tarreau5cbea6f2005-12-17 12:48:26 +01002355 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002356 return 0;
2357}
2358
2359
2360/*
willy tarreaue39cd132005-12-17 13:00:18 +01002361 * returns a message to the client ; the connection is shut down for read,
2362 * and the request is cleared so that no server connection can be initiated.
2363 * The client must be in a valid state for this (HEADER, DATA ...).
2364 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002365 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002366 */
2367void client_retnclose(struct session *s, int len, const char *msg) {
2368 FD_CLR(s->cli_fd, StaticReadEvent);
2369 FD_SET(s->cli_fd, StaticWriteEvent);
2370 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002371 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002372 shutdown(s->cli_fd, SHUT_RD);
2373 s->cli_state = CL_STSHUTR;
2374 strcpy(s->rep->data, msg);
2375 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002376 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002377 s->rep->r += len;
2378 s->req->l = 0;
2379}
2380
2381
2382/*
2383 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002384 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002385 */
2386void client_return(struct session *s, int len, const char *msg) {
2387 strcpy(s->rep->data, msg);
2388 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002389 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002390 s->rep->r += len;
2391 s->req->l = 0;
2392}
2393
willy tarreau9fe663a2005-12-17 13:02:59 +01002394/*
2395 * send a log for the session when we have enough info about it
2396 */
2397void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002398 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002399 struct proxy *p = s->proxy;
2400 int log;
2401 char *uri;
2402 char *pxid;
2403 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002404 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002405
2406 /* This is a first attempt at a better logging system.
2407 * For now, we rely on send_log() to provide the date, although it obviously
2408 * is the date of the log and not of the request, and most fields are not
2409 * computed.
2410 */
2411
willy tarreaua1598082005-12-17 13:08:06 +01002412 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002413
willy tarreau8a86dbf2005-12-18 00:45:59 +01002414 if (s->cli_addr.ss_family == AF_INET)
2415 inet_ntop(AF_INET,
2416 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2417 pn, sizeof(pn));
2418 else
2419 inet_ntop(AF_INET6,
2420 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2421 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002422
willy tarreauc1cae632005-12-17 14:12:23 +01002423 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002424 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002425 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002426
willy tarreauc1cae632005-12-17 14:12:23 +01002427 tm = localtime(&s->logs.tv_accept.tv_sec);
2428 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002429 char tmpline[MAX_SYSLOG_LEN], *h;
2430 int hdr;
2431
2432 h = tmpline;
2433 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2434 *(h++) = ' ';
2435 *(h++) = '{';
2436 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2437 if (hdr)
2438 *(h++) = '|';
2439 if (s->req_cap[hdr] != NULL)
2440 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2441 }
2442 *(h++) = '}';
2443 }
2444
2445 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2446 *(h++) = ' ';
2447 *(h++) = '{';
2448 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2449 if (hdr)
2450 *(h++) = '|';
2451 if (s->rsp_cap[hdr] != NULL)
2452 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2453 }
2454 *(h++) = '}';
2455 }
2456
2457 if (h < tmpline + sizeof(tmpline) - 4) {
2458 *(h++) = ' ';
2459 *(h++) = '"';
2460 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2461 *(h++) = '"';
2462 }
2463 *h = '\0';
2464
willy tarreau0fe39652005-12-18 01:25:24 +01002465 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 +01002466 pn,
2467 (s->cli_addr.ss_family == AF_INET) ?
2468 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2469 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002470 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2471 tm->tm_hour, tm->tm_min, tm->tm_sec,
2472 pxid, srv,
2473 s->logs.t_request,
2474 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2475 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002476 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2477 s->logs.status,
2478 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002479 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2480 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002481 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2482 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2483 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2484 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002485 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002486 }
2487 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002488 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 +01002489 pn,
2490 (s->cli_addr.ss_family == AF_INET) ?
2491 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2492 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002493 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2494 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002495 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002496 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002497 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2498 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002499 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002500 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2501 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002502 }
2503
2504 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002505}
2506
willy tarreaue39cd132005-12-17 13:00:18 +01002507
2508/*
willy tarreau0f7af912005-12-17 12:21:26 +01002509 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002510 * to an accept. It tries to accept as many connections as possible.
2511 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002512 */
2513int event_accept(int fd) {
2514 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002515 struct session *s;
2516 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002517 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002518
willy tarreau5cbea6f2005-12-17 12:48:26 +01002519 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002520 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002521 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002522
willy tarreaub1285d52005-12-18 01:20:14 +01002523 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2524 switch (errno) {
2525 case EAGAIN:
2526 case EINTR:
2527 case ECONNABORTED:
2528 return 0; /* nothing more to accept */
2529 case ENFILE:
2530 send_log(p, LOG_EMERG,
2531 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2532 p->id, maxfd);
2533 return 0;
2534 case EMFILE:
2535 send_log(p, LOG_EMERG,
2536 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2537 p->id, maxfd);
2538 return 0;
2539 case ENOBUFS:
2540 case ENOMEM:
2541 send_log(p, LOG_EMERG,
2542 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2543 p->id, maxfd);
2544 return 0;
2545 default:
2546 return 0;
2547 }
2548 }
willy tarreau0f7af912005-12-17 12:21:26 +01002549
willy tarreau5cbea6f2005-12-17 12:48:26 +01002550 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2551 Alert("out of memory in event_accept().\n");
2552 FD_CLR(fd, StaticReadEvent);
2553 p->state = PR_STIDLE;
2554 close(cfd);
2555 return 0;
2556 }
willy tarreau0f7af912005-12-17 12:21:26 +01002557
willy tarreaub1285d52005-12-18 01:20:14 +01002558 /* if this session comes from a known monitoring system, we want to ignore
2559 * it as soon as possible, which means closing it immediately for TCP.
2560 */
2561 s->flags = 0;
2562 if (addr.ss_family == AF_INET &&
2563 p->mon_mask.s_addr &&
2564 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2565 if (p->mode == PR_MODE_TCP) {
2566 close(cfd);
2567 pool_free(session, s);
2568 continue;
2569 }
2570 s->flags |= SN_MONITOR;
2571 }
2572
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2574 Alert("out of memory in event_accept().\n");
2575 FD_CLR(fd, StaticReadEvent);
2576 p->state = PR_STIDLE;
2577 close(cfd);
2578 pool_free(session, s);
2579 return 0;
2580 }
willy tarreau0f7af912005-12-17 12:21:26 +01002581
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002583 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002584 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2585 close(cfd);
2586 pool_free(task, t);
2587 pool_free(session, s);
2588 return 0;
2589 }
willy tarreau0f7af912005-12-17 12:21:26 +01002590
willy tarreau5cbea6f2005-12-17 12:48:26 +01002591 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2592 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2593 (char *) &one, sizeof(one)) == -1)) {
2594 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2595 close(cfd);
2596 pool_free(task, t);
2597 pool_free(session, s);
2598 return 0;
2599 }
willy tarreau0f7af912005-12-17 12:21:26 +01002600
willy tarreaub952e1d2005-12-18 01:31:20 +01002601 if (p->options & PR_O_TCP_CLI_KA)
2602 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2603
willy tarreau9fe663a2005-12-17 13:02:59 +01002604 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2605 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2606 t->state = TASK_IDLE;
2607 t->process = process_session;
2608 t->context = s;
2609
2610 s->task = t;
2611 s->proxy = p;
2612 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2613 s->srv_state = SV_STIDLE;
2614 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002615
willy tarreau9fe663a2005-12-17 13:02:59 +01002616 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2617 s->cli_fd = cfd;
2618 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002619 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002620 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002621
willy tarreaub1285d52005-12-18 01:20:14 +01002622 if (s->flags & SN_MONITOR)
2623 s->logs.logwait = 0;
2624 else
2625 s->logs.logwait = p->to_log;
2626
willy tarreaua1598082005-12-17 13:08:06 +01002627 s->logs.tv_accept = now;
2628 s->logs.t_request = -1;
2629 s->logs.t_connect = -1;
2630 s->logs.t_data = -1;
2631 s->logs.t_close = 0;
2632 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002633 s->logs.cli_cookie = NULL;
2634 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002635 s->logs.status = -1;
2636 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002637
willy tarreau2f6ba652005-12-17 13:57:42 +01002638 s->uniq_id = totalconn;
2639
willy tarreau4302f492005-12-18 01:00:37 +01002640 if (p->nb_req_cap > 0) {
2641 if ((s->req_cap =
2642 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2643 == NULL) { /* no memory */
2644 close(cfd); /* nothing can be done for this fd without memory */
2645 pool_free(task, t);
2646 pool_free(session, s);
2647 return 0;
2648 }
2649 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2650 }
2651 else
2652 s->req_cap = NULL;
2653
2654 if (p->nb_rsp_cap > 0) {
2655 if ((s->rsp_cap =
2656 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2657 == NULL) { /* no memory */
2658 if (s->req_cap != NULL)
2659 pool_free_to(p->req_cap_pool, s->req_cap);
2660 close(cfd); /* nothing can be done for this fd without memory */
2661 pool_free(task, t);
2662 pool_free(session, s);
2663 return 0;
2664 }
2665 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2666 }
2667 else
2668 s->rsp_cap = NULL;
2669
willy tarreau5cbea6f2005-12-17 12:48:26 +01002670 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2671 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002672 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002673 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002674
willy tarreau8a86dbf2005-12-18 00:45:59 +01002675 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002676 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002677 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002678 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002679
willy tarreau9fe663a2005-12-17 13:02:59 +01002680 if (p->to_log) {
2681 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002682 if (s->logs.logwait & LW_CLIP)
2683 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002684 sess_log(s);
2685 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002686 else if (s->cli_addr.ss_family == AF_INET) {
2687 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2688 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2689 sn, sizeof(sn)) &&
2690 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2691 pn, sizeof(pn))) {
2692 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2693 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2694 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2695 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2696 }
2697 }
2698 else {
2699 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2700 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2701 sn, sizeof(sn)) &&
2702 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2703 pn, sizeof(pn))) {
2704 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2705 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2706 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2707 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2708 }
2709 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002710 }
willy tarreau0f7af912005-12-17 12:21:26 +01002711
willy tarreau982249e2005-12-18 00:57:06 +01002712 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002713 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002714 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002715 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002716 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002717 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002718 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002719 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002720
willy tarreau8a86dbf2005-12-18 00:45:59 +01002721 if (s->cli_addr.ss_family == AF_INET) {
2722 char pn[INET_ADDRSTRLEN];
2723 inet_ntop(AF_INET,
2724 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2725 pn, sizeof(pn));
2726
2727 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2728 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2729 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2730 }
2731 else {
2732 char pn[INET6_ADDRSTRLEN];
2733 inet_ntop(AF_INET6,
2734 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2735 pn, sizeof(pn));
2736
2737 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2738 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2739 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2740 }
2741
willy tarreauef900ab2005-12-17 12:52:52 +01002742 write(1, trash, len);
2743 }
willy tarreau0f7af912005-12-17 12:21:26 +01002744
willy tarreau5cbea6f2005-12-17 12:48:26 +01002745 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002746 if (s->rsp_cap != NULL)
2747 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2748 if (s->req_cap != NULL)
2749 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002750 close(cfd); /* nothing can be done for this fd without memory */
2751 pool_free(task, t);
2752 pool_free(session, s);
2753 return 0;
2754 }
willy tarreau4302f492005-12-18 01:00:37 +01002755
willy tarreau5cbea6f2005-12-17 12:48:26 +01002756 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002757 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002758 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2759 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002760 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002761 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002762
willy tarreau5cbea6f2005-12-17 12:48:26 +01002763 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2764 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002765 if (s->rsp_cap != NULL)
2766 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2767 if (s->req_cap != NULL)
2768 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 close(cfd); /* nothing can be done for this fd without memory */
2770 pool_free(task, t);
2771 pool_free(session, s);
2772 return 0;
2773 }
2774 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002775 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002776 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 +01002777
willy tarreau5cbea6f2005-12-17 12:48:26 +01002778 fdtab[cfd].read = &event_cli_read;
2779 fdtab[cfd].write = &event_cli_write;
2780 fdtab[cfd].owner = t;
2781 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002782
willy tarreaub1285d52005-12-18 01:20:14 +01002783 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2784 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2785 /* Either we got a request from a monitoring system on an HTTP instance,
2786 * or we're in health check mode with the 'httpchk' option enabled. In
2787 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2788 */
2789 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2790 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2791 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002792 }
2793 else {
2794 FD_SET(cfd, StaticReadEvent);
2795 }
2796
willy tarreaub952e1d2005-12-18 01:31:20 +01002797#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2798 if (PrevReadEvent) {
2799 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2800 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2801 }
2802#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002803 fd_insert(cfd);
2804
2805 tv_eternity(&s->cnexpire);
2806 tv_eternity(&s->srexpire);
2807 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002808 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002809 tv_eternity(&s->cwexpire);
2810
willy tarreaub1285d52005-12-18 01:20:14 +01002811 if (s->proxy->clitimeout) {
2812 if (FD_ISSET(cfd, StaticReadEvent))
2813 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2814 if (FD_ISSET(cfd, StaticWriteEvent))
2815 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2816 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002817
willy tarreaub1285d52005-12-18 01:20:14 +01002818 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002819
2820 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002821
2822 if (p->mode != PR_MODE_HEALTH)
2823 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824
2825 p->nbconn++;
2826 actconn++;
2827 totalconn++;
2828
willy tarreaub952e1d2005-12-18 01:31:20 +01002829 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002830 } /* end of while (p->nbconn < p->maxconn) */
2831 return 0;
2832}
willy tarreau0f7af912005-12-17 12:21:26 +01002833
willy tarreau0f7af912005-12-17 12:21:26 +01002834
willy tarreau5cbea6f2005-12-17 12:48:26 +01002835/*
2836 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002837 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2838 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002839 * or -1 if an error occured.
2840 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002841int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 struct task *t = fdtab[fd].owner;
2843 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002844
willy tarreauc5f73ed2005-12-18 01:26:38 +01002845 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002846 socklen_t lskerr = sizeof(skerr);
2847
willy tarreau5cbea6f2005-12-17 12:48:26 +01002848 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002849 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002850 if (skerr)
2851 s->result = -1;
willy tarreaua4a583a2005-12-18 01:39:19 +01002852 else if (s->result != -1) {
2853 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002854 if (s->proxy->options & PR_O_HTTP_CHK) {
2855 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002856 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002857 * so we'll send the request, and won't wake the checker up now.
2858 */
2859#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002860 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002861#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002862 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002863#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002864 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002865 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2866 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2867 return 0;
2868 }
2869 else
2870 s->result = -1;
2871 }
2872 else {
2873 /* good TCP connection is enough */
2874 s->result = 1;
2875 }
2876 }
2877
2878 task_wakeup(&rq, t);
2879 return 0;
2880}
2881
willy tarreau0f7af912005-12-17 12:21:26 +01002882
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002883/*
2884 * This function is used only for server health-checks. It handles
2885 * the server's reply to an HTTP request. It returns 1 if the server replies
2886 * 2xx or 3xx (valid responses), or -1 in other cases.
2887 */
2888int event_srv_chk_r(int fd) {
2889 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002890 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002891 struct task *t = fdtab[fd].owner;
2892 struct server *s = t->context;
2893
willy tarreaua4a583a2005-12-18 01:39:19 +01002894 result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002895#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002896 {
2897 int skerr;
2898 socklen_t lskerr = sizeof(skerr);
2899
2900 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2901 if (!skerr)
2902 len = recv(fd, reply, sizeof(reply), 0);
2903 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002904#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002905 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2906 * but the connection was closed on the remote end. Fortunately, recv still
2907 * works correctly and we don't need to do the getsockopt() on linux.
2908 */
2909 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002910#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002911 if ((len >= sizeof("HTTP/1.0 000")) &&
2912 !memcmp(reply, "HTTP/1.", 7) &&
2913 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
willy tarreaua4a583a2005-12-18 01:39:19 +01002914 result = 1;
2915
2916 if (s->result != -1)
2917 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002918
2919 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002920 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002921 return 0;
2922}
2923
2924
2925/*
2926 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2927 * and moves <end> just after the end of <str>.
2928 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2929 * the shift value (positive or negative) is returned.
2930 * If there's no space left, the move is not done.
2931 *
2932 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002933int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002934 int delta;
2935 int len;
2936
2937 len = strlen(str);
2938 delta = len - (end - pos);
2939
2940 if (delta + b->r >= b->data + BUFSIZE)
2941 return 0; /* no space left */
2942
2943 /* first, protect the end of the buffer */
2944 memmove(end + delta, end, b->data + b->l - end);
2945
2946 /* now, copy str over pos */
2947 memcpy(pos, str,len);
2948
willy tarreau5cbea6f2005-12-17 12:48:26 +01002949 /* we only move data after the displaced zone */
2950 if (b->r > pos) b->r += delta;
2951 if (b->w > pos) b->w += delta;
2952 if (b->h > pos) b->h += delta;
2953 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002954 b->l += delta;
2955
2956 return delta;
2957}
2958
willy tarreau8337c6b2005-12-17 13:41:01 +01002959/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002960 * len is 0.
2961 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002962int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002963 int delta;
2964
2965 delta = len - (end - pos);
2966
2967 if (delta + b->r >= b->data + BUFSIZE)
2968 return 0; /* no space left */
2969
2970 /* first, protect the end of the buffer */
2971 memmove(end + delta, end, b->data + b->l - end);
2972
2973 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002974 if (len)
2975 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002976
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977 /* we only move data after the displaced zone */
2978 if (b->r > pos) b->r += delta;
2979 if (b->w > pos) b->w += delta;
2980 if (b->h > pos) b->h += delta;
2981 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002982 b->l += delta;
2983
2984 return delta;
2985}
2986
2987
2988int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2989 char *old_dst = dst;
2990
2991 while (*str) {
2992 if (*str == '\\') {
2993 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002994 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002995 int len, num;
2996
2997 num = *str - '0';
2998 str++;
2999
willy tarreau8a86dbf2005-12-18 00:45:59 +01003000 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003001 len = matches[num].rm_eo - matches[num].rm_so;
3002 memcpy(dst, src + matches[num].rm_so, len);
3003 dst += len;
3004 }
3005
3006 }
3007 else if (*str == 'x') {
3008 unsigned char hex1, hex2;
3009 str++;
3010
willy tarreauc1f47532005-12-18 01:08:26 +01003011 hex1 = toupper(*str++) - '0';
3012 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003013
3014 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3015 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3016 *dst++ = (hex1<<4) + hex2;
3017 }
3018 else
3019 *dst++ = *str++;
3020 }
3021 else
3022 *dst++ = *str++;
3023 }
3024 *dst = 0;
3025 return dst - old_dst;
3026}
3027
willy tarreauc1f47532005-12-18 01:08:26 +01003028static int ishex(char s)
3029{
3030 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3031}
3032
3033/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3034char *check_replace_string(char *str)
3035{
3036 char *err = NULL;
3037 while (*str) {
3038 if (*str == '\\') {
3039 err = str; /* in case of a backslash, we return the pointer to it */
3040 str++;
3041 if (!*str)
3042 return err;
3043 else if (isdigit((int)*str))
3044 err = NULL;
3045 else if (*str == 'x') {
3046 str++;
3047 if (!ishex(*str))
3048 return err;
3049 str++;
3050 if (!ishex(*str))
3051 return err;
3052 err = NULL;
3053 }
3054 else {
3055 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3056 err = NULL;
3057 }
3058 }
3059 str++;
3060 }
3061 return err;
3062}
3063
3064
willy tarreau9fe663a2005-12-17 13:02:59 +01003065
willy tarreau0f7af912005-12-17 12:21:26 +01003066/*
3067 * manages the client FSM and its socket. BTW, it also tries to handle the
3068 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3069 * 0 else.
3070 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003072 int s = t->srv_state;
3073 int c = t->cli_state;
3074 struct buffer *req = t->req;
3075 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003076 int method_checked = 0;
3077 appsess *asession_temp = NULL;
3078 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003079
willy tarreau750a4722005-12-17 13:21:24 +01003080#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003081 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3082 cli_stnames[c], srv_stnames[s],
3083 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3084 t->crexpire.tv_sec, t->crexpire.tv_usec,
3085 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003086#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003087 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3088 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3089 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3090 //);
3091 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003092 /* now parse the partial (or complete) headers */
3093 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3094 char *ptr;
3095 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003096 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003097
willy tarreau5cbea6f2005-12-17 12:48:26 +01003098 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003099
willy tarreau0f7af912005-12-17 12:21:26 +01003100 /* look for the end of the current header */
3101 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3102 ptr++;
3103
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 int line, len;
3106 /* we can only get here after an end of headers */
3107 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003108
willy tarreaue39cd132005-12-17 13:00:18 +01003109 if (t->flags & SN_CLDENY) {
3110 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003111 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003112 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003113 if (!(t->flags & SN_ERR_MASK))
3114 t->flags |= SN_ERR_PRXCOND;
3115 if (!(t->flags & SN_FINST_MASK))
3116 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003117 return 1;
3118 }
3119
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003121 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3122 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003123 }
willy tarreau0f7af912005-12-17 12:21:26 +01003124
willy tarreau9fe663a2005-12-17 13:02:59 +01003125 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003126 if (t->cli_addr.ss_family == AF_INET) {
3127 unsigned char *pn;
3128 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3129 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3130 pn[0], pn[1], pn[2], pn[3]);
3131 buffer_replace2(req, req->h, req->h, trash, len);
3132 }
3133 else if (t->cli_addr.ss_family == AF_INET6) {
3134 char pn[INET6_ADDRSTRLEN];
3135 inet_ntop(AF_INET6,
3136 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3137 pn, sizeof(pn));
3138 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3139 buffer_replace2(req, req->h, req->h, trash, len);
3140 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003141 }
3142
willy tarreau25c4ea52005-12-18 00:49:49 +01003143 /* add a "connection: close" line if needed */
3144 if (t->proxy->options & PR_O_HTTP_CLOSE)
3145 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3146
willy tarreau982249e2005-12-18 00:57:06 +01003147 if (!memcmp(req->data, "POST ", 5)) {
3148 /* this is a POST request, which is not cacheable by default */
3149 t->flags |= SN_POST;
3150 }
willy tarreaucd878942005-12-17 13:27:43 +01003151
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003153 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003154
willy tarreau750a4722005-12-17 13:21:24 +01003155 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 /* FIXME: we'll set the client in a wait state while we try to
3157 * connect to the server. Is this really needed ? wouldn't it be
3158 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003159 //FD_CLR(t->cli_fd, StaticReadEvent);
3160 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003161
3162 /* FIXME: if we break here (as up to 1.1.23), having the client
3163 * shutdown its connection can lead to an abort further.
3164 * it's better to either return 1 or even jump directly to the
3165 * data state which will save one schedule.
3166 */
3167 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003168
3169 if (!t->proxy->clitimeout ||
3170 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3171 /* If the client has no timeout, or if the server is not ready yet,
3172 * and we know for sure that it can expire, then it's cleaner to
3173 * disable the timeout on the client side so that too low values
3174 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003175 *
3176 * FIXME-20050705: the server needs a way to re-enable this time-out
3177 * when it switches its state, otherwise a client can stay connected
3178 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003179 */
3180 tv_eternity(&t->crexpire);
3181
willy tarreau197e8ec2005-12-17 14:10:59 +01003182 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003183 }
willy tarreau0f7af912005-12-17 12:21:26 +01003184
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3186 if (ptr > req->r - 2) {
3187 /* this is a partial header, let's wait for more to come */
3188 req->lr = ptr;
3189 break;
3190 }
willy tarreau0f7af912005-12-17 12:21:26 +01003191
willy tarreau5cbea6f2005-12-17 12:48:26 +01003192 /* now we know that *ptr is either \r or \n,
3193 * and that there are at least 1 char after it.
3194 */
3195 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3196 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3197 else
3198 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003199
willy tarreau5cbea6f2005-12-17 12:48:26 +01003200 /*
3201 * now we know that we have a full header ; we can do whatever
3202 * we want with these pointers :
3203 * req->h = beginning of header
3204 * ptr = end of header (first \r or \n)
3205 * req->lr = beginning of next line (next rep->h)
3206 * req->r = end of data (not used at this stage)
3207 */
willy tarreau0f7af912005-12-17 12:21:26 +01003208
willy tarreau12350152005-12-18 01:03:27 +01003209 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3210 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3211 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3212
3213 /* skip ; */
3214 request_line++;
3215
3216 /* look if we have a jsessionid */
3217
3218 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3219
3220 /* skip jsessionid= */
3221 request_line += t->proxy->appsession_name_len + 1;
3222
3223 /* First try if we allready have an appsession */
3224 asession_temp = &local_asession;
3225
3226 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3227 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3228 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3229 return 0;
3230 }
3231
3232 /* Copy the sessionid */
3233 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3234 asession_temp->sessid[t->proxy->appsession_len] = 0;
3235 asession_temp->serverid = NULL;
3236
3237 /* only do insert, if lookup fails */
3238 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3239 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3240 Alert("Not enough memory process_cli():asession:calloc().\n");
3241 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3242 return 0;
3243 }
3244 asession_temp->sessid = local_asession.sessid;
3245 asession_temp->serverid = local_asession.serverid;
3246 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003247 } /* end if (chtbl_lookup()) */
3248 else {
willy tarreau12350152005-12-18 01:03:27 +01003249 /*free wasted memory;*/
3250 pool_free_to(apools.sessid, local_asession.sessid);
3251 }
3252
3253 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3254 asession_temp->request_count++;
3255
3256#if defined(DEBUG_HASH)
3257 print_table(&(t->proxy->htbl_proxy));
3258#endif
3259
3260 if (asession_temp->serverid == NULL) {
3261 Alert("Found Application Session without matching server.\n");
3262 } else {
3263 struct server *srv = t->proxy->srv;
3264 while (srv) {
3265 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3266 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3267 /* we found the server and it's usable */
3268 t->flags &= ~SN_CK_MASK;
3269 t->flags |= SN_CK_VALID | SN_DIRECT;
3270 t->srv = srv;
3271 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003272 } else {
willy tarreau12350152005-12-18 01:03:27 +01003273 t->flags &= ~SN_CK_MASK;
3274 t->flags |= SN_CK_DOWN;
3275 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003276 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003277 srv = srv->next;
3278 }/* end while(srv) */
3279 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003280 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003281 else {
3282 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3283 }
willy tarreau598da412005-12-18 01:07:29 +01003284 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003285 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003286 else{
3287 //printf("No Methode-Header with Session-String\n");
3288 }
3289
willy tarreau8337c6b2005-12-17 13:41:01 +01003290 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003291 /* we have a complete HTTP request that we must log */
3292 int urilen;
3293
willy tarreaua1598082005-12-17 13:08:06 +01003294 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003295 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003296 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003297 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003298 if (!(t->flags & SN_ERR_MASK))
3299 t->flags |= SN_ERR_PRXCOND;
3300 if (!(t->flags & SN_FINST_MASK))
3301 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003302 return 1;
3303 }
3304
3305 urilen = ptr - req->h;
3306 if (urilen >= REQURI_LEN)
3307 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003308 memcpy(t->logs.uri, req->h, urilen);
3309 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003310
willy tarreaua1598082005-12-17 13:08:06 +01003311 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003312 sess_log(t);
3313 }
willy tarreau4302f492005-12-18 01:00:37 +01003314 else if (t->logs.logwait & LW_REQHDR) {
3315 struct cap_hdr *h;
3316 int len;
3317 for (h = t->proxy->req_cap; h; h = h->next) {
3318 if ((h->namelen + 2 <= ptr - req->h) &&
3319 (req->h[h->namelen] == ':') &&
3320 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3321
3322 if (t->req_cap[h->index] == NULL)
3323 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3324
3325 len = ptr - (req->h + h->namelen + 2);
3326 if (len > h->len)
3327 len = h->len;
3328
3329 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3330 t->req_cap[h->index][len]=0;
3331 }
3332 }
3333
3334 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003335
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003337
willy tarreau982249e2005-12-18 00:57:06 +01003338 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003339 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003340 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 +01003341 max = ptr - req->h;
3342 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003343 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 trash[len++] = '\n';
3345 write(1, trash, len);
3346 }
willy tarreau0f7af912005-12-17 12:21:26 +01003347
willy tarreau25c4ea52005-12-18 00:49:49 +01003348
3349 /* remove "connection: " if needed */
3350 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3351 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3352 delete_header = 1;
3353 }
3354
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003356 if (!delete_header && t->proxy->req_exp != NULL
3357 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003358 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003359 char term;
3360
3361 term = *ptr;
3362 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003363 exp = t->proxy->req_exp;
3364 do {
3365 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3366 switch (exp->action) {
3367 case ACT_ALLOW:
3368 if (!(t->flags & SN_CLDENY))
3369 t->flags |= SN_CLALLOW;
3370 break;
3371 case ACT_REPLACE:
3372 if (!(t->flags & SN_CLDENY)) {
3373 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3374 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3375 }
3376 break;
3377 case ACT_REMOVE:
3378 if (!(t->flags & SN_CLDENY))
3379 delete_header = 1;
3380 break;
3381 case ACT_DENY:
3382 if (!(t->flags & SN_CLALLOW))
3383 t->flags |= SN_CLDENY;
3384 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003385 case ACT_PASS: /* we simply don't deny this one */
3386 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003387 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003388 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003389 }
willy tarreaue39cd132005-12-17 13:00:18 +01003390 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003391 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003392 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003393
willy tarreau240afa62005-12-17 13:14:35 +01003394 /* Now look for cookies. Conforming to RFC2109, we have to support
3395 * attributes whose name begin with a '$', and associate them with
3396 * the right cookie, if we want to delete this cookie.
3397 * So there are 3 cases for each cookie read :
3398 * 1) it's a special attribute, beginning with a '$' : ignore it.
3399 * 2) it's a server id cookie that we *MAY* want to delete : save
3400 * some pointers on it (last semi-colon, beginning of cookie...)
3401 * 3) it's an application cookie : we *MAY* have to delete a previous
3402 * "special" cookie.
3403 * At the end of loop, if a "special" cookie remains, we may have to
3404 * remove it. If no application cookie persists in the header, we
3405 * *MUST* delete it
3406 */
willy tarreau12350152005-12-18 01:03:27 +01003407 if (!delete_header &&
3408 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003409 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003410 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003412 char *del_colon, *del_cookie, *colon;
3413 int app_cookies;
3414
willy tarreau5cbea6f2005-12-17 12:48:26 +01003415 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003416 colon = p1;
3417 /* del_cookie == NULL => nothing to be deleted */
3418 del_colon = del_cookie = NULL;
3419 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003420
3421 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003422 /* skip spaces and colons, but keep an eye on these ones */
3423 while (p1 < ptr) {
3424 if (*p1 == ';' || *p1 == ',')
3425 colon = p1;
3426 else if (!isspace((int)*p1))
3427 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003428 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003429 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003430
3431 if (p1 == ptr)
3432 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003433
3434 /* p1 is at the beginning of the cookie name */
3435 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003436 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003437 p2++;
3438
3439 if (p2 == ptr)
3440 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003441
3442 p3 = p2 + 1; /* skips the '=' sign */
3443 if (p3 == ptr)
3444 break;
3445
willy tarreau240afa62005-12-17 13:14:35 +01003446 p4 = p3;
3447 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003448 p4++;
3449
3450 /* here, we have the cookie name between p1 and p2,
3451 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003452 * we can process it :
3453 *
3454 * Cookie: NAME=VALUE;
3455 * | || || |
3456 * | || || +--> p4
3457 * | || |+-------> p3
3458 * | || +--------> p2
3459 * | |+------------> p1
3460 * | +-------------> colon
3461 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462 */
3463
willy tarreau240afa62005-12-17 13:14:35 +01003464 if (*p1 == '$') {
3465 /* skip this one */
3466 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003467 else {
3468 /* first, let's see if we want to capture it */
3469 if (t->proxy->capture_name != NULL &&
3470 t->logs.cli_cookie == NULL &&
3471 (p4 - p1 >= t->proxy->capture_namelen) &&
3472 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3473 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003474
willy tarreau8337c6b2005-12-17 13:41:01 +01003475 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3476 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003477 } else {
3478 if (log_len > t->proxy->capture_len)
3479 log_len = t->proxy->capture_len;
3480 memcpy(t->logs.cli_cookie, p1, log_len);
3481 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003482 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003483 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003484
3485 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3486 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3487 /* Cool... it's the right one */
3488 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003489 char *delim;
3490
3491 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3492 * have the server ID betweek p3 and delim, and the original cookie between
3493 * delim+1 and p4. Otherwise, delim==p4 :
3494 *
3495 * Cookie: NAME=SRV~VALUE;
3496 * | || || | |
3497 * | || || | +--> p4
3498 * | || || +--------> delim
3499 * | || |+-----------> p3
3500 * | || +------------> p2
3501 * | |+----------------> p1
3502 * | +-----------------> colon
3503 * +------------------------> req->h
3504 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003505
willy tarreau0174f312005-12-18 01:02:42 +01003506 if (t->proxy->options & PR_O_COOK_PFX) {
3507 for (delim = p3; delim < p4; delim++)
3508 if (*delim == COOKIE_DELIM)
3509 break;
3510 }
3511 else
3512 delim = p4;
3513
3514
3515 /* Here, we'll look for the first running server which supports the cookie.
3516 * This allows to share a same cookie between several servers, for example
3517 * to dedicate backup servers to specific servers only.
3518 */
3519 while (srv) {
3520 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3521 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3522 /* we found the server and it's usable */
3523 t->flags &= ~SN_CK_MASK;
3524 t->flags |= SN_CK_VALID | SN_DIRECT;
3525 t->srv = srv;
3526 break;
willy tarreau12350152005-12-18 01:03:27 +01003527 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003528 /* we found a server, but it's down */
3529 t->flags &= ~SN_CK_MASK;
3530 t->flags |= SN_CK_DOWN;
3531 }
3532 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003533 srv = srv->next;
3534 }
3535
willy tarreau0174f312005-12-18 01:02:42 +01003536 if (!srv && !(t->flags & SN_CK_DOWN)) {
3537 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003538 t->flags &= ~SN_CK_MASK;
3539 t->flags |= SN_CK_INVALID;
3540 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003541
willy tarreau0174f312005-12-18 01:02:42 +01003542 /* depending on the cookie mode, we may have to either :
3543 * - delete the complete cookie if we're in insert+indirect mode, so that
3544 * the server never sees it ;
3545 * - remove the server id from the cookie value, and tag the cookie as an
3546 * application cookie so that it does not get accidentely removed later,
3547 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003548 */
willy tarreau0174f312005-12-18 01:02:42 +01003549 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3550 buffer_replace2(req, p3, delim + 1, NULL, 0);
3551 p4 -= (delim + 1 - p3);
3552 ptr -= (delim + 1 - p3);
3553 del_cookie = del_colon = NULL;
3554 app_cookies++; /* protect the header from deletion */
3555 }
3556 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003557 (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 +01003558 del_cookie = p1;
3559 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003560 }
willy tarreau12350152005-12-18 01:03:27 +01003561 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003562 /* now we know that we must keep this cookie since it's
3563 * not ours. But if we wanted to delete our cookie
3564 * earlier, we cannot remove the complete header, but we
3565 * can remove the previous block itself.
3566 */
3567 app_cookies++;
3568
3569 if (del_cookie != NULL) {
3570 buffer_replace2(req, del_cookie, p1, NULL, 0);
3571 p4 -= (p1 - del_cookie);
3572 ptr -= (p1 - del_cookie);
3573 del_cookie = del_colon = NULL;
3574 }
willy tarreau240afa62005-12-17 13:14:35 +01003575 }
willy tarreau12350152005-12-18 01:03:27 +01003576
3577 if ((t->proxy->appsession_name != NULL) &&
3578 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3579 /* first, let's see if the cookie is our appcookie*/
3580
3581 /* Cool... it's the right one */
3582
3583 asession_temp = &local_asession;
3584
3585 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3586 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3587 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3588 return 0;
3589 }
3590
3591 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3592 asession_temp->sessid[t->proxy->appsession_len] = 0;
3593 asession_temp->serverid = NULL;
3594
3595 /* only do insert, if lookup fails */
3596 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3597 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3598 Alert("Not enough memory process_cli():asession:calloc().\n");
3599 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3600 return 0;
3601 }
3602
3603 asession_temp->sessid = local_asession.sessid;
3604 asession_temp->serverid = local_asession.serverid;
3605 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3606 }
3607 else{
3608 /* free wasted memory */
3609 pool_free_to(apools.sessid, local_asession.sessid);
3610 }
3611
3612 if (asession_temp->serverid == NULL) {
3613 Alert("Found Application Session without matching server.\n");
3614 } else {
3615 struct server *srv = t->proxy->srv;
3616 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003617 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003618 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3619 /* we found the server and it's usable */
3620 t->flags &= ~SN_CK_MASK;
3621 t->flags |= SN_CK_VALID | SN_DIRECT;
3622 t->srv = srv;
3623 break;
3624 } else {
3625 t->flags &= ~SN_CK_MASK;
3626 t->flags |= SN_CK_DOWN;
3627 }
3628 }
3629 srv = srv->next;
3630 }/* end while(srv) */
3631 }/* end else if server == NULL */
3632
3633 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003634 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635 }
willy tarreau240afa62005-12-17 13:14:35 +01003636
willy tarreau5cbea6f2005-12-17 12:48:26 +01003637 /* we'll have to look for another cookie ... */
3638 p1 = p4;
3639 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003640
3641 /* There's no more cookie on this line.
3642 * We may have marked the last one(s) for deletion.
3643 * We must do this now in two ways :
3644 * - if there is no app cookie, we simply delete the header ;
3645 * - if there are app cookies, we must delete the end of the
3646 * string properly, including the colon/semi-colon before
3647 * the cookie name.
3648 */
3649 if (del_cookie != NULL) {
3650 if (app_cookies) {
3651 buffer_replace2(req, del_colon, ptr, NULL, 0);
3652 /* WARNING! <ptr> becomes invalid for now. If some code
3653 * below needs to rely on it before the end of the global
3654 * header loop, we need to correct it with this code :
3655 * ptr = del_colon;
3656 */
3657 }
3658 else
3659 delete_header = 1;
3660 }
3661 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003662
3663 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003664 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003665 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003666 }
willy tarreau240afa62005-12-17 13:14:35 +01003667 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3668
willy tarreau5cbea6f2005-12-17 12:48:26 +01003669 req->h = req->lr;
3670 } /* while (req->lr < req->r) */
3671
3672 /* end of header processing (even if incomplete) */
3673
willy tarreauef900ab2005-12-17 12:52:52 +01003674 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3675 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3676 * full. We cannot loop here since event_cli_read will disable it only if
3677 * req->l == rlim-data
3678 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003679 FD_SET(t->cli_fd, StaticReadEvent);
3680 if (t->proxy->clitimeout)
3681 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3682 else
3683 tv_eternity(&t->crexpire);
3684 }
3685
willy tarreaue39cd132005-12-17 13:00:18 +01003686 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003687 * won't be able to free more later, so the session will never terminate.
3688 */
willy tarreaue39cd132005-12-17 13:00:18 +01003689 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003690 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003691 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003692 if (!(t->flags & SN_ERR_MASK))
3693 t->flags |= SN_ERR_PRXCOND;
3694 if (!(t->flags & SN_FINST_MASK))
3695 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003696 return 1;
3697 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003698 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003699 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003700 tv_eternity(&t->crexpire);
3701 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003702 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003703 if (!(t->flags & SN_ERR_MASK))
3704 t->flags |= SN_ERR_CLICL;
3705 if (!(t->flags & SN_FINST_MASK))
3706 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003707 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003708 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003709 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3710
3711 /* read timeout : give up with an error message.
3712 */
3713 t->logs.status = 408;
3714 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003715 if (!(t->flags & SN_ERR_MASK))
3716 t->flags |= SN_ERR_CLITO;
3717 if (!(t->flags & SN_FINST_MASK))
3718 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003719 return 1;
3720 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003721
3722 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003723 }
3724 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003725 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003726 /* FIXME: this error handling is partly buggy because we always report
3727 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3728 * or HEADER phase. BTW, it's not logical to expire the client while
3729 * we're waiting for the server to connect.
3730 */
willy tarreau0f7af912005-12-17 12:21:26 +01003731 /* read or write error */
3732 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003733 tv_eternity(&t->crexpire);
3734 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003735 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003736 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003737 if (!(t->flags & SN_ERR_MASK))
3738 t->flags |= SN_ERR_CLICL;
3739 if (!(t->flags & SN_FINST_MASK))
3740 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003741 return 1;
3742 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003743 /* last read, or end of server write */
3744 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003745 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003746 tv_eternity(&t->crexpire);
3747 shutdown(t->cli_fd, SHUT_RD);
3748 t->cli_state = CL_STSHUTR;
3749 return 1;
3750 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003751 /* last server read and buffer empty */
3752 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003753 FD_CLR(t->cli_fd, StaticWriteEvent);
3754 tv_eternity(&t->cwexpire);
3755 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003756 /* We must ensure that the read part is still alive when switching
3757 * to shutw */
3758 FD_SET(t->cli_fd, StaticReadEvent);
3759 if (t->proxy->clitimeout)
3760 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003761 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003762 //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 +01003763 return 1;
3764 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003765 /* read timeout */
3766 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3767 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003768 tv_eternity(&t->crexpire);
3769 shutdown(t->cli_fd, SHUT_RD);
3770 t->cli_state = CL_STSHUTR;
3771 if (!(t->flags & SN_ERR_MASK))
3772 t->flags |= SN_ERR_CLITO;
3773 if (!(t->flags & SN_FINST_MASK))
3774 t->flags |= SN_FINST_D;
3775 return 1;
3776 }
3777 /* write timeout */
3778 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3779 FD_CLR(t->cli_fd, StaticWriteEvent);
3780 tv_eternity(&t->cwexpire);
3781 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003782 /* We must ensure that the read part is still alive when switching
3783 * to shutw */
3784 FD_SET(t->cli_fd, StaticReadEvent);
3785 if (t->proxy->clitimeout)
3786 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3787
willy tarreau036e1ce2005-12-17 13:46:33 +01003788 t->cli_state = CL_STSHUTW;
3789 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003790 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003791 if (!(t->flags & SN_FINST_MASK))
3792 t->flags |= SN_FINST_D;
3793 return 1;
3794 }
willy tarreau0f7af912005-12-17 12:21:26 +01003795
willy tarreauc58fc692005-12-17 14:13:08 +01003796 if (req->l >= req->rlim - req->data) {
3797 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003798 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003799 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003800 FD_CLR(t->cli_fd, StaticReadEvent);
3801 tv_eternity(&t->crexpire);
3802 }
3803 }
3804 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003805 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003806 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3807 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003808 if (!t->proxy->clitimeout ||
3809 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3810 /* If the client has no timeout, or if the server not ready yet, and we
3811 * know for sure that it can expire, then it's cleaner to disable the
3812 * timeout on the client side so that too low values cannot make the
3813 * sessions abort too early.
3814 */
willy tarreau0f7af912005-12-17 12:21:26 +01003815 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003816 else
3817 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003818 }
3819 }
3820
3821 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003822 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003823 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3824 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3825 tv_eternity(&t->cwexpire);
3826 }
3827 }
3828 else { /* buffer not empty */
3829 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3830 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003831 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003832 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003833 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3834 t->crexpire = t->cwexpire;
3835 }
willy tarreau0f7af912005-12-17 12:21:26 +01003836 else
3837 tv_eternity(&t->cwexpire);
3838 }
3839 }
3840 return 0; /* other cases change nothing */
3841 }
3842 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003843 if (t->res_cw == RES_ERROR) {
3844 tv_eternity(&t->cwexpire);
3845 fd_delete(t->cli_fd);
3846 t->cli_state = CL_STCLOSE;
3847 if (!(t->flags & SN_ERR_MASK))
3848 t->flags |= SN_ERR_CLICL;
3849 if (!(t->flags & SN_FINST_MASK))
3850 t->flags |= SN_FINST_D;
3851 return 1;
3852 }
3853 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003854 tv_eternity(&t->cwexpire);
3855 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003856 t->cli_state = CL_STCLOSE;
3857 return 1;
3858 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003859 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3860 tv_eternity(&t->cwexpire);
3861 fd_delete(t->cli_fd);
3862 t->cli_state = CL_STCLOSE;
3863 if (!(t->flags & SN_ERR_MASK))
3864 t->flags |= SN_ERR_CLITO;
3865 if (!(t->flags & SN_FINST_MASK))
3866 t->flags |= SN_FINST_D;
3867 return 1;
3868 }
willy tarreau0f7af912005-12-17 12:21:26 +01003869 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003870 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003871 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3872 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3873 tv_eternity(&t->cwexpire);
3874 }
3875 }
3876 else { /* buffer not empty */
3877 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3878 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003879 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003880 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003881 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3882 t->crexpire = t->cwexpire;
3883 }
willy tarreau0f7af912005-12-17 12:21:26 +01003884 else
3885 tv_eternity(&t->cwexpire);
3886 }
3887 }
3888 return 0;
3889 }
3890 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003891 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003892 tv_eternity(&t->crexpire);
3893 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003894 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003895 if (!(t->flags & SN_ERR_MASK))
3896 t->flags |= SN_ERR_CLICL;
3897 if (!(t->flags & SN_FINST_MASK))
3898 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003899 return 1;
3900 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003901 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3902 tv_eternity(&t->crexpire);
3903 fd_delete(t->cli_fd);
3904 t->cli_state = CL_STCLOSE;
3905 return 1;
3906 }
3907 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3908 tv_eternity(&t->crexpire);
3909 fd_delete(t->cli_fd);
3910 t->cli_state = CL_STCLOSE;
3911 if (!(t->flags & SN_ERR_MASK))
3912 t->flags |= SN_ERR_CLITO;
3913 if (!(t->flags & SN_FINST_MASK))
3914 t->flags |= SN_FINST_D;
3915 return 1;
3916 }
willy tarreauef900ab2005-12-17 12:52:52 +01003917 else if (req->l >= req->rlim - req->data) {
3918 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003919
3920 /* FIXME-20050705: is it possible for a client to maintain a session
3921 * after the timeout by sending more data after it receives a close ?
3922 */
3923
willy tarreau0f7af912005-12-17 12:21:26 +01003924 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003925 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003926 FD_CLR(t->cli_fd, StaticReadEvent);
3927 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003928 //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 +01003929 }
3930 }
3931 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003932 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003933 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3934 FD_SET(t->cli_fd, StaticReadEvent);
3935 if (t->proxy->clitimeout)
3936 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3937 else
3938 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003939 //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 +01003940 }
3941 }
3942 return 0;
3943 }
3944 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003945 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003946 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003947 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 +01003948 write(1, trash, len);
3949 }
3950 return 0;
3951 }
3952 return 0;
3953}
3954
3955
3956/*
3957 * manages the server FSM and its socket. It returns 1 if a state has changed
3958 * (and a resync may be needed), 0 else.
3959 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003960int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003961 int s = t->srv_state;
3962 int c = t->cli_state;
3963 struct buffer *req = t->req;
3964 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003965 appsess *asession_temp = NULL;
3966 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003967 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003968
willy tarreau750a4722005-12-17 13:21:24 +01003969#ifdef DEBUG_FULL
3970 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3971#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003972 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3973 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3974 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3975 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003976 if (s == SV_STIDLE) {
3977 if (c == CL_STHEADERS)
3978 return 0; /* stay in idle, waiting for data to reach the client side */
3979 else if (c == CL_STCLOSE ||
3980 c == CL_STSHUTW ||
3981 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3982 tv_eternity(&t->cnexpire);
3983 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003984 if (!(t->flags & SN_ERR_MASK))
3985 t->flags |= SN_ERR_CLICL;
3986 if (!(t->flags & SN_FINST_MASK))
3987 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003988 return 1;
3989 }
3990 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003991 /* initiate a connection to the server */
3992 conn_err = connect_server(t);
3993 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003994 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3995 t->srv_state = SV_STCONN;
3996 }
3997 else { /* try again */
3998 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003999 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004000 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004001 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004002 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4003 t->flags &= ~SN_CK_MASK;
4004 t->flags |= SN_CK_DOWN;
4005 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 }
4007
willy tarreaub1285d52005-12-18 01:20:14 +01004008 conn_err = connect_server(t);
4009 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004010 t->srv_state = SV_STCONN;
4011 break;
4012 }
4013 }
4014 if (t->conn_retries < 0) {
4015 /* if conn_retries < 0 or other error, let's abort */
4016 tv_eternity(&t->cnexpire);
4017 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004018 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004019 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004020 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004021 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004022 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004023 if (!(t->flags & SN_FINST_MASK))
4024 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004025 }
4026 }
4027 return 1;
4028 }
4029 }
4030 else if (s == SV_STCONN) { /* connection in progress */
4031 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
4032 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
4033 return 0; /* nothing changed */
4034 }
4035 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4036 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4037 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004038 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004039 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004041 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004042 if (t->conn_retries >= 0) {
4043 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004044 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004046 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4047 t->flags &= ~SN_CK_MASK;
4048 t->flags |= SN_CK_DOWN;
4049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050 }
willy tarreaub1285d52005-12-18 01:20:14 +01004051 conn_err = connect_server(t);
4052 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004053 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004054 }
willy tarreaub1285d52005-12-18 01:20:14 +01004055 else if (t->res_sw == RES_SILENT)
4056 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4057 else
4058 conn_err = SN_ERR_SRVCL; // it was a connect error.
4059
willy tarreau0f7af912005-12-17 12:21:26 +01004060 /* if conn_retries < 0 or other error, let's abort */
4061 tv_eternity(&t->cnexpire);
4062 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004063 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004064 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004065 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004066 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004067 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004068 if (!(t->flags & SN_FINST_MASK))
4069 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004070 return 1;
4071 }
4072 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004073 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004074
willy tarreau0f7af912005-12-17 12:21:26 +01004075 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004076 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004077 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004078 tv_eternity(&t->swexpire);
4079 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004080 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004081 if (t->proxy->srvtimeout) {
4082 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4083 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4084 t->srexpire = t->swexpire;
4085 }
4086 else
4087 tv_eternity(&t->swexpire);
4088 }
willy tarreau0f7af912005-12-17 12:21:26 +01004089
4090 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4091 FD_SET(t->srv_fd, StaticReadEvent);
4092 if (t->proxy->srvtimeout)
4093 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4094 else
4095 tv_eternity(&t->srexpire);
4096
4097 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004098 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004099
4100 /* if the user wants to log as soon as possible, without counting
4101 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004102 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004103 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4104 sess_log(t);
4105 }
willy tarreau0f7af912005-12-17 12:21:26 +01004106 }
willy tarreauef900ab2005-12-17 12:52:52 +01004107 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004108 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004109 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4110 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004111 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004112 return 1;
4113 }
4114 }
4115 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004116 /* now parse the partial (or complete) headers */
4117 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4118 char *ptr;
4119 int delete_header;
4120
4121 ptr = rep->lr;
4122
4123 /* look for the end of the current header */
4124 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4125 ptr++;
4126
4127 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004128 int line, len;
4129
4130 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004131
4132 /* first, we'll block if security checks have caught nasty things */
4133 if (t->flags & SN_CACHEABLE) {
4134 if ((t->flags & SN_CACHE_COOK) &&
4135 (t->flags & SN_SCK_ANY) &&
4136 (t->proxy->options & PR_O_CHK_CACHE)) {
4137
4138 /* we're in presence of a cacheable response containing
4139 * a set-cookie header. We'll block it as requested by
4140 * the 'checkcache' option, and send an alert.
4141 */
4142 tv_eternity(&t->srexpire);
4143 tv_eternity(&t->swexpire);
4144 fd_delete(t->srv_fd);
4145 t->srv_state = SV_STCLOSE;
4146 t->logs.status = 502;
4147 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4148 if (!(t->flags & SN_ERR_MASK))
4149 t->flags |= SN_ERR_PRXCOND;
4150 if (!(t->flags & SN_FINST_MASK))
4151 t->flags |= SN_FINST_H;
4152
4153 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4154 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4155
4156 return 1;
4157 }
4158 }
4159
willy tarreau982249e2005-12-18 00:57:06 +01004160 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4161 if (t->flags & SN_SVDENY) {
4162 tv_eternity(&t->srexpire);
4163 tv_eternity(&t->swexpire);
4164 fd_delete(t->srv_fd);
4165 t->srv_state = SV_STCLOSE;
4166 t->logs.status = 502;
4167 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4168 if (!(t->flags & SN_ERR_MASK))
4169 t->flags |= SN_ERR_PRXCOND;
4170 if (!(t->flags & SN_FINST_MASK))
4171 t->flags |= SN_FINST_H;
4172 return 1;
4173 }
4174
willy tarreau5cbea6f2005-12-17 12:48:26 +01004175 /* we'll have something else to do here : add new headers ... */
4176
willy tarreaucd878942005-12-17 13:27:43 +01004177 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4178 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004179 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004180 * insert a set-cookie here, except if we want to insert only on POST
4181 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004182 */
willy tarreau750a4722005-12-17 13:21:24 +01004183 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004184 t->proxy->cookie_name,
4185 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004186
willy tarreau036e1ce2005-12-17 13:46:33 +01004187 t->flags |= SN_SCK_INSERTED;
4188
willy tarreau750a4722005-12-17 13:21:24 +01004189 /* Here, we will tell an eventual cache on the client side that we don't
4190 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4191 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4192 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4193 */
willy tarreau240afa62005-12-17 13:14:35 +01004194 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004195 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4196 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01004197
willy tarreau750a4722005-12-17 13:21:24 +01004198 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004199 }
4200
4201 /* headers to be added */
4202 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004203 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4204 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004205 }
4206
willy tarreau25c4ea52005-12-18 00:49:49 +01004207 /* add a "connection: close" line if needed */
4208 if (t->proxy->options & PR_O_HTTP_CLOSE)
4209 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4210
willy tarreau5cbea6f2005-12-17 12:48:26 +01004211 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004212 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004213 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004214
4215 /* if the user wants to log as soon as possible, without counting
4216 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004217 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004218 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4219 t->logs.bytes = rep->h - rep->data;
4220 sess_log(t);
4221 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004222 break;
4223 }
4224
4225 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4226 if (ptr > rep->r - 2) {
4227 /* this is a partial header, let's wait for more to come */
4228 rep->lr = ptr;
4229 break;
4230 }
4231
4232 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4233 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4234
4235 /* now we know that *ptr is either \r or \n,
4236 * and that there are at least 1 char after it.
4237 */
4238 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4239 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4240 else
4241 rep->lr = ptr + 2; /* \r\n or \n\r */
4242
4243 /*
4244 * now we know that we have a full header ; we can do whatever
4245 * we want with these pointers :
4246 * rep->h = beginning of header
4247 * ptr = end of header (first \r or \n)
4248 * rep->lr = beginning of next line (next rep->h)
4249 * rep->r = end of data (not used at this stage)
4250 */
4251
willy tarreaua1598082005-12-17 13:08:06 +01004252
willy tarreau982249e2005-12-18 00:57:06 +01004253 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004254 t->logs.logwait &= ~LW_RESP;
4255 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004256 switch (t->logs.status) {
4257 case 200:
4258 case 203:
4259 case 206:
4260 case 300:
4261 case 301:
4262 case 410:
4263 /* RFC2616 @13.4:
4264 * "A response received with a status code of
4265 * 200, 203, 206, 300, 301 or 410 MAY be stored
4266 * by a cache (...) unless a cache-control
4267 * directive prohibits caching."
4268 *
4269 * RFC2616 @9.5: POST method :
4270 * "Responses to this method are not cacheable,
4271 * unless the response includes appropriate
4272 * Cache-Control or Expires header fields."
4273 */
4274 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4275 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4276 break;
4277 default:
4278 break;
4279 }
willy tarreau4302f492005-12-18 01:00:37 +01004280 }
4281 else if (t->logs.logwait & LW_RSPHDR) {
4282 struct cap_hdr *h;
4283 int len;
4284 for (h = t->proxy->rsp_cap; h; h = h->next) {
4285 if ((h->namelen + 2 <= ptr - rep->h) &&
4286 (rep->h[h->namelen] == ':') &&
4287 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4288
4289 if (t->rsp_cap[h->index] == NULL)
4290 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4291
4292 len = ptr - (rep->h + h->namelen + 2);
4293 if (len > h->len)
4294 len = h->len;
4295
4296 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4297 t->rsp_cap[h->index][len]=0;
4298 }
4299 }
4300
willy tarreaua1598082005-12-17 13:08:06 +01004301 }
4302
willy tarreau5cbea6f2005-12-17 12:48:26 +01004303 delete_header = 0;
4304
willy tarreau982249e2005-12-18 00:57:06 +01004305 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004306 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004307 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 +01004308 max = ptr - rep->h;
4309 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004310 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004311 trash[len++] = '\n';
4312 write(1, trash, len);
4313 }
4314
willy tarreau25c4ea52005-12-18 00:49:49 +01004315 /* remove "connection: " if needed */
4316 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4317 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4318 delete_header = 1;
4319 }
4320
willy tarreau5cbea6f2005-12-17 12:48:26 +01004321 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004322 if (!delete_header && t->proxy->rsp_exp != NULL
4323 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004324 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004325 char term;
4326
4327 term = *ptr;
4328 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004329 exp = t->proxy->rsp_exp;
4330 do {
4331 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4332 switch (exp->action) {
4333 case ACT_ALLOW:
4334 if (!(t->flags & SN_SVDENY))
4335 t->flags |= SN_SVALLOW;
4336 break;
4337 case ACT_REPLACE:
4338 if (!(t->flags & SN_SVDENY)) {
4339 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4340 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4341 }
4342 break;
4343 case ACT_REMOVE:
4344 if (!(t->flags & SN_SVDENY))
4345 delete_header = 1;
4346 break;
4347 case ACT_DENY:
4348 if (!(t->flags & SN_SVALLOW))
4349 t->flags |= SN_SVDENY;
4350 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004351 case ACT_PASS: /* we simply don't deny this one */
4352 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004353 }
4354 break;
4355 }
willy tarreaue39cd132005-12-17 13:00:18 +01004356 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004357 *ptr = term; /* restore the string terminator */
4358 }
4359
willy tarreau97f58572005-12-18 00:53:44 +01004360 /* check for cache-control: or pragma: headers */
4361 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4362 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4363 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4364 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4365 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004366 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004367 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4368 else {
4369 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004370 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004371 t->flags &= ~SN_CACHE_COOK;
4372 }
4373 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004374 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004375 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004376 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004377 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4378 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004379 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004380 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004381 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4382 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4383 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4384 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4385 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4386 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004387 }
4388 }
4389 }
4390
willy tarreau5cbea6f2005-12-17 12:48:26 +01004391 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004392 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004393 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004394 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004395 char *p1, *p2, *p3, *p4;
4396
willy tarreau97f58572005-12-18 00:53:44 +01004397 t->flags |= SN_SCK_ANY;
4398
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4400
4401 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004402 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004403 p1++;
4404
4405 if (p1 == ptr || *p1 == ';') /* end of cookie */
4406 break;
4407
4408 /* p1 is at the beginning of the cookie name */
4409 p2 = p1;
4410
4411 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4412 p2++;
4413
4414 if (p2 == ptr || *p2 == ';') /* next cookie */
4415 break;
4416
4417 p3 = p2 + 1; /* skips the '=' sign */
4418 if (p3 == ptr)
4419 break;
4420
4421 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004422 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004423 p4++;
4424
4425 /* here, we have the cookie name between p1 and p2,
4426 * and its value between p3 and p4.
4427 * we can process it.
4428 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004429
4430 /* first, let's see if we want to capture it */
4431 if (t->proxy->capture_name != NULL &&
4432 t->logs.srv_cookie == NULL &&
4433 (p4 - p1 >= t->proxy->capture_namelen) &&
4434 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4435 int log_len = p4 - p1;
4436
4437 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4438 Alert("HTTP logging : out of memory.\n");
4439 }
4440
4441 if (log_len > t->proxy->capture_len)
4442 log_len = t->proxy->capture_len;
4443 memcpy(t->logs.srv_cookie, p1, log_len);
4444 t->logs.srv_cookie[log_len] = 0;
4445 }
4446
4447 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4448 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004449 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004450 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004451
4452 /* If the cookie is in insert mode on a known server, we'll delete
4453 * this occurrence because we'll insert another one later.
4454 * We'll delete it too if the "indirect" option is set and we're in
4455 * a direct access. */
4456 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004457 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004458 /* this header must be deleted */
4459 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004460 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004461 }
4462 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4463 /* replace bytes p3->p4 with the cookie name associated
4464 * with this server since we know it.
4465 */
4466 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004467 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004468 }
willy tarreau0174f312005-12-18 01:02:42 +01004469 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4470 /* insert the cookie name associated with this server
4471 * before existing cookie, and insert a delimitor between them..
4472 */
4473 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4474 p3[t->srv->cklen] = COOKIE_DELIM;
4475 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4476 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004477 break;
4478 }
willy tarreau12350152005-12-18 01:03:27 +01004479
4480 /* first, let's see if the cookie is our appcookie*/
4481 if ((t->proxy->appsession_name != NULL) &&
4482 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4483
4484 /* Cool... it's the right one */
4485
willy tarreaub952e1d2005-12-18 01:31:20 +01004486 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004487 asession_temp = &local_asession;
4488
willy tarreaub952e1d2005-12-18 01:31:20 +01004489 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004490 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4491 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4492 }
4493 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4494 asession_temp->sessid[t->proxy->appsession_len] = 0;
4495 asession_temp->serverid = NULL;
4496
4497 /* only do insert, if lookup fails */
4498 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4499 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4500 Alert("Not enought Memory process_srv():asession:calloc().\n");
4501 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4502 return 0;
4503 }
4504 asession_temp->sessid = local_asession.sessid;
4505 asession_temp->serverid = local_asession.serverid;
4506 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004507 }/* end if (chtbl_lookup()) */
4508 else {
willy tarreau12350152005-12-18 01:03:27 +01004509 /* free wasted memory */
4510 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004511 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004512
willy tarreaub952e1d2005-12-18 01:31:20 +01004513 if (asession_temp->serverid == NULL) {
4514 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004515 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4516 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4517 }
4518 asession_temp->serverid[0] = '\0';
4519 }
4520
willy tarreaub952e1d2005-12-18 01:31:20 +01004521 if (asession_temp->serverid[0] == '\0')
4522 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004523
4524 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4525
4526#if defined(DEBUG_HASH)
4527 print_table(&(t->proxy->htbl_proxy));
4528#endif
4529 break;
4530 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004531 else {
4532 // fprintf(stderr,"Ignoring unknown cookie : ");
4533 // write(2, p1, p2-p1);
4534 // fprintf(stderr," = ");
4535 // write(2, p3, p4-p3);
4536 // fprintf(stderr,"\n");
4537 }
4538 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4539 } /* we're now at the end of the cookie value */
4540 } /* end of cookie processing */
4541
willy tarreau97f58572005-12-18 00:53:44 +01004542 /* check for any set-cookie in case we check for cacheability */
4543 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4544 (t->proxy->options & PR_O_CHK_CACHE) &&
4545 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4546 t->flags |= SN_SCK_ANY;
4547 }
4548
willy tarreau5cbea6f2005-12-17 12:48:26 +01004549 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004550 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004551 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004552
willy tarreau5cbea6f2005-12-17 12:48:26 +01004553 rep->h = rep->lr;
4554 } /* while (rep->lr < rep->r) */
4555
4556 /* end of header processing (even if incomplete) */
4557
willy tarreauef900ab2005-12-17 12:52:52 +01004558 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4559 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4560 * full. We cannot loop here since event_srv_read will disable it only if
4561 * rep->l == rlim-data
4562 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004563 FD_SET(t->srv_fd, StaticReadEvent);
4564 if (t->proxy->srvtimeout)
4565 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4566 else
4567 tv_eternity(&t->srexpire);
4568 }
willy tarreau0f7af912005-12-17 12:21:26 +01004569
willy tarreau8337c6b2005-12-17 13:41:01 +01004570 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004571 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004572 tv_eternity(&t->srexpire);
4573 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004574 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004575 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004576 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004577 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004578 if (!(t->flags & SN_ERR_MASK))
4579 t->flags |= SN_ERR_SRVCL;
4580 if (!(t->flags & SN_FINST_MASK))
4581 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004582 return 1;
4583 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004584 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004585 * since we are in header mode, if there's no space left for headers, we
4586 * won't be able to free more later, so the session will never terminate.
4587 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004588 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 +01004589 FD_CLR(t->srv_fd, StaticReadEvent);
4590 tv_eternity(&t->srexpire);
4591 shutdown(t->srv_fd, SHUT_RD);
4592 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004593 //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 +01004594 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004595 }
4596 /* read timeout : return a 504 to the client.
4597 */
4598 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4599 tv_eternity(&t->srexpire);
4600 tv_eternity(&t->swexpire);
4601 fd_delete(t->srv_fd);
4602 t->srv_state = SV_STCLOSE;
4603 t->logs.status = 504;
4604 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004605 if (!(t->flags & SN_ERR_MASK))
4606 t->flags |= SN_ERR_SRVTO;
4607 if (!(t->flags & SN_FINST_MASK))
4608 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004609 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004610
4611 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004612 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004613 /* FIXME!!! here, we don't want to switch to SHUTW if the
4614 * client shuts read too early, because we may still have
4615 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004616 * The side-effect is that if the client completely closes its
4617 * connection during SV_STHEADER, the connection to the server
4618 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004619 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004620 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004621 FD_CLR(t->srv_fd, StaticWriteEvent);
4622 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004623
4624 /* We must ensure that the read part is still alive when switching
4625 * to shutw */
4626 FD_SET(t->srv_fd, StaticReadEvent);
4627 if (t->proxy->srvtimeout)
4628 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4629
willy tarreau0f7af912005-12-17 12:21:26 +01004630 shutdown(t->srv_fd, SHUT_WR);
4631 t->srv_state = SV_STSHUTW;
4632 return 1;
4633 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004634 /* write timeout */
4635 /* FIXME!!! here, we don't want to switch to SHUTW if the
4636 * client shuts read too early, because we may still have
4637 * some work to do on the headers.
4638 */
4639 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4640 FD_CLR(t->srv_fd, StaticWriteEvent);
4641 tv_eternity(&t->swexpire);
4642 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004643 /* We must ensure that the read part is still alive when switching
4644 * to shutw */
4645 FD_SET(t->srv_fd, StaticReadEvent);
4646 if (t->proxy->srvtimeout)
4647 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4648
4649 /* We must ensure that the read part is still alive when switching
4650 * to shutw */
4651 FD_SET(t->srv_fd, StaticReadEvent);
4652 if (t->proxy->srvtimeout)
4653 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4654
willy tarreau036e1ce2005-12-17 13:46:33 +01004655 t->srv_state = SV_STSHUTW;
4656 if (!(t->flags & SN_ERR_MASK))
4657 t->flags |= SN_ERR_SRVTO;
4658 if (!(t->flags & SN_FINST_MASK))
4659 t->flags |= SN_FINST_H;
4660 return 1;
4661 }
willy tarreau0f7af912005-12-17 12:21:26 +01004662
4663 if (req->l == 0) {
4664 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4665 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4666 tv_eternity(&t->swexpire);
4667 }
4668 }
4669 else { /* client buffer not empty */
4670 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4671 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004672 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004673 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004674 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4675 t->srexpire = t->swexpire;
4676 }
willy tarreau0f7af912005-12-17 12:21:26 +01004677 else
4678 tv_eternity(&t->swexpire);
4679 }
4680 }
4681
willy tarreau5cbea6f2005-12-17 12:48:26 +01004682 /* be nice with the client side which would like to send a complete header
4683 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4684 * would read all remaining data at once ! The client should not write past rep->lr
4685 * when the server is in header state.
4686 */
4687 //return header_processed;
4688 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004689 }
4690 else if (s == SV_STDATA) {
4691 /* read or write error */
4692 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004693 tv_eternity(&t->srexpire);
4694 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004695 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004696 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004697 if (!(t->flags & SN_ERR_MASK))
4698 t->flags |= SN_ERR_SRVCL;
4699 if (!(t->flags & SN_FINST_MASK))
4700 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004701 return 1;
4702 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004703 /* last read, or end of client write */
4704 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004705 FD_CLR(t->srv_fd, StaticReadEvent);
4706 tv_eternity(&t->srexpire);
4707 shutdown(t->srv_fd, SHUT_RD);
4708 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004709 //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 +01004710 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004711 }
4712 /* end of client read and no more data to send */
4713 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4714 FD_CLR(t->srv_fd, StaticWriteEvent);
4715 tv_eternity(&t->swexpire);
4716 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004717 /* We must ensure that the read part is still alive when switching
4718 * to shutw */
4719 FD_SET(t->srv_fd, StaticReadEvent);
4720 if (t->proxy->srvtimeout)
4721 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4722
willy tarreaua41a8b42005-12-17 14:02:24 +01004723 t->srv_state = SV_STSHUTW;
4724 return 1;
4725 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004726 /* read timeout */
4727 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4728 FD_CLR(t->srv_fd, StaticReadEvent);
4729 tv_eternity(&t->srexpire);
4730 shutdown(t->srv_fd, SHUT_RD);
4731 t->srv_state = SV_STSHUTR;
4732 if (!(t->flags & SN_ERR_MASK))
4733 t->flags |= SN_ERR_SRVTO;
4734 if (!(t->flags & SN_FINST_MASK))
4735 t->flags |= SN_FINST_D;
4736 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004737 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004738 /* write timeout */
4739 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004740 FD_CLR(t->srv_fd, StaticWriteEvent);
4741 tv_eternity(&t->swexpire);
4742 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004743 /* We must ensure that the read part is still alive when switching
4744 * to shutw */
4745 FD_SET(t->srv_fd, StaticReadEvent);
4746 if (t->proxy->srvtimeout)
4747 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004748 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004749 if (!(t->flags & SN_ERR_MASK))
4750 t->flags |= SN_ERR_SRVTO;
4751 if (!(t->flags & SN_FINST_MASK))
4752 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004753 return 1;
4754 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004755
4756 /* recompute request time-outs */
4757 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004758 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4759 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4760 tv_eternity(&t->swexpire);
4761 }
4762 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004763 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004764 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4765 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004766 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004767 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004768 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4769 t->srexpire = t->swexpire;
4770 }
willy tarreau0f7af912005-12-17 12:21:26 +01004771 else
4772 tv_eternity(&t->swexpire);
4773 }
4774 }
4775
willy tarreaub1ff9db2005-12-17 13:51:03 +01004776 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004777 if (rep->l == BUFSIZE) { /* no room to read more data */
4778 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4779 FD_CLR(t->srv_fd, StaticReadEvent);
4780 tv_eternity(&t->srexpire);
4781 }
4782 }
4783 else {
4784 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4785 FD_SET(t->srv_fd, StaticReadEvent);
4786 if (t->proxy->srvtimeout)
4787 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4788 else
4789 tv_eternity(&t->srexpire);
4790 }
4791 }
4792
4793 return 0; /* other cases change nothing */
4794 }
4795 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004796 if (t->res_sw == RES_ERROR) {
4797 //FD_CLR(t->srv_fd, StaticWriteEvent);
4798 tv_eternity(&t->swexpire);
4799 fd_delete(t->srv_fd);
4800 //close(t->srv_fd);
4801 t->srv_state = SV_STCLOSE;
4802 if (!(t->flags & SN_ERR_MASK))
4803 t->flags |= SN_ERR_SRVCL;
4804 if (!(t->flags & SN_FINST_MASK))
4805 t->flags |= SN_FINST_D;
4806 return 1;
4807 }
4808 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004809 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004810 tv_eternity(&t->swexpire);
4811 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004812 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004813 t->srv_state = SV_STCLOSE;
4814 return 1;
4815 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004816 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4817 //FD_CLR(t->srv_fd, StaticWriteEvent);
4818 tv_eternity(&t->swexpire);
4819 fd_delete(t->srv_fd);
4820 //close(t->srv_fd);
4821 t->srv_state = SV_STCLOSE;
4822 if (!(t->flags & SN_ERR_MASK))
4823 t->flags |= SN_ERR_SRVTO;
4824 if (!(t->flags & SN_FINST_MASK))
4825 t->flags |= SN_FINST_D;
4826 return 1;
4827 }
willy tarreau0f7af912005-12-17 12:21:26 +01004828 else if (req->l == 0) {
4829 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4830 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4831 tv_eternity(&t->swexpire);
4832 }
4833 }
4834 else { /* buffer not empty */
4835 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4836 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004837 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004838 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004839 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4840 t->srexpire = t->swexpire;
4841 }
willy tarreau0f7af912005-12-17 12:21:26 +01004842 else
4843 tv_eternity(&t->swexpire);
4844 }
4845 }
4846 return 0;
4847 }
4848 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004849 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004850 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004851 tv_eternity(&t->srexpire);
4852 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004853 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004854 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004855 if (!(t->flags & SN_ERR_MASK))
4856 t->flags |= SN_ERR_SRVCL;
4857 if (!(t->flags & SN_FINST_MASK))
4858 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004859 return 1;
4860 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004861 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4862 //FD_CLR(t->srv_fd, StaticReadEvent);
4863 tv_eternity(&t->srexpire);
4864 fd_delete(t->srv_fd);
4865 //close(t->srv_fd);
4866 t->srv_state = SV_STCLOSE;
4867 return 1;
4868 }
4869 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4870 //FD_CLR(t->srv_fd, StaticReadEvent);
4871 tv_eternity(&t->srexpire);
4872 fd_delete(t->srv_fd);
4873 //close(t->srv_fd);
4874 t->srv_state = SV_STCLOSE;
4875 if (!(t->flags & SN_ERR_MASK))
4876 t->flags |= SN_ERR_SRVTO;
4877 if (!(t->flags & SN_FINST_MASK))
4878 t->flags |= SN_FINST_D;
4879 return 1;
4880 }
willy tarreau0f7af912005-12-17 12:21:26 +01004881 else if (rep->l == BUFSIZE) { /* no room to read more data */
4882 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4883 FD_CLR(t->srv_fd, StaticReadEvent);
4884 tv_eternity(&t->srexpire);
4885 }
4886 }
4887 else {
4888 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4889 FD_SET(t->srv_fd, StaticReadEvent);
4890 if (t->proxy->srvtimeout)
4891 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4892 else
4893 tv_eternity(&t->srexpire);
4894 }
4895 }
4896 return 0;
4897 }
4898 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004899 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004900 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004901 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 +01004902 write(1, trash, len);
4903 }
4904 return 0;
4905 }
4906 return 0;
4907}
4908
4909
willy tarreau5cbea6f2005-12-17 12:48:26 +01004910/* Processes the client and server jobs of a session task, then
4911 * puts it back to the wait queue in a clean state, or
4912 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004913 * the time the task accepts to wait, or TIME_ETERNITY for
4914 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004915 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004916int process_session(struct task *t) {
4917 struct session *s = t->context;
4918 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004919
willy tarreau5cbea6f2005-12-17 12:48:26 +01004920 do {
4921 fsm_resync = 0;
4922 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4923 fsm_resync |= process_cli(s);
4924 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4925 fsm_resync |= process_srv(s);
4926 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4927 } while (fsm_resync);
4928
4929 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004930 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004931 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004932
willy tarreau5cbea6f2005-12-17 12:48:26 +01004933 tv_min(&min1, &s->crexpire, &s->cwexpire);
4934 tv_min(&min2, &s->srexpire, &s->swexpire);
4935 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004936 tv_min(&t->expire, &min1, &min2);
4937
4938 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004939 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004940
willy tarreaub952e1d2005-12-18 01:31:20 +01004941 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004942 }
4943
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004945 actconn--;
4946
willy tarreau982249e2005-12-18 00:57:06 +01004947 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004948 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004949 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 +01004950 write(1, trash, len);
4951 }
4952
willy tarreau750a4722005-12-17 13:21:24 +01004953 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004954 if (s->rep != NULL)
4955 s->logs.bytes = s->rep->total;
4956
willy tarreau9fe663a2005-12-17 13:02:59 +01004957 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004958 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004959 sess_log(s);
4960
willy tarreau0f7af912005-12-17 12:21:26 +01004961 /* the task MUST not be in the run queue anymore */
4962 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004963 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004964 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01004965 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004966}
4967
4968
4969
4970/*
4971 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004972 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004973 */
4974int process_chk(struct task *t) {
4975 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004976 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004977 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004978
willy tarreauef900ab2005-12-17 12:52:52 +01004979 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004980
4981 if (fd < 0) { /* no check currently running */
4982 //fprintf(stderr, "process_chk: 2\n");
4983 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4984 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01004985 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004986 }
4987
4988 /* we'll initiate a new check */
4989 s->result = 0; /* no result yet */
4990 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004991 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004992 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4993 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4994 //fprintf(stderr, "process_chk: 3\n");
4995
willy tarreaua41a8b42005-12-17 14:02:24 +01004996 /* we'll connect to the check port on the server */
4997 sa = s->addr;
4998 sa.sin_port = htons(s->check_port);
4999
willy tarreau0174f312005-12-18 01:02:42 +01005000 /* allow specific binding :
5001 * - server-specific at first
5002 * - proxy-specific next
5003 */
5004 if (s->state & SRV_BIND_SRC) {
5005 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5006 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5007 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5008 s->proxy->id, s->id);
5009 s->result = -1;
5010 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005011 }
willy tarreau0174f312005-12-18 01:02:42 +01005012 else if (s->proxy->options & PR_O_BIND_SRC) {
5013 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5014 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5015 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5016 s->proxy->id);
5017 s->result = -1;
5018 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005019 }
willy tarreau0174f312005-12-18 01:02:42 +01005020
5021 if (!s->result) {
5022 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5023 /* OK, connection in progress or established */
5024
5025 //fprintf(stderr, "process_chk: 4\n");
5026
5027 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5028 fdtab[fd].owner = t;
5029 fdtab[fd].read = &event_srv_chk_r;
5030 fdtab[fd].write = &event_srv_chk_w;
5031 fdtab[fd].state = FD_STCONN; /* connection in progress */
5032 FD_SET(fd, StaticWriteEvent); /* for connect status */
5033 fd_insert(fd);
5034 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5035 tv_delayfrom(&t->expire, &now, s->inter);
5036 task_queue(t); /* restore t to its place in the task list */
5037 return tv_remain(&now, &t->expire);
5038 }
5039 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5040 s->result = -1; /* a real error */
5041 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005042 }
5043 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005044 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005045 }
5046
5047 if (!s->result) { /* nothing done */
5048 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005049 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005050 task_queue(t); /* restore t to its place in the task list */
5051 return tv_remain(&now, &t->expire);
5052 }
5053
5054 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005055 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005056 s->health--; /* still good */
5057 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005058 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005059 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005060 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005061 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005062
willy tarreaudd07e972005-12-18 00:48:48 +01005063 if (find_server(s->proxy) == NULL) {
5064 Alert("Proxy %s has no server available !\n", s->proxy->id);
5065 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5066 }
5067 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005068 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005069 }
5070
5071 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005072 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5073 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005074 }
5075 else {
5076 //fprintf(stderr, "process_chk: 8\n");
5077 /* there was a test running */
5078 if (s->result > 0) { /* good server detected */
5079 //fprintf(stderr, "process_chk: 9\n");
5080 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005081 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005082 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005083 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005084 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005085 }
willy tarreauef900ab2005-12-17 12:52:52 +01005086
willy tarreaue47c8d72005-12-17 12:55:52 +01005087 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005088 s->state |= SRV_RUNNING;
5089 }
willy tarreauef900ab2005-12-17 12:52:52 +01005090 s->curfd = -1; /* no check running anymore */
5091 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005092 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005093 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005094 }
5095 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5096 //fprintf(stderr, "process_chk: 10\n");
5097 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005098 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005099 s->health--; /* still good */
5100 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005101 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005102
willy tarreaudd07e972005-12-18 00:48:48 +01005103 if (s->health == s->rise) {
5104 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005105 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005106
5107 if (find_server(s->proxy) == NULL) {
5108 Alert("Proxy %s has no server available !\n", s->proxy->id);
5109 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5110 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005111 }
willy tarreauef900ab2005-12-17 12:52:52 +01005112
willy tarreau5cbea6f2005-12-17 12:48:26 +01005113 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005114 }
5115 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005116 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005117 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005118 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005119 }
5120 /* if result is 0 and there's no timeout, we have to wait again */
5121 }
5122 //fprintf(stderr, "process_chk: 11\n");
5123 s->result = 0;
5124 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005125 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005126}
5127
5128
willy tarreau5cbea6f2005-12-17 12:48:26 +01005129
willy tarreau0f7af912005-12-17 12:21:26 +01005130#if STATTIME > 0
5131int stats(void);
5132#endif
5133
5134/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005135 * This does 4 things :
5136 * - wake up all expired tasks
5137 * - call all runnable tasks
5138 * - call maintain_proxies() to enable/disable the listeners
5139 * - return the delay till next event in ms, -1 = wait indefinitely
5140 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5141 *
willy tarreau0f7af912005-12-17 12:21:26 +01005142 */
5143
willy tarreau1c2ad212005-12-18 01:11:29 +01005144int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005145 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005146 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005147 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005148
willy tarreaub952e1d2005-12-18 01:31:20 +01005149 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005150
willy tarreau1c2ad212005-12-18 01:11:29 +01005151 /* look for expired tasks and add them to the run queue.
5152 */
5153 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5154 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5155 tnext = t->next;
5156 if (t->state & TASK_RUNNING)
5157 continue;
5158
willy tarreaub952e1d2005-12-18 01:31:20 +01005159 if (tv_iseternity(&t->expire))
5160 continue;
5161
willy tarreau1c2ad212005-12-18 01:11:29 +01005162 /* wakeup expired entries. It doesn't matter if they are
5163 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005164 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005165 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005166 task_wakeup(&rq, t);
5167 }
5168 else {
5169 /* first non-runnable task. Use its expiration date as an upper bound */
5170 int temp_time = tv_remain(&now, &t->expire);
5171 if (temp_time)
5172 next_time = temp_time;
5173 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005174 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005175 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005176
willy tarreau1c2ad212005-12-18 01:11:29 +01005177 /* process each task in the run queue now. Each task may be deleted
5178 * since we only use tnext.
5179 */
5180 tnext = rq;
5181 while ((t = tnext) != NULL) {
5182 int temp_time;
5183
5184 tnext = t->rqnext;
5185 task_sleep(&rq, t);
5186 temp_time = t->process(t);
5187 next_time = MINTIME(temp_time, next_time);
5188 }
5189
5190 /* maintain all proxies in a consistent state. This should quickly become a task */
5191 time2 = maintain_proxies();
5192 return MINTIME(time2, next_time);
5193}
5194
5195
5196#if defined(ENABLE_EPOLL)
5197
5198/*
5199 * Main epoll() loop.
5200 */
5201
5202/* does 3 actions :
5203 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5204 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5205 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5206 *
5207 * returns 0 if initialization failed, !0 otherwise.
5208 */
5209
5210int epoll_loop(int action) {
5211 int next_time;
5212 int status;
5213 int fd;
5214
5215 int fds, count;
5216 int pr, pw, sr, sw;
5217 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5218 struct epoll_event ev;
5219
5220 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005221 static struct epoll_event *epoll_events = NULL;
5222 static int epoll_fd;
5223
5224 if (action == POLL_LOOP_ACTION_INIT) {
5225 epoll_fd = epoll_create(global.maxsock + 1);
5226 if (epoll_fd < 0)
5227 return 0;
5228 else {
5229 epoll_events = (struct epoll_event*)
5230 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5231 PrevReadEvent = (fd_set *)
5232 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5233 PrevWriteEvent = (fd_set *)
5234 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005235 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005236 return 1;
5237 }
5238 else if (action == POLL_LOOP_ACTION_CLEAN) {
5239 if (PrevWriteEvent) free(PrevWriteEvent);
5240 if (PrevReadEvent) free(PrevReadEvent);
5241 if (epoll_events) free(epoll_events);
5242 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005243 epoll_fd = 0;
5244 return 1;
5245 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005246
willy tarreau1c2ad212005-12-18 01:11:29 +01005247 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005248
willy tarreau1c2ad212005-12-18 01:11:29 +01005249 tv_now(&now);
5250
5251 while (1) {
5252 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005253
5254 /* stop when there's no connection left and we don't allow them anymore */
5255 if (!actconn && listeners == 0)
5256 break;
5257
willy tarreau0f7af912005-12-17 12:21:26 +01005258#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005259 {
5260 int time2;
5261 time2 = stats();
5262 next_time = MINTIME(time2, next_time);
5263 }
willy tarreau0f7af912005-12-17 12:21:26 +01005264#endif
5265
willy tarreau1c2ad212005-12-18 01:11:29 +01005266 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5267
5268 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5269 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5270
5271 if ((ro^rn) | (wo^wn)) {
5272 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5273#define FDSETS_ARE_INT_ALIGNED
5274#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005275
willy tarreauad90a0c2005-12-18 01:09:15 +01005276#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5277#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005278 pr = (ro >> count) & 1;
5279 pw = (wo >> count) & 1;
5280 sr = (rn >> count) & 1;
5281 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005282#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005283 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5284 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5285 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5286 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005287#endif
5288#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005289 pr = FD_ISSET(fd, PrevReadEvent);
5290 pw = FD_ISSET(fd, PrevWriteEvent);
5291 sr = FD_ISSET(fd, StaticReadEvent);
5292 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005293#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005294 if (!((sr^pr) | (sw^pw)))
5295 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005296
willy tarreau1c2ad212005-12-18 01:11:29 +01005297 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5298 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005299
willy tarreaub952e1d2005-12-18 01:31:20 +01005300#ifdef EPOLL_CTL_MOD_WORKAROUND
5301 /* I encountered a rarely reproducible problem with
5302 * EPOLL_CTL_MOD where a modified FD (systematically
5303 * the one in epoll_events[0], fd#7) would sometimes
5304 * be set EPOLL_OUT while asked for a read ! This is
5305 * with the 2.4 epoll patch. The workaround is to
5306 * delete then recreate in case of modification.
5307 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5308 * nor RHEL kernels.
5309 */
5310
5311 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5312 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5313
5314 if ((sr | sw))
5315 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5316#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005317 if ((pr | pw)) {
5318 /* the file-descriptor already exists... */
5319 if ((sr | sw)) {
5320 /* ...and it will still exist */
5321 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5322 // perror("epoll_ctl(MOD)");
5323 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005324 }
5325 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005326 /* ...and it will be removed */
5327 if (fdtab[fd].state != FD_STCLOSE &&
5328 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5329 // perror("epoll_ctl(DEL)");
5330 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005331 }
5332 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005333 } else {
5334 /* the file-descriptor did not exist, let's add it */
5335 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5336 // perror("epoll_ctl(ADD)");
5337 // exit(1);
5338 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005339 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005340#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005341 }
5342 ((int*)PrevReadEvent)[fds] = rn;
5343 ((int*)PrevWriteEvent)[fds] = wn;
5344 }
5345 }
5346
5347 /* now let's wait for events */
5348 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5349 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005350
willy tarreau1c2ad212005-12-18 01:11:29 +01005351 for (count = 0; count < status; count++) {
5352 fd = epoll_events[count].data.fd;
5353
5354 if (fdtab[fd].state == FD_STCLOSE)
5355 continue;
5356
5357 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5358 fdtab[fd].read(fd);
5359
5360 if (fdtab[fd].state == FD_STCLOSE)
5361 continue;
5362
5363 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5364 fdtab[fd].write(fd);
5365 }
5366 }
5367 return 1;
5368}
5369#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005370
willy tarreauad90a0c2005-12-18 01:09:15 +01005371
willy tarreau5cbea6f2005-12-17 12:48:26 +01005372
willy tarreau1c2ad212005-12-18 01:11:29 +01005373#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005374
willy tarreau1c2ad212005-12-18 01:11:29 +01005375/*
5376 * Main poll() loop.
5377 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005378
willy tarreau1c2ad212005-12-18 01:11:29 +01005379/* does 3 actions :
5380 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5381 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5382 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5383 *
5384 * returns 0 if initialization failed, !0 otherwise.
5385 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005386
willy tarreau1c2ad212005-12-18 01:11:29 +01005387int poll_loop(int action) {
5388 int next_time;
5389 int status;
5390 int fd, nbfd;
5391
5392 int fds, count;
5393 int sr, sw;
5394 unsigned rn, wn; /* read new, write new */
5395
5396 /* private data */
5397 static struct pollfd *poll_events = NULL;
5398
5399 if (action == POLL_LOOP_ACTION_INIT) {
5400 poll_events = (struct pollfd*)
5401 calloc(1, sizeof(struct pollfd) * global.maxsock);
5402 return 1;
5403 }
5404 else if (action == POLL_LOOP_ACTION_CLEAN) {
5405 if (poll_events)
5406 free(poll_events);
5407 return 1;
5408 }
5409
5410 /* OK, it's POLL_LOOP_ACTION_RUN */
5411
5412 tv_now(&now);
5413
5414 while (1) {
5415 next_time = process_runnable_tasks();
5416
5417 /* stop when there's no connection left and we don't allow them anymore */
5418 if (!actconn && listeners == 0)
5419 break;
5420
5421#if STATTIME > 0
5422 {
5423 int time2;
5424 time2 = stats();
5425 next_time = MINTIME(time2, next_time);
5426 }
5427#endif
5428
5429
5430 nbfd = 0;
5431 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5432
5433 rn = ((int*)StaticReadEvent)[fds];
5434 wn = ((int*)StaticWriteEvent)[fds];
5435
5436 if ((rn|wn)) {
5437 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5438#define FDSETS_ARE_INT_ALIGNED
5439#ifdef FDSETS_ARE_INT_ALIGNED
5440
5441#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5442#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5443 sr = (rn >> count) & 1;
5444 sw = (wn >> count) & 1;
5445#else
5446 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5447 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5448#endif
5449#else
5450 sr = FD_ISSET(fd, StaticReadEvent);
5451 sw = FD_ISSET(fd, StaticWriteEvent);
5452#endif
5453 if ((sr|sw)) {
5454 poll_events[nbfd].fd = fd;
5455 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5456 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005457 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005458 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005459 }
5460 }
5461
5462 /* now let's wait for events */
5463 status = poll(poll_events, nbfd, next_time);
5464 tv_now(&now);
5465
5466 for (count = 0; status > 0 && count < nbfd; count++) {
5467 fd = poll_events[count].fd;
5468
5469 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5470 continue;
5471
5472 /* ok, we found one active fd */
5473 status--;
5474
5475 if (fdtab[fd].state == FD_STCLOSE)
5476 continue;
5477
5478 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5479 fdtab[fd].read(fd);
5480
5481 if (fdtab[fd].state == FD_STCLOSE)
5482 continue;
5483
5484 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5485 fdtab[fd].write(fd);
5486 }
5487 }
5488 return 1;
5489}
willy tarreauad90a0c2005-12-18 01:09:15 +01005490#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005491
willy tarreauad90a0c2005-12-18 01:09:15 +01005492
willy tarreauad90a0c2005-12-18 01:09:15 +01005493
willy tarreau1c2ad212005-12-18 01:11:29 +01005494/*
5495 * Main select() loop.
5496 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005497
willy tarreau1c2ad212005-12-18 01:11:29 +01005498/* does 3 actions :
5499 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5500 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5501 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5502 *
5503 * returns 0 if initialization failed, !0 otherwise.
5504 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005505
willy tarreauad90a0c2005-12-18 01:09:15 +01005506
willy tarreau1c2ad212005-12-18 01:11:29 +01005507int select_loop(int action) {
5508 int next_time;
5509 int status;
5510 int fd,i;
5511 struct timeval delta;
5512 int readnotnull, writenotnull;
5513 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005514
willy tarreau1c2ad212005-12-18 01:11:29 +01005515 if (action == POLL_LOOP_ACTION_INIT) {
5516 ReadEvent = (fd_set *)
5517 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5518 WriteEvent = (fd_set *)
5519 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5520 return 1;
5521 }
5522 else if (action == POLL_LOOP_ACTION_CLEAN) {
5523 if (WriteEvent) free(WriteEvent);
5524 if (ReadEvent) free(ReadEvent);
5525 return 1;
5526 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005527
willy tarreau1c2ad212005-12-18 01:11:29 +01005528 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005529
willy tarreau1c2ad212005-12-18 01:11:29 +01005530 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005531
willy tarreau1c2ad212005-12-18 01:11:29 +01005532 while (1) {
5533 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005534
willy tarreau1c2ad212005-12-18 01:11:29 +01005535 /* stop when there's no connection left and we don't allow them anymore */
5536 if (!actconn && listeners == 0)
5537 break;
5538
5539#if STATTIME > 0
5540 {
5541 int time2;
5542 time2 = stats();
5543 next_time = MINTIME(time2, next_time);
5544 }
5545#endif
5546
willy tarreau1c2ad212005-12-18 01:11:29 +01005547 if (next_time > 0) { /* FIXME */
5548 /* Convert to timeval */
5549 /* to avoid eventual select loops due to timer precision */
5550 next_time += SCHEDULER_RESOLUTION;
5551 delta.tv_sec = next_time / 1000;
5552 delta.tv_usec = (next_time % 1000) * 1000;
5553 }
5554 else if (next_time == 0) { /* allow select to return immediately when needed */
5555 delta.tv_sec = delta.tv_usec = 0;
5556 }
5557
5558
5559 /* let's restore fdset state */
5560
5561 readnotnull = 0; writenotnull = 0;
5562 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5563 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5564 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5565 }
5566
5567 // /* just a verification code, needs to be removed for performance */
5568 // for (i=0; i<maxfd; i++) {
5569 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5570 // abort();
5571 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5572 // abort();
5573 //
5574 // }
5575
5576 status = select(maxfd,
5577 readnotnull ? ReadEvent : NULL,
5578 writenotnull ? WriteEvent : NULL,
5579 NULL,
5580 (next_time >= 0) ? &delta : NULL);
5581
5582 /* this is an experiment on the separation of the select work */
5583 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5584 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5585
5586 tv_now(&now);
5587
5588 if (status > 0) { /* must proceed with events */
5589
5590 int fds;
5591 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005592
willy tarreau1c2ad212005-12-18 01:11:29 +01005593 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5594 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5595 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5596
5597 /* if we specify read first, the accepts and zero reads will be
5598 * seen first. Moreover, system buffers will be flushed faster.
5599 */
5600 if (fdtab[fd].state == FD_STCLOSE)
5601 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005602
willy tarreau1c2ad212005-12-18 01:11:29 +01005603 if (FD_ISSET(fd, ReadEvent))
5604 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005605
willy tarreau1c2ad212005-12-18 01:11:29 +01005606 if (FD_ISSET(fd, WriteEvent))
5607 fdtab[fd].write(fd);
5608 }
5609 }
5610 else {
5611 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005612 }
willy tarreau0f7af912005-12-17 12:21:26 +01005613 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005614 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005615}
5616
5617
5618#if STATTIME > 0
5619/*
5620 * Display proxy statistics regularly. It is designed to be called from the
5621 * select_loop().
5622 */
5623int stats(void) {
5624 static int lines;
5625 static struct timeval nextevt;
5626 static struct timeval lastevt;
5627 static struct timeval starttime = {0,0};
5628 unsigned long totaltime, deltatime;
5629 int ret;
5630
willy tarreau750a4722005-12-17 13:21:24 +01005631 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005632 deltatime = (tv_diff(&lastevt, &now)?:1);
5633 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005634
willy tarreau9fe663a2005-12-17 13:02:59 +01005635 if (global.mode & MODE_STATS) {
5636 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005637 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005638 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5639 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005640 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005641 actconn, totalconn,
5642 stats_tsk_new, stats_tsk_good,
5643 stats_tsk_left, stats_tsk_right,
5644 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5645 }
5646 }
5647
5648 tv_delayfrom(&nextevt, &now, STATTIME);
5649
5650 lastevt=now;
5651 }
5652 ret = tv_remain(&now, &nextevt);
5653 return ret;
5654}
5655#endif
5656
5657
5658/*
5659 * this function enables proxies when there are enough free sessions,
5660 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005661 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005662 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005663 */
5664static int maintain_proxies(void) {
5665 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005666 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005667 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005668
5669 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005670 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005671
5672 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005673 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005674 while (p) {
5675 if (p->nbconn < p->maxconn) {
5676 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005677 for (l = p->listen; l != NULL; l = l->next) {
5678 FD_SET(l->fd, StaticReadEvent);
5679 }
willy tarreau0f7af912005-12-17 12:21:26 +01005680 p->state = PR_STRUN;
5681 }
5682 }
5683 else {
5684 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005685 for (l = p->listen; l != NULL; l = l->next) {
5686 FD_CLR(l->fd, StaticReadEvent);
5687 }
willy tarreau0f7af912005-12-17 12:21:26 +01005688 p->state = PR_STIDLE;
5689 }
5690 }
5691 p = p->next;
5692 }
5693 }
5694 else { /* block all proxies */
5695 while (p) {
5696 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005697 for (l = p->listen; l != NULL; l = l->next) {
5698 FD_CLR(l->fd, StaticReadEvent);
5699 }
willy tarreau0f7af912005-12-17 12:21:26 +01005700 p->state = PR_STIDLE;
5701 }
5702 p = p->next;
5703 }
5704 }
5705
willy tarreau5cbea6f2005-12-17 12:48:26 +01005706 if (stopping) {
5707 p = proxy;
5708 while (p) {
5709 if (p->state != PR_STDISABLED) {
5710 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005711 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005712 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005713 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005714 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005715
willy tarreaua41a8b42005-12-17 14:02:24 +01005716 for (l = p->listen; l != NULL; l = l->next) {
5717 fd_delete(l->fd);
5718 listeners--;
5719 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005720 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005721 }
5722 else {
5723 tleft = MINTIME(t, tleft);
5724 }
5725 }
5726 p = p->next;
5727 }
5728 }
5729 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005730}
5731
5732/*
5733 * this function disables health-check servers so that the process will quickly be ignored
5734 * by load balancers.
5735 */
5736static void soft_stop(void) {
5737 struct proxy *p;
5738
5739 stopping = 1;
5740 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005741 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005742 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005743 if (p->state != PR_STDISABLED) {
5744 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005745 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005746 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005747 }
willy tarreau0f7af912005-12-17 12:21:26 +01005748 p = p->next;
5749 }
5750}
5751
5752/*
5753 * upon SIGUSR1, let's have a soft stop.
5754 */
5755void sig_soft_stop(int sig) {
5756 soft_stop();
5757 signal(sig, SIG_IGN);
5758}
5759
5760
willy tarreau8337c6b2005-12-17 13:41:01 +01005761/*
5762 * this function dumps every server's state when the process receives SIGHUP.
5763 */
5764void sig_dump_state(int sig) {
5765 struct proxy *p = proxy;
5766
5767 Warning("SIGHUP received, dumping servers states.\n");
5768 while (p) {
5769 struct server *s = p->srv;
5770
5771 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5772 while (s) {
5773 if (s->state & SRV_RUNNING) {
5774 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5775 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5776 }
5777 else {
5778 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5779 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5780 }
5781 s = s->next;
5782 }
willy tarreaudd07e972005-12-18 00:48:48 +01005783
5784 if (find_server(p) == NULL) {
5785 Warning("SIGHUP: proxy %s has no server available !\n", p);
5786 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5787 }
5788
willy tarreau8337c6b2005-12-17 13:41:01 +01005789 p = p->next;
5790 }
5791 signal(sig, sig_dump_state);
5792}
5793
willy tarreau0f7af912005-12-17 12:21:26 +01005794void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005795 struct task *t, *tnext;
5796 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005797
willy tarreau5cbea6f2005-12-17 12:48:26 +01005798 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5799 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5800 tnext = t->next;
5801 s = t->context;
5802 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5803 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5804 "req=%d, rep=%d, clifd=%d\n",
5805 s, tv_remain(&now, &t->expire),
5806 s->cli_state,
5807 s->srv_state,
5808 FD_ISSET(s->cli_fd, StaticReadEvent),
5809 FD_ISSET(s->cli_fd, StaticWriteEvent),
5810 FD_ISSET(s->srv_fd, StaticReadEvent),
5811 FD_ISSET(s->srv_fd, StaticWriteEvent),
5812 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5813 );
willy tarreau0f7af912005-12-17 12:21:26 +01005814 }
willy tarreau12350152005-12-18 01:03:27 +01005815}
5816
willy tarreau64a3cc32005-12-18 01:13:11 +01005817#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005818static void fast_stop(void)
5819{
5820 struct proxy *p;
5821 p = proxy;
5822 while (p) {
5823 p->grace = 0;
5824 p = p->next;
5825 }
5826 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005827}
5828
willy tarreau12350152005-12-18 01:03:27 +01005829void sig_int(int sig) {
5830 /* This would normally be a hard stop,
5831 but we want to be sure about deallocation,
5832 and so on, so we do a soft stop with
5833 0 GRACE time
5834 */
5835 fast_stop();
5836 /* If we are killed twice, we decide to die*/
5837 signal(sig, SIG_DFL);
5838}
5839
5840void sig_term(int sig) {
5841 /* This would normally be a hard stop,
5842 but we want to be sure about deallocation,
5843 and so on, so we do a soft stop with
5844 0 GRACE time
5845 */
5846 fast_stop();
5847 /* If we are killed twice, we decide to die*/
5848 signal(sig, SIG_DFL);
5849}
willy tarreau64a3cc32005-12-18 01:13:11 +01005850#endif
willy tarreau12350152005-12-18 01:03:27 +01005851
willy tarreauc1f47532005-12-18 01:08:26 +01005852/* returns the pointer to an error in the replacement string, or NULL if OK */
5853char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005854 struct hdr_exp *exp;
5855
willy tarreauc1f47532005-12-18 01:08:26 +01005856 if (replace != NULL) {
5857 char *err;
5858 err = check_replace_string(replace);
5859 if (err)
5860 return err;
5861 }
5862
willy tarreaue39cd132005-12-17 13:00:18 +01005863 while (*head != NULL)
5864 head = &(*head)->next;
5865
5866 exp = calloc(1, sizeof(struct hdr_exp));
5867
5868 exp->preg = preg;
5869 exp->replace = replace;
5870 exp->action = action;
5871 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005872
5873 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005874}
5875
willy tarreau9fe663a2005-12-17 13:02:59 +01005876
willy tarreau0f7af912005-12-17 12:21:26 +01005877/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005878 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005879 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005880int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005881
willy tarreau9fe663a2005-12-17 13:02:59 +01005882 if (!strcmp(args[0], "global")) { /* new section */
5883 /* no option, nothing special to do */
5884 return 0;
5885 }
5886 else if (!strcmp(args[0], "daemon")) {
5887 global.mode |= MODE_DAEMON;
5888 }
5889 else if (!strcmp(args[0], "debug")) {
5890 global.mode |= MODE_DEBUG;
5891 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005892 else if (!strcmp(args[0], "noepoll")) {
5893 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5894 }
5895 else if (!strcmp(args[0], "nopoll")) {
5896 cfg_polling_mechanism &= ~POLL_USE_POLL;
5897 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005898 else if (!strcmp(args[0], "quiet")) {
5899 global.mode |= MODE_QUIET;
5900 }
5901 else if (!strcmp(args[0], "stats")) {
5902 global.mode |= MODE_STATS;
5903 }
5904 else if (!strcmp(args[0], "uid")) {
5905 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005906 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005907 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005908 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005909 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005910 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005911 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005913 global.uid = atol(args[1]);
5914 }
5915 else if (!strcmp(args[0], "gid")) {
5916 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005917 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005918 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005919 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005920 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005921 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005922 return -1;
5923 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005924 global.gid = atol(args[1]);
5925 }
5926 else if (!strcmp(args[0], "nbproc")) {
5927 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005928 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005929 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005930 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005931 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005932 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005933 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005935 global.nbproc = atol(args[1]);
5936 }
5937 else if (!strcmp(args[0], "maxconn")) {
5938 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005939 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005940 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005941 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005942 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005946 global.maxconn = atol(args[1]);
5947 }
willy tarreaub1285d52005-12-18 01:20:14 +01005948 else if (!strcmp(args[0], "ulimit-n")) {
5949 if (global.rlimit_nofile != 0) {
5950 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5951 return 0;
5952 }
5953 if (*(args[1]) == 0) {
5954 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5955 return -1;
5956 }
5957 global.rlimit_nofile = atol(args[1]);
5958 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005959 else if (!strcmp(args[0], "chroot")) {
5960 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005961 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005962 return 0;
5963 }
5964 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005965 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005966 return -1;
5967 }
5968 global.chroot = strdup(args[1]);
5969 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005970 else if (!strcmp(args[0], "pidfile")) {
5971 if (global.pidfile != NULL) {
5972 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5973 return 0;
5974 }
5975 if (*(args[1]) == 0) {
5976 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5977 return -1;
5978 }
5979 global.pidfile = strdup(args[1]);
5980 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005981 else if (!strcmp(args[0], "log")) { /* syslog server address */
5982 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005983 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005984
5985 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005986 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005987 return -1;
5988 }
5989
5990 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5991 if (!strcmp(log_facilities[facility], args[2]))
5992 break;
5993
5994 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005995 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 exit(1);
5997 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005998
5999 level = 7; /* max syslog level = debug */
6000 if (*(args[3])) {
6001 while (level >= 0 && strcmp(log_levels[level], args[3]))
6002 level--;
6003 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006004 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006005 exit(1);
6006 }
6007 }
6008
willy tarreau9fe663a2005-12-17 13:02:59 +01006009 sa = str2sa(args[1]);
6010 if (!sa->sin_port)
6011 sa->sin_port = htons(SYSLOG_PORT);
6012
6013 if (global.logfac1 == -1) {
6014 global.logsrv1 = *sa;
6015 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006016 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006017 }
6018 else if (global.logfac2 == -1) {
6019 global.logsrv2 = *sa;
6020 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006021 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006022 }
6023 else {
6024 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6025 return -1;
6026 }
6027
6028 }
6029 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006030 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006031 return -1;
6032 }
6033 return 0;
6034}
6035
6036
willy tarreaua41a8b42005-12-17 14:02:24 +01006037void init_default_instance() {
6038 memset(&defproxy, 0, sizeof(defproxy));
6039 defproxy.mode = PR_MODE_TCP;
6040 defproxy.state = PR_STNEW;
6041 defproxy.maxconn = cfg_maxpconn;
6042 defproxy.conn_retries = CONN_RETRIES;
6043 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6044}
6045
willy tarreau9fe663a2005-12-17 13:02:59 +01006046/*
6047 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6048 */
6049int cfg_parse_listen(char *file, int linenum, char **args) {
6050 static struct proxy *curproxy = NULL;
6051 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006052 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006053 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006054
6055 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006056 if (!*args[1]) {
6057 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6058 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006059 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006060 return -1;
6061 }
6062
6063 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006064 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006065 return -1;
6066 }
6067 curproxy->next = proxy;
6068 proxy = curproxy;
6069 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006070
6071 /* parse the listener address if any */
6072 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006073 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006074 if (!curproxy->listen)
6075 return -1;
6076 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006077
willy tarreau9fe663a2005-12-17 13:02:59 +01006078 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006079 curproxy->state = defproxy.state;
6080 curproxy->maxconn = defproxy.maxconn;
6081 curproxy->conn_retries = defproxy.conn_retries;
6082 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006083
6084 if (defproxy.check_req)
6085 curproxy->check_req = strdup(defproxy.check_req);
6086 curproxy->check_len = defproxy.check_len;
6087
6088 if (defproxy.cookie_name)
6089 curproxy->cookie_name = strdup(defproxy.cookie_name);
6090 curproxy->cookie_len = defproxy.cookie_len;
6091
6092 if (defproxy.capture_name)
6093 curproxy->capture_name = strdup(defproxy.capture_name);
6094 curproxy->capture_namelen = defproxy.capture_namelen;
6095 curproxy->capture_len = defproxy.capture_len;
6096
6097 if (defproxy.errmsg.msg400)
6098 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6099 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6100
6101 if (defproxy.errmsg.msg403)
6102 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6103 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6104
6105 if (defproxy.errmsg.msg408)
6106 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6107 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6108
6109 if (defproxy.errmsg.msg500)
6110 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6111 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6112
6113 if (defproxy.errmsg.msg502)
6114 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6115 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6116
6117 if (defproxy.errmsg.msg503)
6118 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6119 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6120
6121 if (defproxy.errmsg.msg504)
6122 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6123 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6124
willy tarreaua41a8b42005-12-17 14:02:24 +01006125 curproxy->clitimeout = defproxy.clitimeout;
6126 curproxy->contimeout = defproxy.contimeout;
6127 curproxy->srvtimeout = defproxy.srvtimeout;
6128 curproxy->mode = defproxy.mode;
6129 curproxy->logfac1 = defproxy.logfac1;
6130 curproxy->logsrv1 = defproxy.logsrv1;
6131 curproxy->loglev1 = defproxy.loglev1;
6132 curproxy->logfac2 = defproxy.logfac2;
6133 curproxy->logsrv2 = defproxy.logsrv2;
6134 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006135 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006136 curproxy->grace = defproxy.grace;
6137 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006138 curproxy->mon_net = defproxy.mon_net;
6139 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006140 return 0;
6141 }
6142 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006143 /* some variables may have already been initialized earlier */
6144 if (defproxy.check_req) free(defproxy.check_req);
6145 if (defproxy.cookie_name) free(defproxy.cookie_name);
6146 if (defproxy.capture_name) free(defproxy.capture_name);
6147 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6148 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6149 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6150 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6151 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6152 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6153 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6154
6155 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006156 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006157 return 0;
6158 }
6159 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006160 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006161 return -1;
6162 }
6163
willy tarreaua41a8b42005-12-17 14:02:24 +01006164 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6165 if (curproxy == &defproxy) {
6166 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6167 return -1;
6168 }
6169
6170 if (strchr(args[1], ':') == NULL) {
6171 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6172 file, linenum, args[0]);
6173 return -1;
6174 }
6175 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006176 if (!curproxy->listen)
6177 return -1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006178 return 0;
6179 }
willy tarreaub1285d52005-12-18 01:20:14 +01006180 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6181 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6182 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6183 file, linenum, args[0]);
6184 return -1;
6185 }
6186 /* flush useless bits */
6187 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6188 return 0;
6189 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006190 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006191 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6192 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6193 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6194 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006195 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006196 return -1;
6197 }
6198 }
6199 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6200 curproxy->state = PR_STDISABLED;
6201 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006202 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6203 curproxy->state = PR_STNEW;
6204 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006205 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6206 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006207// if (curproxy == &defproxy) {
6208// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6209// return -1;
6210// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006211
willy tarreau9fe663a2005-12-17 13:02:59 +01006212 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006213// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6214// file, linenum);
6215// return 0;
6216 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006217 }
6218
6219 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006220 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6221 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006222 return -1;
6223 }
6224 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006225 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006226
6227 cur_arg = 2;
6228 while (*(args[cur_arg])) {
6229 if (!strcmp(args[cur_arg], "rewrite")) {
6230 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006231 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006232 else if (!strcmp(args[cur_arg], "indirect")) {
6233 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006234 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006235 else if (!strcmp(args[cur_arg], "insert")) {
6236 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006237 }
willy tarreau240afa62005-12-17 13:14:35 +01006238 else if (!strcmp(args[cur_arg], "nocache")) {
6239 curproxy->options |= PR_O_COOK_NOC;
6240 }
willy tarreaucd878942005-12-17 13:27:43 +01006241 else if (!strcmp(args[cur_arg], "postonly")) {
6242 curproxy->options |= PR_O_COOK_POST;
6243 }
willy tarreau0174f312005-12-18 01:02:42 +01006244 else if (!strcmp(args[cur_arg], "prefix")) {
6245 curproxy->options |= PR_O_COOK_PFX;
6246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006247 else {
willy tarreau0174f312005-12-18 01:02:42 +01006248 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006249 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006250 return -1;
6251 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006252 cur_arg++;
6253 }
willy tarreau0174f312005-12-18 01:02:42 +01006254 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6255 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6256 file, linenum);
6257 return -1;
6258 }
6259
6260 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6261 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006262 file, linenum);
6263 return -1;
6264 }
willy tarreau12350152005-12-18 01:03:27 +01006265 }/* end else if (!strcmp(args[0], "cookie")) */
6266 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6267// if (curproxy == &defproxy) {
6268// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6269// return -1;
6270// }
6271
6272 if (curproxy->appsession_name != NULL) {
6273// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6274// file, linenum);
6275// return 0;
6276 free(curproxy->appsession_name);
6277 }
6278
6279 if (*(args[5]) == 0) {
6280 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6281 file, linenum, args[0]);
6282 return -1;
6283 }
6284 have_appsession = 1;
6285 curproxy->appsession_name = strdup(args[1]);
6286 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6287 curproxy->appsession_len = atoi(args[3]);
6288 curproxy->appsession_timeout = atoi(args[5]);
6289 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6290 if (rc) {
6291 Alert("Error Init Appsession Hashtable.\n");
6292 return -1;
6293 }
6294 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006295 else if (!strcmp(args[0], "capture")) {
6296 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6297 // if (curproxy == &defproxy) {
6298 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6299 // return -1;
6300 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006301
willy tarreau4302f492005-12-18 01:00:37 +01006302 if (curproxy->capture_name != NULL) {
6303 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6304 // file, linenum, args[0]);
6305 // return 0;
6306 free(curproxy->capture_name);
6307 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006308
willy tarreau4302f492005-12-18 01:00:37 +01006309 if (*(args[4]) == 0) {
6310 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6311 file, linenum, args[0]);
6312 return -1;
6313 }
6314 curproxy->capture_name = strdup(args[2]);
6315 curproxy->capture_namelen = strlen(curproxy->capture_name);
6316 curproxy->capture_len = atol(args[4]);
6317 if (curproxy->capture_len >= CAPTURE_LEN) {
6318 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6319 file, linenum, CAPTURE_LEN - 1);
6320 curproxy->capture_len = CAPTURE_LEN - 1;
6321 }
6322 curproxy->to_log |= LW_COOKIE;
6323 }
6324 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6325 struct cap_hdr *hdr;
6326
6327 if (curproxy == &defproxy) {
6328 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6329 return -1;
6330 }
6331
6332 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6333 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6334 file, linenum, args[0], args[1]);
6335 return -1;
6336 }
6337
6338 hdr = calloc(sizeof(struct cap_hdr), 1);
6339 hdr->next = curproxy->req_cap;
6340 hdr->name = strdup(args[3]);
6341 hdr->namelen = strlen(args[3]);
6342 hdr->len = atol(args[5]);
6343 hdr->index = curproxy->nb_req_cap++;
6344 curproxy->req_cap = hdr;
6345 curproxy->to_log |= LW_REQHDR;
6346 }
6347 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6348 struct cap_hdr *hdr;
6349
6350 if (curproxy == &defproxy) {
6351 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6352 return -1;
6353 }
6354
6355 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6356 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6357 file, linenum, args[0], args[1]);
6358 return -1;
6359 }
6360 hdr = calloc(sizeof(struct cap_hdr), 1);
6361 hdr->next = curproxy->rsp_cap;
6362 hdr->name = strdup(args[3]);
6363 hdr->namelen = strlen(args[3]);
6364 hdr->len = atol(args[5]);
6365 hdr->index = curproxy->nb_rsp_cap++;
6366 curproxy->rsp_cap = hdr;
6367 curproxy->to_log |= LW_RSPHDR;
6368 }
6369 else {
6370 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006371 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006372 return -1;
6373 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006374 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006375 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006376 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006377 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return 0;
6379 }
6380 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006381 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6382 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006383 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006384 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006385 curproxy->contimeout = atol(args[1]);
6386 }
6387 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006388 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006389 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6390 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006391 return 0;
6392 }
6393 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006394 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6395 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006396 return -1;
6397 }
6398 curproxy->clitimeout = atol(args[1]);
6399 }
6400 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006401 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006402 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006403 return 0;
6404 }
6405 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006406 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6407 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006408 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006409 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006410 curproxy->srvtimeout = atol(args[1]);
6411 }
6412 else if (!strcmp(args[0], "retries")) { /* connection retries */
6413 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006414 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6415 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006416 return -1;
6417 }
6418 curproxy->conn_retries = atol(args[1]);
6419 }
6420 else if (!strcmp(args[0], "option")) {
6421 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006422 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006423 return -1;
6424 }
6425 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006426 /* enable reconnections to dispatch */
6427 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006428#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006429 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006430 /* enable transparent proxy connections */
6431 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006432#endif
6433 else if (!strcmp(args[1], "keepalive"))
6434 /* enable keep-alive */
6435 curproxy->options |= PR_O_KEEPALIVE;
6436 else if (!strcmp(args[1], "forwardfor"))
6437 /* insert x-forwarded-for field */
6438 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006439 else if (!strcmp(args[1], "logasap"))
6440 /* log as soon as possible, without waiting for the session to complete */
6441 curproxy->options |= PR_O_LOGASAP;
6442 else if (!strcmp(args[1], "httpclose"))
6443 /* force connection: close in both directions in HTTP mode */
6444 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006445 else if (!strcmp(args[1], "checkcache"))
6446 /* require examination of cacheability of the 'set-cookie' field */
6447 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006448 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006449 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006450 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006451 else if (!strcmp(args[1], "tcplog"))
6452 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006453 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006454 else if (!strcmp(args[1], "dontlognull")) {
6455 /* don't log empty requests */
6456 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006457 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006458 else if (!strcmp(args[1], "tcpka")) {
6459 /* enable TCP keep-alives on client and server sessions */
6460 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6461 }
6462 else if (!strcmp(args[1], "clitcpka")) {
6463 /* enable TCP keep-alives on client sessions */
6464 curproxy->options |= PR_O_TCP_CLI_KA;
6465 }
6466 else if (!strcmp(args[1], "srvtcpka")) {
6467 /* enable TCP keep-alives on server sessions */
6468 curproxy->options |= PR_O_TCP_SRV_KA;
6469 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006470 else if (!strcmp(args[1], "httpchk")) {
6471 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006472 if (curproxy->check_req != NULL) {
6473 free(curproxy->check_req);
6474 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006475 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006476 if (!*args[2]) { /* no argument */
6477 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6478 curproxy->check_len = strlen(DEF_CHECK_REQ);
6479 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006480 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6481 curproxy->check_req = (char *)malloc(reqlen);
6482 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6483 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006484 } else { /* more arguments : METHOD URI [HTTP_VER] */
6485 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6486 if (*args[4])
6487 reqlen += strlen(args[4]);
6488 else
6489 reqlen += strlen("HTTP/1.0");
6490
6491 curproxy->check_req = (char *)malloc(reqlen);
6492 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6493 "%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 +01006494 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006495 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006496 else if (!strcmp(args[1], "persist")) {
6497 /* persist on using the server specified by the cookie, even when it's down */
6498 curproxy->options |= PR_O_PERSIST;
6499 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006500 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006501 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006502 return -1;
6503 }
6504 return 0;
6505 }
6506 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6507 /* enable reconnections to dispatch */
6508 curproxy->options |= PR_O_REDISP;
6509 }
willy tarreaua1598082005-12-17 13:08:06 +01006510#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006511 else if (!strcmp(args[0], "transparent")) {
6512 /* enable transparent proxy connections */
6513 curproxy->options |= PR_O_TRANSP;
6514 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006515#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006516 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6517 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006518 Alert("parsing [%s:%d] : '%s' expects an integer 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->maxconn = atol(args[1]);
6522 }
6523 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6524 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006525 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006526 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006527 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006528 curproxy->grace = atol(args[1]);
6529 }
6530 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006531 if (curproxy == &defproxy) {
6532 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6533 return -1;
6534 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006535 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006536 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006537 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006538 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006539 curproxy->dispatch_addr = *str2sa(args[1]);
6540 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006541 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006542 if (*(args[1])) {
6543 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006544 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006545 }
6546 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006547 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006548 return -1;
6549 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006550 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006551 else /* if no option is set, use round-robin by default */
6552 curproxy->options |= PR_O_BALANCE_RR;
6553 }
6554 else if (!strcmp(args[0], "server")) { /* server address */
6555 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006556 char *rport;
6557 char *raddr;
6558 short realport;
6559 int do_check;
6560
6561 if (curproxy == &defproxy) {
6562 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6563 return -1;
6564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006565
willy tarreaua41a8b42005-12-17 14:02:24 +01006566 if (!*args[2]) {
6567 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006568 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006569 return -1;
6570 }
6571 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6572 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6573 return -1;
6574 }
willy tarreau0174f312005-12-18 01:02:42 +01006575
6576 if (curproxy->srv == NULL)
6577 curproxy->srv = newsrv;
6578 else
6579 curproxy->cursrv->next = newsrv;
6580 curproxy->cursrv = newsrv;
6581
6582 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006583 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006584
6585 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006586 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006587 newsrv->id = strdup(args[1]);
6588
6589 /* several ways to check the port component :
6590 * - IP => port=+0, relative
6591 * - IP: => port=+0, relative
6592 * - IP:N => port=N, absolute
6593 * - IP:+N => port=+N, relative
6594 * - IP:-N => port=-N, relative
6595 */
6596 raddr = strdup(args[2]);
6597 rport = strchr(raddr, ':');
6598 if (rport) {
6599 *rport++ = 0;
6600 realport = atol(rport);
6601 if (!isdigit((int)*rport))
6602 newsrv->state |= SRV_MAPPORTS;
6603 } else {
6604 realport = 0;
6605 newsrv->state |= SRV_MAPPORTS;
6606 }
6607
6608 newsrv->addr = *str2sa(raddr);
6609 newsrv->addr.sin_port = htons(realport);
6610 free(raddr);
6611
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 newsrv->curfd = -1; /* no health-check in progress */
6613 newsrv->inter = DEF_CHKINTR;
6614 newsrv->rise = DEF_RISETIME;
6615 newsrv->fall = DEF_FALLTIME;
6616 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6617 cur_arg = 3;
6618 while (*args[cur_arg]) {
6619 if (!strcmp(args[cur_arg], "cookie")) {
6620 newsrv->cookie = strdup(args[cur_arg + 1]);
6621 newsrv->cklen = strlen(args[cur_arg + 1]);
6622 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006623 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006624 else if (!strcmp(args[cur_arg], "rise")) {
6625 newsrv->rise = atol(args[cur_arg + 1]);
6626 newsrv->health = newsrv->rise;
6627 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006628 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 else if (!strcmp(args[cur_arg], "fall")) {
6630 newsrv->fall = atol(args[cur_arg + 1]);
6631 cur_arg += 2;
6632 }
6633 else if (!strcmp(args[cur_arg], "inter")) {
6634 newsrv->inter = atol(args[cur_arg + 1]);
6635 cur_arg += 2;
6636 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006637 else if (!strcmp(args[cur_arg], "port")) {
6638 newsrv->check_port = atol(args[cur_arg + 1]);
6639 cur_arg += 2;
6640 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006641 else if (!strcmp(args[cur_arg], "backup")) {
6642 newsrv->state |= SRV_BACKUP;
6643 cur_arg ++;
6644 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006645 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006646 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006647 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006648 }
willy tarreau0174f312005-12-18 01:02:42 +01006649 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6650 if (!*args[cur_arg + 1]) {
6651 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6652 file, linenum, "source");
6653 return -1;
6654 }
6655 newsrv->state |= SRV_BIND_SRC;
6656 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6657 cur_arg += 2;
6658 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006659 else {
willy tarreau0174f312005-12-18 01:02:42 +01006660 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 +01006661 file, linenum, newsrv->id);
6662 return -1;
6663 }
6664 }
6665
6666 if (do_check) {
6667 struct task *t;
6668
6669 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6670 newsrv->check_port = realport; /* by default */
6671 if (!newsrv->check_port) {
6672 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 +01006673 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006674 return -1;
6675 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006676
6677 if ((t = pool_alloc(task)) == NULL) {
6678 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6679 return -1;
6680 }
6681
6682 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6683 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6684 t->state = TASK_IDLE;
6685 t->process = process_chk;
6686 t->context = newsrv;
6687
6688 if (curproxy->state != PR_STDISABLED) {
6689 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6690 task_queue(t);
6691 task_wakeup(&rq, t);
6692 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006693 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006694
willy tarreau9fe663a2005-12-17 13:02:59 +01006695 curproxy->nbservers++;
6696 }
6697 else if (!strcmp(args[0], "log")) { /* syslog server address */
6698 struct sockaddr_in *sa;
6699 int facility;
6700
6701 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6702 curproxy->logfac1 = global.logfac1;
6703 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006704 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006705 curproxy->logfac2 = global.logfac2;
6706 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006707 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006708 }
6709 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006710 int level;
6711
willy tarreau0f7af912005-12-17 12:21:26 +01006712 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6713 if (!strcmp(log_facilities[facility], args[2]))
6714 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006715
willy tarreau0f7af912005-12-17 12:21:26 +01006716 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006717 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006718 exit(1);
6719 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006720
willy tarreau8337c6b2005-12-17 13:41:01 +01006721 level = 7; /* max syslog level = debug */
6722 if (*(args[3])) {
6723 while (level >= 0 && strcmp(log_levels[level], args[3]))
6724 level--;
6725 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006726 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006727 exit(1);
6728 }
6729 }
6730
willy tarreau0f7af912005-12-17 12:21:26 +01006731 sa = str2sa(args[1]);
6732 if (!sa->sin_port)
6733 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006734
willy tarreau0f7af912005-12-17 12:21:26 +01006735 if (curproxy->logfac1 == -1) {
6736 curproxy->logsrv1 = *sa;
6737 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006738 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006739 }
6740 else if (curproxy->logfac2 == -1) {
6741 curproxy->logsrv2 = *sa;
6742 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006743 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006744 }
6745 else {
6746 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006747 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006748 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006749 }
6750 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006751 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006752 file, linenum);
6753 return -1;
6754 }
6755 }
willy tarreaua1598082005-12-17 13:08:06 +01006756 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006757 if (!*args[1]) {
6758 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006759 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006760 return -1;
6761 }
6762
6763 curproxy->source_addr = *str2sa(args[1]);
6764 curproxy->options |= PR_O_BIND_SRC;
6765 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006766 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6767 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006768 if (curproxy == &defproxy) {
6769 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6770 return -1;
6771 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006772
6773 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006774 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6775 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006776 return -1;
6777 }
6778
6779 preg = calloc(1, sizeof(regex_t));
6780 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006781 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006782 return -1;
6783 }
6784
willy tarreauc1f47532005-12-18 01:08:26 +01006785 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6786 if (err) {
6787 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6788 file, linenum, *err);
6789 return -1;
6790 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006791 }
6792 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6793 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006794 if (curproxy == &defproxy) {
6795 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6796 return -1;
6797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006798
6799 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006800 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006801 return -1;
6802 }
6803
6804 preg = calloc(1, sizeof(regex_t));
6805 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006806 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006807 return -1;
6808 }
6809
6810 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6811 }
6812 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6813 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006814 if (curproxy == &defproxy) {
6815 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6816 return -1;
6817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006818
6819 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006820 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006821 return -1;
6822 }
6823
6824 preg = calloc(1, sizeof(regex_t));
6825 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006826 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006827 return -1;
6828 }
6829
6830 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6831 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006832 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6833 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006834 if (curproxy == &defproxy) {
6835 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6836 return -1;
6837 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006838
6839 if (*(args[1]) == 0) {
6840 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6841 return -1;
6842 }
6843
6844 preg = calloc(1, sizeof(regex_t));
6845 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6846 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6847 return -1;
6848 }
6849
6850 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6851 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006852 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6853 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006854 if (curproxy == &defproxy) {
6855 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6856 return -1;
6857 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006858
6859 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006860 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006861 return -1;
6862 }
6863
6864 preg = calloc(1, sizeof(regex_t));
6865 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006866 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006867 return -1;
6868 }
6869
6870 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6871 }
6872 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6873 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006874 if (curproxy == &defproxy) {
6875 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6876 return -1;
6877 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006878
6879 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006880 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6881 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006882 return -1;
6883 }
6884
6885 preg = calloc(1, sizeof(regex_t));
6886 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006887 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 return -1;
6889 }
6890
willy tarreauc1f47532005-12-18 01:08:26 +01006891 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6892 if (err) {
6893 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6894 file, linenum, *err);
6895 return -1;
6896 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006897 }
6898 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6899 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006900 if (curproxy == &defproxy) {
6901 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6902 return -1;
6903 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006904
6905 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006906 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006907 return -1;
6908 }
6909
6910 preg = calloc(1, sizeof(regex_t));
6911 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006912 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006913 return -1;
6914 }
6915
6916 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6917 }
6918 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6919 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006920 if (curproxy == &defproxy) {
6921 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6922 return -1;
6923 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006924
6925 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006926 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006927 return -1;
6928 }
6929
6930 preg = calloc(1, sizeof(regex_t));
6931 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006932 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006933 return -1;
6934 }
6935
6936 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6937 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006938 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6939 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006940 if (curproxy == &defproxy) {
6941 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6942 return -1;
6943 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006944
6945 if (*(args[1]) == 0) {
6946 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6947 return -1;
6948 }
6949
6950 preg = calloc(1, sizeof(regex_t));
6951 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6952 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6953 return -1;
6954 }
6955
6956 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6957 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006958 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6959 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006960 if (curproxy == &defproxy) {
6961 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6962 return -1;
6963 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006964
6965 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006966 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006967 return -1;
6968 }
6969
6970 preg = calloc(1, sizeof(regex_t));
6971 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006972 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 return -1;
6974 }
6975
6976 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6977 }
6978 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006979 if (curproxy == &defproxy) {
6980 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6981 return -1;
6982 }
6983
willy tarreau9fe663a2005-12-17 13:02:59 +01006984 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006985 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006986 return 0;
6987 }
6988
6989 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006990 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006991 return -1;
6992 }
6993
willy tarreau4302f492005-12-18 01:00:37 +01006994 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6995 }
6996 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6997 regex_t *preg;
6998
6999 if (*(args[1]) == 0 || *(args[2]) == 0) {
7000 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7001 file, linenum, args[0]);
7002 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007003 }
willy tarreau4302f492005-12-18 01:00:37 +01007004
7005 preg = calloc(1, sizeof(regex_t));
7006 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7007 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7008 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007009 }
willy tarreau4302f492005-12-18 01:00:37 +01007010
willy tarreauc1f47532005-12-18 01:08:26 +01007011 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7012 if (err) {
7013 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7014 file, linenum, *err);
7015 return -1;
7016 }
willy tarreau4302f492005-12-18 01:00:37 +01007017 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007018 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7019 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007020 if (curproxy == &defproxy) {
7021 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7022 return -1;
7023 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007024
7025 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007026 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007027 return -1;
7028 }
willy tarreaue39cd132005-12-17 13:00:18 +01007029
willy tarreau9fe663a2005-12-17 13:02:59 +01007030 preg = calloc(1, sizeof(regex_t));
7031 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007032 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007033 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007034 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007035
willy tarreauc1f47532005-12-18 01:08:26 +01007036 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7037 if (err) {
7038 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7039 file, linenum, *err);
7040 return -1;
7041 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007042 }
willy tarreau982249e2005-12-18 00:57:06 +01007043 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7044 regex_t *preg;
7045 if (curproxy == &defproxy) {
7046 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7047 return -1;
7048 }
7049
7050 if (*(args[1]) == 0) {
7051 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7052 return -1;
7053 }
7054
7055 preg = calloc(1, sizeof(regex_t));
7056 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7057 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7058 return -1;
7059 }
7060
willy tarreauc1f47532005-12-18 01:08:26 +01007061 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7062 if (err) {
7063 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7064 file, linenum, *err);
7065 return -1;
7066 }
willy tarreau982249e2005-12-18 00:57:06 +01007067 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007069 regex_t *preg;
7070 if (curproxy == &defproxy) {
7071 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7072 return -1;
7073 }
willy tarreaue39cd132005-12-17 13:00:18 +01007074
willy tarreaua41a8b42005-12-17 14:02:24 +01007075 if (*(args[1]) == 0 || *(args[2]) == 0) {
7076 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7077 file, linenum, args[0]);
7078 return -1;
7079 }
willy tarreaue39cd132005-12-17 13:00:18 +01007080
willy tarreaua41a8b42005-12-17 14:02:24 +01007081 preg = calloc(1, sizeof(regex_t));
7082 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7083 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7084 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007085 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007086
willy tarreauc1f47532005-12-18 01:08:26 +01007087 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7088 if (err) {
7089 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7090 file, linenum, *err);
7091 return -1;
7092 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007093 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7095 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007096 if (curproxy == &defproxy) {
7097 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7098 return -1;
7099 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007100
7101 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007102 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007103 return -1;
7104 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007105
willy tarreau9fe663a2005-12-17 13:02:59 +01007106 preg = calloc(1, sizeof(regex_t));
7107 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007108 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007110 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007111
willy tarreauc1f47532005-12-18 01:08:26 +01007112 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7113 if (err) {
7114 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7115 file, linenum, *err);
7116 return -1;
7117 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 }
willy tarreau982249e2005-12-18 00:57:06 +01007119 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7120 regex_t *preg;
7121 if (curproxy == &defproxy) {
7122 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7123 return -1;
7124 }
7125
7126 if (*(args[1]) == 0) {
7127 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7128 return -1;
7129 }
7130
7131 preg = calloc(1, sizeof(regex_t));
7132 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7133 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7134 return -1;
7135 }
7136
willy tarreauc1f47532005-12-18 01:08:26 +01007137 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7138 if (err) {
7139 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7140 file, linenum, *err);
7141 return -1;
7142 }
willy tarreau982249e2005-12-18 00:57:06 +01007143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007145 if (curproxy == &defproxy) {
7146 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7147 return -1;
7148 }
7149
willy tarreau9fe663a2005-12-17 13:02:59 +01007150 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007151 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007152 return 0;
7153 }
7154
7155 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007156 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007157 return -1;
7158 }
7159
7160 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7161 }
willy tarreauc1f47532005-12-18 01:08:26 +01007162 else if (!strcmp(args[0], "errorloc") ||
7163 !strcmp(args[0], "errorloc302") ||
7164 !strcmp(args[0], "errorloc303")) { /* error location */
7165 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007166 char *err;
7167
willy tarreaueedaa9f2005-12-17 14:08:03 +01007168 // if (curproxy == &defproxy) {
7169 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7170 // return -1;
7171 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007172
willy tarreau8337c6b2005-12-17 13:41:01 +01007173 if (*(args[2]) == 0) {
7174 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7175 return -1;
7176 }
7177
7178 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007179 if (!strcmp(args[0], "errorloc303")) {
7180 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7181 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7182 } else {
7183 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7184 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7185 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007186
7187 if (errnum == 400) {
7188 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007189 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007190 free(curproxy->errmsg.msg400);
7191 }
7192 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007193 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007194 }
7195 else if (errnum == 403) {
7196 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007197 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007198 free(curproxy->errmsg.msg403);
7199 }
7200 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007201 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007202 }
7203 else if (errnum == 408) {
7204 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007205 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007206 free(curproxy->errmsg.msg408);
7207 }
7208 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007209 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007210 }
7211 else if (errnum == 500) {
7212 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007213 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007214 free(curproxy->errmsg.msg500);
7215 }
7216 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007217 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007218 }
7219 else if (errnum == 502) {
7220 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007221 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007222 free(curproxy->errmsg.msg502);
7223 }
7224 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007225 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007226 }
7227 else if (errnum == 503) {
7228 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007229 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007230 free(curproxy->errmsg.msg503);
7231 }
7232 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007233 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007234 }
7235 else if (errnum == 504) {
7236 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007237 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007238 free(curproxy->errmsg.msg504);
7239 }
7240 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007241 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007242 }
7243 else {
7244 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7245 free(err);
7246 }
7247 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007248 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007249 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007250 return -1;
7251 }
7252 return 0;
7253}
willy tarreaue39cd132005-12-17 13:00:18 +01007254
willy tarreau5cbea6f2005-12-17 12:48:26 +01007255
willy tarreau9fe663a2005-12-17 13:02:59 +01007256/*
7257 * This function reads and parses the configuration file given in the argument.
7258 * returns 0 if OK, -1 if error.
7259 */
7260int readcfgfile(char *file) {
7261 char thisline[256];
7262 char *line;
7263 FILE *f;
7264 int linenum = 0;
7265 char *end;
7266 char *args[MAX_LINE_ARGS];
7267 int arg;
7268 int cfgerr = 0;
7269 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007270
willy tarreau9fe663a2005-12-17 13:02:59 +01007271 struct proxy *curproxy = NULL;
7272 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007273
willy tarreau9fe663a2005-12-17 13:02:59 +01007274 if ((f=fopen(file,"r")) == NULL)
7275 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007276
willy tarreaueedaa9f2005-12-17 14:08:03 +01007277 init_default_instance();
7278
willy tarreau9fe663a2005-12-17 13:02:59 +01007279 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7280 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007281
willy tarreau9fe663a2005-12-17 13:02:59 +01007282 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007283
willy tarreau9fe663a2005-12-17 13:02:59 +01007284 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007285 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 line++;
7287
7288 arg = 0;
7289 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007290
willy tarreau9fe663a2005-12-17 13:02:59 +01007291 while (*line && arg < MAX_LINE_ARGS) {
7292 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7293 * C equivalent value. Other combinations left unchanged (eg: \1).
7294 */
7295 if (*line == '\\') {
7296 int skip = 0;
7297 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7298 *line = line[1];
7299 skip = 1;
7300 }
7301 else if (line[1] == 'r') {
7302 *line = '\r';
7303 skip = 1;
7304 }
7305 else if (line[1] == 'n') {
7306 *line = '\n';
7307 skip = 1;
7308 }
7309 else if (line[1] == 't') {
7310 *line = '\t';
7311 skip = 1;
7312 }
willy tarreauc1f47532005-12-18 01:08:26 +01007313 else if (line[1] == 'x') {
7314 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7315 unsigned char hex1, hex2;
7316 hex1 = toupper(line[2]) - '0';
7317 hex2 = toupper(line[3]) - '0';
7318 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7319 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7320 *line = (hex1<<4) + hex2;
7321 skip = 3;
7322 }
7323 else {
7324 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7325 return -1;
7326 }
7327 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007328 if (skip) {
7329 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7330 end -= skip;
7331 }
7332 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007333 }
willy tarreaua1598082005-12-17 13:08:06 +01007334 else if (*line == '#' || *line == '\n' || *line == '\r') {
7335 /* end of string, end of loop */
7336 *line = 0;
7337 break;
7338 }
willy tarreauc29948c2005-12-17 13:10:27 +01007339 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007340 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007341 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007342 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007343 line++;
7344 args[++arg] = line;
7345 }
7346 else {
7347 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007348 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007349 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007350
willy tarreau9fe663a2005-12-17 13:02:59 +01007351 /* empty line */
7352 if (!**args)
7353 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007354
willy tarreau9fe663a2005-12-17 13:02:59 +01007355 /* zero out remaining args */
7356 while (++arg < MAX_LINE_ARGS) {
7357 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007358 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007359
willy tarreaua41a8b42005-12-17 14:02:24 +01007360 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007361 confsect = CFG_LISTEN;
7362 else if (!strcmp(args[0], "global")) /* global config */
7363 confsect = CFG_GLOBAL;
7364 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007365
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 switch (confsect) {
7367 case CFG_LISTEN:
7368 if (cfg_parse_listen(file, linenum, args) < 0)
7369 return -1;
7370 break;
7371 case CFG_GLOBAL:
7372 if (cfg_parse_global(file, linenum, args) < 0)
7373 return -1;
7374 break;
7375 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007376 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007377 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007378 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007379
7380
willy tarreau0f7af912005-12-17 12:21:26 +01007381 }
7382 fclose(f);
7383
7384 /*
7385 * Now, check for the integrity of all that we have collected.
7386 */
7387
7388 if ((curproxy = proxy) == NULL) {
7389 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7390 file);
7391 return -1;
7392 }
7393
7394 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007395 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007396 if (curproxy->state == PR_STDISABLED) {
7397 curproxy = curproxy->next;
7398 continue;
7399 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007400
7401 if (curproxy->listen == NULL) {
7402 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);
7403 cfgerr++;
7404 }
7405 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007406 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007407 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007408 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7409 file, curproxy->id);
7410 cfgerr++;
7411 }
7412 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7413 if (curproxy->options & PR_O_TRANSP) {
7414 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7415 file, curproxy->id);
7416 cfgerr++;
7417 }
7418 else if (curproxy->srv == NULL) {
7419 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7420 file, curproxy->id);
7421 cfgerr++;
7422 }
willy tarreaua1598082005-12-17 13:08:06 +01007423 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007424 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7425 file, curproxy->id);
7426 }
7427 }
7428 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007429 if (curproxy->cookie_name != NULL) {
7430 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7431 file, curproxy->id);
7432 }
7433 if ((newsrv = curproxy->srv) != NULL) {
7434 Warning("parsing %s : servers will be ignored for listener %s.\n",
7435 file, curproxy->id);
7436 }
willy tarreaue39cd132005-12-17 13:00:18 +01007437 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007438 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7439 file, curproxy->id);
7440 }
willy tarreaue39cd132005-12-17 13:00:18 +01007441 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007442 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7443 file, curproxy->id);
7444 }
7445 }
7446 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7447 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7448 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7449 file, curproxy->id);
7450 cfgerr++;
7451 }
7452 else {
7453 while (newsrv != NULL) {
7454 /* nothing to check for now */
7455 newsrv = newsrv->next;
7456 }
7457 }
7458 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007459
7460 if (curproxy->options & PR_O_LOGASAP)
7461 curproxy->to_log &= ~LW_BYTES;
7462
willy tarreau8337c6b2005-12-17 13:41:01 +01007463 if (curproxy->errmsg.msg400 == NULL) {
7464 curproxy->errmsg.msg400 = (char *)HTTP_400;
7465 curproxy->errmsg.len400 = strlen(HTTP_400);
7466 }
7467 if (curproxy->errmsg.msg403 == NULL) {
7468 curproxy->errmsg.msg403 = (char *)HTTP_403;
7469 curproxy->errmsg.len403 = strlen(HTTP_403);
7470 }
7471 if (curproxy->errmsg.msg408 == NULL) {
7472 curproxy->errmsg.msg408 = (char *)HTTP_408;
7473 curproxy->errmsg.len408 = strlen(HTTP_408);
7474 }
7475 if (curproxy->errmsg.msg500 == NULL) {
7476 curproxy->errmsg.msg500 = (char *)HTTP_500;
7477 curproxy->errmsg.len500 = strlen(HTTP_500);
7478 }
7479 if (curproxy->errmsg.msg502 == NULL) {
7480 curproxy->errmsg.msg502 = (char *)HTTP_502;
7481 curproxy->errmsg.len502 = strlen(HTTP_502);
7482 }
7483 if (curproxy->errmsg.msg503 == NULL) {
7484 curproxy->errmsg.msg503 = (char *)HTTP_503;
7485 curproxy->errmsg.len503 = strlen(HTTP_503);
7486 }
7487 if (curproxy->errmsg.msg504 == NULL) {
7488 curproxy->errmsg.msg504 = (char *)HTTP_504;
7489 curproxy->errmsg.len504 = strlen(HTTP_504);
7490 }
willy tarreau0f7af912005-12-17 12:21:26 +01007491 curproxy = curproxy->next;
7492 }
7493 if (cfgerr > 0) {
7494 Alert("Errors found in configuration file, aborting.\n");
7495 return -1;
7496 }
7497 else
7498 return 0;
7499}
7500
7501
7502/*
7503 * This function initializes all the necessary variables. It only returns
7504 * if everything is OK. If something fails, it exits.
7505 */
7506void init(int argc, char **argv) {
7507 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007508 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007509 char *old_argv = *argv;
7510 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007511 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007512 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007513
7514 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007515 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007516 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007517 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007518 exit(1);
7519 }
7520
willy tarreau4302f492005-12-18 01:00:37 +01007521 /* initialize the log header encoding map : '{|}"#' should be encoded with
7522 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7523 * URL encoding only requires '"', '#' to be encoded as well as non-
7524 * printable characters above.
7525 */
7526 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7527 memset(url_encode_map, 0, sizeof(url_encode_map));
7528 for (i = 0; i < 32; i++) {
7529 FD_SET(i, hdr_encode_map);
7530 FD_SET(i, url_encode_map);
7531 }
7532 for (i = 127; i < 256; i++) {
7533 FD_SET(i, hdr_encode_map);
7534 FD_SET(i, url_encode_map);
7535 }
7536
7537 tmp = "\"#{|}";
7538 while (*tmp) {
7539 FD_SET(*tmp, hdr_encode_map);
7540 tmp++;
7541 }
7542
7543 tmp = "\"#";
7544 while (*tmp) {
7545 FD_SET(*tmp, url_encode_map);
7546 tmp++;
7547 }
7548
willy tarreau64a3cc32005-12-18 01:13:11 +01007549 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7550#if defined(ENABLE_POLL)
7551 cfg_polling_mechanism |= POLL_USE_POLL;
7552#endif
7553#if defined(ENABLE_EPOLL)
7554 cfg_polling_mechanism |= POLL_USE_EPOLL;
7555#endif
7556
willy tarreau0f7af912005-12-17 12:21:26 +01007557 pid = getpid();
7558 progname = *argv;
7559 while ((tmp = strchr(progname, '/')) != NULL)
7560 progname = tmp + 1;
7561
7562 argc--; argv++;
7563 while (argc > 0) {
7564 char *flag;
7565
7566 if (**argv == '-') {
7567 flag = *argv+1;
7568
7569 /* 1 arg */
7570 if (*flag == 'v') {
7571 display_version();
7572 exit(0);
7573 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007574#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007575 else if (*flag == 'd' && flag[1] == 'e')
7576 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007577#endif
7578#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007579 else if (*flag == 'd' && flag[1] == 'p')
7580 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007581#endif
willy tarreau982249e2005-12-18 00:57:06 +01007582 else if (*flag == 'V')
7583 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007584 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007585 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007586 else if (*flag == 'c')
7587 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007588 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007589 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007590 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007591 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007592#if STATTIME > 0
7593 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007594 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007595 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007596 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007597#endif
7598 else { /* >=2 args */
7599 argv++; argc--;
7600 if (argc == 0)
7601 usage(old_argv);
7602
7603 switch (*flag) {
7604 case 'n' : cfg_maxconn = atol(*argv); break;
7605 case 'N' : cfg_maxpconn = atol(*argv); break;
7606 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007607 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007608 default: usage(old_argv);
7609 }
7610 }
7611 }
7612 else
7613 usage(old_argv);
7614 argv++; argc--;
7615 }
7616
willy tarreaud0fb4652005-12-18 01:32:04 +01007617 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7618 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007619
willy tarreau0f7af912005-12-17 12:21:26 +01007620 if (!cfg_cfgfile)
7621 usage(old_argv);
7622
7623 gethostname(hostname, MAX_HOSTNAME_LEN);
7624
willy tarreau12350152005-12-18 01:03:27 +01007625 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007626 if (readcfgfile(cfg_cfgfile) < 0) {
7627 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7628 exit(1);
7629 }
willy tarreau12350152005-12-18 01:03:27 +01007630 if (have_appsession)
7631 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007632
willy tarreau982249e2005-12-18 00:57:06 +01007633 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007634 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7635 exit(0);
7636 }
7637
willy tarreau9fe663a2005-12-17 13:02:59 +01007638 if (cfg_maxconn > 0)
7639 global.maxconn = cfg_maxconn;
7640
willy tarreaufe2c5c12005-12-17 14:14:34 +01007641 if (cfg_pidfile) {
7642 if (global.pidfile)
7643 free(global.pidfile);
7644 global.pidfile = strdup(cfg_pidfile);
7645 }
7646
willy tarreau9fe663a2005-12-17 13:02:59 +01007647 if (global.maxconn == 0)
7648 global.maxconn = DEFAULT_MAXCONN;
7649
7650 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7651
7652 if (arg_mode & MODE_DEBUG) {
7653 /* command line debug mode inhibits configuration mode */
7654 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7655 }
willy tarreau982249e2005-12-18 00:57:06 +01007656 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7657 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007658
7659 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7660 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7661 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7662 }
7663
7664 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7665 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7666 global.nbproc = 1;
7667 }
7668
7669 if (global.nbproc < 1)
7670 global.nbproc = 1;
7671
willy tarreau0f7af912005-12-17 12:21:26 +01007672 StaticReadEvent = (fd_set *)calloc(1,
7673 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007674 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007675 StaticWriteEvent = (fd_set *)calloc(1,
7676 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007677 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007678
7679 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007680 sizeof(struct fdtab) * (global.maxsock));
7681 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007682 fdtab[i].state = FD_STCLOSE;
7683 }
7684}
7685
7686/*
7687 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7688 */
7689int start_proxies() {
7690 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007691 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007692 int fd;
7693
7694 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007695 if (curproxy->state == PR_STDISABLED)
7696 continue;
7697
willy tarreaua41a8b42005-12-17 14:02:24 +01007698 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7699 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007700 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007701 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7702 curproxy->id);
7703 return -1;
7704 }
willy tarreau0f7af912005-12-17 12:21:26 +01007705
willy tarreaua41a8b42005-12-17 14:02:24 +01007706 if (fd >= global.maxsock) {
7707 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7708 curproxy->id);
7709 close(fd);
7710 return -1;
7711 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007712
willy tarreaua41a8b42005-12-17 14:02:24 +01007713 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7714 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7715 (char *) &one, sizeof(one)) == -1)) {
7716 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7717 curproxy->id);
7718 close(fd);
7719 return -1;
7720 }
willy tarreau0f7af912005-12-17 12:21:26 +01007721
willy tarreaua41a8b42005-12-17 14:02:24 +01007722 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7723 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7724 curproxy->id);
7725 }
willy tarreau0f7af912005-12-17 12:21:26 +01007726
willy tarreaua41a8b42005-12-17 14:02:24 +01007727 if (bind(fd,
7728 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007729 listener->addr.ss_family == AF_INET6 ?
7730 sizeof(struct sockaddr_in6) :
7731 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007732 Alert("cannot bind socket for proxy %s. Aborting.\n",
7733 curproxy->id);
7734 close(fd);
7735 return -1;
7736 }
willy tarreau0f7af912005-12-17 12:21:26 +01007737
willy tarreaua41a8b42005-12-17 14:02:24 +01007738 if (listen(fd, curproxy->maxconn) == -1) {
7739 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7740 curproxy->id);
7741 close(fd);
7742 return -1;
7743 }
willy tarreau0f7af912005-12-17 12:21:26 +01007744
willy tarreaua41a8b42005-12-17 14:02:24 +01007745 /* the function for the accept() event */
7746 fdtab[fd].read = &event_accept;
7747 fdtab[fd].write = NULL; /* never called */
7748 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7749 curproxy->state = PR_STRUN;
7750 fdtab[fd].state = FD_STLISTEN;
7751 FD_SET(fd, StaticReadEvent);
7752 fd_insert(fd);
7753 listeners++;
7754 }
willy tarreaua1598082005-12-17 13:08:06 +01007755 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007756 }
7757 return 0;
7758}
7759
willy tarreaub952e1d2005-12-18 01:31:20 +01007760int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007761
7762 appsess *temp1,*temp2;
7763 temp1 = (appsess *)key1;
7764 temp2 = (appsess *)key2;
7765
7766 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7767 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7768
7769 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7770}/* end match_str */
7771
willy tarreaub952e1d2005-12-18 01:31:20 +01007772void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007773 appsess *temp1;
7774
7775 //printf("destroy called\n");
7776 temp1 = (appsess *)data;
7777
7778 if (temp1->sessid)
7779 pool_free_to(apools.sessid, temp1->sessid);
7780
7781 if (temp1->serverid)
7782 pool_free_to(apools.serverid, temp1->serverid);
7783
7784 pool_free(appsess, temp1);
7785} /* end destroy */
7786
7787void appsession_cleanup( void )
7788{
7789 struct proxy *p = proxy;
7790
7791 while(p) {
7792 chtbl_destroy(&(p->htbl_proxy));
7793 p = p->next;
7794 }
7795}/* end appsession_cleanup() */
7796
7797void pool_destroy(void **pool)
7798{
7799 void *temp, *next;
7800 next = pool;
7801 while (next) {
7802 temp = next;
7803 next = *(void **)temp;
7804 free(temp);
7805 }
7806}/* end pool_destroy() */
7807
willy tarreaub952e1d2005-12-18 01:31:20 +01007808void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01007809 struct proxy *p = proxy;
7810 struct cap_hdr *h,*h_next;
7811 struct server *s,*s_next;
7812 struct listener *l,*l_next;
7813
7814 while (p) {
7815 if (p->id)
7816 free(p->id);
7817
7818 if (p->check_req)
7819 free(p->check_req);
7820
7821 if (p->cookie_name)
7822 free(p->cookie_name);
7823
7824 if (p->capture_name)
7825 free(p->capture_name);
7826
7827 /* only strup if the user have set in config.
7828 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01007829 if (p->errmsg.msg400) free(p->errmsg.msg400);
7830 if (p->errmsg.msg403) free(p->errmsg.msg403);
7831 if (p->errmsg.msg408) free(p->errmsg.msg408);
7832 if (p->errmsg.msg500) free(p->errmsg.msg500);
7833 if (p->errmsg.msg502) free(p->errmsg.msg502);
7834 if (p->errmsg.msg503) free(p->errmsg.msg503);
7835 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01007836 */
7837 if (p->appsession_name)
7838 free(p->appsession_name);
7839
7840 h = p->req_cap;
7841 while (h) {
7842 h_next = h->next;
7843 if (h->name)
7844 free(h->name);
7845 pool_destroy(h->pool);
7846 free(h);
7847 h = h_next;
7848 }/* end while(h) */
7849
7850 h = p->rsp_cap;
7851 while (h) {
7852 h_next = h->next;
7853 if (h->name)
7854 free(h->name);
7855
7856 pool_destroy(h->pool);
7857 free(h);
7858 h = h_next;
7859 }/* end while(h) */
7860
7861 s = p->srv;
7862 while (s) {
7863 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01007864 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01007865 free(s->id);
7866
willy tarreaub952e1d2005-12-18 01:31:20 +01007867 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01007868 free(s->cookie);
7869
7870 free(s);
7871 s = s_next;
7872 }/* end while(s) */
7873
7874 l = p->listen;
7875 while (l) {
7876 l_next = l->next;
7877 free(l);
7878 l = l_next;
7879 }/* end while(l) */
7880
7881 pool_destroy((void **) p->req_cap_pool);
7882 pool_destroy((void **) p->rsp_cap_pool);
7883 p = p->next;
7884 }/* end while(p) */
7885
7886 if (global.chroot) free(global.chroot);
7887 if (global.pidfile) free(global.pidfile);
7888
willy tarreau12350152005-12-18 01:03:27 +01007889 if (StaticReadEvent) free(StaticReadEvent);
7890 if (StaticWriteEvent) free(StaticWriteEvent);
7891 if (fdtab) free(fdtab);
7892
7893 pool_destroy(pool_session);
7894 pool_destroy(pool_buffer);
7895 pool_destroy(pool_fdtab);
7896 pool_destroy(pool_requri);
7897 pool_destroy(pool_task);
7898 pool_destroy(pool_capture);
7899 pool_destroy(pool_appsess);
7900
7901 if (have_appsession) {
7902 pool_destroy(apools.serverid);
7903 pool_destroy(apools.sessid);
7904 }
7905} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007906
7907int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007908 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007909 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007910 init(argc, argv);
7911
willy tarreau0f7af912005-12-17 12:21:26 +01007912 signal(SIGQUIT, dump);
7913 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007914 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007915#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007916 signal(SIGINT, sig_int);
7917 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007918#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007919
7920 /* on very high loads, a sigpipe sometimes happen just between the
7921 * getsockopt() which tells "it's OK to write", and the following write :-(
7922 */
willy tarreau3242e862005-12-17 12:27:53 +01007923#ifndef MSG_NOSIGNAL
7924 signal(SIGPIPE, SIG_IGN);
7925#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007926
willy tarreaud0fb4652005-12-18 01:32:04 +01007927 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01007928 if (start_proxies() < 0)
7929 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01007930
7931 if (listeners == 0) {
7932 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
7933 exit(1);
7934 }
7935
7936 /* MODE_QUIET can inhibit alerts and warnings below this line */
7937
7938 global.mode &= ~MODE_STARTING;
7939 if (global.mode & MODE_QUIET) {
7940 /* detach from the tty */
7941 fclose(stdin); fclose(stdout); fclose(stderr);
7942 close(0); close(1); close(2);
7943 }
willy tarreau0f7af912005-12-17 12:21:26 +01007944
willy tarreaufe2c5c12005-12-17 14:14:34 +01007945 /* open log & pid files before the chroot */
7946 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7947 int pidfd;
7948 unlink(global.pidfile);
7949 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7950 if (pidfd < 0) {
7951 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7952 exit(1);
7953 }
7954 pidfile = fdopen(pidfd, "w");
7955 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007956
7957 /* chroot if needed */
7958 if (global.chroot != NULL) {
7959 if (chroot(global.chroot) == -1) {
7960 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7961 exit(1);
7962 }
7963 chdir("/");
7964 }
7965
willy tarreaub1285d52005-12-18 01:20:14 +01007966 /* ulimits */
7967 if (global.rlimit_nofile) {
7968 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7969 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7970 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7971 }
7972 }
7973
willy tarreau9fe663a2005-12-17 13:02:59 +01007974 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007975 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007976 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7977 exit(1);
7978 }
7979
willy tarreau036e1ce2005-12-17 13:46:33 +01007980 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007981 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7982 exit(1);
7983 }
7984
willy tarreaub1285d52005-12-18 01:20:14 +01007985 /* check ulimits */
7986 limit.rlim_cur = limit.rlim_max = 0;
7987 getrlimit(RLIMIT_NOFILE, &limit);
7988 if (limit.rlim_cur < global.maxsock) {
7989 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",
7990 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
7991 }
7992
willy tarreau9fe663a2005-12-17 13:02:59 +01007993 if (global.mode & MODE_DAEMON) {
7994 int ret = 0;
7995 int proc;
7996
7997 /* the father launches the required number of processes */
7998 for (proc = 0; proc < global.nbproc; proc++) {
7999 ret = fork();
8000 if (ret < 0) {
8001 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8002 exit(1); /* there has been an error */
8003 }
8004 else if (ret == 0) /* child breaks here */
8005 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008006 if (pidfile != NULL) {
8007 fprintf(pidfile, "%d\n", ret);
8008 fflush(pidfile);
8009 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008010 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008011 /* close the pidfile both in children and father */
8012 if (pidfile != NULL)
8013 fclose(pidfile);
8014 free(global.pidfile);
8015
willy tarreau9fe663a2005-12-17 13:02:59 +01008016 if (proc == global.nbproc)
8017 exit(0); /* parent must leave */
8018
willy tarreau750a4722005-12-17 13:21:24 +01008019 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8020 * that we can detach from the TTY. We MUST NOT do it in other cases since
8021 * it would have already be done, and 0-2 would have been affected to listening
8022 * sockets
8023 */
8024 if (!(global.mode & MODE_QUIET)) {
8025 /* detach from the tty */
8026 fclose(stdin); fclose(stdout); fclose(stderr);
8027 close(0); close(1); close(2); /* close all fd's */
8028 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8029 }
willy tarreaua1598082005-12-17 13:08:06 +01008030 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008031 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008032 }
8033
willy tarreau1c2ad212005-12-18 01:11:29 +01008034#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008035 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008036 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8037 epoll_loop(POLL_LOOP_ACTION_RUN);
8038 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008039 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008040 }
8041 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008042 Warning("epoll() is not available. Using poll()/select() instead.\n");
8043 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008044 }
8045 }
8046#endif
8047
8048#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008049 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008050 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8051 poll_loop(POLL_LOOP_ACTION_RUN);
8052 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008053 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008054 }
8055 else {
8056 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008057 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008058 }
8059 }
8060#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008061 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008062 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8063 select_loop(POLL_LOOP_ACTION_RUN);
8064 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008065 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008066 }
8067 }
8068
willy tarreau0f7af912005-12-17 12:21:26 +01008069
willy tarreau12350152005-12-18 01:03:27 +01008070 /* Free all Hash Keys and all Hash elements */
8071 appsession_cleanup();
8072 /* Do some cleanup */
8073 deinit();
8074
willy tarreau0f7af912005-12-17 12:21:26 +01008075 exit(0);
8076}
willy tarreau12350152005-12-18 01:03:27 +01008077
8078#if defined(DEBUG_HASH)
8079static void print_table(const CHTbl *htbl) {
8080
8081 ListElmt *element;
8082 int i;
8083 appsess *asession;
8084
8085 /*****************************************************************************
8086 * *
8087 * Display the chained hash table. *
8088 * *
8089 *****************************************************************************/
8090
8091 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8092
8093 for (i = 0; i < TBLSIZ; i++) {
8094 fprintf(stdout, "Bucket[%03d]\n", i);
8095
8096 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8097 //fprintf(stdout, "%c", *(char *)list_data(element));
8098 asession = (appsess *)list_data(element);
8099 fprintf(stdout, "ELEM :%s:", asession->sessid);
8100 fprintf(stdout, " Server :%s: \n", asession->serverid);
8101 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8102 }
8103
8104 fprintf(stdout, "\n");
8105 }
8106 return;
8107} /* end print_table */
8108#endif
8109
8110static int appsession_init(void)
8111{
8112 static int initialized = 0;
8113 int idlen;
8114 struct server *s;
8115 struct proxy *p = proxy;
8116
8117 if (!initialized) {
8118 if (!appsession_task_init()) {
8119 apools.sessid = NULL;
8120 apools.serverid = NULL;
8121 apools.ser_waste = 0;
8122 apools.ser_use = 0;
8123 apools.ser_msize = sizeof(void *);
8124 apools.ses_waste = 0;
8125 apools.ses_use = 0;
8126 apools.ses_msize = sizeof(void *);
8127 while (p) {
8128 s = p->srv;
8129 if (apools.ses_msize < p->appsession_len)
8130 apools.ses_msize = p->appsession_len;
8131 while (s) {
8132 idlen = strlen(s->id);
8133 if (apools.ser_msize < idlen)
8134 apools.ser_msize = idlen;
8135 s = s->next;
8136 }
8137 p = p->next;
8138 }
8139 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8140 apools.ses_msize ++;
8141 }
8142 else {
8143 fprintf(stderr, "appsession_task_init failed\n");
8144 return -1;
8145 }
8146 initialized ++;
8147 }
8148 return 0;
8149}
8150
8151static int appsession_task_init(void)
8152{
8153 static int initialized = 0;
8154 struct task *t;
8155 if (!initialized) {
8156 if ((t = pool_alloc(task)) == NULL)
8157 return -1;
8158 t->next = t->prev = t->rqnext = NULL;
8159 t->wq = LIST_HEAD(wait_queue);
8160 t->state = TASK_IDLE;
8161 t->context = NULL;
8162 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8163 task_queue(t);
8164 t->process = appsession_refresh;
8165 initialized ++;
8166 }
8167 return 0;
8168}
8169
8170static int appsession_refresh(struct task *t) {
8171 struct proxy *p = proxy;
8172 CHTbl *htbl;
8173 ListElmt *element, *last;
8174 int i;
8175 appsess *asession;
8176 void *data;
8177
8178 while (p) {
8179 if (p->appsession_name != NULL) {
8180 htbl = &p->htbl_proxy;
8181 /* if we ever give up the use of TBLSIZ, we need to change this */
8182 for (i = 0; i < TBLSIZ; i++) {
8183 last = NULL;
8184 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8185 asession = (appsess *)list_data(element);
8186 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8187 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8188 int len;
8189 /*
8190 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8191 */
8192 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8193 asession->sessid, asession->serverid?asession->serverid:"(null)");
8194 write(1, trash, len);
8195 }
8196 /* delete the expired element from within the hash table */
8197 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8198 && (htbl->table[i].destroy != NULL)) {
8199 htbl->table[i].destroy(data);
8200 }
8201 if (last == NULL) {/* patient lost his head, get a new one */
8202 element = list_head(&htbl->table[i]);
8203 if (element == NULL) break; /* no heads left, go to next patient */
8204 }
8205 else
8206 element = last;
8207 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8208 else
8209 last = element;
8210 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8211 }
8212 }
8213 p = p->next;
8214 }
8215 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8216 return TBLCHKINT;
8217} /* end appsession_refresh */
8218