blob: 6b634a900c4f76649e53f426dc62b2ab4ef58c73 [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 tarreau11a46062005-12-18 01:43:47 +010086#define HAPROXY_VERSION "1.2.7.1"
87#define HAPROXY_DATE "2005/12/04"
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
Willy TARREAUe78ae262006-01-08 01:24:12 +01002970 if (b->data + b->l < end)
2971 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
2972 return 0;
2973
willy tarreau0f7af912005-12-17 12:21:26 +01002974 /* first, protect the end of the buffer */
2975 memmove(end + delta, end, b->data + b->l - end);
2976
2977 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002978 if (len)
2979 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002980
willy tarreau5cbea6f2005-12-17 12:48:26 +01002981 /* we only move data after the displaced zone */
2982 if (b->r > pos) b->r += delta;
2983 if (b->w > pos) b->w += delta;
2984 if (b->h > pos) b->h += delta;
2985 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002986 b->l += delta;
2987
2988 return delta;
2989}
2990
2991
2992int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2993 char *old_dst = dst;
2994
2995 while (*str) {
2996 if (*str == '\\') {
2997 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002998 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002999 int len, num;
3000
3001 num = *str - '0';
3002 str++;
3003
willy tarreau8a86dbf2005-12-18 00:45:59 +01003004 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003005 len = matches[num].rm_eo - matches[num].rm_so;
3006 memcpy(dst, src + matches[num].rm_so, len);
3007 dst += len;
3008 }
3009
3010 }
3011 else if (*str == 'x') {
3012 unsigned char hex1, hex2;
3013 str++;
3014
willy tarreauc1f47532005-12-18 01:08:26 +01003015 hex1 = toupper(*str++) - '0';
3016 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003017
3018 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3019 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3020 *dst++ = (hex1<<4) + hex2;
3021 }
3022 else
3023 *dst++ = *str++;
3024 }
3025 else
3026 *dst++ = *str++;
3027 }
3028 *dst = 0;
3029 return dst - old_dst;
3030}
3031
willy tarreauc1f47532005-12-18 01:08:26 +01003032static int ishex(char s)
3033{
3034 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3035}
3036
3037/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3038char *check_replace_string(char *str)
3039{
3040 char *err = NULL;
3041 while (*str) {
3042 if (*str == '\\') {
3043 err = str; /* in case of a backslash, we return the pointer to it */
3044 str++;
3045 if (!*str)
3046 return err;
3047 else if (isdigit((int)*str))
3048 err = NULL;
3049 else if (*str == 'x') {
3050 str++;
3051 if (!ishex(*str))
3052 return err;
3053 str++;
3054 if (!ishex(*str))
3055 return err;
3056 err = NULL;
3057 }
3058 else {
3059 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3060 err = NULL;
3061 }
3062 }
3063 str++;
3064 }
3065 return err;
3066}
3067
3068
willy tarreau9fe663a2005-12-17 13:02:59 +01003069
willy tarreau0f7af912005-12-17 12:21:26 +01003070/*
3071 * manages the client FSM and its socket. BTW, it also tries to handle the
3072 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3073 * 0 else.
3074 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003075int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003076 int s = t->srv_state;
3077 int c = t->cli_state;
3078 struct buffer *req = t->req;
3079 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003080 int method_checked = 0;
3081 appsess *asession_temp = NULL;
3082 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003083
willy tarreau750a4722005-12-17 13:21:24 +01003084#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003085 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3086 cli_stnames[c], srv_stnames[s],
3087 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3088 t->crexpire.tv_sec, t->crexpire.tv_usec,
3089 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003090#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003091 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3092 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3093 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3094 //);
3095 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003096 /* now parse the partial (or complete) headers */
3097 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3098 char *ptr;
3099 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003100 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003101
willy tarreau5cbea6f2005-12-17 12:48:26 +01003102 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003103
willy tarreau0f7af912005-12-17 12:21:26 +01003104 /* look for the end of the current header */
3105 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3106 ptr++;
3107
willy tarreau5cbea6f2005-12-17 12:48:26 +01003108 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 int line, len;
3110 /* we can only get here after an end of headers */
3111 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003112
willy tarreaue39cd132005-12-17 13:00:18 +01003113 if (t->flags & SN_CLDENY) {
3114 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003115 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003116 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003117 if (!(t->flags & SN_ERR_MASK))
3118 t->flags |= SN_ERR_PRXCOND;
3119 if (!(t->flags & SN_FINST_MASK))
3120 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003121 return 1;
3122 }
3123
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003125 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3126 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 }
willy tarreau0f7af912005-12-17 12:21:26 +01003128
willy tarreau9fe663a2005-12-17 13:02:59 +01003129 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003130 if (t->cli_addr.ss_family == AF_INET) {
3131 unsigned char *pn;
3132 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3133 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3134 pn[0], pn[1], pn[2], pn[3]);
3135 buffer_replace2(req, req->h, req->h, trash, len);
3136 }
3137 else if (t->cli_addr.ss_family == AF_INET6) {
3138 char pn[INET6_ADDRSTRLEN];
3139 inet_ntop(AF_INET6,
3140 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3141 pn, sizeof(pn));
3142 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3143 buffer_replace2(req, req->h, req->h, trash, len);
3144 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003145 }
3146
willy tarreau25c4ea52005-12-18 00:49:49 +01003147 /* add a "connection: close" line if needed */
3148 if (t->proxy->options & PR_O_HTTP_CLOSE)
3149 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3150
willy tarreau982249e2005-12-18 00:57:06 +01003151 if (!memcmp(req->data, "POST ", 5)) {
3152 /* this is a POST request, which is not cacheable by default */
3153 t->flags |= SN_POST;
3154 }
willy tarreaucd878942005-12-17 13:27:43 +01003155
willy tarreau5cbea6f2005-12-17 12:48:26 +01003156 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003157 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003158
willy tarreau750a4722005-12-17 13:21:24 +01003159 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 /* FIXME: we'll set the client in a wait state while we try to
3161 * connect to the server. Is this really needed ? wouldn't it be
3162 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003163 //FD_CLR(t->cli_fd, StaticReadEvent);
3164 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003165
3166 /* FIXME: if we break here (as up to 1.1.23), having the client
3167 * shutdown its connection can lead to an abort further.
3168 * it's better to either return 1 or even jump directly to the
3169 * data state which will save one schedule.
3170 */
3171 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003172
3173 if (!t->proxy->clitimeout ||
3174 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3175 /* If the client has no timeout, or if the server is not ready yet,
3176 * and we know for sure that it can expire, then it's cleaner to
3177 * disable the timeout on the client side so that too low values
3178 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003179 *
3180 * FIXME-20050705: the server needs a way to re-enable this time-out
3181 * when it switches its state, otherwise a client can stay connected
3182 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003183 */
3184 tv_eternity(&t->crexpire);
3185
willy tarreau197e8ec2005-12-17 14:10:59 +01003186 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003187 }
willy tarreau0f7af912005-12-17 12:21:26 +01003188
willy tarreau5cbea6f2005-12-17 12:48:26 +01003189 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3190 if (ptr > req->r - 2) {
3191 /* this is a partial header, let's wait for more to come */
3192 req->lr = ptr;
3193 break;
3194 }
willy tarreau0f7af912005-12-17 12:21:26 +01003195
willy tarreau5cbea6f2005-12-17 12:48:26 +01003196 /* now we know that *ptr is either \r or \n,
3197 * and that there are at least 1 char after it.
3198 */
3199 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3200 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3201 else
3202 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003203
willy tarreau5cbea6f2005-12-17 12:48:26 +01003204 /*
3205 * now we know that we have a full header ; we can do whatever
3206 * we want with these pointers :
3207 * req->h = beginning of header
3208 * ptr = end of header (first \r or \n)
3209 * req->lr = beginning of next line (next rep->h)
3210 * req->r = end of data (not used at this stage)
3211 */
willy tarreau0f7af912005-12-17 12:21:26 +01003212
willy tarreau12350152005-12-18 01:03:27 +01003213 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3214 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3215 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3216
3217 /* skip ; */
3218 request_line++;
3219
3220 /* look if we have a jsessionid */
3221
3222 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3223
3224 /* skip jsessionid= */
3225 request_line += t->proxy->appsession_name_len + 1;
3226
3227 /* First try if we allready have an appsession */
3228 asession_temp = &local_asession;
3229
3230 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3231 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3232 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3233 return 0;
3234 }
3235
3236 /* Copy the sessionid */
3237 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3238 asession_temp->sessid[t->proxy->appsession_len] = 0;
3239 asession_temp->serverid = NULL;
3240
3241 /* only do insert, if lookup fails */
3242 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3243 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3244 Alert("Not enough memory process_cli():asession:calloc().\n");
3245 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3246 return 0;
3247 }
3248 asession_temp->sessid = local_asession.sessid;
3249 asession_temp->serverid = local_asession.serverid;
3250 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003251 } /* end if (chtbl_lookup()) */
3252 else {
willy tarreau12350152005-12-18 01:03:27 +01003253 /*free wasted memory;*/
3254 pool_free_to(apools.sessid, local_asession.sessid);
3255 }
3256
3257 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3258 asession_temp->request_count++;
3259
3260#if defined(DEBUG_HASH)
3261 print_table(&(t->proxy->htbl_proxy));
3262#endif
3263
3264 if (asession_temp->serverid == NULL) {
3265 Alert("Found Application Session without matching server.\n");
3266 } else {
3267 struct server *srv = t->proxy->srv;
3268 while (srv) {
3269 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3270 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3271 /* we found the server and it's usable */
3272 t->flags &= ~SN_CK_MASK;
3273 t->flags |= SN_CK_VALID | SN_DIRECT;
3274 t->srv = srv;
3275 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003276 } else {
willy tarreau12350152005-12-18 01:03:27 +01003277 t->flags &= ~SN_CK_MASK;
3278 t->flags |= SN_CK_DOWN;
3279 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003280 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003281 srv = srv->next;
3282 }/* end while(srv) */
3283 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003284 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003285 else {
3286 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3287 }
willy tarreau598da412005-12-18 01:07:29 +01003288 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003289 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003290 else{
3291 //printf("No Methode-Header with Session-String\n");
3292 }
3293
willy tarreau8337c6b2005-12-17 13:41:01 +01003294 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003295 /* we have a complete HTTP request that we must log */
3296 int urilen;
3297
willy tarreaua1598082005-12-17 13:08:06 +01003298 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003299 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003300 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003301 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003302 if (!(t->flags & SN_ERR_MASK))
3303 t->flags |= SN_ERR_PRXCOND;
3304 if (!(t->flags & SN_FINST_MASK))
3305 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003306 return 1;
3307 }
3308
3309 urilen = ptr - req->h;
3310 if (urilen >= REQURI_LEN)
3311 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003312 memcpy(t->logs.uri, req->h, urilen);
3313 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003314
willy tarreaua1598082005-12-17 13:08:06 +01003315 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003316 sess_log(t);
3317 }
willy tarreau4302f492005-12-18 01:00:37 +01003318 else if (t->logs.logwait & LW_REQHDR) {
3319 struct cap_hdr *h;
3320 int len;
3321 for (h = t->proxy->req_cap; h; h = h->next) {
3322 if ((h->namelen + 2 <= ptr - req->h) &&
3323 (req->h[h->namelen] == ':') &&
3324 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3325
3326 if (t->req_cap[h->index] == NULL)
3327 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3328
3329 len = ptr - (req->h + h->namelen + 2);
3330 if (len > h->len)
3331 len = h->len;
3332
3333 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3334 t->req_cap[h->index][len]=0;
3335 }
3336 }
3337
3338 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003339
willy tarreau5cbea6f2005-12-17 12:48:26 +01003340 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003341
willy tarreau982249e2005-12-18 00:57:06 +01003342 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003344 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 +01003345 max = ptr - req->h;
3346 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003347 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003348 trash[len++] = '\n';
3349 write(1, trash, len);
3350 }
willy tarreau0f7af912005-12-17 12:21:26 +01003351
willy tarreau25c4ea52005-12-18 00:49:49 +01003352
3353 /* remove "connection: " if needed */
3354 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3355 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3356 delete_header = 1;
3357 }
3358
willy tarreau5cbea6f2005-12-17 12:48:26 +01003359 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003360 if (!delete_header && t->proxy->req_exp != NULL
3361 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003362 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 char term;
3364
3365 term = *ptr;
3366 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003367 exp = t->proxy->req_exp;
3368 do {
3369 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3370 switch (exp->action) {
3371 case ACT_ALLOW:
3372 if (!(t->flags & SN_CLDENY))
3373 t->flags |= SN_CLALLOW;
3374 break;
3375 case ACT_REPLACE:
3376 if (!(t->flags & SN_CLDENY)) {
3377 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3378 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3379 }
3380 break;
3381 case ACT_REMOVE:
3382 if (!(t->flags & SN_CLDENY))
3383 delete_header = 1;
3384 break;
3385 case ACT_DENY:
3386 if (!(t->flags & SN_CLALLOW))
3387 t->flags |= SN_CLDENY;
3388 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003389 case ACT_PASS: /* we simply don't deny this one */
3390 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003391 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003392 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003393 }
willy tarreaue39cd132005-12-17 13:00:18 +01003394 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003396 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003397
willy tarreau240afa62005-12-17 13:14:35 +01003398 /* Now look for cookies. Conforming to RFC2109, we have to support
3399 * attributes whose name begin with a '$', and associate them with
3400 * the right cookie, if we want to delete this cookie.
3401 * So there are 3 cases for each cookie read :
3402 * 1) it's a special attribute, beginning with a '$' : ignore it.
3403 * 2) it's a server id cookie that we *MAY* want to delete : save
3404 * some pointers on it (last semi-colon, beginning of cookie...)
3405 * 3) it's an application cookie : we *MAY* have to delete a previous
3406 * "special" cookie.
3407 * At the end of loop, if a "special" cookie remains, we may have to
3408 * remove it. If no application cookie persists in the header, we
3409 * *MUST* delete it
3410 */
willy tarreau12350152005-12-18 01:03:27 +01003411 if (!delete_header &&
3412 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003413 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003414 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003415 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003416 char *del_colon, *del_cookie, *colon;
3417 int app_cookies;
3418
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003420 colon = p1;
3421 /* del_cookie == NULL => nothing to be deleted */
3422 del_colon = del_cookie = NULL;
3423 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003424
3425 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003426 /* skip spaces and colons, but keep an eye on these ones */
3427 while (p1 < ptr) {
3428 if (*p1 == ';' || *p1 == ',')
3429 colon = p1;
3430 else if (!isspace((int)*p1))
3431 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003432 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003433 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003434
3435 if (p1 == ptr)
3436 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003437
3438 /* p1 is at the beginning of the cookie name */
3439 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003440 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003441 p2++;
3442
3443 if (p2 == ptr)
3444 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003445
3446 p3 = p2 + 1; /* skips the '=' sign */
3447 if (p3 == ptr)
3448 break;
3449
willy tarreau240afa62005-12-17 13:14:35 +01003450 p4 = p3;
3451 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003452 p4++;
3453
3454 /* here, we have the cookie name between p1 and p2,
3455 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003456 * we can process it :
3457 *
3458 * Cookie: NAME=VALUE;
3459 * | || || |
3460 * | || || +--> p4
3461 * | || |+-------> p3
3462 * | || +--------> p2
3463 * | |+------------> p1
3464 * | +-------------> colon
3465 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003466 */
3467
willy tarreau240afa62005-12-17 13:14:35 +01003468 if (*p1 == '$') {
3469 /* skip this one */
3470 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003471 else {
3472 /* first, let's see if we want to capture it */
3473 if (t->proxy->capture_name != NULL &&
3474 t->logs.cli_cookie == NULL &&
3475 (p4 - p1 >= t->proxy->capture_namelen) &&
3476 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3477 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478
willy tarreau8337c6b2005-12-17 13:41:01 +01003479 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3480 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003481 } else {
3482 if (log_len > t->proxy->capture_len)
3483 log_len = t->proxy->capture_len;
3484 memcpy(t->logs.cli_cookie, p1, log_len);
3485 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003486 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003487 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003488
3489 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3490 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3491 /* Cool... it's the right one */
3492 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003493 char *delim;
3494
3495 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3496 * have the server ID betweek p3 and delim, and the original cookie between
3497 * delim+1 and p4. Otherwise, delim==p4 :
3498 *
3499 * Cookie: NAME=SRV~VALUE;
3500 * | || || | |
3501 * | || || | +--> p4
3502 * | || || +--------> delim
3503 * | || |+-----------> p3
3504 * | || +------------> p2
3505 * | |+----------------> p1
3506 * | +-----------------> colon
3507 * +------------------------> req->h
3508 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003509
willy tarreau0174f312005-12-18 01:02:42 +01003510 if (t->proxy->options & PR_O_COOK_PFX) {
3511 for (delim = p3; delim < p4; delim++)
3512 if (*delim == COOKIE_DELIM)
3513 break;
3514 }
3515 else
3516 delim = p4;
3517
3518
3519 /* Here, we'll look for the first running server which supports the cookie.
3520 * This allows to share a same cookie between several servers, for example
3521 * to dedicate backup servers to specific servers only.
3522 */
3523 while (srv) {
3524 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3525 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3526 /* we found the server and it's usable */
3527 t->flags &= ~SN_CK_MASK;
3528 t->flags |= SN_CK_VALID | SN_DIRECT;
3529 t->srv = srv;
3530 break;
willy tarreau12350152005-12-18 01:03:27 +01003531 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003532 /* we found a server, but it's down */
3533 t->flags &= ~SN_CK_MASK;
3534 t->flags |= SN_CK_DOWN;
3535 }
3536 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003537 srv = srv->next;
3538 }
3539
willy tarreau0174f312005-12-18 01:02:42 +01003540 if (!srv && !(t->flags & SN_CK_DOWN)) {
3541 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003542 t->flags &= ~SN_CK_MASK;
3543 t->flags |= SN_CK_INVALID;
3544 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003545
willy tarreau0174f312005-12-18 01:02:42 +01003546 /* depending on the cookie mode, we may have to either :
3547 * - delete the complete cookie if we're in insert+indirect mode, so that
3548 * the server never sees it ;
3549 * - remove the server id from the cookie value, and tag the cookie as an
3550 * application cookie so that it does not get accidentely removed later,
3551 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003552 */
willy tarreau0174f312005-12-18 01:02:42 +01003553 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3554 buffer_replace2(req, p3, delim + 1, NULL, 0);
3555 p4 -= (delim + 1 - p3);
3556 ptr -= (delim + 1 - p3);
3557 del_cookie = del_colon = NULL;
3558 app_cookies++; /* protect the header from deletion */
3559 }
3560 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003561 (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 +01003562 del_cookie = p1;
3563 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003564 }
willy tarreau12350152005-12-18 01:03:27 +01003565 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003566 /* now we know that we must keep this cookie since it's
3567 * not ours. But if we wanted to delete our cookie
3568 * earlier, we cannot remove the complete header, but we
3569 * can remove the previous block itself.
3570 */
3571 app_cookies++;
3572
3573 if (del_cookie != NULL) {
3574 buffer_replace2(req, del_cookie, p1, NULL, 0);
3575 p4 -= (p1 - del_cookie);
3576 ptr -= (p1 - del_cookie);
3577 del_cookie = del_colon = NULL;
3578 }
willy tarreau240afa62005-12-17 13:14:35 +01003579 }
willy tarreau12350152005-12-18 01:03:27 +01003580
3581 if ((t->proxy->appsession_name != NULL) &&
3582 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3583 /* first, let's see if the cookie is our appcookie*/
3584
3585 /* Cool... it's the right one */
3586
3587 asession_temp = &local_asession;
3588
3589 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3590 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3591 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3592 return 0;
3593 }
3594
3595 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3596 asession_temp->sessid[t->proxy->appsession_len] = 0;
3597 asession_temp->serverid = NULL;
3598
3599 /* only do insert, if lookup fails */
3600 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3601 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3602 Alert("Not enough memory process_cli():asession:calloc().\n");
3603 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3604 return 0;
3605 }
3606
3607 asession_temp->sessid = local_asession.sessid;
3608 asession_temp->serverid = local_asession.serverid;
3609 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3610 }
3611 else{
3612 /* free wasted memory */
3613 pool_free_to(apools.sessid, local_asession.sessid);
3614 }
3615
3616 if (asession_temp->serverid == NULL) {
3617 Alert("Found Application Session without matching server.\n");
3618 } else {
3619 struct server *srv = t->proxy->srv;
3620 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003621 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003622 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3623 /* we found the server and it's usable */
3624 t->flags &= ~SN_CK_MASK;
3625 t->flags |= SN_CK_VALID | SN_DIRECT;
3626 t->srv = srv;
3627 break;
3628 } else {
3629 t->flags &= ~SN_CK_MASK;
3630 t->flags |= SN_CK_DOWN;
3631 }
3632 }
3633 srv = srv->next;
3634 }/* end while(srv) */
3635 }/* end else if server == NULL */
3636
3637 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003638 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 }
willy tarreau240afa62005-12-17 13:14:35 +01003640
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 /* we'll have to look for another cookie ... */
3642 p1 = p4;
3643 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003644
3645 /* There's no more cookie on this line.
3646 * We may have marked the last one(s) for deletion.
3647 * We must do this now in two ways :
3648 * - if there is no app cookie, we simply delete the header ;
3649 * - if there are app cookies, we must delete the end of the
3650 * string properly, including the colon/semi-colon before
3651 * the cookie name.
3652 */
3653 if (del_cookie != NULL) {
3654 if (app_cookies) {
3655 buffer_replace2(req, del_colon, ptr, NULL, 0);
3656 /* WARNING! <ptr> becomes invalid for now. If some code
3657 * below needs to rely on it before the end of the global
3658 * header loop, we need to correct it with this code :
3659 * ptr = del_colon;
3660 */
3661 }
3662 else
3663 delete_header = 1;
3664 }
3665 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003666
3667 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003668 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003669 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003670 }
willy tarreau240afa62005-12-17 13:14:35 +01003671 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3672
willy tarreau5cbea6f2005-12-17 12:48:26 +01003673 req->h = req->lr;
3674 } /* while (req->lr < req->r) */
3675
3676 /* end of header processing (even if incomplete) */
3677
willy tarreauef900ab2005-12-17 12:52:52 +01003678 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3679 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3680 * full. We cannot loop here since event_cli_read will disable it only if
3681 * req->l == rlim-data
3682 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683 FD_SET(t->cli_fd, StaticReadEvent);
3684 if (t->proxy->clitimeout)
3685 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3686 else
3687 tv_eternity(&t->crexpire);
3688 }
3689
willy tarreaue39cd132005-12-17 13:00:18 +01003690 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003691 * won't be able to free more later, so the session will never terminate.
3692 */
willy tarreaue39cd132005-12-17 13:00:18 +01003693 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003694 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003695 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003696 if (!(t->flags & SN_ERR_MASK))
3697 t->flags |= SN_ERR_PRXCOND;
3698 if (!(t->flags & SN_FINST_MASK))
3699 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003700 return 1;
3701 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003702 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003703 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003704 tv_eternity(&t->crexpire);
3705 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003706 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003707 if (!(t->flags & SN_ERR_MASK))
3708 t->flags |= SN_ERR_CLICL;
3709 if (!(t->flags & SN_FINST_MASK))
3710 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003711 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003712 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003713 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3714
3715 /* read timeout : give up with an error message.
3716 */
3717 t->logs.status = 408;
3718 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003719 if (!(t->flags & SN_ERR_MASK))
3720 t->flags |= SN_ERR_CLITO;
3721 if (!(t->flags & SN_FINST_MASK))
3722 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003723 return 1;
3724 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003725
3726 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003727 }
3728 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003729 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003730 /* FIXME: this error handling is partly buggy because we always report
3731 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3732 * or HEADER phase. BTW, it's not logical to expire the client while
3733 * we're waiting for the server to connect.
3734 */
willy tarreau0f7af912005-12-17 12:21:26 +01003735 /* read or write error */
3736 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003737 tv_eternity(&t->crexpire);
3738 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003740 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003741 if (!(t->flags & SN_ERR_MASK))
3742 t->flags |= SN_ERR_CLICL;
3743 if (!(t->flags & SN_FINST_MASK))
3744 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003745 return 1;
3746 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003747 /* last read, or end of server write */
3748 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003749 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003750 tv_eternity(&t->crexpire);
3751 shutdown(t->cli_fd, SHUT_RD);
3752 t->cli_state = CL_STSHUTR;
3753 return 1;
3754 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003755 /* last server read and buffer empty */
3756 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003757 FD_CLR(t->cli_fd, StaticWriteEvent);
3758 tv_eternity(&t->cwexpire);
3759 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003760 /* We must ensure that the read part is still alive when switching
3761 * to shutw */
3762 FD_SET(t->cli_fd, StaticReadEvent);
3763 if (t->proxy->clitimeout)
3764 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003765 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003766 //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 +01003767 return 1;
3768 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003769 /* read timeout */
3770 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3771 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003772 tv_eternity(&t->crexpire);
3773 shutdown(t->cli_fd, SHUT_RD);
3774 t->cli_state = CL_STSHUTR;
3775 if (!(t->flags & SN_ERR_MASK))
3776 t->flags |= SN_ERR_CLITO;
3777 if (!(t->flags & SN_FINST_MASK))
3778 t->flags |= SN_FINST_D;
3779 return 1;
3780 }
3781 /* write timeout */
3782 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3783 FD_CLR(t->cli_fd, StaticWriteEvent);
3784 tv_eternity(&t->cwexpire);
3785 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003786 /* We must ensure that the read part is still alive when switching
3787 * to shutw */
3788 FD_SET(t->cli_fd, StaticReadEvent);
3789 if (t->proxy->clitimeout)
3790 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3791
willy tarreau036e1ce2005-12-17 13:46:33 +01003792 t->cli_state = CL_STSHUTW;
3793 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003794 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003795 if (!(t->flags & SN_FINST_MASK))
3796 t->flags |= SN_FINST_D;
3797 return 1;
3798 }
willy tarreau0f7af912005-12-17 12:21:26 +01003799
willy tarreauc58fc692005-12-17 14:13:08 +01003800 if (req->l >= req->rlim - req->data) {
3801 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003802 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003803 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003804 FD_CLR(t->cli_fd, StaticReadEvent);
3805 tv_eternity(&t->crexpire);
3806 }
3807 }
3808 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003809 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003810 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3811 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003812 if (!t->proxy->clitimeout ||
3813 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3814 /* If the client has no timeout, or if the server not ready yet, and we
3815 * know for sure that it can expire, then it's cleaner to disable the
3816 * timeout on the client side so that too low values cannot make the
3817 * sessions abort too early.
3818 */
willy tarreau0f7af912005-12-17 12:21:26 +01003819 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003820 else
3821 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003822 }
3823 }
3824
3825 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003826 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003827 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3828 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3829 tv_eternity(&t->cwexpire);
3830 }
3831 }
3832 else { /* buffer not empty */
3833 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3834 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003835 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003836 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003837 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3838 t->crexpire = t->cwexpire;
3839 }
willy tarreau0f7af912005-12-17 12:21:26 +01003840 else
3841 tv_eternity(&t->cwexpire);
3842 }
3843 }
3844 return 0; /* other cases change nothing */
3845 }
3846 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003847 if (t->res_cw == RES_ERROR) {
3848 tv_eternity(&t->cwexpire);
3849 fd_delete(t->cli_fd);
3850 t->cli_state = CL_STCLOSE;
3851 if (!(t->flags & SN_ERR_MASK))
3852 t->flags |= SN_ERR_CLICL;
3853 if (!(t->flags & SN_FINST_MASK))
3854 t->flags |= SN_FINST_D;
3855 return 1;
3856 }
3857 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003858 tv_eternity(&t->cwexpire);
3859 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003860 t->cli_state = CL_STCLOSE;
3861 return 1;
3862 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003863 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3864 tv_eternity(&t->cwexpire);
3865 fd_delete(t->cli_fd);
3866 t->cli_state = CL_STCLOSE;
3867 if (!(t->flags & SN_ERR_MASK))
3868 t->flags |= SN_ERR_CLITO;
3869 if (!(t->flags & SN_FINST_MASK))
3870 t->flags |= SN_FINST_D;
3871 return 1;
3872 }
willy tarreau0f7af912005-12-17 12:21:26 +01003873 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003874 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003875 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3876 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3877 tv_eternity(&t->cwexpire);
3878 }
3879 }
3880 else { /* buffer not empty */
3881 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3882 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003883 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003884 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003885 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3886 t->crexpire = t->cwexpire;
3887 }
willy tarreau0f7af912005-12-17 12:21:26 +01003888 else
3889 tv_eternity(&t->cwexpire);
3890 }
3891 }
3892 return 0;
3893 }
3894 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003895 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003896 tv_eternity(&t->crexpire);
3897 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003898 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003899 if (!(t->flags & SN_ERR_MASK))
3900 t->flags |= SN_ERR_CLICL;
3901 if (!(t->flags & SN_FINST_MASK))
3902 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003903 return 1;
3904 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003905 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3906 tv_eternity(&t->crexpire);
3907 fd_delete(t->cli_fd);
3908 t->cli_state = CL_STCLOSE;
3909 return 1;
3910 }
3911 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3912 tv_eternity(&t->crexpire);
3913 fd_delete(t->cli_fd);
3914 t->cli_state = CL_STCLOSE;
3915 if (!(t->flags & SN_ERR_MASK))
3916 t->flags |= SN_ERR_CLITO;
3917 if (!(t->flags & SN_FINST_MASK))
3918 t->flags |= SN_FINST_D;
3919 return 1;
3920 }
willy tarreauef900ab2005-12-17 12:52:52 +01003921 else if (req->l >= req->rlim - req->data) {
3922 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003923
3924 /* FIXME-20050705: is it possible for a client to maintain a session
3925 * after the timeout by sending more data after it receives a close ?
3926 */
3927
willy tarreau0f7af912005-12-17 12:21:26 +01003928 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003929 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003930 FD_CLR(t->cli_fd, StaticReadEvent);
3931 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003932 //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 +01003933 }
3934 }
3935 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003936 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003937 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3938 FD_SET(t->cli_fd, StaticReadEvent);
3939 if (t->proxy->clitimeout)
3940 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3941 else
3942 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003943 //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 +01003944 }
3945 }
3946 return 0;
3947 }
3948 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003949 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003950 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003951 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 +01003952 write(1, trash, len);
3953 }
3954 return 0;
3955 }
3956 return 0;
3957}
3958
3959
3960/*
3961 * manages the server FSM and its socket. It returns 1 if a state has changed
3962 * (and a resync may be needed), 0 else.
3963 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003964int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003965 int s = t->srv_state;
3966 int c = t->cli_state;
3967 struct buffer *req = t->req;
3968 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003969 appsess *asession_temp = NULL;
3970 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003971 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003972
willy tarreau750a4722005-12-17 13:21:24 +01003973#ifdef DEBUG_FULL
3974 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3975#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003976 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3977 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3978 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3979 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003980 if (s == SV_STIDLE) {
3981 if (c == CL_STHEADERS)
3982 return 0; /* stay in idle, waiting for data to reach the client side */
3983 else if (c == CL_STCLOSE ||
3984 c == CL_STSHUTW ||
3985 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3986 tv_eternity(&t->cnexpire);
3987 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003988 if (!(t->flags & SN_ERR_MASK))
3989 t->flags |= SN_ERR_CLICL;
3990 if (!(t->flags & SN_FINST_MASK))
3991 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003992 return 1;
3993 }
3994 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003995 /* initiate a connection to the server */
3996 conn_err = connect_server(t);
3997 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003998 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3999 t->srv_state = SV_STCONN;
4000 }
4001 else { /* try again */
4002 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004003 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004004 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004005 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004006 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4007 t->flags &= ~SN_CK_MASK;
4008 t->flags |= SN_CK_DOWN;
4009 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004010 }
4011
willy tarreaub1285d52005-12-18 01:20:14 +01004012 conn_err = connect_server(t);
4013 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004014 t->srv_state = SV_STCONN;
4015 break;
4016 }
4017 }
4018 if (t->conn_retries < 0) {
4019 /* if conn_retries < 0 or other error, let's abort */
4020 tv_eternity(&t->cnexpire);
4021 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004022 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004023 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004024 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004025 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004026 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004027 if (!(t->flags & SN_FINST_MASK))
4028 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004029 }
4030 }
4031 return 1;
4032 }
4033 }
4034 else if (s == SV_STCONN) { /* connection in progress */
4035 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
4036 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
4037 return 0; /* nothing changed */
4038 }
4039 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4040 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4041 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004042 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004043 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004044 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004045 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004046 if (t->conn_retries >= 0) {
4047 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004048 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004049 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004050 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4051 t->flags &= ~SN_CK_MASK;
4052 t->flags |= SN_CK_DOWN;
4053 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004054 }
willy tarreaub1285d52005-12-18 01:20:14 +01004055 conn_err = connect_server(t);
4056 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004057 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004058 }
willy tarreaub1285d52005-12-18 01:20:14 +01004059 else if (t->res_sw == RES_SILENT)
4060 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4061 else
4062 conn_err = SN_ERR_SRVCL; // it was a connect error.
4063
willy tarreau0f7af912005-12-17 12:21:26 +01004064 /* if conn_retries < 0 or other error, let's abort */
4065 tv_eternity(&t->cnexpire);
4066 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004067 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004068 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004069 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004070 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004071 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004072 if (!(t->flags & SN_FINST_MASK))
4073 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004074 return 1;
4075 }
4076 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004077 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004078
willy tarreau0f7af912005-12-17 12:21:26 +01004079 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004080 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004081 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004082 tv_eternity(&t->swexpire);
4083 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004084 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004085 if (t->proxy->srvtimeout) {
4086 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4087 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4088 t->srexpire = t->swexpire;
4089 }
4090 else
4091 tv_eternity(&t->swexpire);
4092 }
willy tarreau0f7af912005-12-17 12:21:26 +01004093
4094 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4095 FD_SET(t->srv_fd, StaticReadEvent);
4096 if (t->proxy->srvtimeout)
4097 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4098 else
4099 tv_eternity(&t->srexpire);
4100
4101 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004102 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004103
4104 /* if the user wants to log as soon as possible, without counting
4105 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004106 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004107 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4108 sess_log(t);
4109 }
willy tarreau0f7af912005-12-17 12:21:26 +01004110 }
willy tarreauef900ab2005-12-17 12:52:52 +01004111 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004112 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004113 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4114 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004115 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004116 return 1;
4117 }
4118 }
4119 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004120 /* now parse the partial (or complete) headers */
4121 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4122 char *ptr;
4123 int delete_header;
4124
4125 ptr = rep->lr;
4126
4127 /* look for the end of the current header */
4128 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4129 ptr++;
4130
4131 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004132 int line, len;
4133
4134 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004135
4136 /* first, we'll block if security checks have caught nasty things */
4137 if (t->flags & SN_CACHEABLE) {
4138 if ((t->flags & SN_CACHE_COOK) &&
4139 (t->flags & SN_SCK_ANY) &&
4140 (t->proxy->options & PR_O_CHK_CACHE)) {
4141
4142 /* we're in presence of a cacheable response containing
4143 * a set-cookie header. We'll block it as requested by
4144 * the 'checkcache' option, and send an alert.
4145 */
4146 tv_eternity(&t->srexpire);
4147 tv_eternity(&t->swexpire);
4148 fd_delete(t->srv_fd);
4149 t->srv_state = SV_STCLOSE;
4150 t->logs.status = 502;
4151 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4152 if (!(t->flags & SN_ERR_MASK))
4153 t->flags |= SN_ERR_PRXCOND;
4154 if (!(t->flags & SN_FINST_MASK))
4155 t->flags |= SN_FINST_H;
4156
4157 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4158 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4159
4160 return 1;
4161 }
4162 }
4163
willy tarreau982249e2005-12-18 00:57:06 +01004164 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4165 if (t->flags & SN_SVDENY) {
4166 tv_eternity(&t->srexpire);
4167 tv_eternity(&t->swexpire);
4168 fd_delete(t->srv_fd);
4169 t->srv_state = SV_STCLOSE;
4170 t->logs.status = 502;
4171 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4172 if (!(t->flags & SN_ERR_MASK))
4173 t->flags |= SN_ERR_PRXCOND;
4174 if (!(t->flags & SN_FINST_MASK))
4175 t->flags |= SN_FINST_H;
4176 return 1;
4177 }
4178
willy tarreau5cbea6f2005-12-17 12:48:26 +01004179 /* we'll have something else to do here : add new headers ... */
4180
willy tarreaucd878942005-12-17 13:27:43 +01004181 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4182 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004183 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004184 * insert a set-cookie here, except if we want to insert only on POST
4185 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004186 */
willy tarreau750a4722005-12-17 13:21:24 +01004187 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004188 t->proxy->cookie_name,
4189 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004190
willy tarreau036e1ce2005-12-17 13:46:33 +01004191 t->flags |= SN_SCK_INSERTED;
4192
willy tarreau750a4722005-12-17 13:21:24 +01004193 /* Here, we will tell an eventual cache on the client side that we don't
4194 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4195 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4196 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4197 */
willy tarreau240afa62005-12-17 13:14:35 +01004198 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004199 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4200 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004201
4202 if (rep->data + rep->l < rep->h)
4203 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4204 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004205 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004206 }
4207
4208 /* headers to be added */
4209 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004210 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4211 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004212 }
4213
willy tarreau25c4ea52005-12-18 00:49:49 +01004214 /* add a "connection: close" line if needed */
4215 if (t->proxy->options & PR_O_HTTP_CLOSE)
4216 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4217
willy tarreau5cbea6f2005-12-17 12:48:26 +01004218 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004219 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004220 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004221
4222 /* if the user wants to log as soon as possible, without counting
4223 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004224 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004225 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4226 t->logs.bytes = rep->h - rep->data;
4227 sess_log(t);
4228 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004229 break;
4230 }
4231
4232 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4233 if (ptr > rep->r - 2) {
4234 /* this is a partial header, let's wait for more to come */
4235 rep->lr = ptr;
4236 break;
4237 }
4238
4239 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4240 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4241
4242 /* now we know that *ptr is either \r or \n,
4243 * and that there are at least 1 char after it.
4244 */
4245 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4246 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4247 else
4248 rep->lr = ptr + 2; /* \r\n or \n\r */
4249
4250 /*
4251 * now we know that we have a full header ; we can do whatever
4252 * we want with these pointers :
4253 * rep->h = beginning of header
4254 * ptr = end of header (first \r or \n)
4255 * rep->lr = beginning of next line (next rep->h)
4256 * rep->r = end of data (not used at this stage)
4257 */
4258
willy tarreaua1598082005-12-17 13:08:06 +01004259
willy tarreau982249e2005-12-18 00:57:06 +01004260 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004261 t->logs.logwait &= ~LW_RESP;
4262 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004263 switch (t->logs.status) {
4264 case 200:
4265 case 203:
4266 case 206:
4267 case 300:
4268 case 301:
4269 case 410:
4270 /* RFC2616 @13.4:
4271 * "A response received with a status code of
4272 * 200, 203, 206, 300, 301 or 410 MAY be stored
4273 * by a cache (...) unless a cache-control
4274 * directive prohibits caching."
4275 *
4276 * RFC2616 @9.5: POST method :
4277 * "Responses to this method are not cacheable,
4278 * unless the response includes appropriate
4279 * Cache-Control or Expires header fields."
4280 */
4281 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4282 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4283 break;
4284 default:
4285 break;
4286 }
willy tarreau4302f492005-12-18 01:00:37 +01004287 }
4288 else if (t->logs.logwait & LW_RSPHDR) {
4289 struct cap_hdr *h;
4290 int len;
4291 for (h = t->proxy->rsp_cap; h; h = h->next) {
4292 if ((h->namelen + 2 <= ptr - rep->h) &&
4293 (rep->h[h->namelen] == ':') &&
4294 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4295
4296 if (t->rsp_cap[h->index] == NULL)
4297 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4298
4299 len = ptr - (rep->h + h->namelen + 2);
4300 if (len > h->len)
4301 len = h->len;
4302
4303 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4304 t->rsp_cap[h->index][len]=0;
4305 }
4306 }
4307
willy tarreaua1598082005-12-17 13:08:06 +01004308 }
4309
willy tarreau5cbea6f2005-12-17 12:48:26 +01004310 delete_header = 0;
4311
willy tarreau982249e2005-12-18 00:57:06 +01004312 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004313 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004314 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 +01004315 max = ptr - rep->h;
4316 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004317 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004318 trash[len++] = '\n';
4319 write(1, trash, len);
4320 }
4321
willy tarreau25c4ea52005-12-18 00:49:49 +01004322 /* remove "connection: " if needed */
4323 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4324 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4325 delete_header = 1;
4326 }
4327
willy tarreau5cbea6f2005-12-17 12:48:26 +01004328 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004329 if (!delete_header && t->proxy->rsp_exp != NULL
4330 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004331 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004332 char term;
4333
4334 term = *ptr;
4335 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004336 exp = t->proxy->rsp_exp;
4337 do {
4338 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4339 switch (exp->action) {
4340 case ACT_ALLOW:
4341 if (!(t->flags & SN_SVDENY))
4342 t->flags |= SN_SVALLOW;
4343 break;
4344 case ACT_REPLACE:
4345 if (!(t->flags & SN_SVDENY)) {
4346 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4347 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4348 }
4349 break;
4350 case ACT_REMOVE:
4351 if (!(t->flags & SN_SVDENY))
4352 delete_header = 1;
4353 break;
4354 case ACT_DENY:
4355 if (!(t->flags & SN_SVALLOW))
4356 t->flags |= SN_SVDENY;
4357 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004358 case ACT_PASS: /* we simply don't deny this one */
4359 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360 }
4361 break;
4362 }
willy tarreaue39cd132005-12-17 13:00:18 +01004363 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004364 *ptr = term; /* restore the string terminator */
4365 }
4366
willy tarreau97f58572005-12-18 00:53:44 +01004367 /* check for cache-control: or pragma: headers */
4368 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4369 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4370 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4371 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4372 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004373 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004374 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4375 else {
4376 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004377 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004378 t->flags &= ~SN_CACHE_COOK;
4379 }
4380 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004381 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004382 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004383 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004384 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4385 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004386 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004387 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004388 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4389 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4390 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4391 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4392 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4393 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004394 }
4395 }
4396 }
4397
willy tarreau5cbea6f2005-12-17 12:48:26 +01004398 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004399 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004400 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004401 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004402 char *p1, *p2, *p3, *p4;
4403
willy tarreau97f58572005-12-18 00:53:44 +01004404 t->flags |= SN_SCK_ANY;
4405
willy tarreau5cbea6f2005-12-17 12:48:26 +01004406 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4407
4408 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004409 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004410 p1++;
4411
4412 if (p1 == ptr || *p1 == ';') /* end of cookie */
4413 break;
4414
4415 /* p1 is at the beginning of the cookie name */
4416 p2 = p1;
4417
4418 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4419 p2++;
4420
4421 if (p2 == ptr || *p2 == ';') /* next cookie */
4422 break;
4423
4424 p3 = p2 + 1; /* skips the '=' sign */
4425 if (p3 == ptr)
4426 break;
4427
4428 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004429 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004430 p4++;
4431
4432 /* here, we have the cookie name between p1 and p2,
4433 * and its value between p3 and p4.
4434 * we can process it.
4435 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004436
4437 /* first, let's see if we want to capture it */
4438 if (t->proxy->capture_name != NULL &&
4439 t->logs.srv_cookie == NULL &&
4440 (p4 - p1 >= t->proxy->capture_namelen) &&
4441 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4442 int log_len = p4 - p1;
4443
4444 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4445 Alert("HTTP logging : out of memory.\n");
4446 }
4447
4448 if (log_len > t->proxy->capture_len)
4449 log_len = t->proxy->capture_len;
4450 memcpy(t->logs.srv_cookie, p1, log_len);
4451 t->logs.srv_cookie[log_len] = 0;
4452 }
4453
4454 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4455 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004456 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004457 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004458
4459 /* If the cookie is in insert mode on a known server, we'll delete
4460 * this occurrence because we'll insert another one later.
4461 * We'll delete it too if the "indirect" option is set and we're in
4462 * a direct access. */
4463 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004464 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004465 /* this header must be deleted */
4466 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004467 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004468 }
4469 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4470 /* replace bytes p3->p4 with the cookie name associated
4471 * with this server since we know it.
4472 */
4473 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004474 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004475 }
willy tarreau0174f312005-12-18 01:02:42 +01004476 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4477 /* insert the cookie name associated with this server
4478 * before existing cookie, and insert a delimitor between them..
4479 */
4480 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4481 p3[t->srv->cklen] = COOKIE_DELIM;
4482 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4483 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004484 break;
4485 }
willy tarreau12350152005-12-18 01:03:27 +01004486
4487 /* first, let's see if the cookie is our appcookie*/
4488 if ((t->proxy->appsession_name != NULL) &&
4489 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4490
4491 /* Cool... it's the right one */
4492
willy tarreaub952e1d2005-12-18 01:31:20 +01004493 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004494 asession_temp = &local_asession;
4495
willy tarreaub952e1d2005-12-18 01:31:20 +01004496 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004497 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4498 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4499 }
4500 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4501 asession_temp->sessid[t->proxy->appsession_len] = 0;
4502 asession_temp->serverid = NULL;
4503
4504 /* only do insert, if lookup fails */
4505 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4506 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4507 Alert("Not enought Memory process_srv():asession:calloc().\n");
4508 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4509 return 0;
4510 }
4511 asession_temp->sessid = local_asession.sessid;
4512 asession_temp->serverid = local_asession.serverid;
4513 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004514 }/* end if (chtbl_lookup()) */
4515 else {
willy tarreau12350152005-12-18 01:03:27 +01004516 /* free wasted memory */
4517 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004518 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004519
willy tarreaub952e1d2005-12-18 01:31:20 +01004520 if (asession_temp->serverid == NULL) {
4521 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004522 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4523 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4524 }
4525 asession_temp->serverid[0] = '\0';
4526 }
4527
willy tarreaub952e1d2005-12-18 01:31:20 +01004528 if (asession_temp->serverid[0] == '\0')
4529 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004530
4531 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4532
4533#if defined(DEBUG_HASH)
4534 print_table(&(t->proxy->htbl_proxy));
4535#endif
4536 break;
4537 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004538 else {
4539 // fprintf(stderr,"Ignoring unknown cookie : ");
4540 // write(2, p1, p2-p1);
4541 // fprintf(stderr," = ");
4542 // write(2, p3, p4-p3);
4543 // fprintf(stderr,"\n");
4544 }
4545 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4546 } /* we're now at the end of the cookie value */
4547 } /* end of cookie processing */
4548
willy tarreau97f58572005-12-18 00:53:44 +01004549 /* check for any set-cookie in case we check for cacheability */
4550 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4551 (t->proxy->options & PR_O_CHK_CACHE) &&
4552 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4553 t->flags |= SN_SCK_ANY;
4554 }
4555
willy tarreau5cbea6f2005-12-17 12:48:26 +01004556 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004557 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004558 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004559
willy tarreau5cbea6f2005-12-17 12:48:26 +01004560 rep->h = rep->lr;
4561 } /* while (rep->lr < rep->r) */
4562
4563 /* end of header processing (even if incomplete) */
4564
willy tarreauef900ab2005-12-17 12:52:52 +01004565 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4566 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4567 * full. We cannot loop here since event_srv_read will disable it only if
4568 * rep->l == rlim-data
4569 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004570 FD_SET(t->srv_fd, StaticReadEvent);
4571 if (t->proxy->srvtimeout)
4572 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4573 else
4574 tv_eternity(&t->srexpire);
4575 }
willy tarreau0f7af912005-12-17 12:21:26 +01004576
willy tarreau8337c6b2005-12-17 13:41:01 +01004577 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004578 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004579 tv_eternity(&t->srexpire);
4580 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004581 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004582 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004583 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004584 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004585 if (!(t->flags & SN_ERR_MASK))
4586 t->flags |= SN_ERR_SRVCL;
4587 if (!(t->flags & SN_FINST_MASK))
4588 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004589 return 1;
4590 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004591 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004592 * since we are in header mode, if there's no space left for headers, we
4593 * won't be able to free more later, so the session will never terminate.
4594 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004595 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 +01004596 FD_CLR(t->srv_fd, StaticReadEvent);
4597 tv_eternity(&t->srexpire);
4598 shutdown(t->srv_fd, SHUT_RD);
4599 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004600 //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 +01004601 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004602 }
4603 /* read timeout : return a 504 to the client.
4604 */
4605 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4606 tv_eternity(&t->srexpire);
4607 tv_eternity(&t->swexpire);
4608 fd_delete(t->srv_fd);
4609 t->srv_state = SV_STCLOSE;
4610 t->logs.status = 504;
4611 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004612 if (!(t->flags & SN_ERR_MASK))
4613 t->flags |= SN_ERR_SRVTO;
4614 if (!(t->flags & SN_FINST_MASK))
4615 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004616 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004617
4618 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004619 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004620 /* FIXME!!! here, we don't want to switch to SHUTW if the
4621 * client shuts read too early, because we may still have
4622 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004623 * The side-effect is that if the client completely closes its
4624 * connection during SV_STHEADER, the connection to the server
4625 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004626 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004627 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004628 FD_CLR(t->srv_fd, StaticWriteEvent);
4629 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004630
4631 /* We must ensure that the read part is still alive when switching
4632 * to shutw */
4633 FD_SET(t->srv_fd, StaticReadEvent);
4634 if (t->proxy->srvtimeout)
4635 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4636
willy tarreau0f7af912005-12-17 12:21:26 +01004637 shutdown(t->srv_fd, SHUT_WR);
4638 t->srv_state = SV_STSHUTW;
4639 return 1;
4640 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004641 /* write timeout */
4642 /* FIXME!!! here, we don't want to switch to SHUTW if the
4643 * client shuts read too early, because we may still have
4644 * some work to do on the headers.
4645 */
4646 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4647 FD_CLR(t->srv_fd, StaticWriteEvent);
4648 tv_eternity(&t->swexpire);
4649 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004650 /* We must ensure that the read part is still alive when switching
4651 * to shutw */
4652 FD_SET(t->srv_fd, StaticReadEvent);
4653 if (t->proxy->srvtimeout)
4654 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4655
4656 /* We must ensure that the read part is still alive when switching
4657 * to shutw */
4658 FD_SET(t->srv_fd, StaticReadEvent);
4659 if (t->proxy->srvtimeout)
4660 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4661
willy tarreau036e1ce2005-12-17 13:46:33 +01004662 t->srv_state = SV_STSHUTW;
4663 if (!(t->flags & SN_ERR_MASK))
4664 t->flags |= SN_ERR_SRVTO;
4665 if (!(t->flags & SN_FINST_MASK))
4666 t->flags |= SN_FINST_H;
4667 return 1;
4668 }
willy tarreau0f7af912005-12-17 12:21:26 +01004669
4670 if (req->l == 0) {
4671 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4672 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4673 tv_eternity(&t->swexpire);
4674 }
4675 }
4676 else { /* client buffer not empty */
4677 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4678 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004679 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004680 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004681 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4682 t->srexpire = t->swexpire;
4683 }
willy tarreau0f7af912005-12-17 12:21:26 +01004684 else
4685 tv_eternity(&t->swexpire);
4686 }
4687 }
4688
willy tarreau5cbea6f2005-12-17 12:48:26 +01004689 /* be nice with the client side which would like to send a complete header
4690 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4691 * would read all remaining data at once ! The client should not write past rep->lr
4692 * when the server is in header state.
4693 */
4694 //return header_processed;
4695 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004696 }
4697 else if (s == SV_STDATA) {
4698 /* read or write error */
4699 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004700 tv_eternity(&t->srexpire);
4701 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004702 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004703 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004704 if (!(t->flags & SN_ERR_MASK))
4705 t->flags |= SN_ERR_SRVCL;
4706 if (!(t->flags & SN_FINST_MASK))
4707 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004708 return 1;
4709 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004710 /* last read, or end of client write */
4711 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004712 FD_CLR(t->srv_fd, StaticReadEvent);
4713 tv_eternity(&t->srexpire);
4714 shutdown(t->srv_fd, SHUT_RD);
4715 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004716 //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 +01004717 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004718 }
4719 /* end of client read and no more data to send */
4720 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4721 FD_CLR(t->srv_fd, StaticWriteEvent);
4722 tv_eternity(&t->swexpire);
4723 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004724 /* We must ensure that the read part is still alive when switching
4725 * to shutw */
4726 FD_SET(t->srv_fd, StaticReadEvent);
4727 if (t->proxy->srvtimeout)
4728 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4729
willy tarreaua41a8b42005-12-17 14:02:24 +01004730 t->srv_state = SV_STSHUTW;
4731 return 1;
4732 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004733 /* read timeout */
4734 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4735 FD_CLR(t->srv_fd, StaticReadEvent);
4736 tv_eternity(&t->srexpire);
4737 shutdown(t->srv_fd, SHUT_RD);
4738 t->srv_state = SV_STSHUTR;
4739 if (!(t->flags & SN_ERR_MASK))
4740 t->flags |= SN_ERR_SRVTO;
4741 if (!(t->flags & SN_FINST_MASK))
4742 t->flags |= SN_FINST_D;
4743 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004744 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004745 /* write timeout */
4746 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004747 FD_CLR(t->srv_fd, StaticWriteEvent);
4748 tv_eternity(&t->swexpire);
4749 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004750 /* We must ensure that the read part is still alive when switching
4751 * to shutw */
4752 FD_SET(t->srv_fd, StaticReadEvent);
4753 if (t->proxy->srvtimeout)
4754 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004755 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004756 if (!(t->flags & SN_ERR_MASK))
4757 t->flags |= SN_ERR_SRVTO;
4758 if (!(t->flags & SN_FINST_MASK))
4759 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004760 return 1;
4761 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004762
4763 /* recompute request time-outs */
4764 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004765 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4766 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4767 tv_eternity(&t->swexpire);
4768 }
4769 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004770 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004771 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4772 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004773 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004774 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004775 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4776 t->srexpire = t->swexpire;
4777 }
willy tarreau0f7af912005-12-17 12:21:26 +01004778 else
4779 tv_eternity(&t->swexpire);
4780 }
4781 }
4782
willy tarreaub1ff9db2005-12-17 13:51:03 +01004783 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004784 if (rep->l == BUFSIZE) { /* no room to read more data */
4785 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4786 FD_CLR(t->srv_fd, StaticReadEvent);
4787 tv_eternity(&t->srexpire);
4788 }
4789 }
4790 else {
4791 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4792 FD_SET(t->srv_fd, StaticReadEvent);
4793 if (t->proxy->srvtimeout)
4794 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4795 else
4796 tv_eternity(&t->srexpire);
4797 }
4798 }
4799
4800 return 0; /* other cases change nothing */
4801 }
4802 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004803 if (t->res_sw == RES_ERROR) {
4804 //FD_CLR(t->srv_fd, StaticWriteEvent);
4805 tv_eternity(&t->swexpire);
4806 fd_delete(t->srv_fd);
4807 //close(t->srv_fd);
4808 t->srv_state = SV_STCLOSE;
4809 if (!(t->flags & SN_ERR_MASK))
4810 t->flags |= SN_ERR_SRVCL;
4811 if (!(t->flags & SN_FINST_MASK))
4812 t->flags |= SN_FINST_D;
4813 return 1;
4814 }
4815 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004817 tv_eternity(&t->swexpire);
4818 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004819 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004820 t->srv_state = SV_STCLOSE;
4821 return 1;
4822 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004823 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4824 //FD_CLR(t->srv_fd, StaticWriteEvent);
4825 tv_eternity(&t->swexpire);
4826 fd_delete(t->srv_fd);
4827 //close(t->srv_fd);
4828 t->srv_state = SV_STCLOSE;
4829 if (!(t->flags & SN_ERR_MASK))
4830 t->flags |= SN_ERR_SRVTO;
4831 if (!(t->flags & SN_FINST_MASK))
4832 t->flags |= SN_FINST_D;
4833 return 1;
4834 }
willy tarreau0f7af912005-12-17 12:21:26 +01004835 else if (req->l == 0) {
4836 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4837 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4838 tv_eternity(&t->swexpire);
4839 }
4840 }
4841 else { /* buffer not empty */
4842 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4843 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004844 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004845 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004846 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4847 t->srexpire = t->swexpire;
4848 }
willy tarreau0f7af912005-12-17 12:21:26 +01004849 else
4850 tv_eternity(&t->swexpire);
4851 }
4852 }
4853 return 0;
4854 }
4855 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004856 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004857 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004858 tv_eternity(&t->srexpire);
4859 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004860 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004861 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004862 if (!(t->flags & SN_ERR_MASK))
4863 t->flags |= SN_ERR_SRVCL;
4864 if (!(t->flags & SN_FINST_MASK))
4865 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004866 return 1;
4867 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004868 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4869 //FD_CLR(t->srv_fd, StaticReadEvent);
4870 tv_eternity(&t->srexpire);
4871 fd_delete(t->srv_fd);
4872 //close(t->srv_fd);
4873 t->srv_state = SV_STCLOSE;
4874 return 1;
4875 }
4876 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4877 //FD_CLR(t->srv_fd, StaticReadEvent);
4878 tv_eternity(&t->srexpire);
4879 fd_delete(t->srv_fd);
4880 //close(t->srv_fd);
4881 t->srv_state = SV_STCLOSE;
4882 if (!(t->flags & SN_ERR_MASK))
4883 t->flags |= SN_ERR_SRVTO;
4884 if (!(t->flags & SN_FINST_MASK))
4885 t->flags |= SN_FINST_D;
4886 return 1;
4887 }
willy tarreau0f7af912005-12-17 12:21:26 +01004888 else if (rep->l == BUFSIZE) { /* no room to read more data */
4889 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4890 FD_CLR(t->srv_fd, StaticReadEvent);
4891 tv_eternity(&t->srexpire);
4892 }
4893 }
4894 else {
4895 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4896 FD_SET(t->srv_fd, StaticReadEvent);
4897 if (t->proxy->srvtimeout)
4898 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4899 else
4900 tv_eternity(&t->srexpire);
4901 }
4902 }
4903 return 0;
4904 }
4905 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004906 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004907 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004908 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 +01004909 write(1, trash, len);
4910 }
4911 return 0;
4912 }
4913 return 0;
4914}
4915
4916
willy tarreau5cbea6f2005-12-17 12:48:26 +01004917/* Processes the client and server jobs of a session task, then
4918 * puts it back to the wait queue in a clean state, or
4919 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004920 * the time the task accepts to wait, or TIME_ETERNITY for
4921 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004922 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004923int process_session(struct task *t) {
4924 struct session *s = t->context;
4925 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004926
willy tarreau5cbea6f2005-12-17 12:48:26 +01004927 do {
4928 fsm_resync = 0;
4929 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4930 fsm_resync |= process_cli(s);
4931 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4932 fsm_resync |= process_srv(s);
4933 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4934 } while (fsm_resync);
4935
4936 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004937 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004938 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004939
willy tarreau5cbea6f2005-12-17 12:48:26 +01004940 tv_min(&min1, &s->crexpire, &s->cwexpire);
4941 tv_min(&min2, &s->srexpire, &s->swexpire);
4942 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004943 tv_min(&t->expire, &min1, &min2);
4944
4945 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004946 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004947
willy tarreaub952e1d2005-12-18 01:31:20 +01004948 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004949 }
4950
willy tarreau5cbea6f2005-12-17 12:48:26 +01004951 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004952 actconn--;
4953
willy tarreau982249e2005-12-18 00:57:06 +01004954 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004955 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004956 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 +01004957 write(1, trash, len);
4958 }
4959
willy tarreau750a4722005-12-17 13:21:24 +01004960 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004961 if (s->rep != NULL)
4962 s->logs.bytes = s->rep->total;
4963
willy tarreau9fe663a2005-12-17 13:02:59 +01004964 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004965 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004966 sess_log(s);
4967
willy tarreau0f7af912005-12-17 12:21:26 +01004968 /* the task MUST not be in the run queue anymore */
4969 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004970 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004971 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01004972 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004973}
4974
4975
4976
4977/*
4978 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004979 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004980 */
4981int process_chk(struct task *t) {
4982 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004983 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004984 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004985
willy tarreauef900ab2005-12-17 12:52:52 +01004986 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004987
4988 if (fd < 0) { /* no check currently running */
4989 //fprintf(stderr, "process_chk: 2\n");
4990 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4991 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01004992 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004993 }
4994
4995 /* we'll initiate a new check */
4996 s->result = 0; /* no result yet */
4997 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004998 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004999 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5000 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5001 //fprintf(stderr, "process_chk: 3\n");
5002
willy tarreaua41a8b42005-12-17 14:02:24 +01005003 /* we'll connect to the check port on the server */
5004 sa = s->addr;
5005 sa.sin_port = htons(s->check_port);
5006
willy tarreau0174f312005-12-18 01:02:42 +01005007 /* allow specific binding :
5008 * - server-specific at first
5009 * - proxy-specific next
5010 */
5011 if (s->state & SRV_BIND_SRC) {
5012 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5013 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5014 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5015 s->proxy->id, s->id);
5016 s->result = -1;
5017 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005018 }
willy tarreau0174f312005-12-18 01:02:42 +01005019 else if (s->proxy->options & PR_O_BIND_SRC) {
5020 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5021 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5022 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5023 s->proxy->id);
5024 s->result = -1;
5025 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005026 }
willy tarreau0174f312005-12-18 01:02:42 +01005027
5028 if (!s->result) {
5029 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5030 /* OK, connection in progress or established */
5031
5032 //fprintf(stderr, "process_chk: 4\n");
5033
5034 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5035 fdtab[fd].owner = t;
5036 fdtab[fd].read = &event_srv_chk_r;
5037 fdtab[fd].write = &event_srv_chk_w;
5038 fdtab[fd].state = FD_STCONN; /* connection in progress */
5039 FD_SET(fd, StaticWriteEvent); /* for connect status */
5040 fd_insert(fd);
5041 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5042 tv_delayfrom(&t->expire, &now, s->inter);
5043 task_queue(t); /* restore t to its place in the task list */
5044 return tv_remain(&now, &t->expire);
5045 }
5046 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5047 s->result = -1; /* a real error */
5048 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005049 }
5050 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005051 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005052 }
5053
5054 if (!s->result) { /* nothing done */
5055 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005056 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005057 task_queue(t); /* restore t to its place in the task list */
5058 return tv_remain(&now, &t->expire);
5059 }
5060
5061 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005062 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005063 s->health--; /* still good */
5064 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005065 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005066 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005067 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005068 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005069
willy tarreaudd07e972005-12-18 00:48:48 +01005070 if (find_server(s->proxy) == NULL) {
5071 Alert("Proxy %s has no server available !\n", s->proxy->id);
5072 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5073 }
5074 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005075 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 }
5077
5078 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005079 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5080 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005081 }
5082 else {
5083 //fprintf(stderr, "process_chk: 8\n");
5084 /* there was a test running */
5085 if (s->result > 0) { /* good server detected */
5086 //fprintf(stderr, "process_chk: 9\n");
5087 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005088 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005089 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005090 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005091 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005092 }
willy tarreauef900ab2005-12-17 12:52:52 +01005093
willy tarreaue47c8d72005-12-17 12:55:52 +01005094 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005095 s->state |= SRV_RUNNING;
5096 }
willy tarreauef900ab2005-12-17 12:52:52 +01005097 s->curfd = -1; /* no check running anymore */
5098 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005099 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005100 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005101 }
5102 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5103 //fprintf(stderr, "process_chk: 10\n");
5104 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005105 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005106 s->health--; /* still good */
5107 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005108 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005109
willy tarreaudd07e972005-12-18 00:48:48 +01005110 if (s->health == s->rise) {
5111 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005112 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005113
5114 if (find_server(s->proxy) == NULL) {
5115 Alert("Proxy %s has no server available !\n", s->proxy->id);
5116 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5117 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005118 }
willy tarreauef900ab2005-12-17 12:52:52 +01005119
willy tarreau5cbea6f2005-12-17 12:48:26 +01005120 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005121 }
5122 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005123 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005124 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005125 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005126 }
5127 /* if result is 0 and there's no timeout, we have to wait again */
5128 }
5129 //fprintf(stderr, "process_chk: 11\n");
5130 s->result = 0;
5131 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005132 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005133}
5134
5135
willy tarreau5cbea6f2005-12-17 12:48:26 +01005136
willy tarreau0f7af912005-12-17 12:21:26 +01005137#if STATTIME > 0
5138int stats(void);
5139#endif
5140
5141/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005142 * This does 4 things :
5143 * - wake up all expired tasks
5144 * - call all runnable tasks
5145 * - call maintain_proxies() to enable/disable the listeners
5146 * - return the delay till next event in ms, -1 = wait indefinitely
5147 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5148 *
willy tarreau0f7af912005-12-17 12:21:26 +01005149 */
5150
willy tarreau1c2ad212005-12-18 01:11:29 +01005151int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005152 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005153 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005154 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005155
willy tarreaub952e1d2005-12-18 01:31:20 +01005156 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005157
willy tarreau1c2ad212005-12-18 01:11:29 +01005158 /* look for expired tasks and add them to the run queue.
5159 */
5160 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5161 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5162 tnext = t->next;
5163 if (t->state & TASK_RUNNING)
5164 continue;
5165
willy tarreaub952e1d2005-12-18 01:31:20 +01005166 if (tv_iseternity(&t->expire))
5167 continue;
5168
willy tarreau1c2ad212005-12-18 01:11:29 +01005169 /* wakeup expired entries. It doesn't matter if they are
5170 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005171 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005172 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005173 task_wakeup(&rq, t);
5174 }
5175 else {
5176 /* first non-runnable task. Use its expiration date as an upper bound */
5177 int temp_time = tv_remain(&now, &t->expire);
5178 if (temp_time)
5179 next_time = temp_time;
5180 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005181 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005182 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005183
willy tarreau1c2ad212005-12-18 01:11:29 +01005184 /* process each task in the run queue now. Each task may be deleted
5185 * since we only use tnext.
5186 */
5187 tnext = rq;
5188 while ((t = tnext) != NULL) {
5189 int temp_time;
5190
5191 tnext = t->rqnext;
5192 task_sleep(&rq, t);
5193 temp_time = t->process(t);
5194 next_time = MINTIME(temp_time, next_time);
5195 }
5196
5197 /* maintain all proxies in a consistent state. This should quickly become a task */
5198 time2 = maintain_proxies();
5199 return MINTIME(time2, next_time);
5200}
5201
5202
5203#if defined(ENABLE_EPOLL)
5204
5205/*
5206 * Main epoll() loop.
5207 */
5208
5209/* does 3 actions :
5210 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5211 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5212 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5213 *
5214 * returns 0 if initialization failed, !0 otherwise.
5215 */
5216
5217int epoll_loop(int action) {
5218 int next_time;
5219 int status;
5220 int fd;
5221
5222 int fds, count;
5223 int pr, pw, sr, sw;
5224 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5225 struct epoll_event ev;
5226
5227 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005228 static struct epoll_event *epoll_events = NULL;
5229 static int epoll_fd;
5230
5231 if (action == POLL_LOOP_ACTION_INIT) {
5232 epoll_fd = epoll_create(global.maxsock + 1);
5233 if (epoll_fd < 0)
5234 return 0;
5235 else {
5236 epoll_events = (struct epoll_event*)
5237 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5238 PrevReadEvent = (fd_set *)
5239 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5240 PrevWriteEvent = (fd_set *)
5241 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005242 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005243 return 1;
5244 }
5245 else if (action == POLL_LOOP_ACTION_CLEAN) {
5246 if (PrevWriteEvent) free(PrevWriteEvent);
5247 if (PrevReadEvent) free(PrevReadEvent);
5248 if (epoll_events) free(epoll_events);
5249 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005250 epoll_fd = 0;
5251 return 1;
5252 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005253
willy tarreau1c2ad212005-12-18 01:11:29 +01005254 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005255
willy tarreau1c2ad212005-12-18 01:11:29 +01005256 tv_now(&now);
5257
5258 while (1) {
5259 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005260
5261 /* stop when there's no connection left and we don't allow them anymore */
5262 if (!actconn && listeners == 0)
5263 break;
5264
willy tarreau0f7af912005-12-17 12:21:26 +01005265#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005266 {
5267 int time2;
5268 time2 = stats();
5269 next_time = MINTIME(time2, next_time);
5270 }
willy tarreau0f7af912005-12-17 12:21:26 +01005271#endif
5272
willy tarreau1c2ad212005-12-18 01:11:29 +01005273 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5274
5275 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5276 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5277
5278 if ((ro^rn) | (wo^wn)) {
5279 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5280#define FDSETS_ARE_INT_ALIGNED
5281#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005282
willy tarreauad90a0c2005-12-18 01:09:15 +01005283#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5284#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005285 pr = (ro >> count) & 1;
5286 pw = (wo >> count) & 1;
5287 sr = (rn >> count) & 1;
5288 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005289#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005290 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5291 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5292 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5293 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005294#endif
5295#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005296 pr = FD_ISSET(fd, PrevReadEvent);
5297 pw = FD_ISSET(fd, PrevWriteEvent);
5298 sr = FD_ISSET(fd, StaticReadEvent);
5299 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005300#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005301 if (!((sr^pr) | (sw^pw)))
5302 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005303
willy tarreau1c2ad212005-12-18 01:11:29 +01005304 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5305 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005306
willy tarreaub952e1d2005-12-18 01:31:20 +01005307#ifdef EPOLL_CTL_MOD_WORKAROUND
5308 /* I encountered a rarely reproducible problem with
5309 * EPOLL_CTL_MOD where a modified FD (systematically
5310 * the one in epoll_events[0], fd#7) would sometimes
5311 * be set EPOLL_OUT while asked for a read ! This is
5312 * with the 2.4 epoll patch. The workaround is to
5313 * delete then recreate in case of modification.
5314 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5315 * nor RHEL kernels.
5316 */
5317
5318 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5319 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5320
5321 if ((sr | sw))
5322 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5323#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005324 if ((pr | pw)) {
5325 /* the file-descriptor already exists... */
5326 if ((sr | sw)) {
5327 /* ...and it will still exist */
5328 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5329 // perror("epoll_ctl(MOD)");
5330 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005331 }
5332 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005333 /* ...and it will be removed */
5334 if (fdtab[fd].state != FD_STCLOSE &&
5335 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5336 // perror("epoll_ctl(DEL)");
5337 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005338 }
5339 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005340 } else {
5341 /* the file-descriptor did not exist, let's add it */
5342 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5343 // perror("epoll_ctl(ADD)");
5344 // exit(1);
5345 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005346 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005347#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005348 }
5349 ((int*)PrevReadEvent)[fds] = rn;
5350 ((int*)PrevWriteEvent)[fds] = wn;
5351 }
5352 }
5353
5354 /* now let's wait for events */
5355 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5356 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005357
willy tarreau1c2ad212005-12-18 01:11:29 +01005358 for (count = 0; count < status; count++) {
5359 fd = epoll_events[count].data.fd;
5360
5361 if (fdtab[fd].state == FD_STCLOSE)
5362 continue;
5363
Willy TARREAUe78ae262006-01-08 01:24:12 +01005364 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) {
5365 if (FD_ISSET(fd, StaticReadEvent))
5366 fdtab[fd].read(fd);
5367 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005368
5369 if (fdtab[fd].state == FD_STCLOSE)
5370 continue;
5371
Willy TARREAUe78ae262006-01-08 01:24:12 +01005372 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) {
5373 if (FD_ISSET(fd, StaticWriteEvent))
5374 fdtab[fd].write(fd);
5375 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005376 }
5377 }
5378 return 1;
5379}
5380#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005381
willy tarreauad90a0c2005-12-18 01:09:15 +01005382
willy tarreau5cbea6f2005-12-17 12:48:26 +01005383
willy tarreau1c2ad212005-12-18 01:11:29 +01005384#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005385
willy tarreau1c2ad212005-12-18 01:11:29 +01005386/*
5387 * Main poll() loop.
5388 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005389
willy tarreau1c2ad212005-12-18 01:11:29 +01005390/* does 3 actions :
5391 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5392 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5393 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5394 *
5395 * returns 0 if initialization failed, !0 otherwise.
5396 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005397
willy tarreau1c2ad212005-12-18 01:11:29 +01005398int poll_loop(int action) {
5399 int next_time;
5400 int status;
5401 int fd, nbfd;
5402
5403 int fds, count;
5404 int sr, sw;
5405 unsigned rn, wn; /* read new, write new */
5406
5407 /* private data */
5408 static struct pollfd *poll_events = NULL;
5409
5410 if (action == POLL_LOOP_ACTION_INIT) {
5411 poll_events = (struct pollfd*)
5412 calloc(1, sizeof(struct pollfd) * global.maxsock);
5413 return 1;
5414 }
5415 else if (action == POLL_LOOP_ACTION_CLEAN) {
5416 if (poll_events)
5417 free(poll_events);
5418 return 1;
5419 }
5420
5421 /* OK, it's POLL_LOOP_ACTION_RUN */
5422
5423 tv_now(&now);
5424
5425 while (1) {
5426 next_time = process_runnable_tasks();
5427
5428 /* stop when there's no connection left and we don't allow them anymore */
5429 if (!actconn && listeners == 0)
5430 break;
5431
5432#if STATTIME > 0
5433 {
5434 int time2;
5435 time2 = stats();
5436 next_time = MINTIME(time2, next_time);
5437 }
5438#endif
5439
5440
5441 nbfd = 0;
5442 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5443
5444 rn = ((int*)StaticReadEvent)[fds];
5445 wn = ((int*)StaticWriteEvent)[fds];
5446
5447 if ((rn|wn)) {
5448 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5449#define FDSETS_ARE_INT_ALIGNED
5450#ifdef FDSETS_ARE_INT_ALIGNED
5451
5452#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5453#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5454 sr = (rn >> count) & 1;
5455 sw = (wn >> count) & 1;
5456#else
5457 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5458 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5459#endif
5460#else
5461 sr = FD_ISSET(fd, StaticReadEvent);
5462 sw = FD_ISSET(fd, StaticWriteEvent);
5463#endif
5464 if ((sr|sw)) {
5465 poll_events[nbfd].fd = fd;
5466 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5467 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005468 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005469 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005470 }
5471 }
5472
5473 /* now let's wait for events */
5474 status = poll(poll_events, nbfd, next_time);
5475 tv_now(&now);
5476
5477 for (count = 0; status > 0 && count < nbfd; count++) {
5478 fd = poll_events[count].fd;
5479
5480 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5481 continue;
5482
5483 /* ok, we found one active fd */
5484 status--;
5485
5486 if (fdtab[fd].state == FD_STCLOSE)
5487 continue;
5488
Willy TARREAUe78ae262006-01-08 01:24:12 +01005489 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) {
5490 if (FD_ISSET(fd, StaticReadEvent))
5491 fdtab[fd].read(fd);
5492 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005493
5494 if (fdtab[fd].state == FD_STCLOSE)
5495 continue;
5496
Willy TARREAUe78ae262006-01-08 01:24:12 +01005497 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) {
5498 if (FD_ISSET(fd, StaticWriteEvent))
5499 fdtab[fd].write(fd);
5500 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005501 }
5502 }
5503 return 1;
5504}
willy tarreauad90a0c2005-12-18 01:09:15 +01005505#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005506
willy tarreauad90a0c2005-12-18 01:09:15 +01005507
willy tarreauad90a0c2005-12-18 01:09:15 +01005508
willy tarreau1c2ad212005-12-18 01:11:29 +01005509/*
5510 * Main select() loop.
5511 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005512
willy tarreau1c2ad212005-12-18 01:11:29 +01005513/* does 3 actions :
5514 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5515 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5516 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5517 *
5518 * returns 0 if initialization failed, !0 otherwise.
5519 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005520
willy tarreauad90a0c2005-12-18 01:09:15 +01005521
willy tarreau1c2ad212005-12-18 01:11:29 +01005522int select_loop(int action) {
5523 int next_time;
5524 int status;
5525 int fd,i;
5526 struct timeval delta;
5527 int readnotnull, writenotnull;
5528 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005529
willy tarreau1c2ad212005-12-18 01:11:29 +01005530 if (action == POLL_LOOP_ACTION_INIT) {
5531 ReadEvent = (fd_set *)
5532 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5533 WriteEvent = (fd_set *)
5534 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5535 return 1;
5536 }
5537 else if (action == POLL_LOOP_ACTION_CLEAN) {
5538 if (WriteEvent) free(WriteEvent);
5539 if (ReadEvent) free(ReadEvent);
5540 return 1;
5541 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005542
willy tarreau1c2ad212005-12-18 01:11:29 +01005543 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005544
willy tarreau1c2ad212005-12-18 01:11:29 +01005545 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005546
willy tarreau1c2ad212005-12-18 01:11:29 +01005547 while (1) {
5548 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005549
willy tarreau1c2ad212005-12-18 01:11:29 +01005550 /* stop when there's no connection left and we don't allow them anymore */
5551 if (!actconn && listeners == 0)
5552 break;
5553
5554#if STATTIME > 0
5555 {
5556 int time2;
5557 time2 = stats();
5558 next_time = MINTIME(time2, next_time);
5559 }
5560#endif
5561
willy tarreau1c2ad212005-12-18 01:11:29 +01005562 if (next_time > 0) { /* FIXME */
5563 /* Convert to timeval */
5564 /* to avoid eventual select loops due to timer precision */
5565 next_time += SCHEDULER_RESOLUTION;
5566 delta.tv_sec = next_time / 1000;
5567 delta.tv_usec = (next_time % 1000) * 1000;
5568 }
5569 else if (next_time == 0) { /* allow select to return immediately when needed */
5570 delta.tv_sec = delta.tv_usec = 0;
5571 }
5572
5573
5574 /* let's restore fdset state */
5575
5576 readnotnull = 0; writenotnull = 0;
5577 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5578 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5579 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5580 }
5581
5582 // /* just a verification code, needs to be removed for performance */
5583 // for (i=0; i<maxfd; i++) {
5584 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5585 // abort();
5586 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5587 // abort();
5588 //
5589 // }
5590
5591 status = select(maxfd,
5592 readnotnull ? ReadEvent : NULL,
5593 writenotnull ? WriteEvent : NULL,
5594 NULL,
5595 (next_time >= 0) ? &delta : NULL);
5596
5597 /* this is an experiment on the separation of the select work */
5598 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5599 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5600
5601 tv_now(&now);
5602
5603 if (status > 0) { /* must proceed with events */
5604
5605 int fds;
5606 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005607
willy tarreau1c2ad212005-12-18 01:11:29 +01005608 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5609 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5610 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5611
5612 /* if we specify read first, the accepts and zero reads will be
5613 * seen first. Moreover, system buffers will be flushed faster.
5614 */
5615 if (fdtab[fd].state == FD_STCLOSE)
5616 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005617
willy tarreau1c2ad212005-12-18 01:11:29 +01005618 if (FD_ISSET(fd, ReadEvent))
5619 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005620
willy tarreau1c2ad212005-12-18 01:11:29 +01005621 if (FD_ISSET(fd, WriteEvent))
5622 fdtab[fd].write(fd);
5623 }
5624 }
5625 else {
5626 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005627 }
willy tarreau0f7af912005-12-17 12:21:26 +01005628 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005629 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005630}
5631
5632
5633#if STATTIME > 0
5634/*
5635 * Display proxy statistics regularly. It is designed to be called from the
5636 * select_loop().
5637 */
5638int stats(void) {
5639 static int lines;
5640 static struct timeval nextevt;
5641 static struct timeval lastevt;
5642 static struct timeval starttime = {0,0};
5643 unsigned long totaltime, deltatime;
5644 int ret;
5645
willy tarreau750a4722005-12-17 13:21:24 +01005646 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005647 deltatime = (tv_diff(&lastevt, &now)?:1);
5648 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005649
willy tarreau9fe663a2005-12-17 13:02:59 +01005650 if (global.mode & MODE_STATS) {
5651 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005652 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005653 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5654 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005655 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005656 actconn, totalconn,
5657 stats_tsk_new, stats_tsk_good,
5658 stats_tsk_left, stats_tsk_right,
5659 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5660 }
5661 }
5662
5663 tv_delayfrom(&nextevt, &now, STATTIME);
5664
5665 lastevt=now;
5666 }
5667 ret = tv_remain(&now, &nextevt);
5668 return ret;
5669}
5670#endif
5671
5672
5673/*
5674 * this function enables proxies when there are enough free sessions,
5675 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005676 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005677 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005678 */
5679static int maintain_proxies(void) {
5680 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005681 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005682 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005683
5684 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005685 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005686
5687 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005688 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005689 while (p) {
5690 if (p->nbconn < p->maxconn) {
5691 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005692 for (l = p->listen; l != NULL; l = l->next) {
5693 FD_SET(l->fd, StaticReadEvent);
5694 }
willy tarreau0f7af912005-12-17 12:21:26 +01005695 p->state = PR_STRUN;
5696 }
5697 }
5698 else {
5699 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005700 for (l = p->listen; l != NULL; l = l->next) {
5701 FD_CLR(l->fd, StaticReadEvent);
5702 }
willy tarreau0f7af912005-12-17 12:21:26 +01005703 p->state = PR_STIDLE;
5704 }
5705 }
5706 p = p->next;
5707 }
5708 }
5709 else { /* block all proxies */
5710 while (p) {
5711 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005712 for (l = p->listen; l != NULL; l = l->next) {
5713 FD_CLR(l->fd, StaticReadEvent);
5714 }
willy tarreau0f7af912005-12-17 12:21:26 +01005715 p->state = PR_STIDLE;
5716 }
5717 p = p->next;
5718 }
5719 }
5720
willy tarreau5cbea6f2005-12-17 12:48:26 +01005721 if (stopping) {
5722 p = proxy;
5723 while (p) {
5724 if (p->state != PR_STDISABLED) {
5725 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005726 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005727 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005728 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005729 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005730
willy tarreaua41a8b42005-12-17 14:02:24 +01005731 for (l = p->listen; l != NULL; l = l->next) {
5732 fd_delete(l->fd);
5733 listeners--;
5734 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005735 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005736 }
5737 else {
5738 tleft = MINTIME(t, tleft);
5739 }
5740 }
5741 p = p->next;
5742 }
5743 }
5744 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005745}
5746
5747/*
5748 * this function disables health-check servers so that the process will quickly be ignored
5749 * by load balancers.
5750 */
5751static void soft_stop(void) {
5752 struct proxy *p;
5753
5754 stopping = 1;
5755 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005756 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005757 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005758 if (p->state != PR_STDISABLED) {
5759 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005760 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005761 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005762 }
willy tarreau0f7af912005-12-17 12:21:26 +01005763 p = p->next;
5764 }
5765}
5766
5767/*
5768 * upon SIGUSR1, let's have a soft stop.
5769 */
5770void sig_soft_stop(int sig) {
5771 soft_stop();
5772 signal(sig, SIG_IGN);
5773}
5774
5775
willy tarreau8337c6b2005-12-17 13:41:01 +01005776/*
5777 * this function dumps every server's state when the process receives SIGHUP.
5778 */
5779void sig_dump_state(int sig) {
5780 struct proxy *p = proxy;
5781
5782 Warning("SIGHUP received, dumping servers states.\n");
5783 while (p) {
5784 struct server *s = p->srv;
5785
5786 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5787 while (s) {
5788 if (s->state & SRV_RUNNING) {
5789 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5790 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5791 }
5792 else {
5793 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5794 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5795 }
5796 s = s->next;
5797 }
willy tarreaudd07e972005-12-18 00:48:48 +01005798
5799 if (find_server(p) == NULL) {
5800 Warning("SIGHUP: proxy %s has no server available !\n", p);
5801 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5802 }
5803
willy tarreau8337c6b2005-12-17 13:41:01 +01005804 p = p->next;
5805 }
5806 signal(sig, sig_dump_state);
5807}
5808
willy tarreau0f7af912005-12-17 12:21:26 +01005809void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005810 struct task *t, *tnext;
5811 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005812
willy tarreau5cbea6f2005-12-17 12:48:26 +01005813 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5814 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5815 tnext = t->next;
5816 s = t->context;
5817 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5818 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5819 "req=%d, rep=%d, clifd=%d\n",
5820 s, tv_remain(&now, &t->expire),
5821 s->cli_state,
5822 s->srv_state,
5823 FD_ISSET(s->cli_fd, StaticReadEvent),
5824 FD_ISSET(s->cli_fd, StaticWriteEvent),
5825 FD_ISSET(s->srv_fd, StaticReadEvent),
5826 FD_ISSET(s->srv_fd, StaticWriteEvent),
5827 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5828 );
willy tarreau0f7af912005-12-17 12:21:26 +01005829 }
willy tarreau12350152005-12-18 01:03:27 +01005830}
5831
willy tarreau64a3cc32005-12-18 01:13:11 +01005832#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005833static void fast_stop(void)
5834{
5835 struct proxy *p;
5836 p = proxy;
5837 while (p) {
5838 p->grace = 0;
5839 p = p->next;
5840 }
5841 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005842}
5843
willy tarreau12350152005-12-18 01:03:27 +01005844void sig_int(int sig) {
5845 /* This would normally be a hard stop,
5846 but we want to be sure about deallocation,
5847 and so on, so we do a soft stop with
5848 0 GRACE time
5849 */
5850 fast_stop();
5851 /* If we are killed twice, we decide to die*/
5852 signal(sig, SIG_DFL);
5853}
5854
5855void sig_term(int sig) {
5856 /* This would normally be a hard stop,
5857 but we want to be sure about deallocation,
5858 and so on, so we do a soft stop with
5859 0 GRACE time
5860 */
5861 fast_stop();
5862 /* If we are killed twice, we decide to die*/
5863 signal(sig, SIG_DFL);
5864}
willy tarreau64a3cc32005-12-18 01:13:11 +01005865#endif
willy tarreau12350152005-12-18 01:03:27 +01005866
willy tarreauc1f47532005-12-18 01:08:26 +01005867/* returns the pointer to an error in the replacement string, or NULL if OK */
5868char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005869 struct hdr_exp *exp;
5870
willy tarreauc1f47532005-12-18 01:08:26 +01005871 if (replace != NULL) {
5872 char *err;
5873 err = check_replace_string(replace);
5874 if (err)
5875 return err;
5876 }
5877
willy tarreaue39cd132005-12-17 13:00:18 +01005878 while (*head != NULL)
5879 head = &(*head)->next;
5880
5881 exp = calloc(1, sizeof(struct hdr_exp));
5882
5883 exp->preg = preg;
5884 exp->replace = replace;
5885 exp->action = action;
5886 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005887
5888 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005889}
5890
willy tarreau9fe663a2005-12-17 13:02:59 +01005891
willy tarreau0f7af912005-12-17 12:21:26 +01005892/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005893 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005894 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005895int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005896
willy tarreau9fe663a2005-12-17 13:02:59 +01005897 if (!strcmp(args[0], "global")) { /* new section */
5898 /* no option, nothing special to do */
5899 return 0;
5900 }
5901 else if (!strcmp(args[0], "daemon")) {
5902 global.mode |= MODE_DAEMON;
5903 }
5904 else if (!strcmp(args[0], "debug")) {
5905 global.mode |= MODE_DEBUG;
5906 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005907 else if (!strcmp(args[0], "noepoll")) {
5908 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5909 }
5910 else if (!strcmp(args[0], "nopoll")) {
5911 cfg_polling_mechanism &= ~POLL_USE_POLL;
5912 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005913 else if (!strcmp(args[0], "quiet")) {
5914 global.mode |= MODE_QUIET;
5915 }
5916 else if (!strcmp(args[0], "stats")) {
5917 global.mode |= MODE_STATS;
5918 }
5919 else if (!strcmp(args[0], "uid")) {
5920 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005921 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005922 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005923 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005924 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005925 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005926 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005928 global.uid = atol(args[1]);
5929 }
5930 else if (!strcmp(args[0], "gid")) {
5931 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005932 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005933 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005934 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005935 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005936 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005937 return -1;
5938 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005939 global.gid = atol(args[1]);
5940 }
5941 else if (!strcmp(args[0], "nbproc")) {
5942 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005945 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005946 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005947 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005948 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005949 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005950 global.nbproc = atol(args[1]);
5951 }
5952 else if (!strcmp(args[0], "maxconn")) {
5953 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005954 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005955 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005956 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005957 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005958 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005959 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005960 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005961 global.maxconn = atol(args[1]);
5962 }
willy tarreaub1285d52005-12-18 01:20:14 +01005963 else if (!strcmp(args[0], "ulimit-n")) {
5964 if (global.rlimit_nofile != 0) {
5965 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5966 return 0;
5967 }
5968 if (*(args[1]) == 0) {
5969 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5970 return -1;
5971 }
5972 global.rlimit_nofile = atol(args[1]);
5973 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005974 else if (!strcmp(args[0], "chroot")) {
5975 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005976 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005977 return 0;
5978 }
5979 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005980 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005981 return -1;
5982 }
5983 global.chroot = strdup(args[1]);
5984 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005985 else if (!strcmp(args[0], "pidfile")) {
5986 if (global.pidfile != NULL) {
5987 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5988 return 0;
5989 }
5990 if (*(args[1]) == 0) {
5991 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5992 return -1;
5993 }
5994 global.pidfile = strdup(args[1]);
5995 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 else if (!strcmp(args[0], "log")) { /* syslog server address */
5997 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005998 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005999
6000 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006001 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006002 return -1;
6003 }
6004
6005 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6006 if (!strcmp(log_facilities[facility], args[2]))
6007 break;
6008
6009 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006010 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006011 exit(1);
6012 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006013
6014 level = 7; /* max syslog level = debug */
6015 if (*(args[3])) {
6016 while (level >= 0 && strcmp(log_levels[level], args[3]))
6017 level--;
6018 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006019 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006020 exit(1);
6021 }
6022 }
6023
willy tarreau9fe663a2005-12-17 13:02:59 +01006024 sa = str2sa(args[1]);
6025 if (!sa->sin_port)
6026 sa->sin_port = htons(SYSLOG_PORT);
6027
6028 if (global.logfac1 == -1) {
6029 global.logsrv1 = *sa;
6030 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006031 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006032 }
6033 else if (global.logfac2 == -1) {
6034 global.logsrv2 = *sa;
6035 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006036 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006037 }
6038 else {
6039 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6040 return -1;
6041 }
6042
6043 }
6044 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006045 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006046 return -1;
6047 }
6048 return 0;
6049}
6050
6051
willy tarreaua41a8b42005-12-17 14:02:24 +01006052void init_default_instance() {
6053 memset(&defproxy, 0, sizeof(defproxy));
6054 defproxy.mode = PR_MODE_TCP;
6055 defproxy.state = PR_STNEW;
6056 defproxy.maxconn = cfg_maxpconn;
6057 defproxy.conn_retries = CONN_RETRIES;
6058 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6059}
6060
willy tarreau9fe663a2005-12-17 13:02:59 +01006061/*
6062 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6063 */
6064int cfg_parse_listen(char *file, int linenum, char **args) {
6065 static struct proxy *curproxy = NULL;
6066 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006067 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006068 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006069
6070 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006071 if (!*args[1]) {
6072 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6073 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006074 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006075 return -1;
6076 }
6077
6078 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006079 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006080 return -1;
6081 }
6082 curproxy->next = proxy;
6083 proxy = curproxy;
6084 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006085
6086 /* parse the listener address if any */
6087 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006088 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006089 if (!curproxy->listen)
6090 return -1;
6091 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006092
willy tarreau9fe663a2005-12-17 13:02:59 +01006093 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006094 curproxy->state = defproxy.state;
6095 curproxy->maxconn = defproxy.maxconn;
6096 curproxy->conn_retries = defproxy.conn_retries;
6097 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006098
6099 if (defproxy.check_req)
6100 curproxy->check_req = strdup(defproxy.check_req);
6101 curproxy->check_len = defproxy.check_len;
6102
6103 if (defproxy.cookie_name)
6104 curproxy->cookie_name = strdup(defproxy.cookie_name);
6105 curproxy->cookie_len = defproxy.cookie_len;
6106
6107 if (defproxy.capture_name)
6108 curproxy->capture_name = strdup(defproxy.capture_name);
6109 curproxy->capture_namelen = defproxy.capture_namelen;
6110 curproxy->capture_len = defproxy.capture_len;
6111
6112 if (defproxy.errmsg.msg400)
6113 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6114 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6115
6116 if (defproxy.errmsg.msg403)
6117 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6118 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6119
6120 if (defproxy.errmsg.msg408)
6121 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6122 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6123
6124 if (defproxy.errmsg.msg500)
6125 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6126 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6127
6128 if (defproxy.errmsg.msg502)
6129 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6130 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6131
6132 if (defproxy.errmsg.msg503)
6133 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6134 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6135
6136 if (defproxy.errmsg.msg504)
6137 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6138 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6139
willy tarreaua41a8b42005-12-17 14:02:24 +01006140 curproxy->clitimeout = defproxy.clitimeout;
6141 curproxy->contimeout = defproxy.contimeout;
6142 curproxy->srvtimeout = defproxy.srvtimeout;
6143 curproxy->mode = defproxy.mode;
6144 curproxy->logfac1 = defproxy.logfac1;
6145 curproxy->logsrv1 = defproxy.logsrv1;
6146 curproxy->loglev1 = defproxy.loglev1;
6147 curproxy->logfac2 = defproxy.logfac2;
6148 curproxy->logsrv2 = defproxy.logsrv2;
6149 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006150 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006151 curproxy->grace = defproxy.grace;
6152 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006153 curproxy->mon_net = defproxy.mon_net;
6154 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006155 return 0;
6156 }
6157 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006158 /* some variables may have already been initialized earlier */
6159 if (defproxy.check_req) free(defproxy.check_req);
6160 if (defproxy.cookie_name) free(defproxy.cookie_name);
6161 if (defproxy.capture_name) free(defproxy.capture_name);
6162 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6163 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6164 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6165 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6166 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6167 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6168 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6169
6170 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006171 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006172 return 0;
6173 }
6174 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006175 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006176 return -1;
6177 }
6178
willy tarreaua41a8b42005-12-17 14:02:24 +01006179 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6180 if (curproxy == &defproxy) {
6181 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6182 return -1;
6183 }
6184
6185 if (strchr(args[1], ':') == NULL) {
6186 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6187 file, linenum, args[0]);
6188 return -1;
6189 }
6190 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006191 if (!curproxy->listen)
6192 return -1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006193 return 0;
6194 }
willy tarreaub1285d52005-12-18 01:20:14 +01006195 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6196 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6197 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6198 file, linenum, args[0]);
6199 return -1;
6200 }
6201 /* flush useless bits */
6202 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6203 return 0;
6204 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006205 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006206 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6207 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6208 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6209 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006210 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006211 return -1;
6212 }
6213 }
6214 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6215 curproxy->state = PR_STDISABLED;
6216 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006217 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6218 curproxy->state = PR_STNEW;
6219 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006220 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6221 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006222// if (curproxy == &defproxy) {
6223// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6224// return -1;
6225// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006226
willy tarreau9fe663a2005-12-17 13:02:59 +01006227 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006228// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6229// file, linenum);
6230// return 0;
6231 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006232 }
6233
6234 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006235 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6236 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006237 return -1;
6238 }
6239 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006240 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006241
6242 cur_arg = 2;
6243 while (*(args[cur_arg])) {
6244 if (!strcmp(args[cur_arg], "rewrite")) {
6245 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006247 else if (!strcmp(args[cur_arg], "indirect")) {
6248 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006249 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006250 else if (!strcmp(args[cur_arg], "insert")) {
6251 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006252 }
willy tarreau240afa62005-12-17 13:14:35 +01006253 else if (!strcmp(args[cur_arg], "nocache")) {
6254 curproxy->options |= PR_O_COOK_NOC;
6255 }
willy tarreaucd878942005-12-17 13:27:43 +01006256 else if (!strcmp(args[cur_arg], "postonly")) {
6257 curproxy->options |= PR_O_COOK_POST;
6258 }
willy tarreau0174f312005-12-18 01:02:42 +01006259 else if (!strcmp(args[cur_arg], "prefix")) {
6260 curproxy->options |= PR_O_COOK_PFX;
6261 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006262 else {
willy tarreau0174f312005-12-18 01:02:42 +01006263 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006264 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006265 return -1;
6266 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 cur_arg++;
6268 }
willy tarreau0174f312005-12-18 01:02:42 +01006269 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6270 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6271 file, linenum);
6272 return -1;
6273 }
6274
6275 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6276 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006277 file, linenum);
6278 return -1;
6279 }
willy tarreau12350152005-12-18 01:03:27 +01006280 }/* end else if (!strcmp(args[0], "cookie")) */
6281 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6282// if (curproxy == &defproxy) {
6283// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6284// return -1;
6285// }
6286
6287 if (curproxy->appsession_name != NULL) {
6288// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6289// file, linenum);
6290// return 0;
6291 free(curproxy->appsession_name);
6292 }
6293
6294 if (*(args[5]) == 0) {
6295 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6296 file, linenum, args[0]);
6297 return -1;
6298 }
6299 have_appsession = 1;
6300 curproxy->appsession_name = strdup(args[1]);
6301 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6302 curproxy->appsession_len = atoi(args[3]);
6303 curproxy->appsession_timeout = atoi(args[5]);
6304 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6305 if (rc) {
6306 Alert("Error Init Appsession Hashtable.\n");
6307 return -1;
6308 }
6309 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006310 else if (!strcmp(args[0], "capture")) {
6311 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6312 // if (curproxy == &defproxy) {
6313 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6314 // return -1;
6315 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006316
willy tarreau4302f492005-12-18 01:00:37 +01006317 if (curproxy->capture_name != NULL) {
6318 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6319 // file, linenum, args[0]);
6320 // return 0;
6321 free(curproxy->capture_name);
6322 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006323
willy tarreau4302f492005-12-18 01:00:37 +01006324 if (*(args[4]) == 0) {
6325 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6326 file, linenum, args[0]);
6327 return -1;
6328 }
6329 curproxy->capture_name = strdup(args[2]);
6330 curproxy->capture_namelen = strlen(curproxy->capture_name);
6331 curproxy->capture_len = atol(args[4]);
6332 if (curproxy->capture_len >= CAPTURE_LEN) {
6333 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6334 file, linenum, CAPTURE_LEN - 1);
6335 curproxy->capture_len = CAPTURE_LEN - 1;
6336 }
6337 curproxy->to_log |= LW_COOKIE;
6338 }
6339 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6340 struct cap_hdr *hdr;
6341
6342 if (curproxy == &defproxy) {
6343 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6344 return -1;
6345 }
6346
6347 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6348 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6349 file, linenum, args[0], args[1]);
6350 return -1;
6351 }
6352
6353 hdr = calloc(sizeof(struct cap_hdr), 1);
6354 hdr->next = curproxy->req_cap;
6355 hdr->name = strdup(args[3]);
6356 hdr->namelen = strlen(args[3]);
6357 hdr->len = atol(args[5]);
6358 hdr->index = curproxy->nb_req_cap++;
6359 curproxy->req_cap = hdr;
6360 curproxy->to_log |= LW_REQHDR;
6361 }
6362 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6363 struct cap_hdr *hdr;
6364
6365 if (curproxy == &defproxy) {
6366 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6367 return -1;
6368 }
6369
6370 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6371 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6372 file, linenum, args[0], args[1]);
6373 return -1;
6374 }
6375 hdr = calloc(sizeof(struct cap_hdr), 1);
6376 hdr->next = curproxy->rsp_cap;
6377 hdr->name = strdup(args[3]);
6378 hdr->namelen = strlen(args[3]);
6379 hdr->len = atol(args[5]);
6380 hdr->index = curproxy->nb_rsp_cap++;
6381 curproxy->rsp_cap = hdr;
6382 curproxy->to_log |= LW_RSPHDR;
6383 }
6384 else {
6385 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006386 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006387 return -1;
6388 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006389 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006390 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006391 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006392 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006393 return 0;
6394 }
6395 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006396 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6397 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006398 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006399 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006400 curproxy->contimeout = atol(args[1]);
6401 }
6402 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006403 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006404 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6405 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006406 return 0;
6407 }
6408 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006409 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6410 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006411 return -1;
6412 }
6413 curproxy->clitimeout = atol(args[1]);
6414 }
6415 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006416 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006417 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006418 return 0;
6419 }
6420 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006421 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6422 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006423 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006424 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006425 curproxy->srvtimeout = atol(args[1]);
6426 }
6427 else if (!strcmp(args[0], "retries")) { /* connection retries */
6428 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006429 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6430 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006431 return -1;
6432 }
6433 curproxy->conn_retries = atol(args[1]);
6434 }
6435 else if (!strcmp(args[0], "option")) {
6436 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006437 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006438 return -1;
6439 }
6440 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006441 /* enable reconnections to dispatch */
6442 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006443#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006444 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006445 /* enable transparent proxy connections */
6446 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006447#endif
6448 else if (!strcmp(args[1], "keepalive"))
6449 /* enable keep-alive */
6450 curproxy->options |= PR_O_KEEPALIVE;
6451 else if (!strcmp(args[1], "forwardfor"))
6452 /* insert x-forwarded-for field */
6453 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006454 else if (!strcmp(args[1], "logasap"))
6455 /* log as soon as possible, without waiting for the session to complete */
6456 curproxy->options |= PR_O_LOGASAP;
6457 else if (!strcmp(args[1], "httpclose"))
6458 /* force connection: close in both directions in HTTP mode */
6459 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006460 else if (!strcmp(args[1], "checkcache"))
6461 /* require examination of cacheability of the 'set-cookie' field */
6462 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006463 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006464 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006465 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006466 else if (!strcmp(args[1], "tcplog"))
6467 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006468 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006469 else if (!strcmp(args[1], "dontlognull")) {
6470 /* don't log empty requests */
6471 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006472 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006473 else if (!strcmp(args[1], "tcpka")) {
6474 /* enable TCP keep-alives on client and server sessions */
6475 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6476 }
6477 else if (!strcmp(args[1], "clitcpka")) {
6478 /* enable TCP keep-alives on client sessions */
6479 curproxy->options |= PR_O_TCP_CLI_KA;
6480 }
6481 else if (!strcmp(args[1], "srvtcpka")) {
6482 /* enable TCP keep-alives on server sessions */
6483 curproxy->options |= PR_O_TCP_SRV_KA;
6484 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006485 else if (!strcmp(args[1], "httpchk")) {
6486 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006487 if (curproxy->check_req != NULL) {
6488 free(curproxy->check_req);
6489 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006490 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006491 if (!*args[2]) { /* no argument */
6492 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6493 curproxy->check_len = strlen(DEF_CHECK_REQ);
6494 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006495 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6496 curproxy->check_req = (char *)malloc(reqlen);
6497 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6498 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006499 } else { /* more arguments : METHOD URI [HTTP_VER] */
6500 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6501 if (*args[4])
6502 reqlen += strlen(args[4]);
6503 else
6504 reqlen += strlen("HTTP/1.0");
6505
6506 curproxy->check_req = (char *)malloc(reqlen);
6507 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6508 "%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 +01006509 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006510 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006511 else if (!strcmp(args[1], "persist")) {
6512 /* persist on using the server specified by the cookie, even when it's down */
6513 curproxy->options |= PR_O_PERSIST;
6514 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006515 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006516 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006517 return -1;
6518 }
6519 return 0;
6520 }
6521 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6522 /* enable reconnections to dispatch */
6523 curproxy->options |= PR_O_REDISP;
6524 }
willy tarreaua1598082005-12-17 13:08:06 +01006525#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006526 else if (!strcmp(args[0], "transparent")) {
6527 /* enable transparent proxy connections */
6528 curproxy->options |= PR_O_TRANSP;
6529 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006530#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006531 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6532 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006533 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006534 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006535 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006536 curproxy->maxconn = atol(args[1]);
6537 }
6538 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6539 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006540 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006541 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006542 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006543 curproxy->grace = atol(args[1]);
6544 }
6545 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006546 if (curproxy == &defproxy) {
6547 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6548 return -1;
6549 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006550 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006551 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006552 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006553 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006554 curproxy->dispatch_addr = *str2sa(args[1]);
6555 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006556 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006557 if (*(args[1])) {
6558 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006559 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006560 }
6561 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006562 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006563 return -1;
6564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006565 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006566 else /* if no option is set, use round-robin by default */
6567 curproxy->options |= PR_O_BALANCE_RR;
6568 }
6569 else if (!strcmp(args[0], "server")) { /* server address */
6570 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006571 char *rport;
6572 char *raddr;
6573 short realport;
6574 int do_check;
6575
6576 if (curproxy == &defproxy) {
6577 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6578 return -1;
6579 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006580
willy tarreaua41a8b42005-12-17 14:02:24 +01006581 if (!*args[2]) {
6582 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006583 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006584 return -1;
6585 }
6586 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6587 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6588 return -1;
6589 }
willy tarreau0174f312005-12-18 01:02:42 +01006590
6591 if (curproxy->srv == NULL)
6592 curproxy->srv = newsrv;
6593 else
6594 curproxy->cursrv->next = newsrv;
6595 curproxy->cursrv = newsrv;
6596
6597 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006598 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006599
6600 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006601 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006602 newsrv->id = strdup(args[1]);
6603
6604 /* several ways to check the port component :
6605 * - IP => port=+0, relative
6606 * - IP: => port=+0, relative
6607 * - IP:N => port=N, absolute
6608 * - IP:+N => port=+N, relative
6609 * - IP:-N => port=-N, relative
6610 */
6611 raddr = strdup(args[2]);
6612 rport = strchr(raddr, ':');
6613 if (rport) {
6614 *rport++ = 0;
6615 realport = atol(rport);
6616 if (!isdigit((int)*rport))
6617 newsrv->state |= SRV_MAPPORTS;
6618 } else {
6619 realport = 0;
6620 newsrv->state |= SRV_MAPPORTS;
6621 }
6622
6623 newsrv->addr = *str2sa(raddr);
6624 newsrv->addr.sin_port = htons(realport);
6625 free(raddr);
6626
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 newsrv->curfd = -1; /* no health-check in progress */
6628 newsrv->inter = DEF_CHKINTR;
6629 newsrv->rise = DEF_RISETIME;
6630 newsrv->fall = DEF_FALLTIME;
6631 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6632 cur_arg = 3;
6633 while (*args[cur_arg]) {
6634 if (!strcmp(args[cur_arg], "cookie")) {
6635 newsrv->cookie = strdup(args[cur_arg + 1]);
6636 newsrv->cklen = strlen(args[cur_arg + 1]);
6637 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006638 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006639 else if (!strcmp(args[cur_arg], "rise")) {
6640 newsrv->rise = atol(args[cur_arg + 1]);
6641 newsrv->health = newsrv->rise;
6642 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006643 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006644 else if (!strcmp(args[cur_arg], "fall")) {
6645 newsrv->fall = atol(args[cur_arg + 1]);
6646 cur_arg += 2;
6647 }
6648 else if (!strcmp(args[cur_arg], "inter")) {
6649 newsrv->inter = atol(args[cur_arg + 1]);
6650 cur_arg += 2;
6651 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006652 else if (!strcmp(args[cur_arg], "port")) {
6653 newsrv->check_port = atol(args[cur_arg + 1]);
6654 cur_arg += 2;
6655 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006656 else if (!strcmp(args[cur_arg], "backup")) {
6657 newsrv->state |= SRV_BACKUP;
6658 cur_arg ++;
6659 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006660 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006661 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006662 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006663 }
willy tarreau0174f312005-12-18 01:02:42 +01006664 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6665 if (!*args[cur_arg + 1]) {
6666 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6667 file, linenum, "source");
6668 return -1;
6669 }
6670 newsrv->state |= SRV_BIND_SRC;
6671 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6672 cur_arg += 2;
6673 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006674 else {
willy tarreau0174f312005-12-18 01:02:42 +01006675 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 +01006676 file, linenum, newsrv->id);
6677 return -1;
6678 }
6679 }
6680
6681 if (do_check) {
6682 struct task *t;
6683
6684 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6685 newsrv->check_port = realport; /* by default */
6686 if (!newsrv->check_port) {
6687 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 +01006688 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006689 return -1;
6690 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006691
6692 if ((t = pool_alloc(task)) == NULL) {
6693 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6694 return -1;
6695 }
6696
6697 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6698 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6699 t->state = TASK_IDLE;
6700 t->process = process_chk;
6701 t->context = newsrv;
6702
6703 if (curproxy->state != PR_STDISABLED) {
6704 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6705 task_queue(t);
6706 task_wakeup(&rq, t);
6707 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006708 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006709
willy tarreau9fe663a2005-12-17 13:02:59 +01006710 curproxy->nbservers++;
6711 }
6712 else if (!strcmp(args[0], "log")) { /* syslog server address */
6713 struct sockaddr_in *sa;
6714 int facility;
6715
6716 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6717 curproxy->logfac1 = global.logfac1;
6718 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006719 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006720 curproxy->logfac2 = global.logfac2;
6721 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006722 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006723 }
6724 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006725 int level;
6726
willy tarreau0f7af912005-12-17 12:21:26 +01006727 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6728 if (!strcmp(log_facilities[facility], args[2]))
6729 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006730
willy tarreau0f7af912005-12-17 12:21:26 +01006731 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006732 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006733 exit(1);
6734 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006735
willy tarreau8337c6b2005-12-17 13:41:01 +01006736 level = 7; /* max syslog level = debug */
6737 if (*(args[3])) {
6738 while (level >= 0 && strcmp(log_levels[level], args[3]))
6739 level--;
6740 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006741 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006742 exit(1);
6743 }
6744 }
6745
willy tarreau0f7af912005-12-17 12:21:26 +01006746 sa = str2sa(args[1]);
6747 if (!sa->sin_port)
6748 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006749
willy tarreau0f7af912005-12-17 12:21:26 +01006750 if (curproxy->logfac1 == -1) {
6751 curproxy->logsrv1 = *sa;
6752 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006753 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006754 }
6755 else if (curproxy->logfac2 == -1) {
6756 curproxy->logsrv2 = *sa;
6757 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006758 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006759 }
6760 else {
6761 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006762 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006764 }
6765 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006766 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006767 file, linenum);
6768 return -1;
6769 }
6770 }
willy tarreaua1598082005-12-17 13:08:06 +01006771 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006772 if (!*args[1]) {
6773 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006774 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006775 return -1;
6776 }
6777
6778 curproxy->source_addr = *str2sa(args[1]);
6779 curproxy->options |= PR_O_BIND_SRC;
6780 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006781 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6782 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006783 if (curproxy == &defproxy) {
6784 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6785 return -1;
6786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006787
6788 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006789 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6790 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006791 return -1;
6792 }
6793
6794 preg = calloc(1, sizeof(regex_t));
6795 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006796 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006797 return -1;
6798 }
6799
willy tarreauc1f47532005-12-18 01:08:26 +01006800 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6801 if (err) {
6802 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6803 file, linenum, *err);
6804 return -1;
6805 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006806 }
6807 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6808 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006809 if (curproxy == &defproxy) {
6810 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6811 return -1;
6812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006813
6814 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006815 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006816 return -1;
6817 }
6818
6819 preg = calloc(1, sizeof(regex_t));
6820 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006821 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006822 return -1;
6823 }
6824
6825 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6826 }
6827 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6828 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006829 if (curproxy == &defproxy) {
6830 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6831 return -1;
6832 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006833
6834 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006835 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006836 return -1;
6837 }
6838
6839 preg = calloc(1, sizeof(regex_t));
6840 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006841 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006842 return -1;
6843 }
6844
6845 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6846 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006847 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6848 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006849 if (curproxy == &defproxy) {
6850 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6851 return -1;
6852 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006853
6854 if (*(args[1]) == 0) {
6855 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6856 return -1;
6857 }
6858
6859 preg = calloc(1, sizeof(regex_t));
6860 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6861 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6862 return -1;
6863 }
6864
6865 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6866 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006867 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6868 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006869 if (curproxy == &defproxy) {
6870 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6871 return -1;
6872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006873
6874 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006875 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006876 return -1;
6877 }
6878
6879 preg = calloc(1, sizeof(regex_t));
6880 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006881 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006882 return -1;
6883 }
6884
6885 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6886 }
6887 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6888 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006889 if (curproxy == &defproxy) {
6890 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6891 return -1;
6892 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006893
6894 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006895 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6896 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006897 return -1;
6898 }
6899
6900 preg = calloc(1, sizeof(regex_t));
6901 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006902 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006903 return -1;
6904 }
6905
willy tarreauc1f47532005-12-18 01:08:26 +01006906 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6907 if (err) {
6908 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6909 file, linenum, *err);
6910 return -1;
6911 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006912 }
6913 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6914 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006915 if (curproxy == &defproxy) {
6916 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6917 return -1;
6918 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006919
6920 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006921 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006922 return -1;
6923 }
6924
6925 preg = calloc(1, sizeof(regex_t));
6926 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006927 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006928 return -1;
6929 }
6930
6931 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6932 }
6933 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6934 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006935 if (curproxy == &defproxy) {
6936 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6937 return -1;
6938 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006939
6940 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006941 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006942 return -1;
6943 }
6944
6945 preg = calloc(1, sizeof(regex_t));
6946 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006947 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006948 return -1;
6949 }
6950
6951 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6952 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006953 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6954 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006955 if (curproxy == &defproxy) {
6956 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6957 return -1;
6958 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006959
6960 if (*(args[1]) == 0) {
6961 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6962 return -1;
6963 }
6964
6965 preg = calloc(1, sizeof(regex_t));
6966 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6967 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6968 return -1;
6969 }
6970
6971 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6972 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006973 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6974 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006975 if (curproxy == &defproxy) {
6976 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6977 return -1;
6978 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006979
6980 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006981 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006982 return -1;
6983 }
6984
6985 preg = calloc(1, sizeof(regex_t));
6986 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006987 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006988 return -1;
6989 }
6990
6991 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6992 }
6993 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006994 if (curproxy == &defproxy) {
6995 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6996 return -1;
6997 }
6998
willy tarreau9fe663a2005-12-17 13:02:59 +01006999 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007000 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007001 return 0;
7002 }
7003
7004 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007005 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007006 return -1;
7007 }
7008
willy tarreau4302f492005-12-18 01:00:37 +01007009 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7010 }
7011 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7012 regex_t *preg;
7013
7014 if (*(args[1]) == 0 || *(args[2]) == 0) {
7015 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7016 file, linenum, args[0]);
7017 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007018 }
willy tarreau4302f492005-12-18 01:00:37 +01007019
7020 preg = calloc(1, sizeof(regex_t));
7021 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7022 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7023 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007024 }
willy tarreau4302f492005-12-18 01:00:37 +01007025
willy tarreauc1f47532005-12-18 01:08:26 +01007026 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7027 if (err) {
7028 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7029 file, linenum, *err);
7030 return -1;
7031 }
willy tarreau4302f492005-12-18 01:00:37 +01007032 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007033 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7034 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007035 if (curproxy == &defproxy) {
7036 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7037 return -1;
7038 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007039
7040 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007041 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007042 return -1;
7043 }
willy tarreaue39cd132005-12-17 13:00:18 +01007044
willy tarreau9fe663a2005-12-17 13:02:59 +01007045 preg = calloc(1, sizeof(regex_t));
7046 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007047 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007048 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007049 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007050
willy tarreauc1f47532005-12-18 01:08:26 +01007051 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7052 if (err) {
7053 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7054 file, linenum, *err);
7055 return -1;
7056 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007057 }
willy tarreau982249e2005-12-18 00:57:06 +01007058 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7059 regex_t *preg;
7060 if (curproxy == &defproxy) {
7061 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7062 return -1;
7063 }
7064
7065 if (*(args[1]) == 0) {
7066 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7067 return -1;
7068 }
7069
7070 preg = calloc(1, sizeof(regex_t));
7071 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7072 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7073 return -1;
7074 }
7075
willy tarreauc1f47532005-12-18 01:08:26 +01007076 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7077 if (err) {
7078 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7079 file, linenum, *err);
7080 return -1;
7081 }
willy tarreau982249e2005-12-18 00:57:06 +01007082 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007084 regex_t *preg;
7085 if (curproxy == &defproxy) {
7086 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7087 return -1;
7088 }
willy tarreaue39cd132005-12-17 13:00:18 +01007089
willy tarreaua41a8b42005-12-17 14:02:24 +01007090 if (*(args[1]) == 0 || *(args[2]) == 0) {
7091 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7092 file, linenum, args[0]);
7093 return -1;
7094 }
willy tarreaue39cd132005-12-17 13:00:18 +01007095
willy tarreaua41a8b42005-12-17 14:02:24 +01007096 preg = calloc(1, sizeof(regex_t));
7097 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7098 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7099 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007100 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007101
willy tarreauc1f47532005-12-18 01:08:26 +01007102 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7103 if (err) {
7104 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7105 file, linenum, *err);
7106 return -1;
7107 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007108 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7110 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007111 if (curproxy == &defproxy) {
7112 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7113 return -1;
7114 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007115
7116 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007117 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007118 return -1;
7119 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007120
willy tarreau9fe663a2005-12-17 13:02:59 +01007121 preg = calloc(1, sizeof(regex_t));
7122 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007123 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007124 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007126
willy tarreauc1f47532005-12-18 01:08:26 +01007127 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7128 if (err) {
7129 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7130 file, linenum, *err);
7131 return -1;
7132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007133 }
willy tarreau982249e2005-12-18 00:57:06 +01007134 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7135 regex_t *preg;
7136 if (curproxy == &defproxy) {
7137 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7138 return -1;
7139 }
7140
7141 if (*(args[1]) == 0) {
7142 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7143 return -1;
7144 }
7145
7146 preg = calloc(1, sizeof(regex_t));
7147 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7148 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7149 return -1;
7150 }
7151
willy tarreauc1f47532005-12-18 01:08:26 +01007152 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7153 if (err) {
7154 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7155 file, linenum, *err);
7156 return -1;
7157 }
willy tarreau982249e2005-12-18 00:57:06 +01007158 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007159 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007160 if (curproxy == &defproxy) {
7161 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7162 return -1;
7163 }
7164
willy tarreau9fe663a2005-12-17 13:02:59 +01007165 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007166 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007167 return 0;
7168 }
7169
7170 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007171 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007172 return -1;
7173 }
7174
7175 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7176 }
willy tarreauc1f47532005-12-18 01:08:26 +01007177 else if (!strcmp(args[0], "errorloc") ||
7178 !strcmp(args[0], "errorloc302") ||
7179 !strcmp(args[0], "errorloc303")) { /* error location */
7180 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007181 char *err;
7182
willy tarreaueedaa9f2005-12-17 14:08:03 +01007183 // if (curproxy == &defproxy) {
7184 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7185 // return -1;
7186 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007187
willy tarreau8337c6b2005-12-17 13:41:01 +01007188 if (*(args[2]) == 0) {
7189 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7190 return -1;
7191 }
7192
7193 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007194 if (!strcmp(args[0], "errorloc303")) {
7195 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7196 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7197 } else {
7198 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7199 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7200 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007201
7202 if (errnum == 400) {
7203 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007204 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007205 free(curproxy->errmsg.msg400);
7206 }
7207 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007208 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007209 }
7210 else if (errnum == 403) {
7211 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007212 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007213 free(curproxy->errmsg.msg403);
7214 }
7215 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007216 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007217 }
7218 else if (errnum == 408) {
7219 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007220 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007221 free(curproxy->errmsg.msg408);
7222 }
7223 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007224 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007225 }
7226 else if (errnum == 500) {
7227 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007228 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007229 free(curproxy->errmsg.msg500);
7230 }
7231 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007232 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007233 }
7234 else if (errnum == 502) {
7235 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007236 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007237 free(curproxy->errmsg.msg502);
7238 }
7239 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007240 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007241 }
7242 else if (errnum == 503) {
7243 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007244 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007245 free(curproxy->errmsg.msg503);
7246 }
7247 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007248 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007249 }
7250 else if (errnum == 504) {
7251 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007252 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007253 free(curproxy->errmsg.msg504);
7254 }
7255 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007256 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007257 }
7258 else {
7259 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7260 free(err);
7261 }
7262 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007263 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007264 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007265 return -1;
7266 }
7267 return 0;
7268}
willy tarreaue39cd132005-12-17 13:00:18 +01007269
willy tarreau5cbea6f2005-12-17 12:48:26 +01007270
willy tarreau9fe663a2005-12-17 13:02:59 +01007271/*
7272 * This function reads and parses the configuration file given in the argument.
7273 * returns 0 if OK, -1 if error.
7274 */
7275int readcfgfile(char *file) {
7276 char thisline[256];
7277 char *line;
7278 FILE *f;
7279 int linenum = 0;
7280 char *end;
7281 char *args[MAX_LINE_ARGS];
7282 int arg;
7283 int cfgerr = 0;
7284 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007285
willy tarreau9fe663a2005-12-17 13:02:59 +01007286 struct proxy *curproxy = NULL;
7287 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007288
willy tarreau9fe663a2005-12-17 13:02:59 +01007289 if ((f=fopen(file,"r")) == NULL)
7290 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007291
willy tarreaueedaa9f2005-12-17 14:08:03 +01007292 init_default_instance();
7293
willy tarreau9fe663a2005-12-17 13:02:59 +01007294 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7295 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007296
willy tarreau9fe663a2005-12-17 13:02:59 +01007297 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007298
willy tarreau9fe663a2005-12-17 13:02:59 +01007299 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007300 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007301 line++;
7302
7303 arg = 0;
7304 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007305
willy tarreau9fe663a2005-12-17 13:02:59 +01007306 while (*line && arg < MAX_LINE_ARGS) {
7307 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7308 * C equivalent value. Other combinations left unchanged (eg: \1).
7309 */
7310 if (*line == '\\') {
7311 int skip = 0;
7312 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7313 *line = line[1];
7314 skip = 1;
7315 }
7316 else if (line[1] == 'r') {
7317 *line = '\r';
7318 skip = 1;
7319 }
7320 else if (line[1] == 'n') {
7321 *line = '\n';
7322 skip = 1;
7323 }
7324 else if (line[1] == 't') {
7325 *line = '\t';
7326 skip = 1;
7327 }
willy tarreauc1f47532005-12-18 01:08:26 +01007328 else if (line[1] == 'x') {
7329 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7330 unsigned char hex1, hex2;
7331 hex1 = toupper(line[2]) - '0';
7332 hex2 = toupper(line[3]) - '0';
7333 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7334 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7335 *line = (hex1<<4) + hex2;
7336 skip = 3;
7337 }
7338 else {
7339 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7340 return -1;
7341 }
7342 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007343 if (skip) {
7344 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7345 end -= skip;
7346 }
7347 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007348 }
willy tarreaua1598082005-12-17 13:08:06 +01007349 else if (*line == '#' || *line == '\n' || *line == '\r') {
7350 /* end of string, end of loop */
7351 *line = 0;
7352 break;
7353 }
willy tarreauc29948c2005-12-17 13:10:27 +01007354 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007355 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007356 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007357 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007358 line++;
7359 args[++arg] = line;
7360 }
7361 else {
7362 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007363 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007364 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007365
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 /* empty line */
7367 if (!**args)
7368 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007369
willy tarreau9fe663a2005-12-17 13:02:59 +01007370 /* zero out remaining args */
7371 while (++arg < MAX_LINE_ARGS) {
7372 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007373 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007374
willy tarreaua41a8b42005-12-17 14:02:24 +01007375 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007376 confsect = CFG_LISTEN;
7377 else if (!strcmp(args[0], "global")) /* global config */
7378 confsect = CFG_GLOBAL;
7379 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007380
willy tarreau9fe663a2005-12-17 13:02:59 +01007381 switch (confsect) {
7382 case CFG_LISTEN:
7383 if (cfg_parse_listen(file, linenum, args) < 0)
7384 return -1;
7385 break;
7386 case CFG_GLOBAL:
7387 if (cfg_parse_global(file, linenum, args) < 0)
7388 return -1;
7389 break;
7390 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007391 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007393 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007394
7395
willy tarreau0f7af912005-12-17 12:21:26 +01007396 }
7397 fclose(f);
7398
7399 /*
7400 * Now, check for the integrity of all that we have collected.
7401 */
7402
7403 if ((curproxy = proxy) == NULL) {
7404 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7405 file);
7406 return -1;
7407 }
7408
7409 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007410 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007411 if (curproxy->state == PR_STDISABLED) {
7412 curproxy = curproxy->next;
7413 continue;
7414 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007415
7416 if (curproxy->listen == NULL) {
7417 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);
7418 cfgerr++;
7419 }
7420 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007421 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007422 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007423 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7424 file, curproxy->id);
7425 cfgerr++;
7426 }
7427 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7428 if (curproxy->options & PR_O_TRANSP) {
7429 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7430 file, curproxy->id);
7431 cfgerr++;
7432 }
7433 else if (curproxy->srv == NULL) {
7434 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7435 file, curproxy->id);
7436 cfgerr++;
7437 }
willy tarreaua1598082005-12-17 13:08:06 +01007438 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007439 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7440 file, curproxy->id);
7441 }
7442 }
7443 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007444 if (curproxy->cookie_name != NULL) {
7445 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7446 file, curproxy->id);
7447 }
7448 if ((newsrv = curproxy->srv) != NULL) {
7449 Warning("parsing %s : servers will be ignored for listener %s.\n",
7450 file, curproxy->id);
7451 }
willy tarreaue39cd132005-12-17 13:00:18 +01007452 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007453 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7454 file, curproxy->id);
7455 }
willy tarreaue39cd132005-12-17 13:00:18 +01007456 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007457 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7458 file, curproxy->id);
7459 }
7460 }
7461 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7462 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7463 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7464 file, curproxy->id);
7465 cfgerr++;
7466 }
7467 else {
7468 while (newsrv != NULL) {
7469 /* nothing to check for now */
7470 newsrv = newsrv->next;
7471 }
7472 }
7473 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007474
7475 if (curproxy->options & PR_O_LOGASAP)
7476 curproxy->to_log &= ~LW_BYTES;
7477
willy tarreau8337c6b2005-12-17 13:41:01 +01007478 if (curproxy->errmsg.msg400 == NULL) {
7479 curproxy->errmsg.msg400 = (char *)HTTP_400;
7480 curproxy->errmsg.len400 = strlen(HTTP_400);
7481 }
7482 if (curproxy->errmsg.msg403 == NULL) {
7483 curproxy->errmsg.msg403 = (char *)HTTP_403;
7484 curproxy->errmsg.len403 = strlen(HTTP_403);
7485 }
7486 if (curproxy->errmsg.msg408 == NULL) {
7487 curproxy->errmsg.msg408 = (char *)HTTP_408;
7488 curproxy->errmsg.len408 = strlen(HTTP_408);
7489 }
7490 if (curproxy->errmsg.msg500 == NULL) {
7491 curproxy->errmsg.msg500 = (char *)HTTP_500;
7492 curproxy->errmsg.len500 = strlen(HTTP_500);
7493 }
7494 if (curproxy->errmsg.msg502 == NULL) {
7495 curproxy->errmsg.msg502 = (char *)HTTP_502;
7496 curproxy->errmsg.len502 = strlen(HTTP_502);
7497 }
7498 if (curproxy->errmsg.msg503 == NULL) {
7499 curproxy->errmsg.msg503 = (char *)HTTP_503;
7500 curproxy->errmsg.len503 = strlen(HTTP_503);
7501 }
7502 if (curproxy->errmsg.msg504 == NULL) {
7503 curproxy->errmsg.msg504 = (char *)HTTP_504;
7504 curproxy->errmsg.len504 = strlen(HTTP_504);
7505 }
willy tarreau0f7af912005-12-17 12:21:26 +01007506 curproxy = curproxy->next;
7507 }
7508 if (cfgerr > 0) {
7509 Alert("Errors found in configuration file, aborting.\n");
7510 return -1;
7511 }
7512 else
7513 return 0;
7514}
7515
7516
7517/*
7518 * This function initializes all the necessary variables. It only returns
7519 * if everything is OK. If something fails, it exits.
7520 */
7521void init(int argc, char **argv) {
7522 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007523 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007524 char *old_argv = *argv;
7525 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007526 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007527 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007528
7529 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007530 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007531 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007532 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007533 exit(1);
7534 }
7535
willy tarreau4302f492005-12-18 01:00:37 +01007536 /* initialize the log header encoding map : '{|}"#' should be encoded with
7537 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7538 * URL encoding only requires '"', '#' to be encoded as well as non-
7539 * printable characters above.
7540 */
7541 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7542 memset(url_encode_map, 0, sizeof(url_encode_map));
7543 for (i = 0; i < 32; i++) {
7544 FD_SET(i, hdr_encode_map);
7545 FD_SET(i, url_encode_map);
7546 }
7547 for (i = 127; i < 256; i++) {
7548 FD_SET(i, hdr_encode_map);
7549 FD_SET(i, url_encode_map);
7550 }
7551
7552 tmp = "\"#{|}";
7553 while (*tmp) {
7554 FD_SET(*tmp, hdr_encode_map);
7555 tmp++;
7556 }
7557
7558 tmp = "\"#";
7559 while (*tmp) {
7560 FD_SET(*tmp, url_encode_map);
7561 tmp++;
7562 }
7563
willy tarreau64a3cc32005-12-18 01:13:11 +01007564 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7565#if defined(ENABLE_POLL)
7566 cfg_polling_mechanism |= POLL_USE_POLL;
7567#endif
7568#if defined(ENABLE_EPOLL)
7569 cfg_polling_mechanism |= POLL_USE_EPOLL;
7570#endif
7571
willy tarreau0f7af912005-12-17 12:21:26 +01007572 pid = getpid();
7573 progname = *argv;
7574 while ((tmp = strchr(progname, '/')) != NULL)
7575 progname = tmp + 1;
7576
7577 argc--; argv++;
7578 while (argc > 0) {
7579 char *flag;
7580
7581 if (**argv == '-') {
7582 flag = *argv+1;
7583
7584 /* 1 arg */
7585 if (*flag == 'v') {
7586 display_version();
7587 exit(0);
7588 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007589#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007590 else if (*flag == 'd' && flag[1] == 'e')
7591 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007592#endif
7593#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007594 else if (*flag == 'd' && flag[1] == 'p')
7595 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007596#endif
willy tarreau982249e2005-12-18 00:57:06 +01007597 else if (*flag == 'V')
7598 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007599 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007600 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007601 else if (*flag == 'c')
7602 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007603 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007604 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007605 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007606 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007607#if STATTIME > 0
7608 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007609 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007610 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007611 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007612#endif
7613 else { /* >=2 args */
7614 argv++; argc--;
7615 if (argc == 0)
7616 usage(old_argv);
7617
7618 switch (*flag) {
7619 case 'n' : cfg_maxconn = atol(*argv); break;
7620 case 'N' : cfg_maxpconn = atol(*argv); break;
7621 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007622 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007623 default: usage(old_argv);
7624 }
7625 }
7626 }
7627 else
7628 usage(old_argv);
7629 argv++; argc--;
7630 }
7631
willy tarreaud0fb4652005-12-18 01:32:04 +01007632 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7633 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007634
willy tarreau0f7af912005-12-17 12:21:26 +01007635 if (!cfg_cfgfile)
7636 usage(old_argv);
7637
7638 gethostname(hostname, MAX_HOSTNAME_LEN);
7639
willy tarreau12350152005-12-18 01:03:27 +01007640 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007641 if (readcfgfile(cfg_cfgfile) < 0) {
7642 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7643 exit(1);
7644 }
willy tarreau12350152005-12-18 01:03:27 +01007645 if (have_appsession)
7646 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007647
willy tarreau982249e2005-12-18 00:57:06 +01007648 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007649 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7650 exit(0);
7651 }
7652
willy tarreau9fe663a2005-12-17 13:02:59 +01007653 if (cfg_maxconn > 0)
7654 global.maxconn = cfg_maxconn;
7655
willy tarreaufe2c5c12005-12-17 14:14:34 +01007656 if (cfg_pidfile) {
7657 if (global.pidfile)
7658 free(global.pidfile);
7659 global.pidfile = strdup(cfg_pidfile);
7660 }
7661
willy tarreau9fe663a2005-12-17 13:02:59 +01007662 if (global.maxconn == 0)
7663 global.maxconn = DEFAULT_MAXCONN;
7664
7665 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7666
7667 if (arg_mode & MODE_DEBUG) {
7668 /* command line debug mode inhibits configuration mode */
7669 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7670 }
willy tarreau982249e2005-12-18 00:57:06 +01007671 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7672 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007673
7674 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7675 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7676 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7677 }
7678
7679 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7680 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7681 global.nbproc = 1;
7682 }
7683
7684 if (global.nbproc < 1)
7685 global.nbproc = 1;
7686
willy tarreau0f7af912005-12-17 12:21:26 +01007687 StaticReadEvent = (fd_set *)calloc(1,
7688 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007689 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007690 StaticWriteEvent = (fd_set *)calloc(1,
7691 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007692 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007693
7694 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007695 sizeof(struct fdtab) * (global.maxsock));
7696 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007697 fdtab[i].state = FD_STCLOSE;
7698 }
7699}
7700
7701/*
7702 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7703 */
7704int start_proxies() {
7705 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007706 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007707 int fd;
7708
7709 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007710 if (curproxy->state == PR_STDISABLED)
7711 continue;
7712
willy tarreaua41a8b42005-12-17 14:02:24 +01007713 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7714 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007715 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007716 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7717 curproxy->id);
7718 return -1;
7719 }
willy tarreau0f7af912005-12-17 12:21:26 +01007720
willy tarreaua41a8b42005-12-17 14:02:24 +01007721 if (fd >= global.maxsock) {
7722 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7723 curproxy->id);
7724 close(fd);
7725 return -1;
7726 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007727
willy tarreaua41a8b42005-12-17 14:02:24 +01007728 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7729 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7730 (char *) &one, sizeof(one)) == -1)) {
7731 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7732 curproxy->id);
7733 close(fd);
7734 return -1;
7735 }
willy tarreau0f7af912005-12-17 12:21:26 +01007736
willy tarreaua41a8b42005-12-17 14:02:24 +01007737 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7738 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7739 curproxy->id);
7740 }
willy tarreau0f7af912005-12-17 12:21:26 +01007741
willy tarreaua41a8b42005-12-17 14:02:24 +01007742 if (bind(fd,
7743 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007744 listener->addr.ss_family == AF_INET6 ?
7745 sizeof(struct sockaddr_in6) :
7746 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007747 Alert("cannot bind socket for proxy %s. Aborting.\n",
7748 curproxy->id);
7749 close(fd);
7750 return -1;
7751 }
willy tarreau0f7af912005-12-17 12:21:26 +01007752
willy tarreaua41a8b42005-12-17 14:02:24 +01007753 if (listen(fd, curproxy->maxconn) == -1) {
7754 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7755 curproxy->id);
7756 close(fd);
7757 return -1;
7758 }
willy tarreau0f7af912005-12-17 12:21:26 +01007759
willy tarreaua41a8b42005-12-17 14:02:24 +01007760 /* the function for the accept() event */
7761 fdtab[fd].read = &event_accept;
7762 fdtab[fd].write = NULL; /* never called */
7763 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7764 curproxy->state = PR_STRUN;
7765 fdtab[fd].state = FD_STLISTEN;
7766 FD_SET(fd, StaticReadEvent);
7767 fd_insert(fd);
7768 listeners++;
7769 }
willy tarreaua1598082005-12-17 13:08:06 +01007770 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007771 }
7772 return 0;
7773}
7774
willy tarreaub952e1d2005-12-18 01:31:20 +01007775int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007776
7777 appsess *temp1,*temp2;
7778 temp1 = (appsess *)key1;
7779 temp2 = (appsess *)key2;
7780
7781 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7782 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7783
7784 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7785}/* end match_str */
7786
willy tarreaub952e1d2005-12-18 01:31:20 +01007787void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007788 appsess *temp1;
7789
7790 //printf("destroy called\n");
7791 temp1 = (appsess *)data;
7792
7793 if (temp1->sessid)
7794 pool_free_to(apools.sessid, temp1->sessid);
7795
7796 if (temp1->serverid)
7797 pool_free_to(apools.serverid, temp1->serverid);
7798
7799 pool_free(appsess, temp1);
7800} /* end destroy */
7801
7802void appsession_cleanup( void )
7803{
7804 struct proxy *p = proxy;
7805
7806 while(p) {
7807 chtbl_destroy(&(p->htbl_proxy));
7808 p = p->next;
7809 }
7810}/* end appsession_cleanup() */
7811
7812void pool_destroy(void **pool)
7813{
7814 void *temp, *next;
7815 next = pool;
7816 while (next) {
7817 temp = next;
7818 next = *(void **)temp;
7819 free(temp);
7820 }
7821}/* end pool_destroy() */
7822
willy tarreaub952e1d2005-12-18 01:31:20 +01007823void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01007824 struct proxy *p = proxy;
7825 struct cap_hdr *h,*h_next;
7826 struct server *s,*s_next;
7827 struct listener *l,*l_next;
7828
7829 while (p) {
7830 if (p->id)
7831 free(p->id);
7832
7833 if (p->check_req)
7834 free(p->check_req);
7835
7836 if (p->cookie_name)
7837 free(p->cookie_name);
7838
7839 if (p->capture_name)
7840 free(p->capture_name);
7841
7842 /* only strup if the user have set in config.
7843 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01007844 if (p->errmsg.msg400) free(p->errmsg.msg400);
7845 if (p->errmsg.msg403) free(p->errmsg.msg403);
7846 if (p->errmsg.msg408) free(p->errmsg.msg408);
7847 if (p->errmsg.msg500) free(p->errmsg.msg500);
7848 if (p->errmsg.msg502) free(p->errmsg.msg502);
7849 if (p->errmsg.msg503) free(p->errmsg.msg503);
7850 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01007851 */
7852 if (p->appsession_name)
7853 free(p->appsession_name);
7854
7855 h = p->req_cap;
7856 while (h) {
7857 h_next = h->next;
7858 if (h->name)
7859 free(h->name);
7860 pool_destroy(h->pool);
7861 free(h);
7862 h = h_next;
7863 }/* end while(h) */
7864
7865 h = p->rsp_cap;
7866 while (h) {
7867 h_next = h->next;
7868 if (h->name)
7869 free(h->name);
7870
7871 pool_destroy(h->pool);
7872 free(h);
7873 h = h_next;
7874 }/* end while(h) */
7875
7876 s = p->srv;
7877 while (s) {
7878 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01007879 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01007880 free(s->id);
7881
willy tarreaub952e1d2005-12-18 01:31:20 +01007882 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01007883 free(s->cookie);
7884
7885 free(s);
7886 s = s_next;
7887 }/* end while(s) */
7888
7889 l = p->listen;
7890 while (l) {
7891 l_next = l->next;
7892 free(l);
7893 l = l_next;
7894 }/* end while(l) */
7895
7896 pool_destroy((void **) p->req_cap_pool);
7897 pool_destroy((void **) p->rsp_cap_pool);
7898 p = p->next;
7899 }/* end while(p) */
7900
7901 if (global.chroot) free(global.chroot);
7902 if (global.pidfile) free(global.pidfile);
7903
willy tarreau12350152005-12-18 01:03:27 +01007904 if (StaticReadEvent) free(StaticReadEvent);
7905 if (StaticWriteEvent) free(StaticWriteEvent);
7906 if (fdtab) free(fdtab);
7907
7908 pool_destroy(pool_session);
7909 pool_destroy(pool_buffer);
7910 pool_destroy(pool_fdtab);
7911 pool_destroy(pool_requri);
7912 pool_destroy(pool_task);
7913 pool_destroy(pool_capture);
7914 pool_destroy(pool_appsess);
7915
7916 if (have_appsession) {
7917 pool_destroy(apools.serverid);
7918 pool_destroy(apools.sessid);
7919 }
7920} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007921
7922int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007923 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007924 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007925 init(argc, argv);
7926
willy tarreau0f7af912005-12-17 12:21:26 +01007927 signal(SIGQUIT, dump);
7928 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007929 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007930#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007931 signal(SIGINT, sig_int);
7932 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007933#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007934
7935 /* on very high loads, a sigpipe sometimes happen just between the
7936 * getsockopt() which tells "it's OK to write", and the following write :-(
7937 */
willy tarreau3242e862005-12-17 12:27:53 +01007938#ifndef MSG_NOSIGNAL
7939 signal(SIGPIPE, SIG_IGN);
7940#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007941
willy tarreaud0fb4652005-12-18 01:32:04 +01007942 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01007943 if (start_proxies() < 0)
7944 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01007945
7946 if (listeners == 0) {
7947 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
7948 exit(1);
7949 }
7950
7951 /* MODE_QUIET can inhibit alerts and warnings below this line */
7952
7953 global.mode &= ~MODE_STARTING;
7954 if (global.mode & MODE_QUIET) {
7955 /* detach from the tty */
7956 fclose(stdin); fclose(stdout); fclose(stderr);
7957 close(0); close(1); close(2);
7958 }
willy tarreau0f7af912005-12-17 12:21:26 +01007959
willy tarreaufe2c5c12005-12-17 14:14:34 +01007960 /* open log & pid files before the chroot */
7961 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7962 int pidfd;
7963 unlink(global.pidfile);
7964 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7965 if (pidfd < 0) {
7966 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7967 exit(1);
7968 }
7969 pidfile = fdopen(pidfd, "w");
7970 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007971
7972 /* chroot if needed */
7973 if (global.chroot != NULL) {
7974 if (chroot(global.chroot) == -1) {
7975 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7976 exit(1);
7977 }
7978 chdir("/");
7979 }
7980
willy tarreaub1285d52005-12-18 01:20:14 +01007981 /* ulimits */
7982 if (global.rlimit_nofile) {
7983 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7984 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7985 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7986 }
7987 }
7988
willy tarreau9fe663a2005-12-17 13:02:59 +01007989 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007990 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007991 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7992 exit(1);
7993 }
7994
willy tarreau036e1ce2005-12-17 13:46:33 +01007995 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007996 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7997 exit(1);
7998 }
7999
willy tarreaub1285d52005-12-18 01:20:14 +01008000 /* check ulimits */
8001 limit.rlim_cur = limit.rlim_max = 0;
8002 getrlimit(RLIMIT_NOFILE, &limit);
8003 if (limit.rlim_cur < global.maxsock) {
8004 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",
8005 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8006 }
8007
willy tarreau9fe663a2005-12-17 13:02:59 +01008008 if (global.mode & MODE_DAEMON) {
8009 int ret = 0;
8010 int proc;
8011
8012 /* the father launches the required number of processes */
8013 for (proc = 0; proc < global.nbproc; proc++) {
8014 ret = fork();
8015 if (ret < 0) {
8016 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8017 exit(1); /* there has been an error */
8018 }
8019 else if (ret == 0) /* child breaks here */
8020 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008021 if (pidfile != NULL) {
8022 fprintf(pidfile, "%d\n", ret);
8023 fflush(pidfile);
8024 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008025 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008026 /* close the pidfile both in children and father */
8027 if (pidfile != NULL)
8028 fclose(pidfile);
8029 free(global.pidfile);
8030
willy tarreau9fe663a2005-12-17 13:02:59 +01008031 if (proc == global.nbproc)
8032 exit(0); /* parent must leave */
8033
willy tarreau750a4722005-12-17 13:21:24 +01008034 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8035 * that we can detach from the TTY. We MUST NOT do it in other cases since
8036 * it would have already be done, and 0-2 would have been affected to listening
8037 * sockets
8038 */
8039 if (!(global.mode & MODE_QUIET)) {
8040 /* detach from the tty */
8041 fclose(stdin); fclose(stdout); fclose(stderr);
8042 close(0); close(1); close(2); /* close all fd's */
8043 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8044 }
willy tarreaua1598082005-12-17 13:08:06 +01008045 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008046 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008047 }
8048
willy tarreau1c2ad212005-12-18 01:11:29 +01008049#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008050 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008051 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8052 epoll_loop(POLL_LOOP_ACTION_RUN);
8053 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008054 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008055 }
8056 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008057 Warning("epoll() is not available. Using poll()/select() instead.\n");
8058 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008059 }
8060 }
8061#endif
8062
8063#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008064 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008065 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8066 poll_loop(POLL_LOOP_ACTION_RUN);
8067 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008068 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008069 }
8070 else {
8071 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008072 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008073 }
8074 }
8075#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008076 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008077 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8078 select_loop(POLL_LOOP_ACTION_RUN);
8079 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008080 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008081 }
8082 }
8083
willy tarreau0f7af912005-12-17 12:21:26 +01008084
willy tarreau12350152005-12-18 01:03:27 +01008085 /* Free all Hash Keys and all Hash elements */
8086 appsession_cleanup();
8087 /* Do some cleanup */
8088 deinit();
8089
willy tarreau0f7af912005-12-17 12:21:26 +01008090 exit(0);
8091}
willy tarreau12350152005-12-18 01:03:27 +01008092
8093#if defined(DEBUG_HASH)
8094static void print_table(const CHTbl *htbl) {
8095
8096 ListElmt *element;
8097 int i;
8098 appsess *asession;
8099
8100 /*****************************************************************************
8101 * *
8102 * Display the chained hash table. *
8103 * *
8104 *****************************************************************************/
8105
8106 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8107
8108 for (i = 0; i < TBLSIZ; i++) {
8109 fprintf(stdout, "Bucket[%03d]\n", i);
8110
8111 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8112 //fprintf(stdout, "%c", *(char *)list_data(element));
8113 asession = (appsess *)list_data(element);
8114 fprintf(stdout, "ELEM :%s:", asession->sessid);
8115 fprintf(stdout, " Server :%s: \n", asession->serverid);
8116 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8117 }
8118
8119 fprintf(stdout, "\n");
8120 }
8121 return;
8122} /* end print_table */
8123#endif
8124
8125static int appsession_init(void)
8126{
8127 static int initialized = 0;
8128 int idlen;
8129 struct server *s;
8130 struct proxy *p = proxy;
8131
8132 if (!initialized) {
8133 if (!appsession_task_init()) {
8134 apools.sessid = NULL;
8135 apools.serverid = NULL;
8136 apools.ser_waste = 0;
8137 apools.ser_use = 0;
8138 apools.ser_msize = sizeof(void *);
8139 apools.ses_waste = 0;
8140 apools.ses_use = 0;
8141 apools.ses_msize = sizeof(void *);
8142 while (p) {
8143 s = p->srv;
8144 if (apools.ses_msize < p->appsession_len)
8145 apools.ses_msize = p->appsession_len;
8146 while (s) {
8147 idlen = strlen(s->id);
8148 if (apools.ser_msize < idlen)
8149 apools.ser_msize = idlen;
8150 s = s->next;
8151 }
8152 p = p->next;
8153 }
8154 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8155 apools.ses_msize ++;
8156 }
8157 else {
8158 fprintf(stderr, "appsession_task_init failed\n");
8159 return -1;
8160 }
8161 initialized ++;
8162 }
8163 return 0;
8164}
8165
8166static int appsession_task_init(void)
8167{
8168 static int initialized = 0;
8169 struct task *t;
8170 if (!initialized) {
8171 if ((t = pool_alloc(task)) == NULL)
8172 return -1;
8173 t->next = t->prev = t->rqnext = NULL;
8174 t->wq = LIST_HEAD(wait_queue);
8175 t->state = TASK_IDLE;
8176 t->context = NULL;
8177 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8178 task_queue(t);
8179 t->process = appsession_refresh;
8180 initialized ++;
8181 }
8182 return 0;
8183}
8184
8185static int appsession_refresh(struct task *t) {
8186 struct proxy *p = proxy;
8187 CHTbl *htbl;
8188 ListElmt *element, *last;
8189 int i;
8190 appsess *asession;
8191 void *data;
8192
8193 while (p) {
8194 if (p->appsession_name != NULL) {
8195 htbl = &p->htbl_proxy;
8196 /* if we ever give up the use of TBLSIZ, we need to change this */
8197 for (i = 0; i < TBLSIZ; i++) {
8198 last = NULL;
8199 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8200 asession = (appsess *)list_data(element);
8201 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8202 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8203 int len;
8204 /*
8205 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8206 */
8207 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8208 asession->sessid, asession->serverid?asession->serverid:"(null)");
8209 write(1, trash, len);
8210 }
8211 /* delete the expired element from within the hash table */
8212 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8213 && (htbl->table[i].destroy != NULL)) {
8214 htbl->table[i].destroy(data);
8215 }
8216 if (last == NULL) {/* patient lost his head, get a new one */
8217 element = list_head(&htbl->table[i]);
8218 if (element == NULL) break; /* no heads left, go to next patient */
8219 }
8220 else
8221 element = last;
8222 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8223 else
8224 last = element;
8225 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8226 }
8227 }
8228 p = p->next;
8229 }
8230 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8231 return TBLCHKINT;
8232} /* end appsession_refresh */
8233