blob: 899417780c1f71ba01f79e3f7b7981ab6030ad18 [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>
55#include <regex.h>
56#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010057#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010058#include <linux/netfilter_ipv4.h>
59#endif
willy tarreau0f7af912005-12-17 12:21:26 +010060
willy tarreau12350152005-12-18 01:03:27 +010061#if defined(__dietlibc__)
62#include <strings.h>
63#endif
64
willy tarreau1c2ad212005-12-18 01:11:29 +010065#if defined(ENABLE_POLL)
66#include <sys/poll.h>
67#endif
68
69#if defined(ENABLE_EPOLL)
70#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010071#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010072#else
73#include "include/epoll.h"
74#endif
75#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010076
willy tarreau598da412005-12-18 01:07:29 +010077#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010078
willy tarreaub1285d52005-12-18 01:20:14 +010079#define HAPROXY_VERSION "1.2.6"
80#define HAPROXY_DATE "2005/07/06"
willy tarreau0f7af912005-12-17 12:21:26 +010081
82/* this is for libc5 for example */
83#ifndef TCP_NODELAY
84#define TCP_NODELAY 1
85#endif
86
87#ifndef SHUT_RD
88#define SHUT_RD 0
89#endif
90
91#ifndef SHUT_WR
92#define SHUT_WR 1
93#endif
94
willy tarreau0174f312005-12-18 01:02:42 +010095/*
96 * BUFSIZE defines the size of a read and write buffer. It is the maximum
97 * amount of bytes which can be stored by the proxy for each session. However,
98 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
99 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
100 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
101 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
102 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
103 */
104#ifndef BUFSIZE
105#define BUFSIZE 16384
106#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100107
108// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100109#ifndef MAXREWRITE
110#define MAXREWRITE (BUFSIZE / 2)
111#endif
112
willy tarreau9fe663a2005-12-17 13:02:59 +0100113#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100114#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100115
willy tarreau5cbea6f2005-12-17 12:48:26 +0100116// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100117#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100118
willy tarreaue39cd132005-12-17 13:00:18 +0100119// max # of added headers per request
120#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100121
122// max # of matches per regexp
123#define MAX_MATCH 10
124
willy tarreau0174f312005-12-18 01:02:42 +0100125// cookie delimitor in "prefix" mode. This character is inserted between the
126// persistence cookie and the original value. The '~' is allowed by RFC2965,
127// and should not be too common in server names.
128#ifndef COOKIE_DELIM
129#define COOKIE_DELIM '~'
130#endif
131
willy tarreau0f7af912005-12-17 12:21:26 +0100132#define CONN_RETRIES 3
133
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100135#define DEF_CHKINTR 2000
136#define DEF_FALLTIME 3
137#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100138#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100139
willy tarreau9fe663a2005-12-17 13:02:59 +0100140/* default connections limit */
141#define DEFAULT_MAXCONN 2000
142
willy tarreau0f7af912005-12-17 12:21:26 +0100143/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
144#define INTBITS 5
145
146/* show stats this every millisecond, 0 to disable */
147#ifndef STATTIME
148#define STATTIME 2000
149#endif
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151/* this reduces the number of calls to select() by choosing appropriate
152 * sheduler precision in milliseconds. It should be near the minimum
153 * time that is needed by select() to collect all events. All timeouts
154 * are rounded up by adding this value prior to pass it to select().
155 */
156#define SCHEDULER_RESOLUTION 9
157
willy tarreau0f7af912005-12-17 12:21:26 +0100158#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
159#define SETNOW(a) (*a=now)
160
willy tarreau9da061b2005-12-17 12:29:56 +0100161/****** string-specific macros and functions ******/
162/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
163#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
164
165/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
166#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
167
willy tarreau0174f312005-12-18 01:02:42 +0100168/* returns 1 only if only zero or one bit is set in X, which means that X is a
169 * power of 2, and 0 otherwise */
170#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100171/*
172 * copies at most <size-1> chars from <src> to <dst>. Last char is always
173 * set to 0, unless <size> is 0. The number of chars copied is returned
174 * (excluding the terminating zero).
175 * This code has been optimized for size and speed : on x86, it's 45 bytes
176 * long, uses only registers, and consumes only 4 cycles per char.
177 */
willy tarreau750a4722005-12-17 13:21:24 +0100178int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100179 char *orig = dst;
180 if (size) {
181 while (--size && (*dst = *src)) {
182 src++; dst++;
183 }
184 *dst = 0;
185 }
186 return dst - orig;
187}
willy tarreau9da061b2005-12-17 12:29:56 +0100188
willy tarreau4302f492005-12-18 01:00:37 +0100189/*
190 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
191 * dynamically allocated. In the first case, <__pool> is updated to point to
192 * the next element in the list.
193 */
194#define pool_alloc_from(__pool, __len) ({ \
195 void *__p; \
196 if ((__p = (__pool)) == NULL) \
197 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
198 else { \
199 __pool = *(void **)(__pool); \
200 } \
201 __p; \
202})
203
204/*
205 * Puts a memory area back to the corresponding pool.
206 * Items are chained directly through a pointer that
207 * is written in the beginning of the memory area, so
208 * there's no need for any carrier cell. This implies
209 * that each memory area is at least as big as one
210 * pointer.
211 */
212#define pool_free_to(__pool, __ptr) ({ \
213 *(void **)(__ptr) = (void *)(__pool); \
214 __pool = (void *)(__ptr); \
215})
216
217
willy tarreau0f7af912005-12-17 12:21:26 +0100218#define MEM_OPTIM
219#ifdef MEM_OPTIM
220/*
221 * Returns a pointer to type <type> taken from the
222 * pool <pool_type> or dynamically allocated. In the
223 * first case, <pool_type> is updated to point to the
224 * next element in the list.
225 */
226#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100227 void *__p; \
228 if ((__p = pool_##type) == NULL) \
229 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100230 else { \
231 pool_##type = *(void **)pool_##type; \
232 } \
willy tarreau4302f492005-12-18 01:00:37 +0100233 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100234})
235
236/*
237 * Puts a memory area back to the corresponding pool.
238 * Items are chained directly through a pointer that
239 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100240 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100241 * that each memory area is at least as big as one
242 * pointer.
243 */
244#define pool_free(type, ptr) ({ \
245 *(void **)ptr = (void *)pool_##type; \
246 pool_##type = (void *)ptr; \
247})
248
249#else
250#define pool_alloc(type) (calloc(1,sizeof_##type));
251#define pool_free(type, ptr) (free(ptr));
252#endif /* MEM_OPTIM */
253
willy tarreau5cbea6f2005-12-17 12:48:26 +0100254#define sizeof_task sizeof(struct task)
255#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100256#define sizeof_buffer sizeof(struct buffer)
257#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100258#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100259#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100260#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100261#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100262
willy tarreau5cbea6f2005-12-17 12:48:26 +0100263/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100264#define FD_STCLOSE 0
265#define FD_STLISTEN 1
266#define FD_STCONN 2
267#define FD_STREADY 3
268#define FD_STERROR 4
269
willy tarreau5cbea6f2005-12-17 12:48:26 +0100270/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100271#define TASK_IDLE 0
272#define TASK_RUNNING 1
273
willy tarreau5cbea6f2005-12-17 12:48:26 +0100274/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100275#define PR_STNEW 0
276#define PR_STIDLE 1
277#define PR_STRUN 2
278#define PR_STDISABLED 3
279
willy tarreau5cbea6f2005-12-17 12:48:26 +0100280/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100281#define PR_MODE_TCP 0
282#define PR_MODE_HTTP 1
283#define PR_MODE_HEALTH 2
284
willy tarreau1c2ad212005-12-18 01:11:29 +0100285/* possible actions for the *poll() loops */
286#define POLL_LOOP_ACTION_INIT 0
287#define POLL_LOOP_ACTION_RUN 1
288#define POLL_LOOP_ACTION_CLEAN 2
289
willy tarreau64a3cc32005-12-18 01:13:11 +0100290/* poll mechanisms available */
291#define POLL_USE_SELECT (1<<0)
292#define POLL_USE_POLL (1<<1)
293#define POLL_USE_EPOLL (1<<2)
294
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100296#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
297#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
298#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
299#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
300#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
301#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
302#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
303#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100304#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100305#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
306#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
307#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
308#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
309#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
310#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
311#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
312#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
313#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
314#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
315#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100316
willy tarreaue39cd132005-12-17 13:00:18 +0100317/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100318#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
319#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
320#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
321#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
322#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
323#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100324#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100325
326#define SN_CK_NONE 0x00000000 /* this session had no cookie */
327#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
328#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
329#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
330#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
331#define SN_CK_SHIFT 6 /* bit shift */
332
willy tarreaub1285d52005-12-18 01:20:14 +0100333#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100334#define SN_ERR_CLITO 0x00000100 /* client time-out */
335#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
336#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
337#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
338#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100339#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
340#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100341#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
342#define SN_ERR_SHIFT 8 /* bit shift */
343
344#define SN_FINST_R 0x00001000 /* session ended during client request */
345#define SN_FINST_C 0x00002000 /* session ended during server connect */
346#define SN_FINST_H 0x00003000 /* session ended during server headers */
347#define SN_FINST_D 0x00004000 /* session ended during data phase */
348#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
349#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
350#define SN_FINST_SHIFT 12 /* bit shift */
351
352#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
353#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
354#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
355#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
356#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100357#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100358#define SN_SCK_SHIFT 16 /* bit shift */
359
willy tarreau97f58572005-12-18 00:53:44 +0100360#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
361#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
362#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100363
364/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100365#define CL_STHEADERS 0
366#define CL_STDATA 1
367#define CL_STSHUTR 2
368#define CL_STSHUTW 3
369#define CL_STCLOSE 4
370
willy tarreau5cbea6f2005-12-17 12:48:26 +0100371/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100372#define SV_STIDLE 0
373#define SV_STCONN 1
374#define SV_STHEADERS 2
375#define SV_STDATA 3
376#define SV_STSHUTR 4
377#define SV_STSHUTW 5
378#define SV_STCLOSE 6
379
380/* result of an I/O event */
381#define RES_SILENT 0 /* didn't happen */
382#define RES_DATA 1 /* data were sent or received */
383#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
384#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
385
willy tarreau9fe663a2005-12-17 13:02:59 +0100386/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100387#define MODE_DEBUG 1
388#define MODE_STATS 2
389#define MODE_LOG 4
390#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100391#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100392#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100393#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100394
395/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100396#define SRV_RUNNING 1 /* the server is UP */
397#define SRV_BACKUP 2 /* this server is a backup server */
398#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100399#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100400
willy tarreaue39cd132005-12-17 13:00:18 +0100401/* what to do when a header matches a regex */
402#define ACT_ALLOW 0 /* allow the request */
403#define ACT_REPLACE 1 /* replace the matching header */
404#define ACT_REMOVE 2 /* remove the matching header */
405#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100406#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100407
willy tarreau9fe663a2005-12-17 13:02:59 +0100408/* configuration sections */
409#define CFG_NONE 0
410#define CFG_GLOBAL 1
411#define CFG_LISTEN 2
412
willy tarreaua1598082005-12-17 13:08:06 +0100413/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100414#define LW_DATE 1 /* date */
415#define LW_CLIP 2 /* CLient IP */
416#define LW_SVIP 4 /* SerVer IP */
417#define LW_SVID 8 /* server ID */
418#define LW_REQ 16 /* http REQuest */
419#define LW_RESP 32 /* http RESPonse */
420#define LW_PXIP 64 /* proxy IP */
421#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100422#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100423#define LW_COOKIE 512 /* captured cookie */
424#define LW_REQHDR 1024 /* request header(s) */
425#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100426
willy tarreau0f7af912005-12-17 12:21:26 +0100427/*********************************************************************/
428
429#define LIST_HEAD(a) ((void *)(&(a)))
430
431/*********************************************************************/
432
willy tarreau4302f492005-12-18 01:00:37 +0100433struct cap_hdr {
434 struct cap_hdr *next;
435 char *name; /* header name, case insensitive */
436 int namelen; /* length of the header name, to speed-up lookups */
437 int len; /* capture length, not including terminal zero */
438 int index; /* index in the output array */
439 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
440};
441
willy tarreau0f7af912005-12-17 12:21:26 +0100442struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100443 struct hdr_exp *next;
444 regex_t *preg; /* expression to look for */
445 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
446 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100447};
448
449struct buffer {
450 unsigned int l; /* data length */
451 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100452 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100453 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100454 char data[BUFSIZE];
455};
456
457struct server {
458 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100459 int state; /* server state (SRV_*) */
460 int cklen; /* the len of the cookie, to speed up checks */
461 char *cookie; /* the id set in the cookie */
462 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100463 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100464 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100465 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100466 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100467 int rise, fall; /* time in iterations */
468 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100469 int result; /* 0 = connect OK, -1 = connect KO */
470 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100471 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100472};
473
willy tarreau5cbea6f2005-12-17 12:48:26 +0100474/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100475struct task {
476 struct task *next, *prev; /* chaining ... */
477 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100478 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 int state; /* task state : IDLE or RUNNING */
480 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100481 int (*process)(struct task *t); /* the function which processes the task */
482 void *context; /* the task's context */
483};
484
485/* WARNING: if new fields are added, they must be initialized in event_accept() */
486struct session {
487 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100488 /* application specific below */
489 struct timeval crexpire; /* expiration date for a client read */
490 struct timeval cwexpire; /* expiration date for a client write */
491 struct timeval srexpire; /* expiration date for a server read */
492 struct timeval swexpire; /* expiration date for a server write */
493 struct timeval cnexpire; /* expiration date for a connect */
494 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
495 struct proxy *proxy; /* the proxy this socket belongs to */
496 int cli_fd; /* the client side fd */
497 int srv_fd; /* the server side fd */
498 int cli_state; /* state of the client side */
499 int srv_state; /* state of the server side */
500 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100502 struct buffer *req; /* request buffer */
503 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100504 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100505 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100506 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100507 char **req_cap; /* array of captured request headers (may be NULL) */
508 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100509 struct {
510 int logwait; /* log fields waiting to be collected : LW_* */
511 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
512 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
513 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
514 long t_data; /* delay before the first data byte from the server ... */
515 unsigned long t_close; /* total session duration */
516 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100517 char *cli_cookie; /* cookie presented by the client, in capture mode */
518 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100519 int status; /* HTTP status from the server, negative if from proxy */
520 long long bytes; /* number of bytes transferred from the server */
521 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100522 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100523};
524
willy tarreaua41a8b42005-12-17 14:02:24 +0100525struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100526 int fd; /* the listen socket */
527 struct sockaddr_storage addr; /* the address we listen to */
528 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100529};
530
531
willy tarreau0f7af912005-12-17 12:21:26 +0100532struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100533 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100534 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 +0100535 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100536 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100537 struct server *srv, *cursrv; /* known servers, current server */
538 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100539 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100540 int cookie_len; /* strlen(cookie_name), computed only once */
541 char *appsession_name; /* name of the cookie to look for */
542 int appsession_name_len; /* strlen(appsession_name), computed only once */
543 int appsession_len; /* length of the appsession cookie value to be used */
544 int appsession_timeout;
545 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100546 char *capture_name; /* beginning of the name of the cookie to capture */
547 int capture_namelen; /* length of the cookie name to match */
548 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100549 int clitimeout; /* client I/O timeout (in milliseconds) */
550 int srvtimeout; /* server I/O timeout (in milliseconds) */
551 int contimeout; /* connect timeout (in milliseconds) */
552 char *id; /* proxy id */
553 int nbconn; /* # of active sessions */
554 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100555 int conn_retries; /* maximum number of connect retries */
556 int options; /* PR_O_REDISP, PR_O_TRANSP */
557 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100558 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100559 struct proxy *next;
560 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100561 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100562 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100563 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100564 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100565 int nb_reqadd, nb_rspadd;
566 struct hdr_exp *req_exp; /* regular expressions for request headers */
567 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100568 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
569 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
570 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
571 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100572 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100573 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100574 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
575 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100576 struct {
577 char *msg400; /* message for error 400 */
578 int len400; /* message length for error 400 */
579 char *msg403; /* message for error 403 */
580 int len403; /* message length for error 403 */
581 char *msg408; /* message for error 408 */
582 int len408; /* message length for error 408 */
583 char *msg500; /* message for error 500 */
584 int len500; /* message length for error 500 */
585 char *msg502; /* message for error 502 */
586 int len502; /* message length for error 502 */
587 char *msg503; /* message for error 503 */
588 int len503; /* message length for error 503 */
589 char *msg504; /* message for error 504 */
590 int len504; /* message length for error 504 */
591 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100592};
593
594/* info about one given fd */
595struct fdtab {
596 int (*read)(int fd); /* read function */
597 int (*write)(int fd); /* write function */
598 struct task *owner; /* the session (or proxy) associated with this fd */
599 int state; /* the state of this fd */
600};
601
602/*********************************************************************/
603
willy tarreau0f7af912005-12-17 12:21:26 +0100604int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100605char *cfg_cfgfile = NULL; /* configuration file */
606char *progname = NULL; /* program name */
607int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100608
609/* global options */
610static struct {
611 int uid;
612 int gid;
613 int nbproc;
614 int maxconn;
615 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100616 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100617 int mode;
618 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100619 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100620 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100621 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100622 struct sockaddr_in logsrv1, logsrv2;
623} global = {
624 logfac1 : -1,
625 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100626 loglev1 : 7, /* max syslog level : debug */
627 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100628 /* others NULL OK */
629};
630
willy tarreau0f7af912005-12-17 12:21:26 +0100631/*********************************************************************/
632
willy tarreau1c2ad212005-12-18 01:11:29 +0100633fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100634 *StaticWriteEvent;
635
willy tarreau64a3cc32005-12-18 01:13:11 +0100636int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100637
willy tarreau0f7af912005-12-17 12:21:26 +0100638void **pool_session = NULL,
639 **pool_buffer = NULL,
640 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100641 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100642 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100643 **pool_capture = NULL,
644 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100645
646struct proxy *proxy = NULL; /* list of all existing proxies */
647struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100648struct task *rq = NULL; /* global run queue */
649struct task wait_queue = { /* global wait queue */
650 prev:LIST_HEAD(wait_queue),
651 next:LIST_HEAD(wait_queue)
652};
willy tarreau0f7af912005-12-17 12:21:26 +0100653
willy tarreau0f7af912005-12-17 12:21:26 +0100654static int totalconn = 0; /* total # of terminated sessions */
655static int actconn = 0; /* # of active sessions */
656static int maxfd = 0; /* # of the highest fd + 1 */
657static int listeners = 0; /* # of listeners */
658static int stopping = 0; /* non zero means stopping in progress */
659static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100660static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100661
willy tarreau08dedbe2005-12-18 01:13:48 +0100662#if defined(ENABLE_EPOLL)
663/* FIXME: this is dirty, but at the moment, there's no other solution to remove
664 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
665 * structure with pointers to functions such as init_fd() and close_fd(), plus
666 * a private structure with several pointers to places such as below.
667 */
668
669static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
670#endif
671
willy tarreau0f7af912005-12-17 12:21:26 +0100672static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100673/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100674static char trash[BUFSIZE];
675
willy tarreaudd07e972005-12-18 00:48:48 +0100676const int zero = 0;
677const int one = 1;
678
willy tarreau0f7af912005-12-17 12:21:26 +0100679/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100680 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100681 */
682
683#define MAX_SYSLOG_LEN 1024
684#define NB_LOG_FACILITIES 24
685const char *log_facilities[NB_LOG_FACILITIES] = {
686 "kern", "user", "mail", "daemon",
687 "auth", "syslog", "lpr", "news",
688 "uucp", "cron", "auth2", "ftp",
689 "ntp", "audit", "alert", "cron2",
690 "local0", "local1", "local2", "local3",
691 "local4", "local5", "local6", "local7"
692};
693
694
695#define NB_LOG_LEVELS 8
696const char *log_levels[NB_LOG_LEVELS] = {
697 "emerg", "alert", "crit", "err",
698 "warning", "notice", "info", "debug"
699};
700
701#define SYSLOG_PORT 514
702
703const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
704 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100705
willy tarreaub1285d52005-12-18 01:20:14 +0100706const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100707const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
708const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
709const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
710 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
711 unknown, Set-cookie Rewritten */
712
willy tarreau0f7af912005-12-17 12:21:26 +0100713#define MAX_HOSTNAME_LEN 32
714static char hostname[MAX_HOSTNAME_LEN] = "";
715
willy tarreau8337c6b2005-12-17 13:41:01 +0100716const char *HTTP_302 =
717 "HTTP/1.0 302 Found\r\n"
718 "Cache-Control: no-cache\r\n"
719 "Connection: close\r\n"
720 "Location: "; /* not terminated since it will be concatenated with the URL */
721
willy tarreauc1f47532005-12-18 01:08:26 +0100722/* same as 302 except that the browser MUST retry with the GET method */
723const char *HTTP_303 =
724 "HTTP/1.0 303 See Other\r\n"
725 "Cache-Control: no-cache\r\n"
726 "Connection: close\r\n"
727 "Location: "; /* not terminated since it will be concatenated with the URL */
728
willy tarreaua1598082005-12-17 13:08:06 +0100729const char *HTTP_400 =
730 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100731 "Cache-Control: no-cache\r\n"
732 "Connection: close\r\n"
733 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100734 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100735
willy tarreaua1598082005-12-17 13:08:06 +0100736const char *HTTP_403 =
737 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100738 "Cache-Control: no-cache\r\n"
739 "Connection: close\r\n"
740 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100741 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
742
willy tarreau8337c6b2005-12-17 13:41:01 +0100743const char *HTTP_408 =
744 "HTTP/1.0 408 Request Time-out\r\n"
745 "Cache-Control: no-cache\r\n"
746 "Connection: close\r\n"
747 "\r\n"
748 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
749
willy tarreau750a4722005-12-17 13:21:24 +0100750const char *HTTP_500 =
751 "HTTP/1.0 500 Server Error\r\n"
752 "Cache-Control: no-cache\r\n"
753 "Connection: close\r\n"
754 "\r\n"
755 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100756
757const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100758 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100759 "Cache-Control: no-cache\r\n"
760 "Connection: close\r\n"
761 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100762 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
763
764const char *HTTP_503 =
765 "HTTP/1.0 503 Service Unavailable\r\n"
766 "Cache-Control: no-cache\r\n"
767 "Connection: close\r\n"
768 "\r\n"
769 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
770
771const char *HTTP_504 =
772 "HTTP/1.0 504 Gateway Time-out\r\n"
773 "Cache-Control: no-cache\r\n"
774 "Connection: close\r\n"
775 "\r\n"
776 "<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 +0100777
willy tarreau0f7af912005-12-17 12:21:26 +0100778/*********************************************************************/
779/* statistics ******************************************************/
780/*********************************************************************/
781
willy tarreau750a4722005-12-17 13:21:24 +0100782#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100783static int stats_tsk_lsrch, stats_tsk_rsrch,
784 stats_tsk_good, stats_tsk_right, stats_tsk_left,
785 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100786#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100787
788
789/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100790/* debugging *******************************************************/
791/*********************************************************************/
792#ifdef DEBUG_FULL
793static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
794static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
795#endif
796
797/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100798/* function prototypes *********************************************/
799/*********************************************************************/
800
801int event_accept(int fd);
802int event_cli_read(int fd);
803int event_cli_write(int fd);
804int event_srv_read(int fd);
805int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100806int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100807
willy tarreau12350152005-12-18 01:03:27 +0100808static int appsession_task_init(void);
809static int appsession_init(void);
810static int appsession_refresh(struct task *t);
811
willy tarreau0f7af912005-12-17 12:21:26 +0100812/*********************************************************************/
813/* general purpose functions ***************************************/
814/*********************************************************************/
815
816void display_version() {
817 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100818 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100819}
820
821/*
822 * This function prints the command line usage and exits
823 */
824void usage(char *name) {
825 display_version();
826 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100827 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100828#if STATTIME > 0
829 "sl"
830#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100831 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100832 " -v displays version\n"
833 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100834 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100835#if STATTIME > 0
836 " -s enables statistics output\n"
837 " -l enables long statistics format\n"
838#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100839 " -D goes daemon ; implies -q\n"
840 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100841 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100842 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100843 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100844 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100845#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100846 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100847#endif
848#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100849 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100850#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100851 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100852 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100853 exit(1);
854}
855
856
857/*
858 * Displays the message on stderr with the date and pid.
859 */
860void Alert(char *fmt, ...) {
861 va_list argp;
862 struct timeval tv;
863 struct tm *tm;
864
willy tarreau982249e2005-12-18 00:57:06 +0100865 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100866 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100867
willy tarreau5cbea6f2005-12-17 12:48:26 +0100868 gettimeofday(&tv, NULL);
869 tm=localtime(&tv.tv_sec);
870 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100871 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100872 vfprintf(stderr, fmt, argp);
873 fflush(stderr);
874 va_end(argp);
875 }
willy tarreau0f7af912005-12-17 12:21:26 +0100876}
877
878
879/*
880 * Displays the message on stderr with the date and pid.
881 */
882void Warning(char *fmt, ...) {
883 va_list argp;
884 struct timeval tv;
885 struct tm *tm;
886
willy tarreau982249e2005-12-18 00:57:06 +0100887 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100888 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100889
willy tarreau5cbea6f2005-12-17 12:48:26 +0100890 gettimeofday(&tv, NULL);
891 tm=localtime(&tv.tv_sec);
892 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100893 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100894 vfprintf(stderr, fmt, argp);
895 fflush(stderr);
896 va_end(argp);
897 }
898}
899
900/*
901 * Displays the message on <out> only if quiet mode is not set.
902 */
903void qfprintf(FILE *out, char *fmt, ...) {
904 va_list argp;
905
willy tarreau982249e2005-12-18 00:57:06 +0100906 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100907 va_start(argp, fmt);
908 vfprintf(out, fmt, argp);
909 fflush(out);
910 va_end(argp);
911 }
willy tarreau0f7af912005-12-17 12:21:26 +0100912}
913
914
915/*
916 * converts <str> to a struct sockaddr_in* which is locally allocated.
917 * The format is "addr:port", where "addr" can be empty or "*" to indicate
918 * INADDR_ANY.
919 */
920struct sockaddr_in *str2sa(char *str) {
921 static struct sockaddr_in sa;
922 char *c;
923 int port;
924
willy tarreaua1598082005-12-17 13:08:06 +0100925 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100926 str=strdup(str);
927
928 if ((c=strrchr(str,':')) != NULL) {
929 *c++=0;
930 port=atol(c);
931 }
932 else
933 port=0;
934
935 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
936 sa.sin_addr.s_addr = INADDR_ANY;
937 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100938 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100939 struct hostent *he;
940
941 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100942 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100943 }
944 else
945 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
946 }
947 sa.sin_port=htons(port);
948 sa.sin_family=AF_INET;
949
950 free(str);
951 return &sa;
952}
953
willy tarreaub1285d52005-12-18 01:20:14 +0100954/*
955 * converts <str> to a two struct in_addr* which are locally allocated.
956 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
957 * is optionnal and either in the dotted or CIDR notation.
958 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
959 */
960int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
961 char *c;
962 unsigned long len;
963
964 memset(mask, 0, sizeof(*mask));
965 memset(addr, 0, sizeof(*addr));
966 str=strdup(str);
967
968 if ((c = strrchr(str, '/')) != NULL) {
969 *c++ = 0;
970 /* c points to the mask */
971 if (strchr(c, '.') != NULL) { /* dotted notation */
972 if (!inet_pton(AF_INET, c, mask))
973 return 0;
974 }
975 else { /* mask length */
976 char *err;
977 len = strtol(c, &err, 10);
978 if (!*c || (err && *err) || (unsigned)len > 32)
979 return 0;
980 if (len)
981 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
982 else
983 mask->s_addr = 0;
984 }
985 }
986 else {
987 mask->s_addr = 0xFFFFFFFF;
988 }
989 if (!inet_pton(AF_INET, str, addr)) {
990 struct hostent *he;
991
992 if ((he = gethostbyname(str)) == NULL) {
993 return 0;
994 }
995 else
996 *addr = *(struct in_addr *) *(he->h_addr_list);
997 }
998 free(str);
999 return 1;
1000}
1001
willy tarreau9fe663a2005-12-17 13:02:59 +01001002
1003/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001004 * converts <str> to a list of listeners which are dynamically allocated.
1005 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1006 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1007 * - <port> is a numerical port from 1 to 65535 ;
1008 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1009 * This can be repeated as many times as necessary, separated by a coma.
1010 * The <tail> argument is a pointer to a current list which should be appended
1011 * to the tail of the new list. The pointer to the new list is returned.
1012 */
1013struct listener *str2listener(char *str, struct listener *tail) {
1014 struct listener *l;
1015 char *c, *next, *range, *dupstr;
1016 int port, end;
1017
1018 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001019
willy tarreaua41a8b42005-12-17 14:02:24 +01001020 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001021 struct sockaddr_storage ss;
1022
willy tarreaua41a8b42005-12-17 14:02:24 +01001023 str = next;
1024 /* 1) look for the end of the first address */
1025 if ((next = strrchr(str, ',')) != NULL) {
1026 *next++ = 0;
1027 }
1028
willy tarreau8a86dbf2005-12-18 00:45:59 +01001029 /* 2) look for the addr/port delimiter, it's the last colon. */
1030 if ((range = strrchr(str, ':')) == NULL) {
1031 Alert("Missing port number: '%s'\n", str);
1032 }
1033
1034 *range++ = 0;
1035
1036 if (strrchr(str, ':') != NULL) {
1037 /* IPv6 address contains ':' */
1038 memset(&ss, 0, sizeof(ss));
1039 ss.ss_family = AF_INET6;
1040
1041 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1042 Alert("Invalid server address: '%s'\n", str);
1043 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001044 }
1045 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001046 memset(&ss, 0, sizeof(ss));
1047 ss.ss_family = AF_INET;
1048
1049 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1050 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1051 }
1052 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1053 struct hostent *he;
1054
1055 if ((he = gethostbyname(str)) == NULL) {
1056 Alert("Invalid server name: '%s'\n", str);
1057 }
1058 else
1059 ((struct sockaddr_in *)&ss)->sin_addr =
1060 *(struct in_addr *) *(he->h_addr_list);
1061 }
1062 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001063
1064 /* 3) look for the port-end delimiter */
1065 if ((c = strchr(range, '-')) != NULL) {
1066 *c++ = 0;
1067 end = atol(c);
1068 }
1069 else {
1070 end = atol(range);
1071 }
1072
1073 for (port = atol(range); port <= end; port++) {
1074 l = (struct listener *)calloc(1, sizeof(struct listener));
1075 l->next = tail;
1076 tail = l;
1077
willy tarreau8a86dbf2005-12-18 00:45:59 +01001078 l->addr = ss;
1079 if (ss.ss_family == AF_INET6)
1080 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1081 else
1082 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1083
willy tarreaua41a8b42005-12-17 14:02:24 +01001084 } /* end for(port) */
1085 } /* end while(next) */
1086 free(dupstr);
1087 return tail;
1088}
1089
willy tarreau4302f492005-12-18 01:00:37 +01001090
1091#define FD_SETS_ARE_BITFIELDS
1092#ifdef FD_SETS_ARE_BITFIELDS
1093/*
1094 * This map is used with all the FD_* macros to check whether a particular bit
1095 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1096 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1097 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1098 * exclusively to the macros.
1099 */
1100fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1101fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1102
1103#else
1104#error "Check if your OS uses bitfields for fd_sets"
1105#endif
1106
1107/* will try to encode the string <string> replacing all characters tagged in
1108 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1109 * prefixed by <escape>, and will store the result between <start> (included
1110 *) and <stop> (excluded), and will always terminate the string with a '\0'
1111 * before <stop>. The position of the '\0' is returned if the conversion
1112 * completes. If bytes are missing between <start> and <stop>, then the
1113 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1114 * cannot even be stored so we return <start> without writing the 0.
1115 * The input string must also be zero-terminated.
1116 */
1117char hextab[16] = "0123456789ABCDEF";
1118char *encode_string(char *start, char *stop,
1119 const char escape, const fd_set *map,
1120 const char *string)
1121{
1122 if (start < stop) {
1123 stop--; /* reserve one byte for the final '\0' */
1124 while (start < stop && *string != 0) {
1125 if (!FD_ISSET((unsigned char)(*string), map))
1126 *start++ = *string;
1127 else {
1128 if (start + 3 >= stop)
1129 break;
1130 *start++ = escape;
1131 *start++ = hextab[(*string >> 4) & 15];
1132 *start++ = hextab[*string & 15];
1133 }
1134 string++;
1135 }
1136 *start = '\0';
1137 }
1138 return start;
1139}
willy tarreaua41a8b42005-12-17 14:02:24 +01001140
1141/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001142 * This function sends a syslog message to both log servers of a proxy,
1143 * or to global log servers if the proxy is NULL.
1144 * It also tries not to waste too much time computing the message header.
1145 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001146 */
1147void send_log(struct proxy *p, int level, char *message, ...) {
1148 static int logfd = -1; /* syslog UDP socket */
1149 static long tvsec = -1; /* to force the string to be initialized */
1150 struct timeval tv;
1151 va_list argp;
1152 static char logmsg[MAX_SYSLOG_LEN];
1153 static char *dataptr = NULL;
1154 int fac_level;
1155 int hdr_len, data_len;
1156 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001157 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001158 int nbloggers = 0;
1159 char *log_ptr;
1160
1161 if (logfd < 0) {
1162 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1163 return;
1164 }
1165
1166 if (level < 0 || progname == NULL || message == NULL)
1167 return;
1168
1169 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001170 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001171 /* this string is rebuild only once a second */
1172 struct tm *tm = localtime(&tv.tv_sec);
1173 tvsec = tv.tv_sec;
1174
willy tarreauc29948c2005-12-17 13:10:27 +01001175 hdr_len = snprintf(logmsg, sizeof(logmsg),
1176 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1177 monthname[tm->tm_mon],
1178 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1179 progname, pid);
1180 /* WARNING: depending upon implementations, snprintf may return
1181 * either -1 or the number of bytes that would be needed to store
1182 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001183 */
willy tarreauc29948c2005-12-17 13:10:27 +01001184 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1185 hdr_len = sizeof(logmsg);
1186
1187 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001188 }
1189
1190 va_start(argp, message);
1191 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001192 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1193 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001194 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001195 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001196
1197 if (p == NULL) {
1198 if (global.logfac1 >= 0) {
1199 sa[nbloggers] = &global.logsrv1;
1200 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001201 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001202 nbloggers++;
1203 }
1204 if (global.logfac2 >= 0) {
1205 sa[nbloggers] = &global.logsrv2;
1206 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001207 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001208 nbloggers++;
1209 }
1210 } else {
1211 if (p->logfac1 >= 0) {
1212 sa[nbloggers] = &p->logsrv1;
1213 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001214 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001215 nbloggers++;
1216 }
1217 if (p->logfac2 >= 0) {
1218 sa[nbloggers] = &p->logsrv2;
1219 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001220 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001221 nbloggers++;
1222 }
1223 }
1224
1225 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001226 /* we can filter the level of the messages that are sent to each logger */
1227 if (level > loglevel[nbloggers])
1228 continue;
1229
willy tarreauc29948c2005-12-17 13:10:27 +01001230 /* For each target, we may have a different facility.
1231 * We can also have a different log level for each message.
1232 * This induces variations in the message header length.
1233 * Since we don't want to recompute it each time, nor copy it every
1234 * time, we only change the facility in the pre-computed header,
1235 * and we change the pointer to the header accordingly.
1236 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001237 fac_level = (facilities[nbloggers] << 3) + level;
1238 log_ptr = logmsg + 3; /* last digit of the log level */
1239 do {
1240 *log_ptr = '0' + fac_level % 10;
1241 fac_level /= 10;
1242 log_ptr--;
1243 } while (fac_level && log_ptr > logmsg);
1244 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001245
willy tarreauc29948c2005-12-17 13:10:27 +01001246 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001247
1248#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001249 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001250 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1251#else
willy tarreauc29948c2005-12-17 13:10:27 +01001252 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001253 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1254#endif
1255 }
willy tarreau0f7af912005-12-17 12:21:26 +01001256}
1257
1258
1259/* sets <tv> to the current time */
1260static inline struct timeval *tv_now(struct timeval *tv) {
1261 if (tv)
1262 gettimeofday(tv, NULL);
1263 return tv;
1264}
1265
1266/*
1267 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1268 */
1269static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1270 if (!tv || !from)
1271 return NULL;
1272 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1273 tv->tv_sec = from->tv_sec + (ms/1000);
1274 while (tv->tv_usec >= 1000000) {
1275 tv->tv_usec -= 1000000;
1276 tv->tv_sec++;
1277 }
1278 return tv;
1279}
1280
1281/*
1282 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1283 */
1284static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001285 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001286 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001287 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001288 return 1;
1289 else if (tv1->tv_usec < tv2->tv_usec)
1290 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001291 else if (tv1->tv_usec > tv2->tv_usec)
1292 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001293 else
1294 return 0;
1295}
1296
1297/*
1298 * returns the absolute difference, in ms, between tv1 and tv2
1299 */
1300unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1301 int cmp;
1302 unsigned long ret;
1303
1304
willy tarreauef900ab2005-12-17 12:52:52 +01001305 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001306 if (!cmp)
1307 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001308 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001309 struct timeval *tmp = tv1;
1310 tv1 = tv2;
1311 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001312 }
willy tarreauef900ab2005-12-17 12:52:52 +01001313 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001314 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001315 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001316 else
willy tarreauef900ab2005-12-17 12:52:52 +01001317 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001318 return (unsigned long) ret;
1319}
1320
1321/*
willy tarreau750a4722005-12-17 13:21:24 +01001322 * returns the difference, in ms, between tv1 and tv2
1323 */
1324static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1325 unsigned long ret;
1326
willy tarreau6e682ce2005-12-17 13:26:49 +01001327 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1328 if (tv2->tv_usec > tv1->tv_usec)
1329 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001330 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001331 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001332 return (unsigned long) ret;
1333}
1334
1335/*
willy tarreau0f7af912005-12-17 12:21:26 +01001336 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1337 */
1338static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001339 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001340 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001341 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001342 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1343 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001344 else
1345 return 0;
1346 }
willy tarreau0f7af912005-12-17 12:21:26 +01001347 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001348 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001349 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001350 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1351 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1352 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001353 else
1354 return 0;
1355}
1356
1357/*
1358 * returns the remaining time between tv1=now and event=tv2
1359 * if tv2 is passed, 0 is returned.
1360 */
1361static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1362 unsigned long ret;
1363
willy tarreau0f7af912005-12-17 12:21:26 +01001364 if (tv_cmp_ms(tv1, tv2) >= 0)
1365 return 0; /* event elapsed */
1366
willy tarreauef900ab2005-12-17 12:52:52 +01001367 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001368 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001369 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001370 else
willy tarreauef900ab2005-12-17 12:52:52 +01001371 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 return (unsigned long) ret;
1373}
1374
1375
1376/*
1377 * zeroes a struct timeval
1378 */
1379
1380static inline struct timeval *tv_eternity(struct timeval *tv) {
1381 tv->tv_sec = tv->tv_usec = 0;
1382 return tv;
1383}
1384
1385/*
1386 * returns 1 if tv is null, else 0
1387 */
1388static inline int tv_iseternity(struct timeval *tv) {
1389 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1390 return 1;
1391 else
1392 return 0;
1393}
1394
1395/*
1396 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1397 * considering that 0 is the eternity.
1398 */
1399static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1400 if (tv_iseternity(tv1))
1401 if (tv_iseternity(tv2))
1402 return 0; /* same */
1403 else
1404 return 1; /* tv1 later than tv2 */
1405 else if (tv_iseternity(tv2))
1406 return -1; /* tv2 later than tv1 */
1407
1408 if (tv1->tv_sec > tv2->tv_sec)
1409 return 1;
1410 else if (tv1->tv_sec < tv2->tv_sec)
1411 return -1;
1412 else if (tv1->tv_usec > tv2->tv_usec)
1413 return 1;
1414 else if (tv1->tv_usec < tv2->tv_usec)
1415 return -1;
1416 else
1417 return 0;
1418}
1419
1420/*
1421 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1422 * considering that 0 is the eternity.
1423 */
1424static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1425 if (tv_iseternity(tv1))
1426 if (tv_iseternity(tv2))
1427 return 0; /* same */
1428 else
1429 return 1; /* tv1 later than tv2 */
1430 else if (tv_iseternity(tv2))
1431 return -1; /* tv2 later than tv1 */
1432
willy tarreauefae1842005-12-17 12:51:03 +01001433 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001434 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001435 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001436 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001437 return -1;
1438 else
1439 return 0;
1440 }
1441 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001442 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001443 return 1;
1444 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001445 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001446 return -1;
1447 else
1448 return 0;
1449}
1450
1451/*
1452 * returns the first event between tv1 and tv2 into tvmin.
1453 * a zero tv is ignored. tvmin is returned.
1454 */
1455static inline struct timeval *tv_min(struct timeval *tvmin,
1456 struct timeval *tv1, struct timeval *tv2) {
1457
1458 if (tv_cmp2(tv1, tv2) <= 0)
1459 *tvmin = *tv1;
1460 else
1461 *tvmin = *tv2;
1462
1463 return tvmin;
1464}
1465
1466
1467
1468/***********************************************************/
1469/* fd management ***************************************/
1470/***********************************************************/
1471
1472
1473
willy tarreau5cbea6f2005-12-17 12:48:26 +01001474/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1475 * The file descriptor is also closed.
1476 */
willy tarreau0f7af912005-12-17 12:21:26 +01001477static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001478 FD_CLR(fd, StaticReadEvent);
1479 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001480#if defined(ENABLE_EPOLL)
1481 if (PrevReadEvent) {
1482 FD_CLR(fd, PrevReadEvent);
1483 FD_CLR(fd, PrevWriteEvent);
1484 }
1485#endif
1486
willy tarreau5cbea6f2005-12-17 12:48:26 +01001487 close(fd);
1488 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001489
1490 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1491 maxfd--;
1492}
1493
1494/* recomputes the maxfd limit from the fd */
1495static inline void fd_insert(int fd) {
1496 if (fd+1 > maxfd)
1497 maxfd = fd+1;
1498}
1499
1500/*************************************************************/
1501/* task management ***************************************/
1502/*************************************************************/
1503
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504/* puts the task <t> in run queue <q>, and returns <t> */
1505static inline struct task *task_wakeup(struct task **q, struct task *t) {
1506 if (t->state == TASK_RUNNING)
1507 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001508 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001509 t->rqnext = *q;
1510 t->state = TASK_RUNNING;
1511 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001512 }
1513}
1514
willy tarreau5cbea6f2005-12-17 12:48:26 +01001515/* removes the task <t> from the queue <q>
1516 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001517 * set the run queue to point to the next one, and return it
1518 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001519static inline struct task *task_sleep(struct task **q, struct task *t) {
1520 if (t->state == TASK_RUNNING) {
1521 *q = t->rqnext;
1522 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001523 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001524 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001525}
1526
1527/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001528 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001529 * from the run queue. A pointer to the task itself is returned.
1530 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001531static inline struct task *task_delete(struct task *t) {
1532 t->prev->next = t->next;
1533 t->next->prev = t->prev;
1534 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001535}
1536
1537/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001538 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001539 */
1540static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001542}
1543
willy tarreau5cbea6f2005-12-17 12:48:26 +01001544/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001545 * may be only moved or left where it was, depending on its timing requirements.
1546 * <task> is returned.
1547 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001548struct task *task_queue(struct task *task) {
1549 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001550 struct task *start_from;
1551
1552 /* first, test if the task was already in a list */
1553 if (task->prev == NULL) {
1554 // start_from = list;
1555 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001556#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001557 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001558#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001559 /* insert the unlinked <task> into the list, searching back from the last entry */
1560 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1561 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001562#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001563 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001564#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001565 }
1566
1567 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1568 // start_from = start_from->next;
1569 // stats_tsk_nsrch++;
1570 // }
1571 }
1572 else if (task->prev == list ||
1573 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1574 start_from = task->next;
1575 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001576#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001577 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001578#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001579 return task; /* it's already in the right place */
1580 }
1581
willy tarreau750a4722005-12-17 13:21:24 +01001582#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001583 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001584#endif
1585
1586 /* if the task is not at the right place, there's little chance that
1587 * it has only shifted a bit, and it will nearly always be queued
1588 * at the end of the list because of constant timeouts
1589 * (observed in real case).
1590 */
1591#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1592 start_from = list->prev; /* assume we'll queue to the end of the list */
1593 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1594 start_from = start_from->prev;
1595#if STATTIME > 0
1596 stats_tsk_lsrch++;
1597#endif
1598 }
1599#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001600 /* insert the unlinked <task> into the list, searching after position <start_from> */
1601 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1602 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001603#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001604 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001605#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001606 }
willy tarreau750a4722005-12-17 13:21:24 +01001607#endif /* WE_REALLY_... */
1608
willy tarreau0f7af912005-12-17 12:21:26 +01001609 /* we need to unlink it now */
1610 task_delete(task);
1611 }
1612 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001613#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001614 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001615#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001616#ifdef LEFT_TO_TOP /* not very good */
1617 start_from = list;
1618 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1619 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001620#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001621 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001622#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001623 }
1624#else
1625 start_from = task->prev->prev; /* valid because of the previous test above */
1626 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1627 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001628#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001629 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001630#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001631 }
1632#endif
1633 /* we need to unlink it now */
1634 task_delete(task);
1635 }
1636 task->prev = start_from;
1637 task->next = start_from->next;
1638 task->next->prev = task;
1639 start_from->next = task;
1640 return task;
1641}
1642
1643
1644/*********************************************************************/
1645/* more specific functions ***************************************/
1646/*********************************************************************/
1647
1648/* some prototypes */
1649static int maintain_proxies(void);
1650
willy tarreau5cbea6f2005-12-17 12:48:26 +01001651/* this either returns the sockname or the original destination address. Code
1652 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1653 */
1654static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001655#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1657#else
willy tarreaua1598082005-12-17 13:08:06 +01001658#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001659 return getsockname(fd, (struct sockaddr *)sa, salen);
1660#else
1661 return -1;
1662#endif
1663#endif
1664}
1665
1666/*
1667 * frees the context associated to a session. It must have been removed first.
1668 */
1669static inline void session_free(struct session *s) {
1670 if (s->req)
1671 pool_free(buffer, s->req);
1672 if (s->rep)
1673 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001674
1675 if (s->rsp_cap != NULL) {
1676 struct cap_hdr *h;
1677 for (h = s->proxy->rsp_cap; h; h = h->next) {
1678 if (s->rsp_cap[h->index] != NULL)
1679 pool_free_to(h->pool, s->rsp_cap[h->index]);
1680 }
1681 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1682 }
1683 if (s->req_cap != NULL) {
1684 struct cap_hdr *h;
1685 for (h = s->proxy->req_cap; h; h = h->next) {
1686 if (s->req_cap[h->index] != NULL)
1687 pool_free_to(h->pool, s->req_cap[h->index]);
1688 }
1689 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1690 }
1691
willy tarreaua1598082005-12-17 13:08:06 +01001692 if (s->logs.uri)
1693 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001694 if (s->logs.cli_cookie)
1695 pool_free(capture, s->logs.cli_cookie);
1696 if (s->logs.srv_cookie)
1697 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001698
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699 pool_free(session, s);
1700}
1701
willy tarreau0f7af912005-12-17 12:21:26 +01001702
1703/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001704 * This function tries to find a running server for the proxy <px>. A first
1705 * pass looks for active servers, and if none is found, a second pass also
1706 * looks for backup servers.
1707 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1708 */
1709static inline struct server *find_server(struct proxy *px) {
1710 struct server *srv = px->cursrv;
1711 int ignore_backup = 1;
1712
1713 do {
1714 do {
1715 if (srv == NULL)
1716 srv = px->srv;
1717 if (srv->state & SRV_RUNNING
1718 && !((srv->state & SRV_BACKUP) && ignore_backup))
1719 return srv;
1720 srv = srv->next;
1721 } while (srv != px->cursrv);
1722 } while (ignore_backup--);
1723 return NULL;
1724}
1725
1726/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001727 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001728 * is set, or to the dispatch server if (s->direct) is 0.
1729 * It can return one of :
1730 * - SN_ERR_NONE if everything's OK
1731 * - SN_ERR_SRVTO if there are no more servers
1732 * - SN_ERR_SRVCL if the connection was refused by the server
1733 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1734 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1735 * - SN_ERR_INTERNAL for any other purely internal errors
1736 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001737 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001738int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001739 int fd;
1740
willy tarreau12350152005-12-18 01:03:27 +01001741#ifdef DEBUG_FULL
1742 fprintf(stderr,"connect_server : s=%p\n",s);
1743#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001744
willy tarreaue39cd132005-12-17 13:00:18 +01001745 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001746 s->srv_addr = s->srv->addr;
1747 }
1748 else if (s->proxy->options & PR_O_BALANCE) {
1749 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001750 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001751
willy tarreau8337c6b2005-12-17 13:41:01 +01001752 srv = find_server(s->proxy);
1753
1754 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001755 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001756
willy tarreau8337c6b2005-12-17 13:41:01 +01001757 s->srv_addr = srv->addr;
1758 s->srv = srv;
1759 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001760 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001761 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001762 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001763 }
willy tarreaua1598082005-12-17 13:08:06 +01001764 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001765 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001766 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001767 }
1768 else if (s->proxy->options & PR_O_TRANSP) {
1769 /* in transparent mode, use the original dest addr if no dispatch specified */
1770 int salen = sizeof(struct sockaddr_in);
1771 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1772 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001773 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774 }
1775 }
willy tarreau0f7af912005-12-17 12:21:26 +01001776
willy tarreaua41a8b42005-12-17 14:02:24 +01001777 /* if this server remaps proxied ports, we'll use
1778 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001779 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001780 struct sockaddr_in sockname;
1781 int namelen;
1782
1783 namelen = sizeof(sockname);
1784 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1785 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1786 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1787 }
1788
willy tarreau0f7af912005-12-17 12:21:26 +01001789 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001790 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001791
1792 if (errno == ENFILE)
1793 send_log(s->proxy, LOG_EMERG,
1794 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1795 s->proxy->id, maxfd);
1796 else if (errno == EMFILE)
1797 send_log(s->proxy, LOG_EMERG,
1798 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1799 s->proxy->id, maxfd);
1800 else if (errno == ENOBUFS || errno == ENOMEM)
1801 send_log(s->proxy, LOG_EMERG,
1802 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1803 s->proxy->id, maxfd);
1804 /* this is a resource error */
1805 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001806 }
1807
willy tarreau9fe663a2005-12-17 13:02:59 +01001808 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001809 /* do not log anything there, it's a normal condition when this option
1810 * is used to serialize connections to a server !
1811 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001812 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1813 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001814 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001815 }
1816
willy tarreau0f7af912005-12-17 12:21:26 +01001817 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1818 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001820 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001821 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001822 }
1823
willy tarreau0174f312005-12-18 01:02:42 +01001824 /* allow specific binding :
1825 * - server-specific at first
1826 * - proxy-specific next
1827 */
1828 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1829 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1830 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1831 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1832 s->proxy->id, s->srv->id);
1833 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001834 send_log(s->proxy, LOG_EMERG,
1835 "Cannot bind to source address before connect() for server %s/%s.\n",
1836 s->proxy->id, s->srv->id);
1837 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001838 }
1839 }
1840 else if (s->proxy->options & PR_O_BIND_SRC) {
1841 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1842 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1843 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1844 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001845 send_log(s->proxy, LOG_EMERG,
1846 "Cannot bind to source address before connect() for server %s/%s.\n",
1847 s->proxy->id, s->srv->id);
1848 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001849 }
willy tarreaua1598082005-12-17 13:08:06 +01001850 }
1851
willy tarreaub1285d52005-12-18 01:20:14 +01001852 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1853 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1854
1855 if (errno == EAGAIN || errno == EADDRINUSE) {
1856 char *msg;
1857 if (errno == EAGAIN) /* no free ports left, try again later */
1858 msg = "no free ports";
1859 else
1860 msg = "local address already in use";
1861
1862 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001863 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001864 send_log(s->proxy, LOG_EMERG,
1865 "Connect() failed for server %s/%s: %s.\n",
1866 s->proxy->id, s->srv->id, msg);
1867 return SN_ERR_RESOURCE;
1868 } else if (errno == ETIMEDOUT) {
willy tarreau0f7af912005-12-17 12:21:26 +01001869 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001870 return SN_ERR_SRVTO;
1871 } else {
1872 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
1873 close(fd);
1874 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001875 }
1876 }
1877
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001879 fdtab[fd].read = &event_srv_read;
1880 fdtab[fd].write = &event_srv_write;
1881 fdtab[fd].state = FD_STCONN; /* connection in progress */
1882
1883 FD_SET(fd, StaticWriteEvent); /* for connect status */
1884
1885 fd_insert(fd);
1886
1887 if (s->proxy->contimeout)
1888 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1889 else
1890 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001891 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001892}
1893
1894/*
1895 * this function is called on a read event from a client socket.
1896 * It returns 0.
1897 */
1898int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 struct task *t = fdtab[fd].owner;
1900 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001901 struct buffer *b = s->req;
1902 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001903
willy tarreau12350152005-12-18 01:03:27 +01001904#ifdef DEBUG_FULL
1905 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1906#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001907
willy tarreau0f7af912005-12-17 12:21:26 +01001908 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001909#ifdef FILL_BUFFERS
1910 while (1)
1911#else
1912 do
1913#endif
1914 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001915 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1916 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001917 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001918 }
1919 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001920 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001921 }
1922 else {
1923 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001924 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1925 * since it means that the rewrite protection has been removed. This
1926 * implies that the if statement can be removed.
1927 */
1928 if (max > b->rlim - b->data)
1929 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001930 }
1931
1932 if (max == 0) { /* not anymore room to store data */
1933 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001934 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001935 }
1936
willy tarreau3242e862005-12-17 12:27:53 +01001937#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001938 {
1939 int skerr, lskerr;
1940
1941 lskerr = sizeof(skerr);
1942 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1943 if (skerr)
1944 ret = -1;
1945 else
1946 ret = recv(fd, b->r, max, 0);
1947 }
willy tarreau3242e862005-12-17 12:27:53 +01001948#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001949 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001950#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001951 if (ret > 0) {
1952 b->r += ret;
1953 b->l += ret;
1954 s->res_cr = RES_DATA;
1955
1956 if (b->r == b->data + BUFSIZE) {
1957 b->r = b->data; /* wrap around the buffer */
1958 }
willy tarreaua1598082005-12-17 13:08:06 +01001959
1960 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001961 /* we hope to read more data or to get a close on next round */
1962 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001963 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001964 else if (ret == 0) {
1965 s->res_cr = RES_NULL;
1966 break;
1967 }
1968 else if (errno == EAGAIN) {/* ignore EAGAIN */
1969 break;
1970 }
1971 else {
1972 s->res_cr = RES_ERROR;
1973 fdtab[fd].state = FD_STERROR;
1974 break;
1975 }
1976 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01001977#ifndef FILL_BUFFERS
1978 while (0);
1979#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001980 }
1981 else {
1982 s->res_cr = RES_ERROR;
1983 fdtab[fd].state = FD_STERROR;
1984 }
1985
willy tarreau5cbea6f2005-12-17 12:48:26 +01001986 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001987 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001988 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1989 else
1990 tv_eternity(&s->crexpire);
1991
1992 task_wakeup(&rq, t);
1993 }
willy tarreau0f7af912005-12-17 12:21:26 +01001994
willy tarreau0f7af912005-12-17 12:21:26 +01001995 return 0;
1996}
1997
1998
1999/*
2000 * this function is called on a read event from a server socket.
2001 * It returns 0.
2002 */
2003int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 struct task *t = fdtab[fd].owner;
2005 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002006 struct buffer *b = s->rep;
2007 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002008
willy tarreau12350152005-12-18 01:03:27 +01002009#ifdef DEBUG_FULL
2010 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2011#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002012
willy tarreau0f7af912005-12-17 12:21:26 +01002013 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002014#ifdef FILL_BUFFERS
2015 while (1)
2016#else
2017 do
2018#endif
2019 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002020 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2021 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002022 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002023 }
2024 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002025 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002026 }
2027 else {
2028 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002029 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2030 * since it means that the rewrite protection has been removed. This
2031 * implies that the if statement can be removed.
2032 */
2033 if (max > b->rlim - b->data)
2034 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002035 }
2036
2037 if (max == 0) { /* not anymore room to store data */
2038 FD_CLR(fd, StaticReadEvent);
2039 break;
2040 }
2041
willy tarreau3242e862005-12-17 12:27:53 +01002042#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002043 {
2044 int skerr, lskerr;
2045
2046 lskerr = sizeof(skerr);
2047 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2048 if (skerr)
2049 ret = -1;
2050 else
2051 ret = recv(fd, b->r, max, 0);
2052 }
willy tarreau3242e862005-12-17 12:27:53 +01002053#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002054 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002055#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002056 if (ret > 0) {
2057 b->r += ret;
2058 b->l += ret;
2059 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002060
willy tarreau5cbea6f2005-12-17 12:48:26 +01002061 if (b->r == b->data + BUFSIZE) {
2062 b->r = b->data; /* wrap around the buffer */
2063 }
willy tarreaua1598082005-12-17 13:08:06 +01002064
2065 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002066 /* we hope to read more data or to get a close on next round */
2067 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002068 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002069 else if (ret == 0) {
2070 s->res_sr = RES_NULL;
2071 break;
2072 }
2073 else if (errno == EAGAIN) {/* ignore EAGAIN */
2074 break;
2075 }
2076 else {
2077 s->res_sr = RES_ERROR;
2078 fdtab[fd].state = FD_STERROR;
2079 break;
2080 }
2081 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002082#ifndef FILL_BUFFERS
2083 while (0);
2084#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002085 }
2086 else {
2087 s->res_sr = RES_ERROR;
2088 fdtab[fd].state = FD_STERROR;
2089 }
2090
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002092 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002093 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2094 else
2095 tv_eternity(&s->srexpire);
2096
2097 task_wakeup(&rq, t);
2098 }
willy tarreau0f7af912005-12-17 12:21:26 +01002099
willy tarreau0f7af912005-12-17 12:21:26 +01002100 return 0;
2101}
2102
2103/*
2104 * this function is called on a write event from a client socket.
2105 * It returns 0.
2106 */
2107int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002108 struct task *t = fdtab[fd].owner;
2109 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002110 struct buffer *b = s->rep;
2111 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002112
willy tarreau12350152005-12-18 01:03:27 +01002113#ifdef DEBUG_FULL
2114 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2115#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002116
2117 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002118 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002119 // max = BUFSIZE; BUG !!!!
2120 max = 0;
2121 }
2122 else if (b->r > b->w) {
2123 max = b->r - b->w;
2124 }
2125 else
2126 max = b->data + BUFSIZE - b->w;
2127
willy tarreau0f7af912005-12-17 12:21:26 +01002128 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002129#ifndef MSG_NOSIGNAL
2130 int skerr, lskerr;
2131#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002132
2133 if (max == 0) {
2134 s->res_cw = RES_NULL;
2135 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002136 tv_eternity(&s->cwexpire);
2137 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002138 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002139 }
2140
willy tarreau3242e862005-12-17 12:27:53 +01002141#ifndef MSG_NOSIGNAL
2142 lskerr=sizeof(skerr);
2143 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2144 if (skerr)
2145 ret = -1;
2146 else
2147 ret = send(fd, b->w, max, MSG_DONTWAIT);
2148#else
willy tarreau0f7af912005-12-17 12:21:26 +01002149 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002150#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002151
2152 if (ret > 0) {
2153 b->l -= ret;
2154 b->w += ret;
2155
2156 s->res_cw = RES_DATA;
2157
2158 if (b->w == b->data + BUFSIZE) {
2159 b->w = b->data; /* wrap around the buffer */
2160 }
2161 }
2162 else if (ret == 0) {
2163 /* nothing written, just make as if we were never called */
2164// s->res_cw = RES_NULL;
2165 return 0;
2166 }
2167 else if (errno == EAGAIN) /* ignore EAGAIN */
2168 return 0;
2169 else {
2170 s->res_cw = RES_ERROR;
2171 fdtab[fd].state = FD_STERROR;
2172 }
2173 }
2174 else {
2175 s->res_cw = RES_ERROR;
2176 fdtab[fd].state = FD_STERROR;
2177 }
2178
willy tarreaub1ff9db2005-12-17 13:51:03 +01002179 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002180 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002181 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2182 s->crexpire = s->cwexpire;
2183 }
willy tarreau0f7af912005-12-17 12:21:26 +01002184 else
2185 tv_eternity(&s->cwexpire);
2186
willy tarreau5cbea6f2005-12-17 12:48:26 +01002187 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002188 return 0;
2189}
2190
2191
2192/*
2193 * this function is called on a write event from a server socket.
2194 * It returns 0.
2195 */
2196int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002197 struct task *t = fdtab[fd].owner;
2198 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002199 struct buffer *b = s->req;
2200 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002201
willy tarreau12350152005-12-18 01:03:27 +01002202#ifdef DEBUG_FULL
2203 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2204#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002205
2206 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002207 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002208 // max = BUFSIZE; BUG !!!!
2209 max = 0;
2210 }
2211 else if (b->r > b->w) {
2212 max = b->r - b->w;
2213 }
2214 else
2215 max = b->data + BUFSIZE - b->w;
2216
willy tarreau0f7af912005-12-17 12:21:26 +01002217 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002218#ifndef MSG_NOSIGNAL
2219 int skerr, lskerr;
2220#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002221 if (max == 0) {
2222 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002223 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002224 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002225 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002226 tv_eternity(&s->swexpire);
2227 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002228 return 0;
2229 }
2230
willy tarreauef900ab2005-12-17 12:52:52 +01002231
willy tarreau3242e862005-12-17 12:27:53 +01002232#ifndef MSG_NOSIGNAL
2233 lskerr=sizeof(skerr);
2234 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2235 if (skerr)
2236 ret = -1;
2237 else
2238 ret = send(fd, b->w, max, MSG_DONTWAIT);
2239#else
willy tarreau0f7af912005-12-17 12:21:26 +01002240 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002241#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002242 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002243 if (ret > 0) {
2244 b->l -= ret;
2245 b->w += ret;
2246
2247 s->res_sw = RES_DATA;
2248
2249 if (b->w == b->data + BUFSIZE) {
2250 b->w = b->data; /* wrap around the buffer */
2251 }
2252 }
2253 else if (ret == 0) {
2254 /* nothing written, just make as if we were never called */
2255 // s->res_sw = RES_NULL;
2256 return 0;
2257 }
2258 else if (errno == EAGAIN) /* ignore EAGAIN */
2259 return 0;
2260 else {
2261 s->res_sw = RES_ERROR;
2262 fdtab[fd].state = FD_STERROR;
2263 }
2264 }
2265 else {
2266 s->res_sw = RES_ERROR;
2267 fdtab[fd].state = FD_STERROR;
2268 }
2269
willy tarreaub1ff9db2005-12-17 13:51:03 +01002270 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002271 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002272 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2273 s->srexpire = s->swexpire;
2274 }
willy tarreau0f7af912005-12-17 12:21:26 +01002275 else
2276 tv_eternity(&s->swexpire);
2277
willy tarreau5cbea6f2005-12-17 12:48:26 +01002278 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002279 return 0;
2280}
2281
2282
2283/*
willy tarreaue39cd132005-12-17 13:00:18 +01002284 * returns a message to the client ; the connection is shut down for read,
2285 * and the request is cleared so that no server connection can be initiated.
2286 * The client must be in a valid state for this (HEADER, DATA ...).
2287 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002288 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002289 */
2290void client_retnclose(struct session *s, int len, const char *msg) {
2291 FD_CLR(s->cli_fd, StaticReadEvent);
2292 FD_SET(s->cli_fd, StaticWriteEvent);
2293 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002294 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002295 shutdown(s->cli_fd, SHUT_RD);
2296 s->cli_state = CL_STSHUTR;
2297 strcpy(s->rep->data, msg);
2298 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002299 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002300 s->rep->r += len;
2301 s->req->l = 0;
2302}
2303
2304
2305/*
2306 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002307 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002308 */
2309void client_return(struct session *s, int len, const char *msg) {
2310 strcpy(s->rep->data, msg);
2311 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002312 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002313 s->rep->r += len;
2314 s->req->l = 0;
2315}
2316
willy tarreau9fe663a2005-12-17 13:02:59 +01002317/*
2318 * send a log for the session when we have enough info about it
2319 */
2320void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002321 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002322 struct proxy *p = s->proxy;
2323 int log;
2324 char *uri;
2325 char *pxid;
2326 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002327 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002328
2329 /* This is a first attempt at a better logging system.
2330 * For now, we rely on send_log() to provide the date, although it obviously
2331 * is the date of the log and not of the request, and most fields are not
2332 * computed.
2333 */
2334
willy tarreaua1598082005-12-17 13:08:06 +01002335 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002336
willy tarreau8a86dbf2005-12-18 00:45:59 +01002337 if (s->cli_addr.ss_family == AF_INET)
2338 inet_ntop(AF_INET,
2339 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2340 pn, sizeof(pn));
2341 else
2342 inet_ntop(AF_INET6,
2343 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2344 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002345
willy tarreauc1cae632005-12-17 14:12:23 +01002346 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002347 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002348 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002349
willy tarreauc1cae632005-12-17 14:12:23 +01002350 tm = localtime(&s->logs.tv_accept.tv_sec);
2351 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002352 char tmpline[MAX_SYSLOG_LEN], *h;
2353 int hdr;
2354
2355 h = tmpline;
2356 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2357 *(h++) = ' ';
2358 *(h++) = '{';
2359 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2360 if (hdr)
2361 *(h++) = '|';
2362 if (s->req_cap[hdr] != NULL)
2363 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2364 }
2365 *(h++) = '}';
2366 }
2367
2368 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2369 *(h++) = ' ';
2370 *(h++) = '{';
2371 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2372 if (hdr)
2373 *(h++) = '|';
2374 if (s->rsp_cap[hdr] != NULL)
2375 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2376 }
2377 *(h++) = '}';
2378 }
2379
2380 if (h < tmpline + sizeof(tmpline) - 4) {
2381 *(h++) = ' ';
2382 *(h++) = '"';
2383 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2384 *(h++) = '"';
2385 }
2386 *h = '\0';
2387
willy tarreau0fe39652005-12-18 01:25:24 +01002388 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 +01002389 pn,
2390 (s->cli_addr.ss_family == AF_INET) ?
2391 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2392 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002393 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2394 tm->tm_hour, tm->tm_min, tm->tm_sec,
2395 pxid, srv,
2396 s->logs.t_request,
2397 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2398 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002399 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2400 s->logs.status,
2401 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002402 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2403 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002404 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2405 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2406 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2407 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002408 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002409 }
2410 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002411 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 +01002412 pn,
2413 (s->cli_addr.ss_family == AF_INET) ?
2414 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2415 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002416 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2417 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002418 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002419 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002420 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2421 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002422 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002423 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2424 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002425 }
2426
2427 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002428}
2429
willy tarreaue39cd132005-12-17 13:00:18 +01002430
2431/*
willy tarreau0f7af912005-12-17 12:21:26 +01002432 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002433 * to an accept. It tries to accept as many connections as possible.
2434 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002435 */
2436int event_accept(int fd) {
2437 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002438 struct session *s;
2439 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002440 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002441
willy tarreau5cbea6f2005-12-17 12:48:26 +01002442 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002443 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002444 int laddr = sizeof(addr);
willy tarreaub1285d52005-12-18 01:20:14 +01002445 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2446 switch (errno) {
2447 case EAGAIN:
2448 case EINTR:
2449 case ECONNABORTED:
2450 return 0; /* nothing more to accept */
2451 case ENFILE:
2452 send_log(p, LOG_EMERG,
2453 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2454 p->id, maxfd);
2455 return 0;
2456 case EMFILE:
2457 send_log(p, LOG_EMERG,
2458 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2459 p->id, maxfd);
2460 return 0;
2461 case ENOBUFS:
2462 case ENOMEM:
2463 send_log(p, LOG_EMERG,
2464 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2465 p->id, maxfd);
2466 return 0;
2467 default:
2468 return 0;
2469 }
2470 }
willy tarreau0f7af912005-12-17 12:21:26 +01002471
willy tarreau5cbea6f2005-12-17 12:48:26 +01002472 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2473 Alert("out of memory in event_accept().\n");
2474 FD_CLR(fd, StaticReadEvent);
2475 p->state = PR_STIDLE;
2476 close(cfd);
2477 return 0;
2478 }
willy tarreau0f7af912005-12-17 12:21:26 +01002479
willy tarreaub1285d52005-12-18 01:20:14 +01002480 /* if this session comes from a known monitoring system, we want to ignore
2481 * it as soon as possible, which means closing it immediately for TCP.
2482 */
2483 s->flags = 0;
2484 if (addr.ss_family == AF_INET &&
2485 p->mon_mask.s_addr &&
2486 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2487 if (p->mode == PR_MODE_TCP) {
2488 close(cfd);
2489 pool_free(session, s);
2490 continue;
2491 }
2492 s->flags |= SN_MONITOR;
2493 }
2494
willy tarreau5cbea6f2005-12-17 12:48:26 +01002495 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2496 Alert("out of memory in event_accept().\n");
2497 FD_CLR(fd, StaticReadEvent);
2498 p->state = PR_STIDLE;
2499 close(cfd);
2500 pool_free(session, s);
2501 return 0;
2502 }
willy tarreau0f7af912005-12-17 12:21:26 +01002503
willy tarreau5cbea6f2005-12-17 12:48:26 +01002504 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002505 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2507 close(cfd);
2508 pool_free(task, t);
2509 pool_free(session, s);
2510 return 0;
2511 }
willy tarreau0f7af912005-12-17 12:21:26 +01002512
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2514 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2515 (char *) &one, sizeof(one)) == -1)) {
2516 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2517 close(cfd);
2518 pool_free(task, t);
2519 pool_free(session, s);
2520 return 0;
2521 }
willy tarreau0f7af912005-12-17 12:21:26 +01002522
willy tarreau9fe663a2005-12-17 13:02:59 +01002523 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2524 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2525 t->state = TASK_IDLE;
2526 t->process = process_session;
2527 t->context = s;
2528
2529 s->task = t;
2530 s->proxy = p;
2531 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2532 s->srv_state = SV_STIDLE;
2533 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002534
willy tarreau9fe663a2005-12-17 13:02:59 +01002535 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2536 s->cli_fd = cfd;
2537 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002538 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002539 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002540
willy tarreaub1285d52005-12-18 01:20:14 +01002541 if (s->flags & SN_MONITOR)
2542 s->logs.logwait = 0;
2543 else
2544 s->logs.logwait = p->to_log;
2545
willy tarreaua1598082005-12-17 13:08:06 +01002546 s->logs.tv_accept = now;
2547 s->logs.t_request = -1;
2548 s->logs.t_connect = -1;
2549 s->logs.t_data = -1;
2550 s->logs.t_close = 0;
2551 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002552 s->logs.cli_cookie = NULL;
2553 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002554 s->logs.status = -1;
2555 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002556
willy tarreau2f6ba652005-12-17 13:57:42 +01002557 s->uniq_id = totalconn;
2558
willy tarreau4302f492005-12-18 01:00:37 +01002559 if (p->nb_req_cap > 0) {
2560 if ((s->req_cap =
2561 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2562 == NULL) { /* no memory */
2563 close(cfd); /* nothing can be done for this fd without memory */
2564 pool_free(task, t);
2565 pool_free(session, s);
2566 return 0;
2567 }
2568 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2569 }
2570 else
2571 s->req_cap = NULL;
2572
2573 if (p->nb_rsp_cap > 0) {
2574 if ((s->rsp_cap =
2575 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2576 == NULL) { /* no memory */
2577 if (s->req_cap != NULL)
2578 pool_free_to(p->req_cap_pool, s->req_cap);
2579 close(cfd); /* nothing can be done for this fd without memory */
2580 pool_free(task, t);
2581 pool_free(session, s);
2582 return 0;
2583 }
2584 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2585 }
2586 else
2587 s->rsp_cap = NULL;
2588
willy tarreau5cbea6f2005-12-17 12:48:26 +01002589 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2590 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002591 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002595 if (addr.ss_family != AF_INET ||
2596 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002597 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002598
willy tarreau9fe663a2005-12-17 13:02:59 +01002599 if (p->to_log) {
2600 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002601 if (s->logs.logwait & LW_CLIP)
2602 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002603 sess_log(s);
2604 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002605 else if (s->cli_addr.ss_family == AF_INET) {
2606 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2607 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2608 sn, sizeof(sn)) &&
2609 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2610 pn, sizeof(pn))) {
2611 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2612 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2613 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2614 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2615 }
2616 }
2617 else {
2618 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2619 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2620 sn, sizeof(sn)) &&
2621 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2622 pn, sizeof(pn))) {
2623 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2624 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2625 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2626 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2627 }
2628 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002629 }
willy tarreau0f7af912005-12-17 12:21:26 +01002630
willy tarreau982249e2005-12-18 00:57:06 +01002631 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002632 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002633 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002634 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002635 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002636 if (addr.ss_family != AF_INET ||
2637 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002638 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002639
willy tarreau8a86dbf2005-12-18 00:45:59 +01002640 if (s->cli_addr.ss_family == AF_INET) {
2641 char pn[INET_ADDRSTRLEN];
2642 inet_ntop(AF_INET,
2643 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2644 pn, sizeof(pn));
2645
2646 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2647 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2648 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2649 }
2650 else {
2651 char pn[INET6_ADDRSTRLEN];
2652 inet_ntop(AF_INET6,
2653 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2654 pn, sizeof(pn));
2655
2656 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2657 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2658 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2659 }
2660
willy tarreauef900ab2005-12-17 12:52:52 +01002661 write(1, trash, len);
2662 }
willy tarreau0f7af912005-12-17 12:21:26 +01002663
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002665 if (s->rsp_cap != NULL)
2666 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2667 if (s->req_cap != NULL)
2668 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669 close(cfd); /* nothing can be done for this fd without memory */
2670 pool_free(task, t);
2671 pool_free(session, s);
2672 return 0;
2673 }
willy tarreau4302f492005-12-18 01:00:37 +01002674
willy tarreau5cbea6f2005-12-17 12:48:26 +01002675 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002676 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002677 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2678 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002679 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002680 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002681
willy tarreau5cbea6f2005-12-17 12:48:26 +01002682 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2683 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002684 if (s->rsp_cap != NULL)
2685 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2686 if (s->req_cap != NULL)
2687 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002688 close(cfd); /* nothing can be done for this fd without memory */
2689 pool_free(task, t);
2690 pool_free(session, s);
2691 return 0;
2692 }
2693 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002694 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002695 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 +01002696
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 fdtab[cfd].read = &event_cli_read;
2698 fdtab[cfd].write = &event_cli_write;
2699 fdtab[cfd].owner = t;
2700 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002701
willy tarreaub1285d52005-12-18 01:20:14 +01002702 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2703 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2704 /* Either we got a request from a monitoring system on an HTTP instance,
2705 * or we're in health check mode with the 'httpchk' option enabled. In
2706 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2707 */
2708 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2709 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2710 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 }
2712 else {
2713 FD_SET(cfd, StaticReadEvent);
2714 }
2715
2716 fd_insert(cfd);
2717
2718 tv_eternity(&s->cnexpire);
2719 tv_eternity(&s->srexpire);
2720 tv_eternity(&s->swexpire);
2721 tv_eternity(&s->cwexpire);
2722
willy tarreaub1285d52005-12-18 01:20:14 +01002723 if (s->proxy->clitimeout) {
2724 if (FD_ISSET(cfd, StaticReadEvent))
2725 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2726 if (FD_ISSET(cfd, StaticWriteEvent))
2727 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2728 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002729
willy tarreaub1285d52005-12-18 01:20:14 +01002730 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002731
2732 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002733
2734 if (p->mode != PR_MODE_HEALTH)
2735 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002736
2737 p->nbconn++;
2738 actconn++;
2739 totalconn++;
2740
2741 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2742 } /* end of while (p->nbconn < p->maxconn) */
2743 return 0;
2744}
willy tarreau0f7af912005-12-17 12:21:26 +01002745
willy tarreau0f7af912005-12-17 12:21:26 +01002746
willy tarreau5cbea6f2005-12-17 12:48:26 +01002747/*
2748 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002749 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2750 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002751 * or -1 if an error occured.
2752 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002753int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002754 struct task *t = fdtab[fd].owner;
2755 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002756
willy tarreau5cbea6f2005-12-17 12:48:26 +01002757 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002758 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002759 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002760 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002761 if (skerr)
2762 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002763 else {
2764 if (s->proxy->options & PR_O_HTTP_CHK) {
2765 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002766 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002767 * so we'll send the request, and won't wake the checker up now.
2768 */
2769#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002770 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002771#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002772 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002773#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002774 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002775 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2776 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2777 return 0;
2778 }
2779 else
2780 s->result = -1;
2781 }
2782 else {
2783 /* good TCP connection is enough */
2784 s->result = 1;
2785 }
2786 }
2787
2788 task_wakeup(&rq, t);
2789 return 0;
2790}
2791
willy tarreau0f7af912005-12-17 12:21:26 +01002792
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002793/*
2794 * This function is used only for server health-checks. It handles
2795 * the server's reply to an HTTP request. It returns 1 if the server replies
2796 * 2xx or 3xx (valid responses), or -1 in other cases.
2797 */
2798int event_srv_chk_r(int fd) {
2799 char reply[64];
2800 int len;
2801 struct task *t = fdtab[fd].owner;
2802 struct server *s = t->context;
2803
2804 int skerr, lskerr;
2805 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002806
2807 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002808#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002809 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2810 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002811 len = recv(fd, reply, sizeof(reply), 0);
2812#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002813 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2814 * but the connection was closed on the remote end. Fortunately, recv still
2815 * works correctly and we don't need to do the getsockopt() on linux.
2816 */
2817 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002818#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002819 if ((len >= sizeof("HTTP/1.0 000")) &&
2820 !memcmp(reply, "HTTP/1.", 7) &&
2821 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2822 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002823
2824 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002825 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002826 return 0;
2827}
2828
2829
2830/*
2831 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2832 * and moves <end> just after the end of <str>.
2833 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2834 * the shift value (positive or negative) is returned.
2835 * If there's no space left, the move is not done.
2836 *
2837 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002838int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002839 int delta;
2840 int len;
2841
2842 len = strlen(str);
2843 delta = len - (end - pos);
2844
2845 if (delta + b->r >= b->data + BUFSIZE)
2846 return 0; /* no space left */
2847
2848 /* first, protect the end of the buffer */
2849 memmove(end + delta, end, b->data + b->l - end);
2850
2851 /* now, copy str over pos */
2852 memcpy(pos, str,len);
2853
willy tarreau5cbea6f2005-12-17 12:48:26 +01002854 /* we only move data after the displaced zone */
2855 if (b->r > pos) b->r += delta;
2856 if (b->w > pos) b->w += delta;
2857 if (b->h > pos) b->h += delta;
2858 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002859 b->l += delta;
2860
2861 return delta;
2862}
2863
willy tarreau8337c6b2005-12-17 13:41:01 +01002864/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002865 * len is 0.
2866 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002867int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002868 int delta;
2869
2870 delta = len - (end - pos);
2871
2872 if (delta + b->r >= b->data + BUFSIZE)
2873 return 0; /* no space left */
2874
2875 /* first, protect the end of the buffer */
2876 memmove(end + delta, end, b->data + b->l - end);
2877
2878 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002879 if (len)
2880 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002881
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882 /* we only move data after the displaced zone */
2883 if (b->r > pos) b->r += delta;
2884 if (b->w > pos) b->w += delta;
2885 if (b->h > pos) b->h += delta;
2886 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002887 b->l += delta;
2888
2889 return delta;
2890}
2891
2892
2893int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2894 char *old_dst = dst;
2895
2896 while (*str) {
2897 if (*str == '\\') {
2898 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002899 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002900 int len, num;
2901
2902 num = *str - '0';
2903 str++;
2904
willy tarreau8a86dbf2005-12-18 00:45:59 +01002905 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002906 len = matches[num].rm_eo - matches[num].rm_so;
2907 memcpy(dst, src + matches[num].rm_so, len);
2908 dst += len;
2909 }
2910
2911 }
2912 else if (*str == 'x') {
2913 unsigned char hex1, hex2;
2914 str++;
2915
willy tarreauc1f47532005-12-18 01:08:26 +01002916 hex1 = toupper(*str++) - '0';
2917 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002918
2919 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2920 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2921 *dst++ = (hex1<<4) + hex2;
2922 }
2923 else
2924 *dst++ = *str++;
2925 }
2926 else
2927 *dst++ = *str++;
2928 }
2929 *dst = 0;
2930 return dst - old_dst;
2931}
2932
willy tarreauc1f47532005-12-18 01:08:26 +01002933static int ishex(char s)
2934{
2935 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
2936}
2937
2938/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
2939char *check_replace_string(char *str)
2940{
2941 char *err = NULL;
2942 while (*str) {
2943 if (*str == '\\') {
2944 err = str; /* in case of a backslash, we return the pointer to it */
2945 str++;
2946 if (!*str)
2947 return err;
2948 else if (isdigit((int)*str))
2949 err = NULL;
2950 else if (*str == 'x') {
2951 str++;
2952 if (!ishex(*str))
2953 return err;
2954 str++;
2955 if (!ishex(*str))
2956 return err;
2957 err = NULL;
2958 }
2959 else {
2960 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
2961 err = NULL;
2962 }
2963 }
2964 str++;
2965 }
2966 return err;
2967}
2968
2969
willy tarreau9fe663a2005-12-17 13:02:59 +01002970
willy tarreau0f7af912005-12-17 12:21:26 +01002971/*
2972 * manages the client FSM and its socket. BTW, it also tries to handle the
2973 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2974 * 0 else.
2975 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002976int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002977 int s = t->srv_state;
2978 int c = t->cli_state;
2979 struct buffer *req = t->req;
2980 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01002981 int method_checked = 0;
2982 appsess *asession_temp = NULL;
2983 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01002984
willy tarreau750a4722005-12-17 13:21:24 +01002985#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01002986 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
2987 cli_stnames[c], srv_stnames[s],
2988 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2989 t->crexpire.tv_sec, t->crexpire.tv_usec,
2990 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01002991#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002992 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2993 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2994 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2995 //);
2996 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002997 /* now parse the partial (or complete) headers */
2998 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2999 char *ptr;
3000 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003001 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003002
willy tarreau5cbea6f2005-12-17 12:48:26 +01003003 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003004
willy tarreau0f7af912005-12-17 12:21:26 +01003005 /* look for the end of the current header */
3006 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3007 ptr++;
3008
willy tarreau5cbea6f2005-12-17 12:48:26 +01003009 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010 int line, len;
3011 /* we can only get here after an end of headers */
3012 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003013
willy tarreaue39cd132005-12-17 13:00:18 +01003014 if (t->flags & SN_CLDENY) {
3015 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003016 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003017 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003018 if (!(t->flags & SN_ERR_MASK))
3019 t->flags |= SN_ERR_PRXCOND;
3020 if (!(t->flags & SN_FINST_MASK))
3021 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003022 return 1;
3023 }
3024
willy tarreau5cbea6f2005-12-17 12:48:26 +01003025 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003026 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3027 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003028 }
willy tarreau0f7af912005-12-17 12:21:26 +01003029
willy tarreau9fe663a2005-12-17 13:02:59 +01003030 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003031 if (t->cli_addr.ss_family == AF_INET) {
3032 unsigned char *pn;
3033 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3034 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3035 pn[0], pn[1], pn[2], pn[3]);
3036 buffer_replace2(req, req->h, req->h, trash, len);
3037 }
3038 else if (t->cli_addr.ss_family == AF_INET6) {
3039 char pn[INET6_ADDRSTRLEN];
3040 inet_ntop(AF_INET6,
3041 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3042 pn, sizeof(pn));
3043 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3044 buffer_replace2(req, req->h, req->h, trash, len);
3045 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003046 }
3047
willy tarreau25c4ea52005-12-18 00:49:49 +01003048 /* add a "connection: close" line if needed */
3049 if (t->proxy->options & PR_O_HTTP_CLOSE)
3050 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3051
willy tarreau982249e2005-12-18 00:57:06 +01003052 if (!memcmp(req->data, "POST ", 5)) {
3053 /* this is a POST request, which is not cacheable by default */
3054 t->flags |= SN_POST;
3055 }
willy tarreaucd878942005-12-17 13:27:43 +01003056
willy tarreau5cbea6f2005-12-17 12:48:26 +01003057 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003058 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003059
willy tarreau750a4722005-12-17 13:21:24 +01003060 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003061 /* FIXME: we'll set the client in a wait state while we try to
3062 * connect to the server. Is this really needed ? wouldn't it be
3063 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003064 //FD_CLR(t->cli_fd, StaticReadEvent);
3065 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003066
3067 /* FIXME: if we break here (as up to 1.1.23), having the client
3068 * shutdown its connection can lead to an abort further.
3069 * it's better to either return 1 or even jump directly to the
3070 * data state which will save one schedule.
3071 */
3072 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003073
3074 if (!t->proxy->clitimeout ||
3075 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3076 /* If the client has no timeout, or if the server is not ready yet,
3077 * and we know for sure that it can expire, then it's cleaner to
3078 * disable the timeout on the client side so that too low values
3079 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003080 *
3081 * FIXME-20050705: the server needs a way to re-enable this time-out
3082 * when it switches its state, otherwise a client can stay connected
3083 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003084 */
3085 tv_eternity(&t->crexpire);
3086
willy tarreau197e8ec2005-12-17 14:10:59 +01003087 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003088 }
willy tarreau0f7af912005-12-17 12:21:26 +01003089
willy tarreau5cbea6f2005-12-17 12:48:26 +01003090 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3091 if (ptr > req->r - 2) {
3092 /* this is a partial header, let's wait for more to come */
3093 req->lr = ptr;
3094 break;
3095 }
willy tarreau0f7af912005-12-17 12:21:26 +01003096
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 /* now we know that *ptr is either \r or \n,
3098 * and that there are at least 1 char after it.
3099 */
3100 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3101 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3102 else
3103 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003104
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105 /*
3106 * now we know that we have a full header ; we can do whatever
3107 * we want with these pointers :
3108 * req->h = beginning of header
3109 * ptr = end of header (first \r or \n)
3110 * req->lr = beginning of next line (next rep->h)
3111 * req->r = end of data (not used at this stage)
3112 */
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreau12350152005-12-18 01:03:27 +01003114 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3115 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3116 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3117
3118 /* skip ; */
3119 request_line++;
3120
3121 /* look if we have a jsessionid */
3122
3123 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3124
3125 /* skip jsessionid= */
3126 request_line += t->proxy->appsession_name_len + 1;
3127
3128 /* First try if we allready have an appsession */
3129 asession_temp = &local_asession;
3130
3131 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3132 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3133 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3134 return 0;
3135 }
3136
3137 /* Copy the sessionid */
3138 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3139 asession_temp->sessid[t->proxy->appsession_len] = 0;
3140 asession_temp->serverid = NULL;
3141
3142 /* only do insert, if lookup fails */
3143 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3144 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3145 Alert("Not enough memory process_cli():asession:calloc().\n");
3146 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3147 return 0;
3148 }
3149 asession_temp->sessid = local_asession.sessid;
3150 asession_temp->serverid = local_asession.serverid;
3151 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3152 } /* end if(chtbl_lookup()) */
3153 else{
3154 /*free wasted memory;*/
3155 pool_free_to(apools.sessid, local_asession.sessid);
3156 }
3157
3158 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3159 asession_temp->request_count++;
3160
3161#if defined(DEBUG_HASH)
3162 print_table(&(t->proxy->htbl_proxy));
3163#endif
3164
3165 if (asession_temp->serverid == NULL) {
3166 Alert("Found Application Session without matching server.\n");
3167 } else {
3168 struct server *srv = t->proxy->srv;
3169 while (srv) {
3170 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3171 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3172 /* we found the server and it's usable */
3173 t->flags &= ~SN_CK_MASK;
3174 t->flags |= SN_CK_VALID | SN_DIRECT;
3175 t->srv = srv;
3176 break;
3177 }else {
3178 t->flags &= ~SN_CK_MASK;
3179 t->flags |= SN_CK_DOWN;
3180 }
3181 }/* end if(strcmp()) */
3182 srv = srv->next;
3183 }/* end while(srv) */
3184 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreau12350152005-12-18 01:03:27 +01003185 }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
3186 else {
3187 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3188 }
willy tarreau598da412005-12-18 01:07:29 +01003189 method_checked = 1;
willy tarreau12350152005-12-18 01:03:27 +01003190 }/* end if(!method_checked ...) */
3191 else{
3192 //printf("No Methode-Header with Session-String\n");
3193 }
3194
willy tarreau8337c6b2005-12-17 13:41:01 +01003195 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003196 /* we have a complete HTTP request that we must log */
3197 int urilen;
3198
willy tarreaua1598082005-12-17 13:08:06 +01003199 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003200 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003201 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003202 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003203 if (!(t->flags & SN_ERR_MASK))
3204 t->flags |= SN_ERR_PRXCOND;
3205 if (!(t->flags & SN_FINST_MASK))
3206 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003207 return 1;
3208 }
3209
3210 urilen = ptr - req->h;
3211 if (urilen >= REQURI_LEN)
3212 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003213 memcpy(t->logs.uri, req->h, urilen);
3214 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003215
willy tarreaua1598082005-12-17 13:08:06 +01003216 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003217 sess_log(t);
3218 }
willy tarreau4302f492005-12-18 01:00:37 +01003219 else if (t->logs.logwait & LW_REQHDR) {
3220 struct cap_hdr *h;
3221 int len;
3222 for (h = t->proxy->req_cap; h; h = h->next) {
3223 if ((h->namelen + 2 <= ptr - req->h) &&
3224 (req->h[h->namelen] == ':') &&
3225 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3226
3227 if (t->req_cap[h->index] == NULL)
3228 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3229
3230 len = ptr - (req->h + h->namelen + 2);
3231 if (len > h->len)
3232 len = h->len;
3233
3234 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3235 t->req_cap[h->index][len]=0;
3236 }
3237 }
3238
3239 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003240
willy tarreau5cbea6f2005-12-17 12:48:26 +01003241 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003242
willy tarreau982249e2005-12-18 00:57:06 +01003243 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003244 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003245 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 +01003246 max = ptr - req->h;
3247 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003248 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003249 trash[len++] = '\n';
3250 write(1, trash, len);
3251 }
willy tarreau0f7af912005-12-17 12:21:26 +01003252
willy tarreau25c4ea52005-12-18 00:49:49 +01003253
3254 /* remove "connection: " if needed */
3255 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3256 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3257 delete_header = 1;
3258 }
3259
willy tarreau5cbea6f2005-12-17 12:48:26 +01003260 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003261 if (!delete_header && t->proxy->req_exp != NULL
3262 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003263 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003264 char term;
3265
3266 term = *ptr;
3267 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003268 exp = t->proxy->req_exp;
3269 do {
3270 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3271 switch (exp->action) {
3272 case ACT_ALLOW:
3273 if (!(t->flags & SN_CLDENY))
3274 t->flags |= SN_CLALLOW;
3275 break;
3276 case ACT_REPLACE:
3277 if (!(t->flags & SN_CLDENY)) {
3278 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3279 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3280 }
3281 break;
3282 case ACT_REMOVE:
3283 if (!(t->flags & SN_CLDENY))
3284 delete_header = 1;
3285 break;
3286 case ACT_DENY:
3287 if (!(t->flags & SN_CLALLOW))
3288 t->flags |= SN_CLDENY;
3289 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003290 case ACT_PASS: /* we simply don't deny this one */
3291 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003292 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003293 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003294 }
willy tarreaue39cd132005-12-17 13:00:18 +01003295 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003296 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003297 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003298
willy tarreau240afa62005-12-17 13:14:35 +01003299 /* Now look for cookies. Conforming to RFC2109, we have to support
3300 * attributes whose name begin with a '$', and associate them with
3301 * the right cookie, if we want to delete this cookie.
3302 * So there are 3 cases for each cookie read :
3303 * 1) it's a special attribute, beginning with a '$' : ignore it.
3304 * 2) it's a server id cookie that we *MAY* want to delete : save
3305 * some pointers on it (last semi-colon, beginning of cookie...)
3306 * 3) it's an application cookie : we *MAY* have to delete a previous
3307 * "special" cookie.
3308 * At the end of loop, if a "special" cookie remains, we may have to
3309 * remove it. If no application cookie persists in the header, we
3310 * *MUST* delete it
3311 */
willy tarreau12350152005-12-18 01:03:27 +01003312 if (!delete_header &&
3313 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003314 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003315 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003316 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003317 char *del_colon, *del_cookie, *colon;
3318 int app_cookies;
3319
willy tarreau5cbea6f2005-12-17 12:48:26 +01003320 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003321 colon = p1;
3322 /* del_cookie == NULL => nothing to be deleted */
3323 del_colon = del_cookie = NULL;
3324 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003325
3326 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003327 /* skip spaces and colons, but keep an eye on these ones */
3328 while (p1 < ptr) {
3329 if (*p1 == ';' || *p1 == ',')
3330 colon = p1;
3331 else if (!isspace((int)*p1))
3332 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003333 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003334 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003335
3336 if (p1 == ptr)
3337 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003338
3339 /* p1 is at the beginning of the cookie name */
3340 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003341 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003342 p2++;
3343
3344 if (p2 == ptr)
3345 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003346
3347 p3 = p2 + 1; /* skips the '=' sign */
3348 if (p3 == ptr)
3349 break;
3350
willy tarreau240afa62005-12-17 13:14:35 +01003351 p4 = p3;
3352 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 p4++;
3354
3355 /* here, we have the cookie name between p1 and p2,
3356 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003357 * we can process it :
3358 *
3359 * Cookie: NAME=VALUE;
3360 * | || || |
3361 * | || || +--> p4
3362 * | || |+-------> p3
3363 * | || +--------> p2
3364 * | |+------------> p1
3365 * | +-------------> colon
3366 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 */
3368
willy tarreau240afa62005-12-17 13:14:35 +01003369 if (*p1 == '$') {
3370 /* skip this one */
3371 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003372 else {
3373 /* first, let's see if we want to capture it */
3374 if (t->proxy->capture_name != NULL &&
3375 t->logs.cli_cookie == NULL &&
3376 (p4 - p1 >= t->proxy->capture_namelen) &&
3377 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3378 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003379
willy tarreau8337c6b2005-12-17 13:41:01 +01003380 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3381 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003382 } else {
3383 if (log_len > t->proxy->capture_len)
3384 log_len = t->proxy->capture_len;
3385 memcpy(t->logs.cli_cookie, p1, log_len);
3386 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003387 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003388 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003389
3390 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3391 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3392 /* Cool... it's the right one */
3393 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003394 char *delim;
3395
3396 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3397 * have the server ID betweek p3 and delim, and the original cookie between
3398 * delim+1 and p4. Otherwise, delim==p4 :
3399 *
3400 * Cookie: NAME=SRV~VALUE;
3401 * | || || | |
3402 * | || || | +--> p4
3403 * | || || +--------> delim
3404 * | || |+-----------> p3
3405 * | || +------------> p2
3406 * | |+----------------> p1
3407 * | +-----------------> colon
3408 * +------------------------> req->h
3409 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003410
willy tarreau0174f312005-12-18 01:02:42 +01003411 if (t->proxy->options & PR_O_COOK_PFX) {
3412 for (delim = p3; delim < p4; delim++)
3413 if (*delim == COOKIE_DELIM)
3414 break;
3415 }
3416 else
3417 delim = p4;
3418
3419
3420 /* Here, we'll look for the first running server which supports the cookie.
3421 * This allows to share a same cookie between several servers, for example
3422 * to dedicate backup servers to specific servers only.
3423 */
3424 while (srv) {
3425 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3426 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3427 /* we found the server and it's usable */
3428 t->flags &= ~SN_CK_MASK;
3429 t->flags |= SN_CK_VALID | SN_DIRECT;
3430 t->srv = srv;
3431 break;
willy tarreau12350152005-12-18 01:03:27 +01003432 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003433 /* we found a server, but it's down */
3434 t->flags &= ~SN_CK_MASK;
3435 t->flags |= SN_CK_DOWN;
3436 }
3437 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003438 srv = srv->next;
3439 }
3440
willy tarreau0174f312005-12-18 01:02:42 +01003441 if (!srv && !(t->flags & SN_CK_DOWN)) {
3442 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003443 t->flags &= ~SN_CK_MASK;
3444 t->flags |= SN_CK_INVALID;
3445 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003446
willy tarreau0174f312005-12-18 01:02:42 +01003447 /* depending on the cookie mode, we may have to either :
3448 * - delete the complete cookie if we're in insert+indirect mode, so that
3449 * the server never sees it ;
3450 * - remove the server id from the cookie value, and tag the cookie as an
3451 * application cookie so that it does not get accidentely removed later,
3452 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003453 */
willy tarreau0174f312005-12-18 01:02:42 +01003454 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3455 buffer_replace2(req, p3, delim + 1, NULL, 0);
3456 p4 -= (delim + 1 - p3);
3457 ptr -= (delim + 1 - p3);
3458 del_cookie = del_colon = NULL;
3459 app_cookies++; /* protect the header from deletion */
3460 }
3461 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003462 (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 +01003463 del_cookie = p1;
3464 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003465 }
willy tarreau12350152005-12-18 01:03:27 +01003466 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003467 /* now we know that we must keep this cookie since it's
3468 * not ours. But if we wanted to delete our cookie
3469 * earlier, we cannot remove the complete header, but we
3470 * can remove the previous block itself.
3471 */
3472 app_cookies++;
3473
3474 if (del_cookie != NULL) {
3475 buffer_replace2(req, del_cookie, p1, NULL, 0);
3476 p4 -= (p1 - del_cookie);
3477 ptr -= (p1 - del_cookie);
3478 del_cookie = del_colon = NULL;
3479 }
willy tarreau240afa62005-12-17 13:14:35 +01003480 }
willy tarreau12350152005-12-18 01:03:27 +01003481
3482 if ((t->proxy->appsession_name != NULL) &&
3483 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3484 /* first, let's see if the cookie is our appcookie*/
3485
3486 /* Cool... it's the right one */
3487
3488 asession_temp = &local_asession;
3489
3490 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3491 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3492 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3493 return 0;
3494 }
3495
3496 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3497 asession_temp->sessid[t->proxy->appsession_len] = 0;
3498 asession_temp->serverid = NULL;
3499
3500 /* only do insert, if lookup fails */
3501 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3502 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3503 Alert("Not enough memory process_cli():asession:calloc().\n");
3504 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3505 return 0;
3506 }
3507
3508 asession_temp->sessid = local_asession.sessid;
3509 asession_temp->serverid = local_asession.serverid;
3510 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3511 }
3512 else{
3513 /* free wasted memory */
3514 pool_free_to(apools.sessid, local_asession.sessid);
3515 }
3516
3517 if (asession_temp->serverid == NULL) {
3518 Alert("Found Application Session without matching server.\n");
3519 } else {
3520 struct server *srv = t->proxy->srv;
3521 while (srv) {
3522 if(strcmp(srv->id, asession_temp->serverid) == 0) {
3523 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3524 /* we found the server and it's usable */
3525 t->flags &= ~SN_CK_MASK;
3526 t->flags |= SN_CK_VALID | SN_DIRECT;
3527 t->srv = srv;
3528 break;
3529 } else {
3530 t->flags &= ~SN_CK_MASK;
3531 t->flags |= SN_CK_DOWN;
3532 }
3533 }
3534 srv = srv->next;
3535 }/* end while(srv) */
3536 }/* end else if server == NULL */
3537
3538 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003539 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003540 }
willy tarreau240afa62005-12-17 13:14:35 +01003541
willy tarreau5cbea6f2005-12-17 12:48:26 +01003542 /* we'll have to look for another cookie ... */
3543 p1 = p4;
3544 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003545
3546 /* There's no more cookie on this line.
3547 * We may have marked the last one(s) for deletion.
3548 * We must do this now in two ways :
3549 * - if there is no app cookie, we simply delete the header ;
3550 * - if there are app cookies, we must delete the end of the
3551 * string properly, including the colon/semi-colon before
3552 * the cookie name.
3553 */
3554 if (del_cookie != NULL) {
3555 if (app_cookies) {
3556 buffer_replace2(req, del_colon, ptr, NULL, 0);
3557 /* WARNING! <ptr> becomes invalid for now. If some code
3558 * below needs to rely on it before the end of the global
3559 * header loop, we need to correct it with this code :
3560 * ptr = del_colon;
3561 */
3562 }
3563 else
3564 delete_header = 1;
3565 }
3566 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003567
3568 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003569 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003570 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003571 }
willy tarreau240afa62005-12-17 13:14:35 +01003572 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3573
willy tarreau5cbea6f2005-12-17 12:48:26 +01003574 req->h = req->lr;
3575 } /* while (req->lr < req->r) */
3576
3577 /* end of header processing (even if incomplete) */
3578
willy tarreauef900ab2005-12-17 12:52:52 +01003579 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3580 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3581 * full. We cannot loop here since event_cli_read will disable it only if
3582 * req->l == rlim-data
3583 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003584 FD_SET(t->cli_fd, StaticReadEvent);
3585 if (t->proxy->clitimeout)
3586 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3587 else
3588 tv_eternity(&t->crexpire);
3589 }
3590
willy tarreaue39cd132005-12-17 13:00:18 +01003591 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003592 * won't be able to free more later, so the session will never terminate.
3593 */
willy tarreaue39cd132005-12-17 13:00:18 +01003594 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003595 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003596 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003597 if (!(t->flags & SN_ERR_MASK))
3598 t->flags |= SN_ERR_PRXCOND;
3599 if (!(t->flags & SN_FINST_MASK))
3600 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003601 return 1;
3602 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003603 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003604 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003605 tv_eternity(&t->crexpire);
3606 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003607 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003608 if (!(t->flags & SN_ERR_MASK))
3609 t->flags |= SN_ERR_CLICL;
3610 if (!(t->flags & SN_FINST_MASK))
3611 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003612 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003613 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003614 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3615
3616 /* read timeout : give up with an error message.
3617 */
3618 t->logs.status = 408;
3619 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003620 if (!(t->flags & SN_ERR_MASK))
3621 t->flags |= SN_ERR_CLITO;
3622 if (!(t->flags & SN_FINST_MASK))
3623 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003624 return 1;
3625 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626
3627 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003628 }
3629 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003630 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003631 /* FIXME: this error handling is partly buggy because we always report
3632 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3633 * or HEADER phase. BTW, it's not logical to expire the client while
3634 * we're waiting for the server to connect.
3635 */
willy tarreau0f7af912005-12-17 12:21:26 +01003636 /* read or write error */
3637 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003638 tv_eternity(&t->crexpire);
3639 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003640 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003641 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003642 if (!(t->flags & SN_ERR_MASK))
3643 t->flags |= SN_ERR_CLICL;
3644 if (!(t->flags & SN_FINST_MASK))
3645 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003646 return 1;
3647 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003648 /* last read, or end of server write */
3649 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003650 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003651 tv_eternity(&t->crexpire);
3652 shutdown(t->cli_fd, SHUT_RD);
3653 t->cli_state = CL_STSHUTR;
3654 return 1;
3655 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003656 /* last server read and buffer empty */
3657 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003658 FD_CLR(t->cli_fd, StaticWriteEvent);
3659 tv_eternity(&t->cwexpire);
3660 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003661 /* We must ensure that the read part is still alive when switching
3662 * to shutw */
3663 FD_SET(t->cli_fd, StaticReadEvent);
3664 if (t->proxy->clitimeout)
3665 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003666 t->cli_state = CL_STSHUTW;
3667 return 1;
3668 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003669 /* read timeout */
3670 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3671 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003672 tv_eternity(&t->crexpire);
3673 shutdown(t->cli_fd, SHUT_RD);
3674 t->cli_state = CL_STSHUTR;
3675 if (!(t->flags & SN_ERR_MASK))
3676 t->flags |= SN_ERR_CLITO;
3677 if (!(t->flags & SN_FINST_MASK))
3678 t->flags |= SN_FINST_D;
3679 return 1;
3680 }
3681 /* write timeout */
3682 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3683 FD_CLR(t->cli_fd, StaticWriteEvent);
3684 tv_eternity(&t->cwexpire);
3685 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003686 /* We must ensure that the read part is still alive when switching
3687 * to shutw */
3688 FD_SET(t->cli_fd, StaticReadEvent);
3689 if (t->proxy->clitimeout)
3690 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3691
willy tarreau036e1ce2005-12-17 13:46:33 +01003692 t->cli_state = CL_STSHUTW;
3693 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003694 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003695 if (!(t->flags & SN_FINST_MASK))
3696 t->flags |= SN_FINST_D;
3697 return 1;
3698 }
willy tarreau0f7af912005-12-17 12:21:26 +01003699
willy tarreauc58fc692005-12-17 14:13:08 +01003700 if (req->l >= req->rlim - req->data) {
3701 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003702 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003703 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003704 FD_CLR(t->cli_fd, StaticReadEvent);
3705 tv_eternity(&t->crexpire);
3706 }
3707 }
3708 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003709 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003710 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3711 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003712 if (!t->proxy->clitimeout ||
3713 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3714 /* If the client has no timeout, or if the server not ready yet, and we
3715 * know for sure that it can expire, then it's cleaner to disable the
3716 * timeout on the client side so that too low values cannot make the
3717 * sessions abort too early.
3718 */
willy tarreau0f7af912005-12-17 12:21:26 +01003719 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003720 else
3721 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003722 }
3723 }
3724
3725 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003726 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003727 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3728 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3729 tv_eternity(&t->cwexpire);
3730 }
3731 }
3732 else { /* buffer not empty */
3733 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3734 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003735 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003736 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003737 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3738 t->crexpire = t->cwexpire;
3739 }
willy tarreau0f7af912005-12-17 12:21:26 +01003740 else
3741 tv_eternity(&t->cwexpire);
3742 }
3743 }
3744 return 0; /* other cases change nothing */
3745 }
3746 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003747 if (t->res_cw == RES_ERROR) {
3748 tv_eternity(&t->cwexpire);
3749 fd_delete(t->cli_fd);
3750 t->cli_state = CL_STCLOSE;
3751 if (!(t->flags & SN_ERR_MASK))
3752 t->flags |= SN_ERR_CLICL;
3753 if (!(t->flags & SN_FINST_MASK))
3754 t->flags |= SN_FINST_D;
3755 return 1;
3756 }
3757 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003758 tv_eternity(&t->cwexpire);
3759 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003760 t->cli_state = CL_STCLOSE;
3761 return 1;
3762 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003763 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3764 tv_eternity(&t->cwexpire);
3765 fd_delete(t->cli_fd);
3766 t->cli_state = CL_STCLOSE;
3767 if (!(t->flags & SN_ERR_MASK))
3768 t->flags |= SN_ERR_CLITO;
3769 if (!(t->flags & SN_FINST_MASK))
3770 t->flags |= SN_FINST_D;
3771 return 1;
3772 }
willy tarreau0f7af912005-12-17 12:21:26 +01003773 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003774 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003775 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3776 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3777 tv_eternity(&t->cwexpire);
3778 }
3779 }
3780 else { /* buffer not empty */
3781 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3782 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003783 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003784 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003785 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3786 t->crexpire = t->cwexpire;
3787 }
willy tarreau0f7af912005-12-17 12:21:26 +01003788 else
3789 tv_eternity(&t->cwexpire);
3790 }
3791 }
3792 return 0;
3793 }
3794 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003795 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003796 tv_eternity(&t->crexpire);
3797 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003798 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003799 if (!(t->flags & SN_ERR_MASK))
3800 t->flags |= SN_ERR_CLICL;
3801 if (!(t->flags & SN_FINST_MASK))
3802 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003803 return 1;
3804 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003805 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3806 tv_eternity(&t->crexpire);
3807 fd_delete(t->cli_fd);
3808 t->cli_state = CL_STCLOSE;
3809 return 1;
3810 }
3811 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3812 tv_eternity(&t->crexpire);
3813 fd_delete(t->cli_fd);
3814 t->cli_state = CL_STCLOSE;
3815 if (!(t->flags & SN_ERR_MASK))
3816 t->flags |= SN_ERR_CLITO;
3817 if (!(t->flags & SN_FINST_MASK))
3818 t->flags |= SN_FINST_D;
3819 return 1;
3820 }
willy tarreauef900ab2005-12-17 12:52:52 +01003821 else if (req->l >= req->rlim - req->data) {
3822 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003823
3824 /* FIXME-20050705: is it possible for a client to maintain a session
3825 * after the timeout by sending more data after it receives a close ?
3826 */
3827
willy tarreau0f7af912005-12-17 12:21:26 +01003828 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003829 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003830 FD_CLR(t->cli_fd, StaticReadEvent);
3831 tv_eternity(&t->crexpire);
3832 }
3833 }
3834 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003835 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003836 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3837 FD_SET(t->cli_fd, StaticReadEvent);
3838 if (t->proxy->clitimeout)
3839 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3840 else
3841 tv_eternity(&t->crexpire);
3842 }
3843 }
3844 return 0;
3845 }
3846 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003847 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003848 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003849 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 +01003850 write(1, trash, len);
3851 }
3852 return 0;
3853 }
3854 return 0;
3855}
3856
3857
3858/*
3859 * manages the server FSM and its socket. It returns 1 if a state has changed
3860 * (and a resync may be needed), 0 else.
3861 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003863 int s = t->srv_state;
3864 int c = t->cli_state;
3865 struct buffer *req = t->req;
3866 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003867 appsess *asession_temp = NULL;
3868 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003869 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003870
willy tarreau750a4722005-12-17 13:21:24 +01003871#ifdef DEBUG_FULL
3872 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3873#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003874 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3875 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3876 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3877 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003878 if (s == SV_STIDLE) {
3879 if (c == CL_STHEADERS)
3880 return 0; /* stay in idle, waiting for data to reach the client side */
3881 else if (c == CL_STCLOSE ||
3882 c == CL_STSHUTW ||
3883 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3884 tv_eternity(&t->cnexpire);
3885 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003886 if (!(t->flags & SN_ERR_MASK))
3887 t->flags |= SN_ERR_CLICL;
3888 if (!(t->flags & SN_FINST_MASK))
3889 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003890 return 1;
3891 }
3892 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003893 /* initiate a connection to the server */
3894 conn_err = connect_server(t);
3895 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003896 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3897 t->srv_state = SV_STCONN;
3898 }
3899 else { /* try again */
3900 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003901 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003902 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003903 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003904 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3905 t->flags &= ~SN_CK_MASK;
3906 t->flags |= SN_CK_DOWN;
3907 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003908 }
3909
willy tarreaub1285d52005-12-18 01:20:14 +01003910 conn_err = connect_server(t);
3911 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003912 t->srv_state = SV_STCONN;
3913 break;
3914 }
3915 }
3916 if (t->conn_retries < 0) {
3917 /* if conn_retries < 0 or other error, let's abort */
3918 tv_eternity(&t->cnexpire);
3919 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003920 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003921 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003922 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003923 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01003924 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01003925 if (!(t->flags & SN_FINST_MASK))
3926 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003927 }
3928 }
3929 return 1;
3930 }
3931 }
3932 else if (s == SV_STCONN) { /* connection in progress */
3933 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3934 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3935 return 0; /* nothing changed */
3936 }
3937 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3938 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3939 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003940 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003941 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003942 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003943 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003944 if (t->conn_retries >= 0) {
3945 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003946 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003947 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003948 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3949 t->flags &= ~SN_CK_MASK;
3950 t->flags |= SN_CK_DOWN;
3951 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003952 }
willy tarreaub1285d52005-12-18 01:20:14 +01003953 conn_err = connect_server(t);
3954 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003955 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003956 }
willy tarreaub1285d52005-12-18 01:20:14 +01003957 else if (t->res_sw == RES_SILENT)
3958 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
3959 else
3960 conn_err = SN_ERR_SRVCL; // it was a connect error.
3961
willy tarreau0f7af912005-12-17 12:21:26 +01003962 /* if conn_retries < 0 or other error, let's abort */
3963 tv_eternity(&t->cnexpire);
3964 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003965 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003966 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003967 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003968 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01003969 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01003970 if (!(t->flags & SN_FINST_MASK))
3971 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003972 return 1;
3973 }
3974 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003975 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003976
willy tarreau0f7af912005-12-17 12:21:26 +01003977 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003978 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003979 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003980 tv_eternity(&t->swexpire);
3981 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003982 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003983 if (t->proxy->srvtimeout) {
3984 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3985 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3986 t->srexpire = t->swexpire;
3987 }
3988 else
3989 tv_eternity(&t->swexpire);
3990 }
willy tarreau0f7af912005-12-17 12:21:26 +01003991
3992 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3993 FD_SET(t->srv_fd, StaticReadEvent);
3994 if (t->proxy->srvtimeout)
3995 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3996 else
3997 tv_eternity(&t->srexpire);
3998
3999 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004000 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004001
4002 /* if the user wants to log as soon as possible, without counting
4003 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004004 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004005 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4006 sess_log(t);
4007 }
willy tarreau0f7af912005-12-17 12:21:26 +01004008 }
willy tarreauef900ab2005-12-17 12:52:52 +01004009 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004010 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004011 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4012 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004013 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004014 return 1;
4015 }
4016 }
4017 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004018 /* now parse the partial (or complete) headers */
4019 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4020 char *ptr;
4021 int delete_header;
4022
4023 ptr = rep->lr;
4024
4025 /* look for the end of the current header */
4026 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4027 ptr++;
4028
4029 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004030 int line, len;
4031
4032 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004033
4034 /* first, we'll block if security checks have caught nasty things */
4035 if (t->flags & SN_CACHEABLE) {
4036 if ((t->flags & SN_CACHE_COOK) &&
4037 (t->flags & SN_SCK_ANY) &&
4038 (t->proxy->options & PR_O_CHK_CACHE)) {
4039
4040 /* we're in presence of a cacheable response containing
4041 * a set-cookie header. We'll block it as requested by
4042 * the 'checkcache' option, and send an alert.
4043 */
4044 tv_eternity(&t->srexpire);
4045 tv_eternity(&t->swexpire);
4046 fd_delete(t->srv_fd);
4047 t->srv_state = SV_STCLOSE;
4048 t->logs.status = 502;
4049 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4050 if (!(t->flags & SN_ERR_MASK))
4051 t->flags |= SN_ERR_PRXCOND;
4052 if (!(t->flags & SN_FINST_MASK))
4053 t->flags |= SN_FINST_H;
4054
4055 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4056 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4057
4058 return 1;
4059 }
4060 }
4061
willy tarreau982249e2005-12-18 00:57:06 +01004062 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4063 if (t->flags & SN_SVDENY) {
4064 tv_eternity(&t->srexpire);
4065 tv_eternity(&t->swexpire);
4066 fd_delete(t->srv_fd);
4067 t->srv_state = SV_STCLOSE;
4068 t->logs.status = 502;
4069 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4070 if (!(t->flags & SN_ERR_MASK))
4071 t->flags |= SN_ERR_PRXCOND;
4072 if (!(t->flags & SN_FINST_MASK))
4073 t->flags |= SN_FINST_H;
4074 return 1;
4075 }
4076
willy tarreau5cbea6f2005-12-17 12:48:26 +01004077 /* we'll have something else to do here : add new headers ... */
4078
willy tarreaucd878942005-12-17 13:27:43 +01004079 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4080 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004081 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004082 * insert a set-cookie here, except if we want to insert only on POST
4083 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004084 */
willy tarreau750a4722005-12-17 13:21:24 +01004085 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004086 t->proxy->cookie_name,
4087 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004088
willy tarreau036e1ce2005-12-17 13:46:33 +01004089 t->flags |= SN_SCK_INSERTED;
4090
willy tarreau750a4722005-12-17 13:21:24 +01004091 /* Here, we will tell an eventual cache on the client side that we don't
4092 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4093 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4094 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4095 */
willy tarreau240afa62005-12-17 13:14:35 +01004096 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004097 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4098 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01004099
willy tarreau750a4722005-12-17 13:21:24 +01004100 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004101 }
4102
4103 /* headers to be added */
4104 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004105 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4106 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004107 }
4108
willy tarreau25c4ea52005-12-18 00:49:49 +01004109 /* add a "connection: close" line if needed */
4110 if (t->proxy->options & PR_O_HTTP_CLOSE)
4111 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4112
willy tarreau5cbea6f2005-12-17 12:48:26 +01004113 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004114 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004115 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004116
4117 /* if the user wants to log as soon as possible, without counting
4118 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004119 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004120 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4121 t->logs.bytes = rep->h - rep->data;
4122 sess_log(t);
4123 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004124 break;
4125 }
4126
4127 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4128 if (ptr > rep->r - 2) {
4129 /* this is a partial header, let's wait for more to come */
4130 rep->lr = ptr;
4131 break;
4132 }
4133
4134 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4135 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4136
4137 /* now we know that *ptr is either \r or \n,
4138 * and that there are at least 1 char after it.
4139 */
4140 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4141 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4142 else
4143 rep->lr = ptr + 2; /* \r\n or \n\r */
4144
4145 /*
4146 * now we know that we have a full header ; we can do whatever
4147 * we want with these pointers :
4148 * rep->h = beginning of header
4149 * ptr = end of header (first \r or \n)
4150 * rep->lr = beginning of next line (next rep->h)
4151 * rep->r = end of data (not used at this stage)
4152 */
4153
willy tarreaua1598082005-12-17 13:08:06 +01004154
willy tarreau982249e2005-12-18 00:57:06 +01004155 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004156 t->logs.logwait &= ~LW_RESP;
4157 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004158 switch (t->logs.status) {
4159 case 200:
4160 case 203:
4161 case 206:
4162 case 300:
4163 case 301:
4164 case 410:
4165 /* RFC2616 @13.4:
4166 * "A response received with a status code of
4167 * 200, 203, 206, 300, 301 or 410 MAY be stored
4168 * by a cache (...) unless a cache-control
4169 * directive prohibits caching."
4170 *
4171 * RFC2616 @9.5: POST method :
4172 * "Responses to this method are not cacheable,
4173 * unless the response includes appropriate
4174 * Cache-Control or Expires header fields."
4175 */
4176 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4177 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4178 break;
4179 default:
4180 break;
4181 }
willy tarreau4302f492005-12-18 01:00:37 +01004182 }
4183 else if (t->logs.logwait & LW_RSPHDR) {
4184 struct cap_hdr *h;
4185 int len;
4186 for (h = t->proxy->rsp_cap; h; h = h->next) {
4187 if ((h->namelen + 2 <= ptr - rep->h) &&
4188 (rep->h[h->namelen] == ':') &&
4189 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4190
4191 if (t->rsp_cap[h->index] == NULL)
4192 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4193
4194 len = ptr - (rep->h + h->namelen + 2);
4195 if (len > h->len)
4196 len = h->len;
4197
4198 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4199 t->rsp_cap[h->index][len]=0;
4200 }
4201 }
4202
willy tarreaua1598082005-12-17 13:08:06 +01004203 }
4204
willy tarreau5cbea6f2005-12-17 12:48:26 +01004205 delete_header = 0;
4206
willy tarreau982249e2005-12-18 00:57:06 +01004207 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004208 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004209 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 +01004210 max = ptr - rep->h;
4211 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004212 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 trash[len++] = '\n';
4214 write(1, trash, len);
4215 }
4216
willy tarreau25c4ea52005-12-18 00:49:49 +01004217 /* remove "connection: " if needed */
4218 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4219 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4220 delete_header = 1;
4221 }
4222
willy tarreau5cbea6f2005-12-17 12:48:26 +01004223 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004224 if (!delete_header && t->proxy->rsp_exp != NULL
4225 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004226 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004227 char term;
4228
4229 term = *ptr;
4230 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004231 exp = t->proxy->rsp_exp;
4232 do {
4233 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4234 switch (exp->action) {
4235 case ACT_ALLOW:
4236 if (!(t->flags & SN_SVDENY))
4237 t->flags |= SN_SVALLOW;
4238 break;
4239 case ACT_REPLACE:
4240 if (!(t->flags & SN_SVDENY)) {
4241 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4242 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4243 }
4244 break;
4245 case ACT_REMOVE:
4246 if (!(t->flags & SN_SVDENY))
4247 delete_header = 1;
4248 break;
4249 case ACT_DENY:
4250 if (!(t->flags & SN_SVALLOW))
4251 t->flags |= SN_SVDENY;
4252 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004253 case ACT_PASS: /* we simply don't deny this one */
4254 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004255 }
4256 break;
4257 }
willy tarreaue39cd132005-12-17 13:00:18 +01004258 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004259 *ptr = term; /* restore the string terminator */
4260 }
4261
willy tarreau97f58572005-12-18 00:53:44 +01004262 /* check for cache-control: or pragma: headers */
4263 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4264 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4265 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4266 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4267 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004268 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004269 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4270 else {
4271 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004272 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004273 t->flags &= ~SN_CACHE_COOK;
4274 }
4275 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004276 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004277 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004278 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004279 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4280 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004281 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004282 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004283 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4284 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4285 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4286 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4287 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4288 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004289 }
4290 }
4291 }
4292
willy tarreau5cbea6f2005-12-17 12:48:26 +01004293 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004294 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004295 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004296 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004297 char *p1, *p2, *p3, *p4;
4298
willy tarreau97f58572005-12-18 00:53:44 +01004299 t->flags |= SN_SCK_ANY;
4300
willy tarreau5cbea6f2005-12-17 12:48:26 +01004301 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4302
4303 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004304 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004305 p1++;
4306
4307 if (p1 == ptr || *p1 == ';') /* end of cookie */
4308 break;
4309
4310 /* p1 is at the beginning of the cookie name */
4311 p2 = p1;
4312
4313 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4314 p2++;
4315
4316 if (p2 == ptr || *p2 == ';') /* next cookie */
4317 break;
4318
4319 p3 = p2 + 1; /* skips the '=' sign */
4320 if (p3 == ptr)
4321 break;
4322
4323 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004324 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004325 p4++;
4326
4327 /* here, we have the cookie name between p1 and p2,
4328 * and its value between p3 and p4.
4329 * we can process it.
4330 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004331
4332 /* first, let's see if we want to capture it */
4333 if (t->proxy->capture_name != NULL &&
4334 t->logs.srv_cookie == NULL &&
4335 (p4 - p1 >= t->proxy->capture_namelen) &&
4336 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4337 int log_len = p4 - p1;
4338
4339 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4340 Alert("HTTP logging : out of memory.\n");
4341 }
4342
4343 if (log_len > t->proxy->capture_len)
4344 log_len = t->proxy->capture_len;
4345 memcpy(t->logs.srv_cookie, p1, log_len);
4346 t->logs.srv_cookie[log_len] = 0;
4347 }
4348
4349 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4350 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004351 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004352 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004353
4354 /* If the cookie is in insert mode on a known server, we'll delete
4355 * this occurrence because we'll insert another one later.
4356 * We'll delete it too if the "indirect" option is set and we're in
4357 * a direct access. */
4358 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004359 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004360 /* this header must be deleted */
4361 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004362 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004363 }
4364 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4365 /* replace bytes p3->p4 with the cookie name associated
4366 * with this server since we know it.
4367 */
4368 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004369 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004370 }
willy tarreau0174f312005-12-18 01:02:42 +01004371 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4372 /* insert the cookie name associated with this server
4373 * before existing cookie, and insert a delimitor between them..
4374 */
4375 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4376 p3[t->srv->cklen] = COOKIE_DELIM;
4377 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4378 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004379 break;
4380 }
willy tarreau12350152005-12-18 01:03:27 +01004381
4382 /* first, let's see if the cookie is our appcookie*/
4383 if ((t->proxy->appsession_name != NULL) &&
4384 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4385
4386 /* Cool... it's the right one */
4387
4388 size_t server_id_len = strlen(t->srv->id)+1;
4389 asession_temp = &local_asession;
4390
4391 if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
4392 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4393 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4394 }
4395 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4396 asession_temp->sessid[t->proxy->appsession_len] = 0;
4397 asession_temp->serverid = NULL;
4398
4399 /* only do insert, if lookup fails */
4400 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4401 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4402 Alert("Not enought Memory process_srv():asession:calloc().\n");
4403 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4404 return 0;
4405 }
4406 asession_temp->sessid = local_asession.sessid;
4407 asession_temp->serverid = local_asession.serverid;
4408 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4409 }/* end if(chtbl_lookup()) */
4410 else
4411 {
4412 /* free wasted memory */
4413 pool_free_to(apools.sessid, local_asession.sessid);
4414 } /* end else from if(chtbl_lookup()) */
4415
4416 if(asession_temp->serverid == NULL){
4417 if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
4418 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4419 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4420 }
4421 asession_temp->serverid[0] = '\0';
4422 }
4423
4424 if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
4425
4426 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4427
4428#if defined(DEBUG_HASH)
4429 print_table(&(t->proxy->htbl_proxy));
4430#endif
4431 break;
4432 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004433 else {
4434 // fprintf(stderr,"Ignoring unknown cookie : ");
4435 // write(2, p1, p2-p1);
4436 // fprintf(stderr," = ");
4437 // write(2, p3, p4-p3);
4438 // fprintf(stderr,"\n");
4439 }
4440 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4441 } /* we're now at the end of the cookie value */
4442 } /* end of cookie processing */
4443
willy tarreau97f58572005-12-18 00:53:44 +01004444 /* check for any set-cookie in case we check for cacheability */
4445 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4446 (t->proxy->options & PR_O_CHK_CACHE) &&
4447 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4448 t->flags |= SN_SCK_ANY;
4449 }
4450
willy tarreau5cbea6f2005-12-17 12:48:26 +01004451 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004452 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004453 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004454
willy tarreau5cbea6f2005-12-17 12:48:26 +01004455 rep->h = rep->lr;
4456 } /* while (rep->lr < rep->r) */
4457
4458 /* end of header processing (even if incomplete) */
4459
willy tarreauef900ab2005-12-17 12:52:52 +01004460 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4461 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4462 * full. We cannot loop here since event_srv_read will disable it only if
4463 * rep->l == rlim-data
4464 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004465 FD_SET(t->srv_fd, StaticReadEvent);
4466 if (t->proxy->srvtimeout)
4467 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4468 else
4469 tv_eternity(&t->srexpire);
4470 }
willy tarreau0f7af912005-12-17 12:21:26 +01004471
willy tarreau8337c6b2005-12-17 13:41:01 +01004472 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004473 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004474 tv_eternity(&t->srexpire);
4475 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004476 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004477 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004478 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004479 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004480 if (!(t->flags & SN_ERR_MASK))
4481 t->flags |= SN_ERR_SRVCL;
4482 if (!(t->flags & SN_FINST_MASK))
4483 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004484 return 1;
4485 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004486 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004487 * since we are in header mode, if there's no space left for headers, we
4488 * won't be able to free more later, so the session will never terminate.
4489 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004490 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 +01004491 FD_CLR(t->srv_fd, StaticReadEvent);
4492 tv_eternity(&t->srexpire);
4493 shutdown(t->srv_fd, SHUT_RD);
4494 t->srv_state = SV_STSHUTR;
4495 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004496 }
4497 /* read timeout : return a 504 to the client.
4498 */
4499 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4500 tv_eternity(&t->srexpire);
4501 tv_eternity(&t->swexpire);
4502 fd_delete(t->srv_fd);
4503 t->srv_state = SV_STCLOSE;
4504 t->logs.status = 504;
4505 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004506 if (!(t->flags & SN_ERR_MASK))
4507 t->flags |= SN_ERR_SRVTO;
4508 if (!(t->flags & SN_FINST_MASK))
4509 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004510 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004511
4512 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004513 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004514 /* FIXME!!! here, we don't want to switch to SHUTW if the
4515 * client shuts read too early, because we may still have
4516 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004517 * The side-effect is that if the client completely closes its
4518 * connection during SV_STHEADER, the connection to the server
4519 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004520 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004521 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004522 FD_CLR(t->srv_fd, StaticWriteEvent);
4523 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004524
4525 /* We must ensure that the read part is still alive when switching
4526 * to shutw */
4527 FD_SET(t->srv_fd, StaticReadEvent);
4528 if (t->proxy->srvtimeout)
4529 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4530
willy tarreau0f7af912005-12-17 12:21:26 +01004531 shutdown(t->srv_fd, SHUT_WR);
4532 t->srv_state = SV_STSHUTW;
4533 return 1;
4534 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004535 /* write timeout */
4536 /* FIXME!!! here, we don't want to switch to SHUTW if the
4537 * client shuts read too early, because we may still have
4538 * some work to do on the headers.
4539 */
4540 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4541 FD_CLR(t->srv_fd, StaticWriteEvent);
4542 tv_eternity(&t->swexpire);
4543 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004544 /* We must ensure that the read part is still alive when switching
4545 * to shutw */
4546 FD_SET(t->srv_fd, StaticReadEvent);
4547 if (t->proxy->srvtimeout)
4548 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4549
4550 /* We must ensure that the read part is still alive when switching
4551 * to shutw */
4552 FD_SET(t->srv_fd, StaticReadEvent);
4553 if (t->proxy->srvtimeout)
4554 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4555
willy tarreau036e1ce2005-12-17 13:46:33 +01004556 t->srv_state = SV_STSHUTW;
4557 if (!(t->flags & SN_ERR_MASK))
4558 t->flags |= SN_ERR_SRVTO;
4559 if (!(t->flags & SN_FINST_MASK))
4560 t->flags |= SN_FINST_H;
4561 return 1;
4562 }
willy tarreau0f7af912005-12-17 12:21:26 +01004563
4564 if (req->l == 0) {
4565 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4566 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4567 tv_eternity(&t->swexpire);
4568 }
4569 }
4570 else { /* client buffer not empty */
4571 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4572 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004573 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004574 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004575 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4576 t->srexpire = t->swexpire;
4577 }
willy tarreau0f7af912005-12-17 12:21:26 +01004578 else
4579 tv_eternity(&t->swexpire);
4580 }
4581 }
4582
willy tarreau5cbea6f2005-12-17 12:48:26 +01004583 /* be nice with the client side which would like to send a complete header
4584 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4585 * would read all remaining data at once ! The client should not write past rep->lr
4586 * when the server is in header state.
4587 */
4588 //return header_processed;
4589 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004590 }
4591 else if (s == SV_STDATA) {
4592 /* read or write error */
4593 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004594 tv_eternity(&t->srexpire);
4595 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004596 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004597 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004598 if (!(t->flags & SN_ERR_MASK))
4599 t->flags |= SN_ERR_SRVCL;
4600 if (!(t->flags & SN_FINST_MASK))
4601 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004602 return 1;
4603 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004604 /* last read, or end of client write */
4605 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004606 FD_CLR(t->srv_fd, StaticReadEvent);
4607 tv_eternity(&t->srexpire);
4608 shutdown(t->srv_fd, SHUT_RD);
4609 t->srv_state = SV_STSHUTR;
4610 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004611 }
4612 /* end of client read and no more data to send */
4613 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4614 FD_CLR(t->srv_fd, StaticWriteEvent);
4615 tv_eternity(&t->swexpire);
4616 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004617 /* We must ensure that the read part is still alive when switching
4618 * to shutw */
4619 FD_SET(t->srv_fd, StaticReadEvent);
4620 if (t->proxy->srvtimeout)
4621 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4622
willy tarreaua41a8b42005-12-17 14:02:24 +01004623 t->srv_state = SV_STSHUTW;
4624 return 1;
4625 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004626 /* read timeout */
4627 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4628 FD_CLR(t->srv_fd, StaticReadEvent);
4629 tv_eternity(&t->srexpire);
4630 shutdown(t->srv_fd, SHUT_RD);
4631 t->srv_state = SV_STSHUTR;
4632 if (!(t->flags & SN_ERR_MASK))
4633 t->flags |= SN_ERR_SRVTO;
4634 if (!(t->flags & SN_FINST_MASK))
4635 t->flags |= SN_FINST_D;
4636 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004637 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004638 /* write timeout */
4639 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004640 FD_CLR(t->srv_fd, StaticWriteEvent);
4641 tv_eternity(&t->swexpire);
4642 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004643 /* We must ensure that the read part is still alive when switching
4644 * to shutw */
4645 FD_SET(t->srv_fd, StaticReadEvent);
4646 if (t->proxy->srvtimeout)
4647 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004648 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004649 if (!(t->flags & SN_ERR_MASK))
4650 t->flags |= SN_ERR_SRVTO;
4651 if (!(t->flags & SN_FINST_MASK))
4652 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004653 return 1;
4654 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004655
4656 /* recompute request time-outs */
4657 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004658 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4659 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4660 tv_eternity(&t->swexpire);
4661 }
4662 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004663 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004664 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4665 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004666 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004667 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004668 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4669 t->srexpire = t->swexpire;
4670 }
willy tarreau0f7af912005-12-17 12:21:26 +01004671 else
4672 tv_eternity(&t->swexpire);
4673 }
4674 }
4675
willy tarreaub1ff9db2005-12-17 13:51:03 +01004676 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004677 if (rep->l == BUFSIZE) { /* no room to read more data */
4678 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4679 FD_CLR(t->srv_fd, StaticReadEvent);
4680 tv_eternity(&t->srexpire);
4681 }
4682 }
4683 else {
4684 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4685 FD_SET(t->srv_fd, StaticReadEvent);
4686 if (t->proxy->srvtimeout)
4687 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4688 else
4689 tv_eternity(&t->srexpire);
4690 }
4691 }
4692
4693 return 0; /* other cases change nothing */
4694 }
4695 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004696 if (t->res_sw == RES_ERROR) {
4697 //FD_CLR(t->srv_fd, StaticWriteEvent);
4698 tv_eternity(&t->swexpire);
4699 fd_delete(t->srv_fd);
4700 //close(t->srv_fd);
4701 t->srv_state = SV_STCLOSE;
4702 if (!(t->flags & SN_ERR_MASK))
4703 t->flags |= SN_ERR_SRVCL;
4704 if (!(t->flags & SN_FINST_MASK))
4705 t->flags |= SN_FINST_D;
4706 return 1;
4707 }
4708 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004709 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004710 tv_eternity(&t->swexpire);
4711 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004712 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004713 t->srv_state = SV_STCLOSE;
4714 return 1;
4715 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004716 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4717 //FD_CLR(t->srv_fd, StaticWriteEvent);
4718 tv_eternity(&t->swexpire);
4719 fd_delete(t->srv_fd);
4720 //close(t->srv_fd);
4721 t->srv_state = SV_STCLOSE;
4722 if (!(t->flags & SN_ERR_MASK))
4723 t->flags |= SN_ERR_SRVTO;
4724 if (!(t->flags & SN_FINST_MASK))
4725 t->flags |= SN_FINST_D;
4726 return 1;
4727 }
willy tarreau0f7af912005-12-17 12:21:26 +01004728 else if (req->l == 0) {
4729 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4730 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4731 tv_eternity(&t->swexpire);
4732 }
4733 }
4734 else { /* buffer not empty */
4735 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4736 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004737 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004738 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004739 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4740 t->srexpire = t->swexpire;
4741 }
willy tarreau0f7af912005-12-17 12:21:26 +01004742 else
4743 tv_eternity(&t->swexpire);
4744 }
4745 }
4746 return 0;
4747 }
4748 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004749 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004750 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004751 tv_eternity(&t->srexpire);
4752 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004753 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004754 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004755 if (!(t->flags & SN_ERR_MASK))
4756 t->flags |= SN_ERR_SRVCL;
4757 if (!(t->flags & SN_FINST_MASK))
4758 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004759 return 1;
4760 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004761 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4762 //FD_CLR(t->srv_fd, StaticReadEvent);
4763 tv_eternity(&t->srexpire);
4764 fd_delete(t->srv_fd);
4765 //close(t->srv_fd);
4766 t->srv_state = SV_STCLOSE;
4767 return 1;
4768 }
4769 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4770 //FD_CLR(t->srv_fd, StaticReadEvent);
4771 tv_eternity(&t->srexpire);
4772 fd_delete(t->srv_fd);
4773 //close(t->srv_fd);
4774 t->srv_state = SV_STCLOSE;
4775 if (!(t->flags & SN_ERR_MASK))
4776 t->flags |= SN_ERR_SRVTO;
4777 if (!(t->flags & SN_FINST_MASK))
4778 t->flags |= SN_FINST_D;
4779 return 1;
4780 }
willy tarreau0f7af912005-12-17 12:21:26 +01004781 else if (rep->l == BUFSIZE) { /* no room to read more data */
4782 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4783 FD_CLR(t->srv_fd, StaticReadEvent);
4784 tv_eternity(&t->srexpire);
4785 }
4786 }
4787 else {
4788 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4789 FD_SET(t->srv_fd, StaticReadEvent);
4790 if (t->proxy->srvtimeout)
4791 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4792 else
4793 tv_eternity(&t->srexpire);
4794 }
4795 }
4796 return 0;
4797 }
4798 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004799 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004800 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004801 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 +01004802 write(1, trash, len);
4803 }
4804 return 0;
4805 }
4806 return 0;
4807}
4808
4809
willy tarreau5cbea6f2005-12-17 12:48:26 +01004810/* Processes the client and server jobs of a session task, then
4811 * puts it back to the wait queue in a clean state, or
4812 * cleans up its resources if it must be deleted. Returns
4813 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004814 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004815int process_session(struct task *t) {
4816 struct session *s = t->context;
4817 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004818
willy tarreau5cbea6f2005-12-17 12:48:26 +01004819 do {
4820 fsm_resync = 0;
4821 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4822 fsm_resync |= process_cli(s);
4823 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4824 fsm_resync |= process_srv(s);
4825 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4826 } while (fsm_resync);
4827
4828 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004829 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004830 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004831
willy tarreau5cbea6f2005-12-17 12:48:26 +01004832 tv_min(&min1, &s->crexpire, &s->cwexpire);
4833 tv_min(&min2, &s->srexpire, &s->swexpire);
4834 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004835 tv_min(&t->expire, &min1, &min2);
4836
4837 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004838 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004839
willy tarreau5cbea6f2005-12-17 12:48:26 +01004840 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004841 }
4842
willy tarreau5cbea6f2005-12-17 12:48:26 +01004843 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004844 actconn--;
4845
willy tarreau982249e2005-12-18 00:57:06 +01004846 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004847 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004848 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 +01004849 write(1, trash, len);
4850 }
4851
willy tarreau750a4722005-12-17 13:21:24 +01004852 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004853 if (s->rep != NULL)
4854 s->logs.bytes = s->rep->total;
4855
willy tarreau9fe663a2005-12-17 13:02:59 +01004856 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004857 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004858 sess_log(s);
4859
willy tarreau0f7af912005-12-17 12:21:26 +01004860 /* the task MUST not be in the run queue anymore */
4861 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004862 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004863 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004864 return -1; /* rest in peace for eternity */
4865}
4866
4867
4868
4869/*
4870 * manages a server health-check. Returns
4871 * the time the task accepts to wait, or -1 for infinity.
4872 */
4873int process_chk(struct task *t) {
4874 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004875 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004876 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877
willy tarreauef900ab2005-12-17 12:52:52 +01004878 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004879
4880 if (fd < 0) { /* no check currently running */
4881 //fprintf(stderr, "process_chk: 2\n");
4882 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4883 task_queue(t); /* restore t to its place in the task list */
4884 return tv_remain(&now, &t->expire);
4885 }
4886
4887 /* we'll initiate a new check */
4888 s->result = 0; /* no result yet */
4889 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004890 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004891 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4892 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4893 //fprintf(stderr, "process_chk: 3\n");
4894
willy tarreaua41a8b42005-12-17 14:02:24 +01004895 /* we'll connect to the check port on the server */
4896 sa = s->addr;
4897 sa.sin_port = htons(s->check_port);
4898
willy tarreau0174f312005-12-18 01:02:42 +01004899 /* allow specific binding :
4900 * - server-specific at first
4901 * - proxy-specific next
4902 */
4903 if (s->state & SRV_BIND_SRC) {
4904 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4905 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4906 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4907 s->proxy->id, s->id);
4908 s->result = -1;
4909 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004910 }
willy tarreau0174f312005-12-18 01:02:42 +01004911 else if (s->proxy->options & PR_O_BIND_SRC) {
4912 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4913 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4914 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4915 s->proxy->id);
4916 s->result = -1;
4917 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004918 }
willy tarreau0174f312005-12-18 01:02:42 +01004919
4920 if (!s->result) {
4921 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4922 /* OK, connection in progress or established */
4923
4924 //fprintf(stderr, "process_chk: 4\n");
4925
4926 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4927 fdtab[fd].owner = t;
4928 fdtab[fd].read = &event_srv_chk_r;
4929 fdtab[fd].write = &event_srv_chk_w;
4930 fdtab[fd].state = FD_STCONN; /* connection in progress */
4931 FD_SET(fd, StaticWriteEvent); /* for connect status */
4932 fd_insert(fd);
4933 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4934 tv_delayfrom(&t->expire, &now, s->inter);
4935 task_queue(t); /* restore t to its place in the task list */
4936 return tv_remain(&now, &t->expire);
4937 }
4938 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4939 s->result = -1; /* a real error */
4940 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 }
4942 }
willy tarreau08dedbe2005-12-18 01:13:48 +01004943 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004944 }
4945
4946 if (!s->result) { /* nothing done */
4947 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004948 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004949 task_queue(t); /* restore t to its place in the task list */
4950 return tv_remain(&now, &t->expire);
4951 }
4952
4953 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004954 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004955 s->health--; /* still good */
4956 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004957 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004958 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004959 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004960 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004961
willy tarreaudd07e972005-12-18 00:48:48 +01004962 if (find_server(s->proxy) == NULL) {
4963 Alert("Proxy %s has no server available !\n", s->proxy->id);
4964 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4965 }
4966 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004967 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004968 }
4969
4970 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004971 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4972 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004973 }
4974 else {
4975 //fprintf(stderr, "process_chk: 8\n");
4976 /* there was a test running */
4977 if (s->result > 0) { /* good server detected */
4978 //fprintf(stderr, "process_chk: 9\n");
4979 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004980 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004981 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004982 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004983 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004984 }
willy tarreauef900ab2005-12-17 12:52:52 +01004985
willy tarreaue47c8d72005-12-17 12:55:52 +01004986 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004987 s->state |= SRV_RUNNING;
4988 }
willy tarreauef900ab2005-12-17 12:52:52 +01004989 s->curfd = -1; /* no check running anymore */
4990 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004991 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004992 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004993 }
4994 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4995 //fprintf(stderr, "process_chk: 10\n");
4996 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004997 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004998 s->health--; /* still good */
4999 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005000 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005001
willy tarreaudd07e972005-12-18 00:48:48 +01005002 if (s->health == s->rise) {
5003 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005004 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005005
5006 if (find_server(s->proxy) == NULL) {
5007 Alert("Proxy %s has no server available !\n", s->proxy->id);
5008 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5009 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005010 }
willy tarreauef900ab2005-12-17 12:52:52 +01005011
willy tarreau5cbea6f2005-12-17 12:48:26 +01005012 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005013 }
5014 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005015 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005016 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005017 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005018 }
5019 /* if result is 0 and there's no timeout, we have to wait again */
5020 }
5021 //fprintf(stderr, "process_chk: 11\n");
5022 s->result = 0;
5023 task_queue(t); /* restore t to its place in the task list */
5024 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005025}
5026
5027
willy tarreau5cbea6f2005-12-17 12:48:26 +01005028
willy tarreau0f7af912005-12-17 12:21:26 +01005029#if STATTIME > 0
5030int stats(void);
5031#endif
5032
5033/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005034 * This does 4 things :
5035 * - wake up all expired tasks
5036 * - call all runnable tasks
5037 * - call maintain_proxies() to enable/disable the listeners
5038 * - return the delay till next event in ms, -1 = wait indefinitely
5039 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5040 *
willy tarreau0f7af912005-12-17 12:21:26 +01005041 */
5042
willy tarreau1c2ad212005-12-18 01:11:29 +01005043int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005044 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005045 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005046 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005047
willy tarreau1c2ad212005-12-18 01:11:29 +01005048 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005049
willy tarreau1c2ad212005-12-18 01:11:29 +01005050 /* look for expired tasks and add them to the run queue.
5051 */
5052 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5053 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5054 tnext = t->next;
5055 if (t->state & TASK_RUNNING)
5056 continue;
5057
5058 /* wakeup expired entries. It doesn't matter if they are
5059 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005060 */
willy tarreau1c2ad212005-12-18 01:11:29 +01005061 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
5062 task_wakeup(&rq, t);
5063 }
5064 else {
5065 /* first non-runnable task. Use its expiration date as an upper bound */
5066 int temp_time = tv_remain(&now, &t->expire);
5067 if (temp_time)
5068 next_time = temp_time;
5069 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005070 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005071 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005072
willy tarreau1c2ad212005-12-18 01:11:29 +01005073 /* process each task in the run queue now. Each task may be deleted
5074 * since we only use tnext.
5075 */
5076 tnext = rq;
5077 while ((t = tnext) != NULL) {
5078 int temp_time;
5079
5080 tnext = t->rqnext;
5081 task_sleep(&rq, t);
5082 temp_time = t->process(t);
5083 next_time = MINTIME(temp_time, next_time);
5084 }
5085
5086 /* maintain all proxies in a consistent state. This should quickly become a task */
5087 time2 = maintain_proxies();
5088 return MINTIME(time2, next_time);
5089}
5090
5091
5092#if defined(ENABLE_EPOLL)
5093
5094/*
5095 * Main epoll() loop.
5096 */
5097
5098/* does 3 actions :
5099 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5100 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5101 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5102 *
5103 * returns 0 if initialization failed, !0 otherwise.
5104 */
5105
5106int epoll_loop(int action) {
5107 int next_time;
5108 int status;
5109 int fd;
5110
5111 int fds, count;
5112 int pr, pw, sr, sw;
5113 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5114 struct epoll_event ev;
5115
5116 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005117 static struct epoll_event *epoll_events = NULL;
5118 static int epoll_fd;
5119
5120 if (action == POLL_LOOP_ACTION_INIT) {
5121 epoll_fd = epoll_create(global.maxsock + 1);
5122 if (epoll_fd < 0)
5123 return 0;
5124 else {
5125 epoll_events = (struct epoll_event*)
5126 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5127 PrevReadEvent = (fd_set *)
5128 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5129 PrevWriteEvent = (fd_set *)
5130 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005131 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005132 return 1;
5133 }
5134 else if (action == POLL_LOOP_ACTION_CLEAN) {
5135 if (PrevWriteEvent) free(PrevWriteEvent);
5136 if (PrevReadEvent) free(PrevReadEvent);
5137 if (epoll_events) free(epoll_events);
5138 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005139 epoll_fd = 0;
5140 return 1;
5141 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005142
willy tarreau1c2ad212005-12-18 01:11:29 +01005143 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005144
willy tarreau1c2ad212005-12-18 01:11:29 +01005145 tv_now(&now);
5146
5147 while (1) {
5148 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005149
5150 /* stop when there's no connection left and we don't allow them anymore */
5151 if (!actconn && listeners == 0)
5152 break;
5153
willy tarreau0f7af912005-12-17 12:21:26 +01005154#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005155 {
5156 int time2;
5157 time2 = stats();
5158 next_time = MINTIME(time2, next_time);
5159 }
willy tarreau0f7af912005-12-17 12:21:26 +01005160#endif
5161
willy tarreau1c2ad212005-12-18 01:11:29 +01005162 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5163
5164 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5165 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5166
5167 if ((ro^rn) | (wo^wn)) {
5168 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5169#define FDSETS_ARE_INT_ALIGNED
5170#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005171
willy tarreauad90a0c2005-12-18 01:09:15 +01005172#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5173#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005174 pr = (ro >> count) & 1;
5175 pw = (wo >> count) & 1;
5176 sr = (rn >> count) & 1;
5177 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005178#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005179 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5180 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5181 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5182 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005183#endif
5184#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005185 pr = FD_ISSET(fd, PrevReadEvent);
5186 pw = FD_ISSET(fd, PrevWriteEvent);
5187 sr = FD_ISSET(fd, StaticReadEvent);
5188 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005189#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005190 if (!((sr^pr) | (sw^pw)))
5191 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005192
willy tarreau1c2ad212005-12-18 01:11:29 +01005193 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5194 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005195
willy tarreau1c2ad212005-12-18 01:11:29 +01005196 if ((pr | pw)) {
5197 /* the file-descriptor already exists... */
5198 if ((sr | sw)) {
5199 /* ...and it will still exist */
5200 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5201 // perror("epoll_ctl(MOD)");
5202 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005203 }
5204 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005205 /* ...and it will be removed */
5206 if (fdtab[fd].state != FD_STCLOSE &&
5207 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5208 // perror("epoll_ctl(DEL)");
5209 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005210 }
5211 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005212 } else {
5213 /* the file-descriptor did not exist, let's add it */
5214 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5215 // perror("epoll_ctl(ADD)");
5216 // exit(1);
5217 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005218 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005219 }
5220 ((int*)PrevReadEvent)[fds] = rn;
5221 ((int*)PrevWriteEvent)[fds] = wn;
5222 }
5223 }
5224
5225 /* now let's wait for events */
5226 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5227 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005228
willy tarreau1c2ad212005-12-18 01:11:29 +01005229 for (count = 0; count < status; count++) {
5230 fd = epoll_events[count].data.fd;
5231
5232 if (fdtab[fd].state == FD_STCLOSE)
5233 continue;
5234
5235 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5236 fdtab[fd].read(fd);
5237
5238 if (fdtab[fd].state == FD_STCLOSE)
5239 continue;
5240
5241 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5242 fdtab[fd].write(fd);
5243 }
5244 }
5245 return 1;
5246}
5247#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005248
willy tarreauad90a0c2005-12-18 01:09:15 +01005249
willy tarreau5cbea6f2005-12-17 12:48:26 +01005250
willy tarreau1c2ad212005-12-18 01:11:29 +01005251#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005252
willy tarreau1c2ad212005-12-18 01:11:29 +01005253/*
5254 * Main poll() loop.
5255 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005256
willy tarreau1c2ad212005-12-18 01:11:29 +01005257/* does 3 actions :
5258 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5259 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5260 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5261 *
5262 * returns 0 if initialization failed, !0 otherwise.
5263 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005264
willy tarreau1c2ad212005-12-18 01:11:29 +01005265int poll_loop(int action) {
5266 int next_time;
5267 int status;
5268 int fd, nbfd;
5269
5270 int fds, count;
5271 int sr, sw;
5272 unsigned rn, wn; /* read new, write new */
5273
5274 /* private data */
5275 static struct pollfd *poll_events = NULL;
5276
5277 if (action == POLL_LOOP_ACTION_INIT) {
5278 poll_events = (struct pollfd*)
5279 calloc(1, sizeof(struct pollfd) * global.maxsock);
5280 return 1;
5281 }
5282 else if (action == POLL_LOOP_ACTION_CLEAN) {
5283 if (poll_events)
5284 free(poll_events);
5285 return 1;
5286 }
5287
5288 /* OK, it's POLL_LOOP_ACTION_RUN */
5289
5290 tv_now(&now);
5291
5292 while (1) {
5293 next_time = process_runnable_tasks();
5294
5295 /* stop when there's no connection left and we don't allow them anymore */
5296 if (!actconn && listeners == 0)
5297 break;
5298
5299#if STATTIME > 0
5300 {
5301 int time2;
5302 time2 = stats();
5303 next_time = MINTIME(time2, next_time);
5304 }
5305#endif
5306
5307
5308 nbfd = 0;
5309 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5310
5311 rn = ((int*)StaticReadEvent)[fds];
5312 wn = ((int*)StaticWriteEvent)[fds];
5313
5314 if ((rn|wn)) {
5315 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5316#define FDSETS_ARE_INT_ALIGNED
5317#ifdef FDSETS_ARE_INT_ALIGNED
5318
5319#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5320#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5321 sr = (rn >> count) & 1;
5322 sw = (wn >> count) & 1;
5323#else
5324 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5325 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5326#endif
5327#else
5328 sr = FD_ISSET(fd, StaticReadEvent);
5329 sw = FD_ISSET(fd, StaticWriteEvent);
5330#endif
5331 if ((sr|sw)) {
5332 poll_events[nbfd].fd = fd;
5333 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5334 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005335 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005336 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005337 }
5338 }
5339
5340 /* now let's wait for events */
5341 status = poll(poll_events, nbfd, next_time);
5342 tv_now(&now);
5343
5344 for (count = 0; status > 0 && count < nbfd; count++) {
5345 fd = poll_events[count].fd;
5346
5347 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5348 continue;
5349
5350 /* ok, we found one active fd */
5351 status--;
5352
5353 if (fdtab[fd].state == FD_STCLOSE)
5354 continue;
5355
5356 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5357 fdtab[fd].read(fd);
5358
5359 if (fdtab[fd].state == FD_STCLOSE)
5360 continue;
5361
5362 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5363 fdtab[fd].write(fd);
5364 }
5365 }
5366 return 1;
5367}
willy tarreauad90a0c2005-12-18 01:09:15 +01005368#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005369
willy tarreauad90a0c2005-12-18 01:09:15 +01005370
willy tarreauad90a0c2005-12-18 01:09:15 +01005371
willy tarreau1c2ad212005-12-18 01:11:29 +01005372/*
5373 * Main select() loop.
5374 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005375
willy tarreau1c2ad212005-12-18 01:11:29 +01005376/* does 3 actions :
5377 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5378 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5379 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5380 *
5381 * returns 0 if initialization failed, !0 otherwise.
5382 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005383
willy tarreauad90a0c2005-12-18 01:09:15 +01005384
willy tarreau1c2ad212005-12-18 01:11:29 +01005385int select_loop(int action) {
5386 int next_time;
5387 int status;
5388 int fd,i;
5389 struct timeval delta;
5390 int readnotnull, writenotnull;
5391 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005392
willy tarreau1c2ad212005-12-18 01:11:29 +01005393 if (action == POLL_LOOP_ACTION_INIT) {
5394 ReadEvent = (fd_set *)
5395 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5396 WriteEvent = (fd_set *)
5397 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5398 return 1;
5399 }
5400 else if (action == POLL_LOOP_ACTION_CLEAN) {
5401 if (WriteEvent) free(WriteEvent);
5402 if (ReadEvent) free(ReadEvent);
5403 return 1;
5404 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005405
willy tarreau1c2ad212005-12-18 01:11:29 +01005406 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005407
willy tarreau1c2ad212005-12-18 01:11:29 +01005408 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005409
willy tarreau1c2ad212005-12-18 01:11:29 +01005410 while (1) {
5411 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005412
willy tarreau1c2ad212005-12-18 01:11:29 +01005413 /* stop when there's no connection left and we don't allow them anymore */
5414 if (!actconn && listeners == 0)
5415 break;
5416
5417#if STATTIME > 0
5418 {
5419 int time2;
5420 time2 = stats();
5421 next_time = MINTIME(time2, next_time);
5422 }
5423#endif
5424
willy tarreau1c2ad212005-12-18 01:11:29 +01005425 if (next_time > 0) { /* FIXME */
5426 /* Convert to timeval */
5427 /* to avoid eventual select loops due to timer precision */
5428 next_time += SCHEDULER_RESOLUTION;
5429 delta.tv_sec = next_time / 1000;
5430 delta.tv_usec = (next_time % 1000) * 1000;
5431 }
5432 else if (next_time == 0) { /* allow select to return immediately when needed */
5433 delta.tv_sec = delta.tv_usec = 0;
5434 }
5435
5436
5437 /* let's restore fdset state */
5438
5439 readnotnull = 0; writenotnull = 0;
5440 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5441 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5442 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5443 }
5444
5445 // /* just a verification code, needs to be removed for performance */
5446 // for (i=0; i<maxfd; i++) {
5447 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5448 // abort();
5449 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5450 // abort();
5451 //
5452 // }
5453
5454 status = select(maxfd,
5455 readnotnull ? ReadEvent : NULL,
5456 writenotnull ? WriteEvent : NULL,
5457 NULL,
5458 (next_time >= 0) ? &delta : NULL);
5459
5460 /* this is an experiment on the separation of the select work */
5461 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5462 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5463
5464 tv_now(&now);
5465
5466 if (status > 0) { /* must proceed with events */
5467
5468 int fds;
5469 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005470
willy tarreau1c2ad212005-12-18 01:11:29 +01005471 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5472 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5473 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5474
5475 /* if we specify read first, the accepts and zero reads will be
5476 * seen first. Moreover, system buffers will be flushed faster.
5477 */
5478 if (fdtab[fd].state == FD_STCLOSE)
5479 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005480
willy tarreau1c2ad212005-12-18 01:11:29 +01005481 if (FD_ISSET(fd, ReadEvent))
5482 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005483
willy tarreau1c2ad212005-12-18 01:11:29 +01005484 if (FD_ISSET(fd, WriteEvent))
5485 fdtab[fd].write(fd);
5486 }
5487 }
5488 else {
5489 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005490 }
willy tarreau0f7af912005-12-17 12:21:26 +01005491 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005492 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005493}
5494
5495
5496#if STATTIME > 0
5497/*
5498 * Display proxy statistics regularly. It is designed to be called from the
5499 * select_loop().
5500 */
5501int stats(void) {
5502 static int lines;
5503 static struct timeval nextevt;
5504 static struct timeval lastevt;
5505 static struct timeval starttime = {0,0};
5506 unsigned long totaltime, deltatime;
5507 int ret;
5508
willy tarreau750a4722005-12-17 13:21:24 +01005509 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005510 deltatime = (tv_diff(&lastevt, &now)?:1);
5511 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005512
willy tarreau9fe663a2005-12-17 13:02:59 +01005513 if (global.mode & MODE_STATS) {
5514 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005515 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005516 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5517 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005518 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005519 actconn, totalconn,
5520 stats_tsk_new, stats_tsk_good,
5521 stats_tsk_left, stats_tsk_right,
5522 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5523 }
5524 }
5525
5526 tv_delayfrom(&nextevt, &now, STATTIME);
5527
5528 lastevt=now;
5529 }
5530 ret = tv_remain(&now, &nextevt);
5531 return ret;
5532}
5533#endif
5534
5535
5536/*
5537 * this function enables proxies when there are enough free sessions,
5538 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005539 * select_loop(). It returns the time left before next expiration event
5540 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005541 */
5542static int maintain_proxies(void) {
5543 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005544 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005545 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005546
5547 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005548 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005549
5550 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005551 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005552 while (p) {
5553 if (p->nbconn < p->maxconn) {
5554 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005555 for (l = p->listen; l != NULL; l = l->next) {
5556 FD_SET(l->fd, StaticReadEvent);
5557 }
willy tarreau0f7af912005-12-17 12:21:26 +01005558 p->state = PR_STRUN;
5559 }
5560 }
5561 else {
5562 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005563 for (l = p->listen; l != NULL; l = l->next) {
5564 FD_CLR(l->fd, StaticReadEvent);
5565 }
willy tarreau0f7af912005-12-17 12:21:26 +01005566 p->state = PR_STIDLE;
5567 }
5568 }
5569 p = p->next;
5570 }
5571 }
5572 else { /* block all proxies */
5573 while (p) {
5574 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005575 for (l = p->listen; l != NULL; l = l->next) {
5576 FD_CLR(l->fd, StaticReadEvent);
5577 }
willy tarreau0f7af912005-12-17 12:21:26 +01005578 p->state = PR_STIDLE;
5579 }
5580 p = p->next;
5581 }
5582 }
5583
willy tarreau5cbea6f2005-12-17 12:48:26 +01005584 if (stopping) {
5585 p = proxy;
5586 while (p) {
5587 if (p->state != PR_STDISABLED) {
5588 int t;
5589 t = tv_remain(&now, &p->stop_time);
5590 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005591 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005592 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005593
willy tarreaua41a8b42005-12-17 14:02:24 +01005594 for (l = p->listen; l != NULL; l = l->next) {
5595 fd_delete(l->fd);
5596 listeners--;
5597 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005598 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005599 }
5600 else {
5601 tleft = MINTIME(t, tleft);
5602 }
5603 }
5604 p = p->next;
5605 }
5606 }
5607 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005608}
5609
5610/*
5611 * this function disables health-check servers so that the process will quickly be ignored
5612 * by load balancers.
5613 */
5614static void soft_stop(void) {
5615 struct proxy *p;
5616
5617 stopping = 1;
5618 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005619 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005620 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005621 if (p->state != PR_STDISABLED) {
5622 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005623 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005624 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005625 }
willy tarreau0f7af912005-12-17 12:21:26 +01005626 p = p->next;
5627 }
5628}
5629
5630/*
5631 * upon SIGUSR1, let's have a soft stop.
5632 */
5633void sig_soft_stop(int sig) {
5634 soft_stop();
5635 signal(sig, SIG_IGN);
5636}
5637
5638
willy tarreau8337c6b2005-12-17 13:41:01 +01005639/*
5640 * this function dumps every server's state when the process receives SIGHUP.
5641 */
5642void sig_dump_state(int sig) {
5643 struct proxy *p = proxy;
5644
5645 Warning("SIGHUP received, dumping servers states.\n");
5646 while (p) {
5647 struct server *s = p->srv;
5648
5649 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5650 while (s) {
5651 if (s->state & SRV_RUNNING) {
5652 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5653 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5654 }
5655 else {
5656 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5657 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5658 }
5659 s = s->next;
5660 }
willy tarreaudd07e972005-12-18 00:48:48 +01005661
5662 if (find_server(p) == NULL) {
5663 Warning("SIGHUP: proxy %s has no server available !\n", p);
5664 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5665 }
5666
willy tarreau8337c6b2005-12-17 13:41:01 +01005667 p = p->next;
5668 }
5669 signal(sig, sig_dump_state);
5670}
5671
willy tarreau0f7af912005-12-17 12:21:26 +01005672void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005673 struct task *t, *tnext;
5674 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005675
willy tarreau5cbea6f2005-12-17 12:48:26 +01005676 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5677 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5678 tnext = t->next;
5679 s = t->context;
5680 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5681 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5682 "req=%d, rep=%d, clifd=%d\n",
5683 s, tv_remain(&now, &t->expire),
5684 s->cli_state,
5685 s->srv_state,
5686 FD_ISSET(s->cli_fd, StaticReadEvent),
5687 FD_ISSET(s->cli_fd, StaticWriteEvent),
5688 FD_ISSET(s->srv_fd, StaticReadEvent),
5689 FD_ISSET(s->srv_fd, StaticWriteEvent),
5690 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5691 );
willy tarreau0f7af912005-12-17 12:21:26 +01005692 }
willy tarreau12350152005-12-18 01:03:27 +01005693}
5694
willy tarreau64a3cc32005-12-18 01:13:11 +01005695#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005696static void fast_stop(void)
5697{
5698 struct proxy *p;
5699 p = proxy;
5700 while (p) {
5701 p->grace = 0;
5702 p = p->next;
5703 }
5704 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005705}
5706
willy tarreau12350152005-12-18 01:03:27 +01005707void sig_int(int sig) {
5708 /* This would normally be a hard stop,
5709 but we want to be sure about deallocation,
5710 and so on, so we do a soft stop with
5711 0 GRACE time
5712 */
5713 fast_stop();
5714 /* If we are killed twice, we decide to die*/
5715 signal(sig, SIG_DFL);
5716}
5717
5718void sig_term(int sig) {
5719 /* This would normally be a hard stop,
5720 but we want to be sure about deallocation,
5721 and so on, so we do a soft stop with
5722 0 GRACE time
5723 */
5724 fast_stop();
5725 /* If we are killed twice, we decide to die*/
5726 signal(sig, SIG_DFL);
5727}
willy tarreau64a3cc32005-12-18 01:13:11 +01005728#endif
willy tarreau12350152005-12-18 01:03:27 +01005729
willy tarreauc1f47532005-12-18 01:08:26 +01005730/* returns the pointer to an error in the replacement string, or NULL if OK */
5731char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005732 struct hdr_exp *exp;
5733
willy tarreauc1f47532005-12-18 01:08:26 +01005734 if (replace != NULL) {
5735 char *err;
5736 err = check_replace_string(replace);
5737 if (err)
5738 return err;
5739 }
5740
willy tarreaue39cd132005-12-17 13:00:18 +01005741 while (*head != NULL)
5742 head = &(*head)->next;
5743
5744 exp = calloc(1, sizeof(struct hdr_exp));
5745
5746 exp->preg = preg;
5747 exp->replace = replace;
5748 exp->action = action;
5749 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005750
5751 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005752}
5753
willy tarreau9fe663a2005-12-17 13:02:59 +01005754
willy tarreau0f7af912005-12-17 12:21:26 +01005755/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005756 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005757 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005758int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005759
willy tarreau9fe663a2005-12-17 13:02:59 +01005760 if (!strcmp(args[0], "global")) { /* new section */
5761 /* no option, nothing special to do */
5762 return 0;
5763 }
5764 else if (!strcmp(args[0], "daemon")) {
5765 global.mode |= MODE_DAEMON;
5766 }
5767 else if (!strcmp(args[0], "debug")) {
5768 global.mode |= MODE_DEBUG;
5769 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005770 else if (!strcmp(args[0], "noepoll")) {
5771 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5772 }
5773 else if (!strcmp(args[0], "nopoll")) {
5774 cfg_polling_mechanism &= ~POLL_USE_POLL;
5775 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005776 else if (!strcmp(args[0], "quiet")) {
5777 global.mode |= MODE_QUIET;
5778 }
5779 else if (!strcmp(args[0], "stats")) {
5780 global.mode |= MODE_STATS;
5781 }
5782 else if (!strcmp(args[0], "uid")) {
5783 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005784 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005785 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005786 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005787 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005788 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005789 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005790 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005791 global.uid = atol(args[1]);
5792 }
5793 else if (!strcmp(args[0], "gid")) {
5794 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005795 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005796 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005797 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005798 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005799 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005800 return -1;
5801 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005802 global.gid = atol(args[1]);
5803 }
5804 else if (!strcmp(args[0], "nbproc")) {
5805 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005806 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005807 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005808 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005809 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005810 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005811 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005812 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005813 global.nbproc = atol(args[1]);
5814 }
5815 else if (!strcmp(args[0], "maxconn")) {
5816 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005817 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005818 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005819 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005820 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005821 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005822 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005823 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005824 global.maxconn = atol(args[1]);
5825 }
willy tarreaub1285d52005-12-18 01:20:14 +01005826 else if (!strcmp(args[0], "ulimit-n")) {
5827 if (global.rlimit_nofile != 0) {
5828 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5829 return 0;
5830 }
5831 if (*(args[1]) == 0) {
5832 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5833 return -1;
5834 }
5835 global.rlimit_nofile = atol(args[1]);
5836 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005837 else if (!strcmp(args[0], "chroot")) {
5838 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005839 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005840 return 0;
5841 }
5842 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005843 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005844 return -1;
5845 }
5846 global.chroot = strdup(args[1]);
5847 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005848 else if (!strcmp(args[0], "pidfile")) {
5849 if (global.pidfile != NULL) {
5850 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5851 return 0;
5852 }
5853 if (*(args[1]) == 0) {
5854 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5855 return -1;
5856 }
5857 global.pidfile = strdup(args[1]);
5858 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005859 else if (!strcmp(args[0], "log")) { /* syslog server address */
5860 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005861 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005862
5863 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005864 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005865 return -1;
5866 }
5867
5868 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5869 if (!strcmp(log_facilities[facility], args[2]))
5870 break;
5871
5872 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005873 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005874 exit(1);
5875 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005876
5877 level = 7; /* max syslog level = debug */
5878 if (*(args[3])) {
5879 while (level >= 0 && strcmp(log_levels[level], args[3]))
5880 level--;
5881 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005882 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005883 exit(1);
5884 }
5885 }
5886
willy tarreau9fe663a2005-12-17 13:02:59 +01005887 sa = str2sa(args[1]);
5888 if (!sa->sin_port)
5889 sa->sin_port = htons(SYSLOG_PORT);
5890
5891 if (global.logfac1 == -1) {
5892 global.logsrv1 = *sa;
5893 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005894 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005895 }
5896 else if (global.logfac2 == -1) {
5897 global.logsrv2 = *sa;
5898 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005899 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005900 }
5901 else {
5902 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5903 return -1;
5904 }
5905
5906 }
5907 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005908 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005909 return -1;
5910 }
5911 return 0;
5912}
5913
5914
willy tarreaua41a8b42005-12-17 14:02:24 +01005915void init_default_instance() {
5916 memset(&defproxy, 0, sizeof(defproxy));
5917 defproxy.mode = PR_MODE_TCP;
5918 defproxy.state = PR_STNEW;
5919 defproxy.maxconn = cfg_maxpconn;
5920 defproxy.conn_retries = CONN_RETRIES;
5921 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
5922}
5923
willy tarreau9fe663a2005-12-17 13:02:59 +01005924/*
5925 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5926 */
5927int cfg_parse_listen(char *file, int linenum, char **args) {
5928 static struct proxy *curproxy = NULL;
5929 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01005930 char *err;
willy tarreau12350152005-12-18 01:03:27 +01005931 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01005932
5933 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005934 if (!*args[1]) {
5935 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5936 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005937 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005938 return -1;
5939 }
5940
5941 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005942 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005943 return -1;
5944 }
5945 curproxy->next = proxy;
5946 proxy = curproxy;
5947 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005948 if (strchr(args[2], ':') != NULL)
5949 curproxy->listen = str2listener(args[2], curproxy->listen);
5950
willy tarreau9fe663a2005-12-17 13:02:59 +01005951 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005952 curproxy->state = defproxy.state;
5953 curproxy->maxconn = defproxy.maxconn;
5954 curproxy->conn_retries = defproxy.conn_retries;
5955 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005956
5957 if (defproxy.check_req)
5958 curproxy->check_req = strdup(defproxy.check_req);
5959 curproxy->check_len = defproxy.check_len;
5960
5961 if (defproxy.cookie_name)
5962 curproxy->cookie_name = strdup(defproxy.cookie_name);
5963 curproxy->cookie_len = defproxy.cookie_len;
5964
5965 if (defproxy.capture_name)
5966 curproxy->capture_name = strdup(defproxy.capture_name);
5967 curproxy->capture_namelen = defproxy.capture_namelen;
5968 curproxy->capture_len = defproxy.capture_len;
5969
5970 if (defproxy.errmsg.msg400)
5971 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5972 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5973
5974 if (defproxy.errmsg.msg403)
5975 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5976 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5977
5978 if (defproxy.errmsg.msg408)
5979 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5980 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5981
5982 if (defproxy.errmsg.msg500)
5983 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5984 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5985
5986 if (defproxy.errmsg.msg502)
5987 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5988 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5989
5990 if (defproxy.errmsg.msg503)
5991 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5992 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5993
5994 if (defproxy.errmsg.msg504)
5995 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5996 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5997
willy tarreaua41a8b42005-12-17 14:02:24 +01005998 curproxy->clitimeout = defproxy.clitimeout;
5999 curproxy->contimeout = defproxy.contimeout;
6000 curproxy->srvtimeout = defproxy.srvtimeout;
6001 curproxy->mode = defproxy.mode;
6002 curproxy->logfac1 = defproxy.logfac1;
6003 curproxy->logsrv1 = defproxy.logsrv1;
6004 curproxy->loglev1 = defproxy.loglev1;
6005 curproxy->logfac2 = defproxy.logfac2;
6006 curproxy->logsrv2 = defproxy.logsrv2;
6007 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006008 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006009 curproxy->grace = defproxy.grace;
6010 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006011 curproxy->mon_net = defproxy.mon_net;
6012 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006013 return 0;
6014 }
6015 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006016 /* some variables may have already been initialized earlier */
6017 if (defproxy.check_req) free(defproxy.check_req);
6018 if (defproxy.cookie_name) free(defproxy.cookie_name);
6019 if (defproxy.capture_name) free(defproxy.capture_name);
6020 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6021 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6022 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6023 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6024 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6025 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6026 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6027
6028 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006029 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006030 return 0;
6031 }
6032 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006033 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006034 return -1;
6035 }
6036
willy tarreaua41a8b42005-12-17 14:02:24 +01006037 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6038 if (curproxy == &defproxy) {
6039 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6040 return -1;
6041 }
6042
6043 if (strchr(args[1], ':') == NULL) {
6044 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6045 file, linenum, args[0]);
6046 return -1;
6047 }
6048 curproxy->listen = str2listener(args[1], curproxy->listen);
6049 return 0;
6050 }
willy tarreaub1285d52005-12-18 01:20:14 +01006051 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6052 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6053 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6054 file, linenum, args[0]);
6055 return -1;
6056 }
6057 /* flush useless bits */
6058 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6059 return 0;
6060 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006061 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006062 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6063 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6064 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6065 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006066 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006067 return -1;
6068 }
6069 }
6070 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6071 curproxy->state = PR_STDISABLED;
6072 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006073 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6074 curproxy->state = PR_STNEW;
6075 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006076 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6077 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006078// if (curproxy == &defproxy) {
6079// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6080// return -1;
6081// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006082
willy tarreau9fe663a2005-12-17 13:02:59 +01006083 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006084// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6085// file, linenum);
6086// return 0;
6087 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006088 }
6089
6090 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006091 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6092 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006093 return -1;
6094 }
6095 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006096 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006097
6098 cur_arg = 2;
6099 while (*(args[cur_arg])) {
6100 if (!strcmp(args[cur_arg], "rewrite")) {
6101 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006102 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006103 else if (!strcmp(args[cur_arg], "indirect")) {
6104 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006105 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006106 else if (!strcmp(args[cur_arg], "insert")) {
6107 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006108 }
willy tarreau240afa62005-12-17 13:14:35 +01006109 else if (!strcmp(args[cur_arg], "nocache")) {
6110 curproxy->options |= PR_O_COOK_NOC;
6111 }
willy tarreaucd878942005-12-17 13:27:43 +01006112 else if (!strcmp(args[cur_arg], "postonly")) {
6113 curproxy->options |= PR_O_COOK_POST;
6114 }
willy tarreau0174f312005-12-18 01:02:42 +01006115 else if (!strcmp(args[cur_arg], "prefix")) {
6116 curproxy->options |= PR_O_COOK_PFX;
6117 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006118 else {
willy tarreau0174f312005-12-18 01:02:42 +01006119 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006120 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006121 return -1;
6122 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006123 cur_arg++;
6124 }
willy tarreau0174f312005-12-18 01:02:42 +01006125 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6126 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6127 file, linenum);
6128 return -1;
6129 }
6130
6131 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6132 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006133 file, linenum);
6134 return -1;
6135 }
willy tarreau12350152005-12-18 01:03:27 +01006136 }/* end else if (!strcmp(args[0], "cookie")) */
6137 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6138// if (curproxy == &defproxy) {
6139// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6140// return -1;
6141// }
6142
6143 if (curproxy->appsession_name != NULL) {
6144// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6145// file, linenum);
6146// return 0;
6147 free(curproxy->appsession_name);
6148 }
6149
6150 if (*(args[5]) == 0) {
6151 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6152 file, linenum, args[0]);
6153 return -1;
6154 }
6155 have_appsession = 1;
6156 curproxy->appsession_name = strdup(args[1]);
6157 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6158 curproxy->appsession_len = atoi(args[3]);
6159 curproxy->appsession_timeout = atoi(args[5]);
6160 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6161 if (rc) {
6162 Alert("Error Init Appsession Hashtable.\n");
6163 return -1;
6164 }
6165 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006166 else if (!strcmp(args[0], "capture")) {
6167 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6168 // if (curproxy == &defproxy) {
6169 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6170 // return -1;
6171 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006172
willy tarreau4302f492005-12-18 01:00:37 +01006173 if (curproxy->capture_name != NULL) {
6174 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6175 // file, linenum, args[0]);
6176 // return 0;
6177 free(curproxy->capture_name);
6178 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006179
willy tarreau4302f492005-12-18 01:00:37 +01006180 if (*(args[4]) == 0) {
6181 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6182 file, linenum, args[0]);
6183 return -1;
6184 }
6185 curproxy->capture_name = strdup(args[2]);
6186 curproxy->capture_namelen = strlen(curproxy->capture_name);
6187 curproxy->capture_len = atol(args[4]);
6188 if (curproxy->capture_len >= CAPTURE_LEN) {
6189 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6190 file, linenum, CAPTURE_LEN - 1);
6191 curproxy->capture_len = CAPTURE_LEN - 1;
6192 }
6193 curproxy->to_log |= LW_COOKIE;
6194 }
6195 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6196 struct cap_hdr *hdr;
6197
6198 if (curproxy == &defproxy) {
6199 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6200 return -1;
6201 }
6202
6203 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6204 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6205 file, linenum, args[0], args[1]);
6206 return -1;
6207 }
6208
6209 hdr = calloc(sizeof(struct cap_hdr), 1);
6210 hdr->next = curproxy->req_cap;
6211 hdr->name = strdup(args[3]);
6212 hdr->namelen = strlen(args[3]);
6213 hdr->len = atol(args[5]);
6214 hdr->index = curproxy->nb_req_cap++;
6215 curproxy->req_cap = hdr;
6216 curproxy->to_log |= LW_REQHDR;
6217 }
6218 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6219 struct cap_hdr *hdr;
6220
6221 if (curproxy == &defproxy) {
6222 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6223 return -1;
6224 }
6225
6226 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6227 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6228 file, linenum, args[0], args[1]);
6229 return -1;
6230 }
6231 hdr = calloc(sizeof(struct cap_hdr), 1);
6232 hdr->next = curproxy->rsp_cap;
6233 hdr->name = strdup(args[3]);
6234 hdr->namelen = strlen(args[3]);
6235 hdr->len = atol(args[5]);
6236 hdr->index = curproxy->nb_rsp_cap++;
6237 curproxy->rsp_cap = hdr;
6238 curproxy->to_log |= LW_RSPHDR;
6239 }
6240 else {
6241 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006242 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006243 return -1;
6244 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006245 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006246 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006247 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006248 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006249 return 0;
6250 }
6251 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006252 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6253 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006254 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006255 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006256 curproxy->contimeout = atol(args[1]);
6257 }
6258 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006259 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006260 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6261 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006262 return 0;
6263 }
6264 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006265 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6266 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 return -1;
6268 }
6269 curproxy->clitimeout = atol(args[1]);
6270 }
6271 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006272 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006273 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006274 return 0;
6275 }
6276 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006277 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6278 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006279 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006280 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006281 curproxy->srvtimeout = atol(args[1]);
6282 }
6283 else if (!strcmp(args[0], "retries")) { /* connection retries */
6284 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006285 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6286 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006287 return -1;
6288 }
6289 curproxy->conn_retries = atol(args[1]);
6290 }
6291 else if (!strcmp(args[0], "option")) {
6292 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006293 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006294 return -1;
6295 }
6296 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006297 /* enable reconnections to dispatch */
6298 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006299#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006300 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006301 /* enable transparent proxy connections */
6302 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006303#endif
6304 else if (!strcmp(args[1], "keepalive"))
6305 /* enable keep-alive */
6306 curproxy->options |= PR_O_KEEPALIVE;
6307 else if (!strcmp(args[1], "forwardfor"))
6308 /* insert x-forwarded-for field */
6309 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006310 else if (!strcmp(args[1], "logasap"))
6311 /* log as soon as possible, without waiting for the session to complete */
6312 curproxy->options |= PR_O_LOGASAP;
6313 else if (!strcmp(args[1], "httpclose"))
6314 /* force connection: close in both directions in HTTP mode */
6315 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006316 else if (!strcmp(args[1], "checkcache"))
6317 /* require examination of cacheability of the 'set-cookie' field */
6318 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006319 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006320 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006321 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006322 else if (!strcmp(args[1], "tcplog"))
6323 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006324 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006325 else if (!strcmp(args[1], "dontlognull")) {
6326 /* don't log empty requests */
6327 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006328 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006329 else if (!strcmp(args[1], "httpchk")) {
6330 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006331 if (curproxy->check_req != NULL) {
6332 free(curproxy->check_req);
6333 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006334 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006335 if (!*args[2]) { /* no argument */
6336 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6337 curproxy->check_len = strlen(DEF_CHECK_REQ);
6338 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006339 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6340 curproxy->check_req = (char *)malloc(reqlen);
6341 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6342 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006343 } else { /* more arguments : METHOD URI [HTTP_VER] */
6344 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6345 if (*args[4])
6346 reqlen += strlen(args[4]);
6347 else
6348 reqlen += strlen("HTTP/1.0");
6349
6350 curproxy->check_req = (char *)malloc(reqlen);
6351 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6352 "%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 +01006353 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006354 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006355 else if (!strcmp(args[1], "persist")) {
6356 /* persist on using the server specified by the cookie, even when it's down */
6357 curproxy->options |= PR_O_PERSIST;
6358 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006359 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006360 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 return -1;
6362 }
6363 return 0;
6364 }
6365 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6366 /* enable reconnections to dispatch */
6367 curproxy->options |= PR_O_REDISP;
6368 }
willy tarreaua1598082005-12-17 13:08:06 +01006369#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006370 else if (!strcmp(args[0], "transparent")) {
6371 /* enable transparent proxy connections */
6372 curproxy->options |= PR_O_TRANSP;
6373 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006374#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006375 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6376 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006377 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006378 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006379 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006380 curproxy->maxconn = atol(args[1]);
6381 }
6382 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6383 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006384 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006385 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006386 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006387 curproxy->grace = atol(args[1]);
6388 }
6389 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006390 if (curproxy == &defproxy) {
6391 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6392 return -1;
6393 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006394 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006395 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006396 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006397 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006398 curproxy->dispatch_addr = *str2sa(args[1]);
6399 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006400 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006401 if (*(args[1])) {
6402 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006403 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006404 }
6405 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006406 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006407 return -1;
6408 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006409 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006410 else /* if no option is set, use round-robin by default */
6411 curproxy->options |= PR_O_BALANCE_RR;
6412 }
6413 else if (!strcmp(args[0], "server")) { /* server address */
6414 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006415 char *rport;
6416 char *raddr;
6417 short realport;
6418 int do_check;
6419
6420 if (curproxy == &defproxy) {
6421 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6422 return -1;
6423 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006424
willy tarreaua41a8b42005-12-17 14:02:24 +01006425 if (!*args[2]) {
6426 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006427 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006428 return -1;
6429 }
6430 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6431 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6432 return -1;
6433 }
willy tarreau0174f312005-12-18 01:02:42 +01006434
6435 if (curproxy->srv == NULL)
6436 curproxy->srv = newsrv;
6437 else
6438 curproxy->cursrv->next = newsrv;
6439 curproxy->cursrv = newsrv;
6440
6441 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006442 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006443
6444 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006445 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006446 newsrv->id = strdup(args[1]);
6447
6448 /* several ways to check the port component :
6449 * - IP => port=+0, relative
6450 * - IP: => port=+0, relative
6451 * - IP:N => port=N, absolute
6452 * - IP:+N => port=+N, relative
6453 * - IP:-N => port=-N, relative
6454 */
6455 raddr = strdup(args[2]);
6456 rport = strchr(raddr, ':');
6457 if (rport) {
6458 *rport++ = 0;
6459 realport = atol(rport);
6460 if (!isdigit((int)*rport))
6461 newsrv->state |= SRV_MAPPORTS;
6462 } else {
6463 realport = 0;
6464 newsrv->state |= SRV_MAPPORTS;
6465 }
6466
6467 newsrv->addr = *str2sa(raddr);
6468 newsrv->addr.sin_port = htons(realport);
6469 free(raddr);
6470
willy tarreau9fe663a2005-12-17 13:02:59 +01006471 newsrv->curfd = -1; /* no health-check in progress */
6472 newsrv->inter = DEF_CHKINTR;
6473 newsrv->rise = DEF_RISETIME;
6474 newsrv->fall = DEF_FALLTIME;
6475 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6476 cur_arg = 3;
6477 while (*args[cur_arg]) {
6478 if (!strcmp(args[cur_arg], "cookie")) {
6479 newsrv->cookie = strdup(args[cur_arg + 1]);
6480 newsrv->cklen = strlen(args[cur_arg + 1]);
6481 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006482 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006483 else if (!strcmp(args[cur_arg], "rise")) {
6484 newsrv->rise = atol(args[cur_arg + 1]);
6485 newsrv->health = newsrv->rise;
6486 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006487 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006488 else if (!strcmp(args[cur_arg], "fall")) {
6489 newsrv->fall = atol(args[cur_arg + 1]);
6490 cur_arg += 2;
6491 }
6492 else if (!strcmp(args[cur_arg], "inter")) {
6493 newsrv->inter = atol(args[cur_arg + 1]);
6494 cur_arg += 2;
6495 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006496 else if (!strcmp(args[cur_arg], "port")) {
6497 newsrv->check_port = atol(args[cur_arg + 1]);
6498 cur_arg += 2;
6499 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006500 else if (!strcmp(args[cur_arg], "backup")) {
6501 newsrv->state |= SRV_BACKUP;
6502 cur_arg ++;
6503 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006504 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006505 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006506 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006507 }
willy tarreau0174f312005-12-18 01:02:42 +01006508 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6509 if (!*args[cur_arg + 1]) {
6510 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6511 file, linenum, "source");
6512 return -1;
6513 }
6514 newsrv->state |= SRV_BIND_SRC;
6515 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6516 cur_arg += 2;
6517 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006518 else {
willy tarreau0174f312005-12-18 01:02:42 +01006519 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 +01006520 file, linenum, newsrv->id);
6521 return -1;
6522 }
6523 }
6524
6525 if (do_check) {
6526 struct task *t;
6527
6528 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6529 newsrv->check_port = realport; /* by default */
6530 if (!newsrv->check_port) {
6531 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 +01006532 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006533 return -1;
6534 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006535
6536 if ((t = pool_alloc(task)) == NULL) {
6537 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6538 return -1;
6539 }
6540
6541 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6542 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6543 t->state = TASK_IDLE;
6544 t->process = process_chk;
6545 t->context = newsrv;
6546
6547 if (curproxy->state != PR_STDISABLED) {
6548 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6549 task_queue(t);
6550 task_wakeup(&rq, t);
6551 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006552 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006553
willy tarreau9fe663a2005-12-17 13:02:59 +01006554 curproxy->nbservers++;
6555 }
6556 else if (!strcmp(args[0], "log")) { /* syslog server address */
6557 struct sockaddr_in *sa;
6558 int facility;
6559
6560 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6561 curproxy->logfac1 = global.logfac1;
6562 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006563 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006564 curproxy->logfac2 = global.logfac2;
6565 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006566 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006567 }
6568 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006569 int level;
6570
willy tarreau0f7af912005-12-17 12:21:26 +01006571 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6572 if (!strcmp(log_facilities[facility], args[2]))
6573 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006574
willy tarreau0f7af912005-12-17 12:21:26 +01006575 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006576 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006577 exit(1);
6578 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006579
willy tarreau8337c6b2005-12-17 13:41:01 +01006580 level = 7; /* max syslog level = debug */
6581 if (*(args[3])) {
6582 while (level >= 0 && strcmp(log_levels[level], args[3]))
6583 level--;
6584 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006585 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006586 exit(1);
6587 }
6588 }
6589
willy tarreau0f7af912005-12-17 12:21:26 +01006590 sa = str2sa(args[1]);
6591 if (!sa->sin_port)
6592 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006593
willy tarreau0f7af912005-12-17 12:21:26 +01006594 if (curproxy->logfac1 == -1) {
6595 curproxy->logsrv1 = *sa;
6596 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006597 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006598 }
6599 else if (curproxy->logfac2 == -1) {
6600 curproxy->logsrv2 = *sa;
6601 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006602 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006603 }
6604 else {
6605 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006606 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006607 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006608 }
6609 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006610 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006611 file, linenum);
6612 return -1;
6613 }
6614 }
willy tarreaua1598082005-12-17 13:08:06 +01006615 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006616 if (!*args[1]) {
6617 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006618 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006619 return -1;
6620 }
6621
6622 curproxy->source_addr = *str2sa(args[1]);
6623 curproxy->options |= PR_O_BIND_SRC;
6624 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006625 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6626 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006627 if (curproxy == &defproxy) {
6628 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6629 return -1;
6630 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006631
6632 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006633 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6634 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006635 return -1;
6636 }
6637
6638 preg = calloc(1, sizeof(regex_t));
6639 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006640 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006641 return -1;
6642 }
6643
willy tarreauc1f47532005-12-18 01:08:26 +01006644 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6645 if (err) {
6646 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6647 file, linenum, *err);
6648 return -1;
6649 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006650 }
6651 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6652 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006653 if (curproxy == &defproxy) {
6654 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6655 return -1;
6656 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006657
6658 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006659 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006660 return -1;
6661 }
6662
6663 preg = calloc(1, sizeof(regex_t));
6664 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006665 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006666 return -1;
6667 }
6668
6669 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6670 }
6671 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6672 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006673 if (curproxy == &defproxy) {
6674 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6675 return -1;
6676 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006677
6678 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006679 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006680 return -1;
6681 }
6682
6683 preg = calloc(1, sizeof(regex_t));
6684 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006685 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006686 return -1;
6687 }
6688
6689 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6690 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006691 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6692 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006693 if (curproxy == &defproxy) {
6694 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6695 return -1;
6696 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006697
6698 if (*(args[1]) == 0) {
6699 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6700 return -1;
6701 }
6702
6703 preg = calloc(1, sizeof(regex_t));
6704 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6705 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6706 return -1;
6707 }
6708
6709 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6710 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006711 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6712 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006713 if (curproxy == &defproxy) {
6714 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6715 return -1;
6716 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006717
6718 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006719 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006720 return -1;
6721 }
6722
6723 preg = calloc(1, sizeof(regex_t));
6724 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006725 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006726 return -1;
6727 }
6728
6729 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6730 }
6731 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6732 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006733 if (curproxy == &defproxy) {
6734 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6735 return -1;
6736 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006737
6738 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006739 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6740 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006741 return -1;
6742 }
6743
6744 preg = calloc(1, sizeof(regex_t));
6745 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006746 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006747 return -1;
6748 }
6749
willy tarreauc1f47532005-12-18 01:08:26 +01006750 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6751 if (err) {
6752 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6753 file, linenum, *err);
6754 return -1;
6755 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006756 }
6757 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6758 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006759 if (curproxy == &defproxy) {
6760 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6761 return -1;
6762 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006763
6764 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006765 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006766 return -1;
6767 }
6768
6769 preg = calloc(1, sizeof(regex_t));
6770 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006771 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006772 return -1;
6773 }
6774
6775 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6776 }
6777 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6778 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006779 if (curproxy == &defproxy) {
6780 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6781 return -1;
6782 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006783
6784 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006785 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006786 return -1;
6787 }
6788
6789 preg = calloc(1, sizeof(regex_t));
6790 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006791 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006792 return -1;
6793 }
6794
6795 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6796 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006797 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6798 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006799 if (curproxy == &defproxy) {
6800 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6801 return -1;
6802 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006803
6804 if (*(args[1]) == 0) {
6805 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6806 return -1;
6807 }
6808
6809 preg = calloc(1, sizeof(regex_t));
6810 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6811 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6812 return -1;
6813 }
6814
6815 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6816 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006817 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6818 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006819 if (curproxy == &defproxy) {
6820 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6821 return -1;
6822 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006823
6824 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006825 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006826 return -1;
6827 }
6828
6829 preg = calloc(1, sizeof(regex_t));
6830 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006831 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006832 return -1;
6833 }
6834
6835 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6836 }
6837 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006838 if (curproxy == &defproxy) {
6839 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6840 return -1;
6841 }
6842
willy tarreau9fe663a2005-12-17 13:02:59 +01006843 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006844 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006845 return 0;
6846 }
6847
6848 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006849 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006850 return -1;
6851 }
6852
willy tarreau4302f492005-12-18 01:00:37 +01006853 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6854 }
6855 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6856 regex_t *preg;
6857
6858 if (*(args[1]) == 0 || *(args[2]) == 0) {
6859 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6860 file, linenum, args[0]);
6861 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006862 }
willy tarreau4302f492005-12-18 01:00:37 +01006863
6864 preg = calloc(1, sizeof(regex_t));
6865 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6866 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6867 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006868 }
willy tarreau4302f492005-12-18 01:00:37 +01006869
willy tarreauc1f47532005-12-18 01:08:26 +01006870 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6871 if (err) {
6872 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6873 file, linenum, *err);
6874 return -1;
6875 }
willy tarreau4302f492005-12-18 01:00:37 +01006876 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006877 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6878 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006879 if (curproxy == &defproxy) {
6880 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6881 return -1;
6882 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006883
6884 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006885 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006886 return -1;
6887 }
willy tarreaue39cd132005-12-17 13:00:18 +01006888
willy tarreau9fe663a2005-12-17 13:02:59 +01006889 preg = calloc(1, sizeof(regex_t));
6890 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006891 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006892 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006893 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006894
willy tarreauc1f47532005-12-18 01:08:26 +01006895 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6896 if (err) {
6897 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6898 file, linenum, *err);
6899 return -1;
6900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006901 }
willy tarreau982249e2005-12-18 00:57:06 +01006902 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6903 regex_t *preg;
6904 if (curproxy == &defproxy) {
6905 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6906 return -1;
6907 }
6908
6909 if (*(args[1]) == 0) {
6910 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6911 return -1;
6912 }
6913
6914 preg = calloc(1, sizeof(regex_t));
6915 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6916 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6917 return -1;
6918 }
6919
willy tarreauc1f47532005-12-18 01:08:26 +01006920 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6921 if (err) {
6922 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6923 file, linenum, *err);
6924 return -1;
6925 }
willy tarreau982249e2005-12-18 00:57:06 +01006926 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006927 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01006928 regex_t *preg;
6929 if (curproxy == &defproxy) {
6930 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6931 return -1;
6932 }
willy tarreaue39cd132005-12-17 13:00:18 +01006933
willy tarreaua41a8b42005-12-17 14:02:24 +01006934 if (*(args[1]) == 0 || *(args[2]) == 0) {
6935 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6936 file, linenum, args[0]);
6937 return -1;
6938 }
willy tarreaue39cd132005-12-17 13:00:18 +01006939
willy tarreaua41a8b42005-12-17 14:02:24 +01006940 preg = calloc(1, sizeof(regex_t));
6941 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6942 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6943 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006944 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006945
willy tarreauc1f47532005-12-18 01:08:26 +01006946 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6947 if (err) {
6948 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6949 file, linenum, *err);
6950 return -1;
6951 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006952 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006953 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
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 tarreau9fe663a2005-12-17 13:02:59 +01006959
6960 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006961 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006962 return -1;
6963 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006964
willy tarreau9fe663a2005-12-17 13:02:59 +01006965 preg = calloc(1, sizeof(regex_t));
6966 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006967 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006968 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006969 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006970
willy tarreauc1f47532005-12-18 01:08:26 +01006971 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6972 if (err) {
6973 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6974 file, linenum, *err);
6975 return -1;
6976 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006977 }
willy tarreau982249e2005-12-18 00:57:06 +01006978 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
6979 regex_t *preg;
6980 if (curproxy == &defproxy) {
6981 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6982 return -1;
6983 }
6984
6985 if (*(args[1]) == 0) {
6986 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6987 return -1;
6988 }
6989
6990 preg = calloc(1, sizeof(regex_t));
6991 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6992 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6993 return -1;
6994 }
6995
willy tarreauc1f47532005-12-18 01:08:26 +01006996 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6997 if (err) {
6998 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6999 file, linenum, *err);
7000 return -1;
7001 }
willy tarreau982249e2005-12-18 00:57:06 +01007002 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007003 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007004 if (curproxy == &defproxy) {
7005 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7006 return -1;
7007 }
7008
willy tarreau9fe663a2005-12-17 13:02:59 +01007009 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007010 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007011 return 0;
7012 }
7013
7014 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007015 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007016 return -1;
7017 }
7018
7019 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7020 }
willy tarreauc1f47532005-12-18 01:08:26 +01007021 else if (!strcmp(args[0], "errorloc") ||
7022 !strcmp(args[0], "errorloc302") ||
7023 !strcmp(args[0], "errorloc303")) { /* error location */
7024 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007025 char *err;
7026
willy tarreaueedaa9f2005-12-17 14:08:03 +01007027 // if (curproxy == &defproxy) {
7028 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7029 // return -1;
7030 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007031
willy tarreau8337c6b2005-12-17 13:41:01 +01007032 if (*(args[2]) == 0) {
7033 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7034 return -1;
7035 }
7036
7037 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007038 if (!strcmp(args[0], "errorloc303")) {
7039 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7040 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7041 } else {
7042 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7043 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7044 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007045
7046 if (errnum == 400) {
7047 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007048 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007049 free(curproxy->errmsg.msg400);
7050 }
7051 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007052 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007053 }
7054 else if (errnum == 403) {
7055 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007056 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007057 free(curproxy->errmsg.msg403);
7058 }
7059 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007060 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007061 }
7062 else if (errnum == 408) {
7063 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007064 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007065 free(curproxy->errmsg.msg408);
7066 }
7067 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007068 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007069 }
7070 else if (errnum == 500) {
7071 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007072 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007073 free(curproxy->errmsg.msg500);
7074 }
7075 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007076 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007077 }
7078 else if (errnum == 502) {
7079 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007080 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007081 free(curproxy->errmsg.msg502);
7082 }
7083 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007084 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007085 }
7086 else if (errnum == 503) {
7087 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007088 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007089 free(curproxy->errmsg.msg503);
7090 }
7091 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007092 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007093 }
7094 else if (errnum == 504) {
7095 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007096 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007097 free(curproxy->errmsg.msg504);
7098 }
7099 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007100 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007101 }
7102 else {
7103 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7104 free(err);
7105 }
7106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007107 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007108 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007109 return -1;
7110 }
7111 return 0;
7112}
willy tarreaue39cd132005-12-17 13:00:18 +01007113
willy tarreau5cbea6f2005-12-17 12:48:26 +01007114
willy tarreau9fe663a2005-12-17 13:02:59 +01007115/*
7116 * This function reads and parses the configuration file given in the argument.
7117 * returns 0 if OK, -1 if error.
7118 */
7119int readcfgfile(char *file) {
7120 char thisline[256];
7121 char *line;
7122 FILE *f;
7123 int linenum = 0;
7124 char *end;
7125 char *args[MAX_LINE_ARGS];
7126 int arg;
7127 int cfgerr = 0;
7128 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007129
willy tarreau9fe663a2005-12-17 13:02:59 +01007130 struct proxy *curproxy = NULL;
7131 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007132
willy tarreau9fe663a2005-12-17 13:02:59 +01007133 if ((f=fopen(file,"r")) == NULL)
7134 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007135
willy tarreaueedaa9f2005-12-17 14:08:03 +01007136 init_default_instance();
7137
willy tarreau9fe663a2005-12-17 13:02:59 +01007138 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7139 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007140
willy tarreau9fe663a2005-12-17 13:02:59 +01007141 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007142
willy tarreau9fe663a2005-12-17 13:02:59 +01007143 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007144 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007145 line++;
7146
7147 arg = 0;
7148 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007149
willy tarreau9fe663a2005-12-17 13:02:59 +01007150 while (*line && arg < MAX_LINE_ARGS) {
7151 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7152 * C equivalent value. Other combinations left unchanged (eg: \1).
7153 */
7154 if (*line == '\\') {
7155 int skip = 0;
7156 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7157 *line = line[1];
7158 skip = 1;
7159 }
7160 else if (line[1] == 'r') {
7161 *line = '\r';
7162 skip = 1;
7163 }
7164 else if (line[1] == 'n') {
7165 *line = '\n';
7166 skip = 1;
7167 }
7168 else if (line[1] == 't') {
7169 *line = '\t';
7170 skip = 1;
7171 }
willy tarreauc1f47532005-12-18 01:08:26 +01007172 else if (line[1] == 'x') {
7173 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7174 unsigned char hex1, hex2;
7175 hex1 = toupper(line[2]) - '0';
7176 hex2 = toupper(line[3]) - '0';
7177 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7178 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7179 *line = (hex1<<4) + hex2;
7180 skip = 3;
7181 }
7182 else {
7183 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7184 return -1;
7185 }
7186 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007187 if (skip) {
7188 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7189 end -= skip;
7190 }
7191 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007192 }
willy tarreaua1598082005-12-17 13:08:06 +01007193 else if (*line == '#' || *line == '\n' || *line == '\r') {
7194 /* end of string, end of loop */
7195 *line = 0;
7196 break;
7197 }
willy tarreauc29948c2005-12-17 13:10:27 +01007198 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007199 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007200 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007201 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007202 line++;
7203 args[++arg] = line;
7204 }
7205 else {
7206 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007207 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007208 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007209
willy tarreau9fe663a2005-12-17 13:02:59 +01007210 /* empty line */
7211 if (!**args)
7212 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007213
willy tarreau9fe663a2005-12-17 13:02:59 +01007214 /* zero out remaining args */
7215 while (++arg < MAX_LINE_ARGS) {
7216 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007217 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007218
willy tarreaua41a8b42005-12-17 14:02:24 +01007219 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007220 confsect = CFG_LISTEN;
7221 else if (!strcmp(args[0], "global")) /* global config */
7222 confsect = CFG_GLOBAL;
7223 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007224
willy tarreau9fe663a2005-12-17 13:02:59 +01007225 switch (confsect) {
7226 case CFG_LISTEN:
7227 if (cfg_parse_listen(file, linenum, args) < 0)
7228 return -1;
7229 break;
7230 case CFG_GLOBAL:
7231 if (cfg_parse_global(file, linenum, args) < 0)
7232 return -1;
7233 break;
7234 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007235 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007236 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007238
7239
willy tarreau0f7af912005-12-17 12:21:26 +01007240 }
7241 fclose(f);
7242
7243 /*
7244 * Now, check for the integrity of all that we have collected.
7245 */
7246
7247 if ((curproxy = proxy) == NULL) {
7248 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7249 file);
7250 return -1;
7251 }
7252
7253 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007254 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007255 if (curproxy->state == PR_STDISABLED) {
7256 curproxy = curproxy->next;
7257 continue;
7258 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007259 if ((curproxy->mode != PR_MODE_HEALTH) &&
7260 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007261 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007262 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7263 file, curproxy->id);
7264 cfgerr++;
7265 }
7266 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7267 if (curproxy->options & PR_O_TRANSP) {
7268 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7269 file, curproxy->id);
7270 cfgerr++;
7271 }
7272 else if (curproxy->srv == NULL) {
7273 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7274 file, curproxy->id);
7275 cfgerr++;
7276 }
willy tarreaua1598082005-12-17 13:08:06 +01007277 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007278 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7279 file, curproxy->id);
7280 }
7281 }
7282 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007283 if (curproxy->cookie_name != NULL) {
7284 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7285 file, curproxy->id);
7286 }
7287 if ((newsrv = curproxy->srv) != NULL) {
7288 Warning("parsing %s : servers will be ignored for listener %s.\n",
7289 file, curproxy->id);
7290 }
willy tarreaue39cd132005-12-17 13:00:18 +01007291 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007292 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7293 file, curproxy->id);
7294 }
willy tarreaue39cd132005-12-17 13:00:18 +01007295 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007296 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7297 file, curproxy->id);
7298 }
7299 }
7300 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7301 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7302 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7303 file, curproxy->id);
7304 cfgerr++;
7305 }
7306 else {
7307 while (newsrv != NULL) {
7308 /* nothing to check for now */
7309 newsrv = newsrv->next;
7310 }
7311 }
7312 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007313
7314 if (curproxy->options & PR_O_LOGASAP)
7315 curproxy->to_log &= ~LW_BYTES;
7316
willy tarreau8337c6b2005-12-17 13:41:01 +01007317 if (curproxy->errmsg.msg400 == NULL) {
7318 curproxy->errmsg.msg400 = (char *)HTTP_400;
7319 curproxy->errmsg.len400 = strlen(HTTP_400);
7320 }
7321 if (curproxy->errmsg.msg403 == NULL) {
7322 curproxy->errmsg.msg403 = (char *)HTTP_403;
7323 curproxy->errmsg.len403 = strlen(HTTP_403);
7324 }
7325 if (curproxy->errmsg.msg408 == NULL) {
7326 curproxy->errmsg.msg408 = (char *)HTTP_408;
7327 curproxy->errmsg.len408 = strlen(HTTP_408);
7328 }
7329 if (curproxy->errmsg.msg500 == NULL) {
7330 curproxy->errmsg.msg500 = (char *)HTTP_500;
7331 curproxy->errmsg.len500 = strlen(HTTP_500);
7332 }
7333 if (curproxy->errmsg.msg502 == NULL) {
7334 curproxy->errmsg.msg502 = (char *)HTTP_502;
7335 curproxy->errmsg.len502 = strlen(HTTP_502);
7336 }
7337 if (curproxy->errmsg.msg503 == NULL) {
7338 curproxy->errmsg.msg503 = (char *)HTTP_503;
7339 curproxy->errmsg.len503 = strlen(HTTP_503);
7340 }
7341 if (curproxy->errmsg.msg504 == NULL) {
7342 curproxy->errmsg.msg504 = (char *)HTTP_504;
7343 curproxy->errmsg.len504 = strlen(HTTP_504);
7344 }
willy tarreau0f7af912005-12-17 12:21:26 +01007345 curproxy = curproxy->next;
7346 }
7347 if (cfgerr > 0) {
7348 Alert("Errors found in configuration file, aborting.\n");
7349 return -1;
7350 }
7351 else
7352 return 0;
7353}
7354
7355
7356/*
7357 * This function initializes all the necessary variables. It only returns
7358 * if everything is OK. If something fails, it exits.
7359 */
7360void init(int argc, char **argv) {
7361 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007362 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007363 char *old_argv = *argv;
7364 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007365 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007366 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007367
7368 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007369 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007370 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007371 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007372 exit(1);
7373 }
7374
willy tarreau4302f492005-12-18 01:00:37 +01007375 /* initialize the log header encoding map : '{|}"#' should be encoded with
7376 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7377 * URL encoding only requires '"', '#' to be encoded as well as non-
7378 * printable characters above.
7379 */
7380 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7381 memset(url_encode_map, 0, sizeof(url_encode_map));
7382 for (i = 0; i < 32; i++) {
7383 FD_SET(i, hdr_encode_map);
7384 FD_SET(i, url_encode_map);
7385 }
7386 for (i = 127; i < 256; i++) {
7387 FD_SET(i, hdr_encode_map);
7388 FD_SET(i, url_encode_map);
7389 }
7390
7391 tmp = "\"#{|}";
7392 while (*tmp) {
7393 FD_SET(*tmp, hdr_encode_map);
7394 tmp++;
7395 }
7396
7397 tmp = "\"#";
7398 while (*tmp) {
7399 FD_SET(*tmp, url_encode_map);
7400 tmp++;
7401 }
7402
willy tarreau64a3cc32005-12-18 01:13:11 +01007403 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7404#if defined(ENABLE_POLL)
7405 cfg_polling_mechanism |= POLL_USE_POLL;
7406#endif
7407#if defined(ENABLE_EPOLL)
7408 cfg_polling_mechanism |= POLL_USE_EPOLL;
7409#endif
7410
willy tarreau0f7af912005-12-17 12:21:26 +01007411 pid = getpid();
7412 progname = *argv;
7413 while ((tmp = strchr(progname, '/')) != NULL)
7414 progname = tmp + 1;
7415
7416 argc--; argv++;
7417 while (argc > 0) {
7418 char *flag;
7419
7420 if (**argv == '-') {
7421 flag = *argv+1;
7422
7423 /* 1 arg */
7424 if (*flag == 'v') {
7425 display_version();
7426 exit(0);
7427 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007428#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007429 else if (*flag == 'd' && flag[1] == 'e')
7430 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007431#endif
7432#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007433 else if (*flag == 'd' && flag[1] == 'p')
7434 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007435#endif
willy tarreau982249e2005-12-18 00:57:06 +01007436 else if (*flag == 'V')
7437 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007438 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007439 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007440 else if (*flag == 'c')
7441 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007442 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007443 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007444 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007445 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007446#if STATTIME > 0
7447 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007448 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007449 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007450 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007451#endif
7452 else { /* >=2 args */
7453 argv++; argc--;
7454 if (argc == 0)
7455 usage(old_argv);
7456
7457 switch (*flag) {
7458 case 'n' : cfg_maxconn = atol(*argv); break;
7459 case 'N' : cfg_maxpconn = atol(*argv); break;
7460 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007461 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007462 default: usage(old_argv);
7463 }
7464 }
7465 }
7466 else
7467 usage(old_argv);
7468 argv++; argc--;
7469 }
7470
willy tarreau982249e2005-12-18 00:57:06 +01007471 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007472
willy tarreau0f7af912005-12-17 12:21:26 +01007473 if (!cfg_cfgfile)
7474 usage(old_argv);
7475
7476 gethostname(hostname, MAX_HOSTNAME_LEN);
7477
willy tarreau12350152005-12-18 01:03:27 +01007478 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007479 if (readcfgfile(cfg_cfgfile) < 0) {
7480 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7481 exit(1);
7482 }
willy tarreau12350152005-12-18 01:03:27 +01007483 if (have_appsession)
7484 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007485
willy tarreau982249e2005-12-18 00:57:06 +01007486 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007487 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7488 exit(0);
7489 }
7490
willy tarreau9fe663a2005-12-17 13:02:59 +01007491 if (cfg_maxconn > 0)
7492 global.maxconn = cfg_maxconn;
7493
willy tarreaufe2c5c12005-12-17 14:14:34 +01007494 if (cfg_pidfile) {
7495 if (global.pidfile)
7496 free(global.pidfile);
7497 global.pidfile = strdup(cfg_pidfile);
7498 }
7499
willy tarreau9fe663a2005-12-17 13:02:59 +01007500 if (global.maxconn == 0)
7501 global.maxconn = DEFAULT_MAXCONN;
7502
7503 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7504
7505 if (arg_mode & MODE_DEBUG) {
7506 /* command line debug mode inhibits configuration mode */
7507 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7508 }
willy tarreau982249e2005-12-18 00:57:06 +01007509 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7510 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007511
7512 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7513 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7514 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7515 }
7516
7517 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7518 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7519 global.nbproc = 1;
7520 }
7521
7522 if (global.nbproc < 1)
7523 global.nbproc = 1;
7524
willy tarreau0f7af912005-12-17 12:21:26 +01007525 StaticReadEvent = (fd_set *)calloc(1,
7526 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007527 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007528 StaticWriteEvent = (fd_set *)calloc(1,
7529 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007530 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007531
7532 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007533 sizeof(struct fdtab) * (global.maxsock));
7534 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007535 fdtab[i].state = FD_STCLOSE;
7536 }
7537}
7538
7539/*
7540 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7541 */
7542int start_proxies() {
7543 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007544 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007545 int fd;
7546
7547 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007548 if (curproxy->state == PR_STDISABLED)
7549 continue;
7550
willy tarreaua41a8b42005-12-17 14:02:24 +01007551 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7552 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007553 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007554 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7555 curproxy->id);
7556 return -1;
7557 }
willy tarreau0f7af912005-12-17 12:21:26 +01007558
willy tarreaua41a8b42005-12-17 14:02:24 +01007559 if (fd >= global.maxsock) {
7560 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7561 curproxy->id);
7562 close(fd);
7563 return -1;
7564 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007565
willy tarreaua41a8b42005-12-17 14:02:24 +01007566 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7567 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7568 (char *) &one, sizeof(one)) == -1)) {
7569 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7570 curproxy->id);
7571 close(fd);
7572 return -1;
7573 }
willy tarreau0f7af912005-12-17 12:21:26 +01007574
willy tarreaua41a8b42005-12-17 14:02:24 +01007575 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7576 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7577 curproxy->id);
7578 }
willy tarreau0f7af912005-12-17 12:21:26 +01007579
willy tarreaua41a8b42005-12-17 14:02:24 +01007580 if (bind(fd,
7581 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007582 listener->addr.ss_family == AF_INET6 ?
7583 sizeof(struct sockaddr_in6) :
7584 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007585 Alert("cannot bind socket for proxy %s. Aborting.\n",
7586 curproxy->id);
7587 close(fd);
7588 return -1;
7589 }
willy tarreau0f7af912005-12-17 12:21:26 +01007590
willy tarreaua41a8b42005-12-17 14:02:24 +01007591 if (listen(fd, curproxy->maxconn) == -1) {
7592 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7593 curproxy->id);
7594 close(fd);
7595 return -1;
7596 }
willy tarreau0f7af912005-12-17 12:21:26 +01007597
willy tarreaua41a8b42005-12-17 14:02:24 +01007598 /* the function for the accept() event */
7599 fdtab[fd].read = &event_accept;
7600 fdtab[fd].write = NULL; /* never called */
7601 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7602 curproxy->state = PR_STRUN;
7603 fdtab[fd].state = FD_STLISTEN;
7604 FD_SET(fd, StaticReadEvent);
7605 fd_insert(fd);
7606 listeners++;
7607 }
willy tarreaua1598082005-12-17 13:08:06 +01007608 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007609 }
7610 return 0;
7611}
7612
willy tarreau12350152005-12-18 01:03:27 +01007613int match_str(const void *key1, const void *key2){
7614
7615 appsess *temp1,*temp2;
7616 temp1 = (appsess *)key1;
7617 temp2 = (appsess *)key2;
7618
7619 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7620 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7621
7622 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7623}/* end match_str */
7624
7625void destroy(void *data){
7626 appsess *temp1;
7627
7628 //printf("destroy called\n");
7629 temp1 = (appsess *)data;
7630
7631 if (temp1->sessid)
7632 pool_free_to(apools.sessid, temp1->sessid);
7633
7634 if (temp1->serverid)
7635 pool_free_to(apools.serverid, temp1->serverid);
7636
7637 pool_free(appsess, temp1);
7638} /* end destroy */
7639
7640void appsession_cleanup( void )
7641{
7642 struct proxy *p = proxy;
7643
7644 while(p) {
7645 chtbl_destroy(&(p->htbl_proxy));
7646 p = p->next;
7647 }
7648}/* end appsession_cleanup() */
7649
7650void pool_destroy(void **pool)
7651{
7652 void *temp, *next;
7653 next = pool;
7654 while (next) {
7655 temp = next;
7656 next = *(void **)temp;
7657 free(temp);
7658 }
7659}/* end pool_destroy() */
7660
7661void deinit(void){
7662 struct proxy *p = proxy;
7663 struct cap_hdr *h,*h_next;
7664 struct server *s,*s_next;
7665 struct listener *l,*l_next;
7666
7667 while (p) {
7668 if (p->id)
7669 free(p->id);
7670
7671 if (p->check_req)
7672 free(p->check_req);
7673
7674 if (p->cookie_name)
7675 free(p->cookie_name);
7676
7677 if (p->capture_name)
7678 free(p->capture_name);
7679
7680 /* only strup if the user have set in config.
7681 When should we free it?!
7682 if(p->errmsg.msg400) free(p->errmsg.msg400);
7683 if(p->errmsg.msg403) free(p->errmsg.msg403);
7684 if(p->errmsg.msg408) free(p->errmsg.msg408);
7685 if(p->errmsg.msg500) free(p->errmsg.msg500);
7686 if(p->errmsg.msg502) free(p->errmsg.msg502);
7687 if(p->errmsg.msg503) free(p->errmsg.msg503);
7688 if(p->errmsg.msg504) free(p->errmsg.msg504);
7689 */
7690 if (p->appsession_name)
7691 free(p->appsession_name);
7692
7693 h = p->req_cap;
7694 while (h) {
7695 h_next = h->next;
7696 if (h->name)
7697 free(h->name);
7698 pool_destroy(h->pool);
7699 free(h);
7700 h = h_next;
7701 }/* end while(h) */
7702
7703 h = p->rsp_cap;
7704 while (h) {
7705 h_next = h->next;
7706 if (h->name)
7707 free(h->name);
7708
7709 pool_destroy(h->pool);
7710 free(h);
7711 h = h_next;
7712 }/* end while(h) */
7713
7714 s = p->srv;
7715 while (s) {
7716 s_next = s->next;
7717 if(s->id)
7718 free(s->id);
7719
7720 if(s->cookie)
7721 free(s->cookie);
7722
7723 free(s);
7724 s = s_next;
7725 }/* end while(s) */
7726
7727 l = p->listen;
7728 while (l) {
7729 l_next = l->next;
7730 free(l);
7731 l = l_next;
7732 }/* end while(l) */
7733
7734 pool_destroy((void **) p->req_cap_pool);
7735 pool_destroy((void **) p->rsp_cap_pool);
7736 p = p->next;
7737 }/* end while(p) */
7738
7739 if (global.chroot) free(global.chroot);
7740 if (global.pidfile) free(global.pidfile);
7741
willy tarreau12350152005-12-18 01:03:27 +01007742 if (StaticReadEvent) free(StaticReadEvent);
7743 if (StaticWriteEvent) free(StaticWriteEvent);
7744 if (fdtab) free(fdtab);
7745
7746 pool_destroy(pool_session);
7747 pool_destroy(pool_buffer);
7748 pool_destroy(pool_fdtab);
7749 pool_destroy(pool_requri);
7750 pool_destroy(pool_task);
7751 pool_destroy(pool_capture);
7752 pool_destroy(pool_appsess);
7753
7754 if (have_appsession) {
7755 pool_destroy(apools.serverid);
7756 pool_destroy(apools.sessid);
7757 }
7758} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007759
7760int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007761 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007762 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007763 init(argc, argv);
7764
willy tarreau9fe663a2005-12-17 13:02:59 +01007765 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007766 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007767 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007768 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007769 }
7770
7771 signal(SIGQUIT, dump);
7772 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007773 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007774#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007775 signal(SIGINT, sig_int);
7776 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007777#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007778
7779 /* on very high loads, a sigpipe sometimes happen just between the
7780 * getsockopt() which tells "it's OK to write", and the following write :-(
7781 */
willy tarreau3242e862005-12-17 12:27:53 +01007782#ifndef MSG_NOSIGNAL
7783 signal(SIGPIPE, SIG_IGN);
7784#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007785
7786 if (start_proxies() < 0)
7787 exit(1);
7788
willy tarreaufe2c5c12005-12-17 14:14:34 +01007789 /* open log & pid files before the chroot */
7790 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7791 int pidfd;
7792 unlink(global.pidfile);
7793 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7794 if (pidfd < 0) {
7795 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7796 exit(1);
7797 }
7798 pidfile = fdopen(pidfd, "w");
7799 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007800
7801 /* chroot if needed */
7802 if (global.chroot != NULL) {
7803 if (chroot(global.chroot) == -1) {
7804 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7805 exit(1);
7806 }
7807 chdir("/");
7808 }
7809
willy tarreaub1285d52005-12-18 01:20:14 +01007810 /* ulimits */
7811 if (global.rlimit_nofile) {
7812 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7813 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7814 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7815 }
7816 }
7817
willy tarreau9fe663a2005-12-17 13:02:59 +01007818 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007819 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007820 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7821 exit(1);
7822 }
7823
willy tarreau036e1ce2005-12-17 13:46:33 +01007824 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007825 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7826 exit(1);
7827 }
7828
willy tarreaub1285d52005-12-18 01:20:14 +01007829 /* check ulimits */
7830 limit.rlim_cur = limit.rlim_max = 0;
7831 getrlimit(RLIMIT_NOFILE, &limit);
7832 if (limit.rlim_cur < global.maxsock) {
7833 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",
7834 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
7835 }
7836
willy tarreau9fe663a2005-12-17 13:02:59 +01007837 if (global.mode & MODE_DAEMON) {
7838 int ret = 0;
7839 int proc;
7840
7841 /* the father launches the required number of processes */
7842 for (proc = 0; proc < global.nbproc; proc++) {
7843 ret = fork();
7844 if (ret < 0) {
7845 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7846 exit(1); /* there has been an error */
7847 }
7848 else if (ret == 0) /* child breaks here */
7849 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007850 if (pidfile != NULL) {
7851 fprintf(pidfile, "%d\n", ret);
7852 fflush(pidfile);
7853 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007854 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007855 /* close the pidfile both in children and father */
7856 if (pidfile != NULL)
7857 fclose(pidfile);
7858 free(global.pidfile);
7859
willy tarreau9fe663a2005-12-17 13:02:59 +01007860 if (proc == global.nbproc)
7861 exit(0); /* parent must leave */
7862
willy tarreau750a4722005-12-17 13:21:24 +01007863 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7864 * that we can detach from the TTY. We MUST NOT do it in other cases since
7865 * it would have already be done, and 0-2 would have been affected to listening
7866 * sockets
7867 */
7868 if (!(global.mode & MODE_QUIET)) {
7869 /* detach from the tty */
7870 fclose(stdin); fclose(stdout); fclose(stderr);
7871 close(0); close(1); close(2); /* close all fd's */
7872 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7873 }
willy tarreaua1598082005-12-17 13:08:06 +01007874 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007875 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007876 }
7877
willy tarreau1c2ad212005-12-18 01:11:29 +01007878#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007879 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007880 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
7881 epoll_loop(POLL_LOOP_ACTION_RUN);
7882 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007883 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007884 }
7885 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01007886 Warning("epoll() is not available. Using poll()/select() instead.\n");
7887 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007888 }
7889 }
7890#endif
7891
7892#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007893 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007894 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
7895 poll_loop(POLL_LOOP_ACTION_RUN);
7896 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007897 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007898 }
7899 else {
7900 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01007901 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007902 }
7903 }
7904#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01007905 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007906 if (select_loop(POLL_LOOP_ACTION_INIT)) {
7907 select_loop(POLL_LOOP_ACTION_RUN);
7908 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007909 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01007910 }
7911 }
7912
willy tarreau0f7af912005-12-17 12:21:26 +01007913
willy tarreau12350152005-12-18 01:03:27 +01007914 /* Free all Hash Keys and all Hash elements */
7915 appsession_cleanup();
7916 /* Do some cleanup */
7917 deinit();
7918
willy tarreau0f7af912005-12-17 12:21:26 +01007919 exit(0);
7920}
willy tarreau12350152005-12-18 01:03:27 +01007921
7922#if defined(DEBUG_HASH)
7923static void print_table(const CHTbl *htbl) {
7924
7925 ListElmt *element;
7926 int i;
7927 appsess *asession;
7928
7929 /*****************************************************************************
7930 * *
7931 * Display the chained hash table. *
7932 * *
7933 *****************************************************************************/
7934
7935 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
7936
7937 for (i = 0; i < TBLSIZ; i++) {
7938 fprintf(stdout, "Bucket[%03d]\n", i);
7939
7940 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7941 //fprintf(stdout, "%c", *(char *)list_data(element));
7942 asession = (appsess *)list_data(element);
7943 fprintf(stdout, "ELEM :%s:", asession->sessid);
7944 fprintf(stdout, " Server :%s: \n", asession->serverid);
7945 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
7946 }
7947
7948 fprintf(stdout, "\n");
7949 }
7950 return;
7951} /* end print_table */
7952#endif
7953
7954static int appsession_init(void)
7955{
7956 static int initialized = 0;
7957 int idlen;
7958 struct server *s;
7959 struct proxy *p = proxy;
7960
7961 if (!initialized) {
7962 if (!appsession_task_init()) {
7963 apools.sessid = NULL;
7964 apools.serverid = NULL;
7965 apools.ser_waste = 0;
7966 apools.ser_use = 0;
7967 apools.ser_msize = sizeof(void *);
7968 apools.ses_waste = 0;
7969 apools.ses_use = 0;
7970 apools.ses_msize = sizeof(void *);
7971 while (p) {
7972 s = p->srv;
7973 if (apools.ses_msize < p->appsession_len)
7974 apools.ses_msize = p->appsession_len;
7975 while (s) {
7976 idlen = strlen(s->id);
7977 if (apools.ser_msize < idlen)
7978 apools.ser_msize = idlen;
7979 s = s->next;
7980 }
7981 p = p->next;
7982 }
7983 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
7984 apools.ses_msize ++;
7985 }
7986 else {
7987 fprintf(stderr, "appsession_task_init failed\n");
7988 return -1;
7989 }
7990 initialized ++;
7991 }
7992 return 0;
7993}
7994
7995static int appsession_task_init(void)
7996{
7997 static int initialized = 0;
7998 struct task *t;
7999 if (!initialized) {
8000 if ((t = pool_alloc(task)) == NULL)
8001 return -1;
8002 t->next = t->prev = t->rqnext = NULL;
8003 t->wq = LIST_HEAD(wait_queue);
8004 t->state = TASK_IDLE;
8005 t->context = NULL;
8006 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8007 task_queue(t);
8008 t->process = appsession_refresh;
8009 initialized ++;
8010 }
8011 return 0;
8012}
8013
8014static int appsession_refresh(struct task *t) {
8015 struct proxy *p = proxy;
8016 CHTbl *htbl;
8017 ListElmt *element, *last;
8018 int i;
8019 appsess *asession;
8020 void *data;
8021
8022 while (p) {
8023 if (p->appsession_name != NULL) {
8024 htbl = &p->htbl_proxy;
8025 /* if we ever give up the use of TBLSIZ, we need to change this */
8026 for (i = 0; i < TBLSIZ; i++) {
8027 last = NULL;
8028 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8029 asession = (appsess *)list_data(element);
8030 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8031 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8032 int len;
8033 /*
8034 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8035 */
8036 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8037 asession->sessid, asession->serverid?asession->serverid:"(null)");
8038 write(1, trash, len);
8039 }
8040 /* delete the expired element from within the hash table */
8041 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8042 && (htbl->table[i].destroy != NULL)) {
8043 htbl->table[i].destroy(data);
8044 }
8045 if (last == NULL) {/* patient lost his head, get a new one */
8046 element = list_head(&htbl->table[i]);
8047 if (element == NULL) break; /* no heads left, go to next patient */
8048 }
8049 else
8050 element = last;
8051 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8052 else
8053 last = element;
8054 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8055 }
8056 }
8057 p = p->next;
8058 }
8059 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8060 return TBLCHKINT;
8061} /* end appsession_refresh */
8062