blob: 34d9b408ac9029af35643fbbfdbb729a7d94a822 [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"
willy tarreauc5f73ed2005-12-18 01:26:38 +010080#define HAPROXY_DATE "2005/08/07"
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 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001654static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *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 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001770 socklen_t salen = sizeof(struct sockaddr_in);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001771 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;
willy tarreauc5f73ed2005-12-18 01:26:38 +01001781 socklen_t namelen;
willy tarreaua41a8b42005-12-17 14:02:24 +01001782
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 tarreauc5f73ed2005-12-18 01:26:38 +01002444 socklen_t 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 tarreauc5f73ed2005-12-18 01:26:38 +01002592 socklen_t 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 tarreauc5f73ed2005-12-18 01:26:38 +01002633 socklen_t 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 tarreauc5f73ed2005-12-18 01:26:38 +01002757 int skerr;
2758 socklen_t lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002759 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002760 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002761 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002762 if (skerr)
2763 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002764 else {
2765 if (s->proxy->options & PR_O_HTTP_CHK) {
2766 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002767 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002768 * so we'll send the request, and won't wake the checker up now.
2769 */
2770#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002771 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002772#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002773 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002774#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002775 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002776 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2777 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2778 return 0;
2779 }
2780 else
2781 s->result = -1;
2782 }
2783 else {
2784 /* good TCP connection is enough */
2785 s->result = 1;
2786 }
2787 }
2788
2789 task_wakeup(&rq, t);
2790 return 0;
2791}
2792
willy tarreau0f7af912005-12-17 12:21:26 +01002793
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002794/*
2795 * This function is used only for server health-checks. It handles
2796 * the server's reply to an HTTP request. It returns 1 if the server replies
2797 * 2xx or 3xx (valid responses), or -1 in other cases.
2798 */
2799int event_srv_chk_r(int fd) {
2800 char reply[64];
2801 int len;
2802 struct task *t = fdtab[fd].owner;
2803 struct server *s = t->context;
2804
2805 int skerr, lskerr;
2806 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002807
2808 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002809#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002810 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2811 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002812 len = recv(fd, reply, sizeof(reply), 0);
2813#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002814 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2815 * but the connection was closed on the remote end. Fortunately, recv still
2816 * works correctly and we don't need to do the getsockopt() on linux.
2817 */
2818 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002819#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002820 if ((len >= sizeof("HTTP/1.0 000")) &&
2821 !memcmp(reply, "HTTP/1.", 7) &&
2822 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2823 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002824
2825 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002826 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002827 return 0;
2828}
2829
2830
2831/*
2832 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2833 * and moves <end> just after the end of <str>.
2834 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2835 * the shift value (positive or negative) is returned.
2836 * If there's no space left, the move is not done.
2837 *
2838 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002839int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002840 int delta;
2841 int len;
2842
2843 len = strlen(str);
2844 delta = len - (end - pos);
2845
2846 if (delta + b->r >= b->data + BUFSIZE)
2847 return 0; /* no space left */
2848
2849 /* first, protect the end of the buffer */
2850 memmove(end + delta, end, b->data + b->l - end);
2851
2852 /* now, copy str over pos */
2853 memcpy(pos, str,len);
2854
willy tarreau5cbea6f2005-12-17 12:48:26 +01002855 /* we only move data after the displaced zone */
2856 if (b->r > pos) b->r += delta;
2857 if (b->w > pos) b->w += delta;
2858 if (b->h > pos) b->h += delta;
2859 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002860 b->l += delta;
2861
2862 return delta;
2863}
2864
willy tarreau8337c6b2005-12-17 13:41:01 +01002865/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002866 * len is 0.
2867 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002869 int delta;
2870
2871 delta = len - (end - pos);
2872
2873 if (delta + b->r >= b->data + BUFSIZE)
2874 return 0; /* no space left */
2875
2876 /* first, protect the end of the buffer */
2877 memmove(end + delta, end, b->data + b->l - end);
2878
2879 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002880 if (len)
2881 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002882
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883 /* we only move data after the displaced zone */
2884 if (b->r > pos) b->r += delta;
2885 if (b->w > pos) b->w += delta;
2886 if (b->h > pos) b->h += delta;
2887 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002888 b->l += delta;
2889
2890 return delta;
2891}
2892
2893
2894int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2895 char *old_dst = dst;
2896
2897 while (*str) {
2898 if (*str == '\\') {
2899 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002900 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002901 int len, num;
2902
2903 num = *str - '0';
2904 str++;
2905
willy tarreau8a86dbf2005-12-18 00:45:59 +01002906 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002907 len = matches[num].rm_eo - matches[num].rm_so;
2908 memcpy(dst, src + matches[num].rm_so, len);
2909 dst += len;
2910 }
2911
2912 }
2913 else if (*str == 'x') {
2914 unsigned char hex1, hex2;
2915 str++;
2916
willy tarreauc1f47532005-12-18 01:08:26 +01002917 hex1 = toupper(*str++) - '0';
2918 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002919
2920 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2921 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2922 *dst++ = (hex1<<4) + hex2;
2923 }
2924 else
2925 *dst++ = *str++;
2926 }
2927 else
2928 *dst++ = *str++;
2929 }
2930 *dst = 0;
2931 return dst - old_dst;
2932}
2933
willy tarreauc1f47532005-12-18 01:08:26 +01002934static int ishex(char s)
2935{
2936 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
2937}
2938
2939/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
2940char *check_replace_string(char *str)
2941{
2942 char *err = NULL;
2943 while (*str) {
2944 if (*str == '\\') {
2945 err = str; /* in case of a backslash, we return the pointer to it */
2946 str++;
2947 if (!*str)
2948 return err;
2949 else if (isdigit((int)*str))
2950 err = NULL;
2951 else if (*str == 'x') {
2952 str++;
2953 if (!ishex(*str))
2954 return err;
2955 str++;
2956 if (!ishex(*str))
2957 return err;
2958 err = NULL;
2959 }
2960 else {
2961 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
2962 err = NULL;
2963 }
2964 }
2965 str++;
2966 }
2967 return err;
2968}
2969
2970
willy tarreau9fe663a2005-12-17 13:02:59 +01002971
willy tarreau0f7af912005-12-17 12:21:26 +01002972/*
2973 * manages the client FSM and its socket. BTW, it also tries to handle the
2974 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2975 * 0 else.
2976 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002977int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002978 int s = t->srv_state;
2979 int c = t->cli_state;
2980 struct buffer *req = t->req;
2981 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01002982 int method_checked = 0;
2983 appsess *asession_temp = NULL;
2984 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01002985
willy tarreau750a4722005-12-17 13:21:24 +01002986#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01002987 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
2988 cli_stnames[c], srv_stnames[s],
2989 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2990 t->crexpire.tv_sec, t->crexpire.tv_usec,
2991 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01002992#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002993 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2994 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2995 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2996 //);
2997 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002998 /* now parse the partial (or complete) headers */
2999 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3000 char *ptr;
3001 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003002 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003003
willy tarreau5cbea6f2005-12-17 12:48:26 +01003004 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003005
willy tarreau0f7af912005-12-17 12:21:26 +01003006 /* look for the end of the current header */
3007 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3008 ptr++;
3009
willy tarreau5cbea6f2005-12-17 12:48:26 +01003010 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003011 int line, len;
3012 /* we can only get here after an end of headers */
3013 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003014
willy tarreaue39cd132005-12-17 13:00:18 +01003015 if (t->flags & SN_CLDENY) {
3016 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003017 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003018 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003019 if (!(t->flags & SN_ERR_MASK))
3020 t->flags |= SN_ERR_PRXCOND;
3021 if (!(t->flags & SN_FINST_MASK))
3022 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003023 return 1;
3024 }
3025
willy tarreau5cbea6f2005-12-17 12:48:26 +01003026 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003027 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3028 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003029 }
willy tarreau0f7af912005-12-17 12:21:26 +01003030
willy tarreau9fe663a2005-12-17 13:02:59 +01003031 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003032 if (t->cli_addr.ss_family == AF_INET) {
3033 unsigned char *pn;
3034 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3035 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3036 pn[0], pn[1], pn[2], pn[3]);
3037 buffer_replace2(req, req->h, req->h, trash, len);
3038 }
3039 else if (t->cli_addr.ss_family == AF_INET6) {
3040 char pn[INET6_ADDRSTRLEN];
3041 inet_ntop(AF_INET6,
3042 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3043 pn, sizeof(pn));
3044 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3045 buffer_replace2(req, req->h, req->h, trash, len);
3046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003047 }
3048
willy tarreau25c4ea52005-12-18 00:49:49 +01003049 /* add a "connection: close" line if needed */
3050 if (t->proxy->options & PR_O_HTTP_CLOSE)
3051 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3052
willy tarreau982249e2005-12-18 00:57:06 +01003053 if (!memcmp(req->data, "POST ", 5)) {
3054 /* this is a POST request, which is not cacheable by default */
3055 t->flags |= SN_POST;
3056 }
willy tarreaucd878942005-12-17 13:27:43 +01003057
willy tarreau5cbea6f2005-12-17 12:48:26 +01003058 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003059 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003060
willy tarreau750a4722005-12-17 13:21:24 +01003061 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003062 /* FIXME: we'll set the client in a wait state while we try to
3063 * connect to the server. Is this really needed ? wouldn't it be
3064 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003065 //FD_CLR(t->cli_fd, StaticReadEvent);
3066 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003067
3068 /* FIXME: if we break here (as up to 1.1.23), having the client
3069 * shutdown its connection can lead to an abort further.
3070 * it's better to either return 1 or even jump directly to the
3071 * data state which will save one schedule.
3072 */
3073 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003074
3075 if (!t->proxy->clitimeout ||
3076 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3077 /* If the client has no timeout, or if the server is not ready yet,
3078 * and we know for sure that it can expire, then it's cleaner to
3079 * disable the timeout on the client side so that too low values
3080 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003081 *
3082 * FIXME-20050705: the server needs a way to re-enable this time-out
3083 * when it switches its state, otherwise a client can stay connected
3084 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003085 */
3086 tv_eternity(&t->crexpire);
3087
willy tarreau197e8ec2005-12-17 14:10:59 +01003088 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003089 }
willy tarreau0f7af912005-12-17 12:21:26 +01003090
willy tarreau5cbea6f2005-12-17 12:48:26 +01003091 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3092 if (ptr > req->r - 2) {
3093 /* this is a partial header, let's wait for more to come */
3094 req->lr = ptr;
3095 break;
3096 }
willy tarreau0f7af912005-12-17 12:21:26 +01003097
willy tarreau5cbea6f2005-12-17 12:48:26 +01003098 /* now we know that *ptr is either \r or \n,
3099 * and that there are at least 1 char after it.
3100 */
3101 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3102 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3103 else
3104 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003105
willy tarreau5cbea6f2005-12-17 12:48:26 +01003106 /*
3107 * now we know that we have a full header ; we can do whatever
3108 * we want with these pointers :
3109 * req->h = beginning of header
3110 * ptr = end of header (first \r or \n)
3111 * req->lr = beginning of next line (next rep->h)
3112 * req->r = end of data (not used at this stage)
3113 */
willy tarreau0f7af912005-12-17 12:21:26 +01003114
willy tarreau12350152005-12-18 01:03:27 +01003115 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3116 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3117 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3118
3119 /* skip ; */
3120 request_line++;
3121
3122 /* look if we have a jsessionid */
3123
3124 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3125
3126 /* skip jsessionid= */
3127 request_line += t->proxy->appsession_name_len + 1;
3128
3129 /* First try if we allready have an appsession */
3130 asession_temp = &local_asession;
3131
3132 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3133 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3134 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3135 return 0;
3136 }
3137
3138 /* Copy the sessionid */
3139 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3140 asession_temp->sessid[t->proxy->appsession_len] = 0;
3141 asession_temp->serverid = NULL;
3142
3143 /* only do insert, if lookup fails */
3144 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3145 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3146 Alert("Not enough memory process_cli():asession:calloc().\n");
3147 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3148 return 0;
3149 }
3150 asession_temp->sessid = local_asession.sessid;
3151 asession_temp->serverid = local_asession.serverid;
3152 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3153 } /* end if(chtbl_lookup()) */
3154 else{
3155 /*free wasted memory;*/
3156 pool_free_to(apools.sessid, local_asession.sessid);
3157 }
3158
3159 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3160 asession_temp->request_count++;
3161
3162#if defined(DEBUG_HASH)
3163 print_table(&(t->proxy->htbl_proxy));
3164#endif
3165
3166 if (asession_temp->serverid == NULL) {
3167 Alert("Found Application Session without matching server.\n");
3168 } else {
3169 struct server *srv = t->proxy->srv;
3170 while (srv) {
3171 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3172 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3173 /* we found the server and it's usable */
3174 t->flags &= ~SN_CK_MASK;
3175 t->flags |= SN_CK_VALID | SN_DIRECT;
3176 t->srv = srv;
3177 break;
3178 }else {
3179 t->flags &= ~SN_CK_MASK;
3180 t->flags |= SN_CK_DOWN;
3181 }
3182 }/* end if(strcmp()) */
3183 srv = srv->next;
3184 }/* end while(srv) */
3185 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreau12350152005-12-18 01:03:27 +01003186 }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
3187 else {
3188 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3189 }
willy tarreau598da412005-12-18 01:07:29 +01003190 method_checked = 1;
willy tarreau12350152005-12-18 01:03:27 +01003191 }/* end if(!method_checked ...) */
3192 else{
3193 //printf("No Methode-Header with Session-String\n");
3194 }
3195
willy tarreau8337c6b2005-12-17 13:41:01 +01003196 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003197 /* we have a complete HTTP request that we must log */
3198 int urilen;
3199
willy tarreaua1598082005-12-17 13:08:06 +01003200 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003201 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003202 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003203 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003204 if (!(t->flags & SN_ERR_MASK))
3205 t->flags |= SN_ERR_PRXCOND;
3206 if (!(t->flags & SN_FINST_MASK))
3207 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003208 return 1;
3209 }
3210
3211 urilen = ptr - req->h;
3212 if (urilen >= REQURI_LEN)
3213 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003214 memcpy(t->logs.uri, req->h, urilen);
3215 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003216
willy tarreaua1598082005-12-17 13:08:06 +01003217 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003218 sess_log(t);
3219 }
willy tarreau4302f492005-12-18 01:00:37 +01003220 else if (t->logs.logwait & LW_REQHDR) {
3221 struct cap_hdr *h;
3222 int len;
3223 for (h = t->proxy->req_cap; h; h = h->next) {
3224 if ((h->namelen + 2 <= ptr - req->h) &&
3225 (req->h[h->namelen] == ':') &&
3226 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3227
3228 if (t->req_cap[h->index] == NULL)
3229 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3230
3231 len = ptr - (req->h + h->namelen + 2);
3232 if (len > h->len)
3233 len = h->len;
3234
3235 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3236 t->req_cap[h->index][len]=0;
3237 }
3238 }
3239
3240 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003241
willy tarreau5cbea6f2005-12-17 12:48:26 +01003242 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003243
willy tarreau982249e2005-12-18 00:57:06 +01003244 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003245 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003246 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 +01003247 max = ptr - req->h;
3248 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003249 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003250 trash[len++] = '\n';
3251 write(1, trash, len);
3252 }
willy tarreau0f7af912005-12-17 12:21:26 +01003253
willy tarreau25c4ea52005-12-18 00:49:49 +01003254
3255 /* remove "connection: " if needed */
3256 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3257 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3258 delete_header = 1;
3259 }
3260
willy tarreau5cbea6f2005-12-17 12:48:26 +01003261 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003262 if (!delete_header && t->proxy->req_exp != NULL
3263 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003264 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003265 char term;
3266
3267 term = *ptr;
3268 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003269 exp = t->proxy->req_exp;
3270 do {
3271 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3272 switch (exp->action) {
3273 case ACT_ALLOW:
3274 if (!(t->flags & SN_CLDENY))
3275 t->flags |= SN_CLALLOW;
3276 break;
3277 case ACT_REPLACE:
3278 if (!(t->flags & SN_CLDENY)) {
3279 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3280 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3281 }
3282 break;
3283 case ACT_REMOVE:
3284 if (!(t->flags & SN_CLDENY))
3285 delete_header = 1;
3286 break;
3287 case ACT_DENY:
3288 if (!(t->flags & SN_CLALLOW))
3289 t->flags |= SN_CLDENY;
3290 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003291 case ACT_PASS: /* we simply don't deny this one */
3292 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003293 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003294 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003295 }
willy tarreaue39cd132005-12-17 13:00:18 +01003296 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003297 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003298 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003299
willy tarreau240afa62005-12-17 13:14:35 +01003300 /* Now look for cookies. Conforming to RFC2109, we have to support
3301 * attributes whose name begin with a '$', and associate them with
3302 * the right cookie, if we want to delete this cookie.
3303 * So there are 3 cases for each cookie read :
3304 * 1) it's a special attribute, beginning with a '$' : ignore it.
3305 * 2) it's a server id cookie that we *MAY* want to delete : save
3306 * some pointers on it (last semi-colon, beginning of cookie...)
3307 * 3) it's an application cookie : we *MAY* have to delete a previous
3308 * "special" cookie.
3309 * At the end of loop, if a "special" cookie remains, we may have to
3310 * remove it. If no application cookie persists in the header, we
3311 * *MUST* delete it
3312 */
willy tarreau12350152005-12-18 01:03:27 +01003313 if (!delete_header &&
3314 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003315 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003316 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003317 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003318 char *del_colon, *del_cookie, *colon;
3319 int app_cookies;
3320
willy tarreau5cbea6f2005-12-17 12:48:26 +01003321 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003322 colon = p1;
3323 /* del_cookie == NULL => nothing to be deleted */
3324 del_colon = del_cookie = NULL;
3325 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003326
3327 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003328 /* skip spaces and colons, but keep an eye on these ones */
3329 while (p1 < ptr) {
3330 if (*p1 == ';' || *p1 == ',')
3331 colon = p1;
3332 else if (!isspace((int)*p1))
3333 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003335 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003336
3337 if (p1 == ptr)
3338 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003339
3340 /* p1 is at the beginning of the cookie name */
3341 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003342 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003343 p2++;
3344
3345 if (p2 == ptr)
3346 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347
3348 p3 = p2 + 1; /* skips the '=' sign */
3349 if (p3 == ptr)
3350 break;
3351
willy tarreau240afa62005-12-17 13:14:35 +01003352 p4 = p3;
3353 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003354 p4++;
3355
3356 /* here, we have the cookie name between p1 and p2,
3357 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003358 * we can process it :
3359 *
3360 * Cookie: NAME=VALUE;
3361 * | || || |
3362 * | || || +--> p4
3363 * | || |+-------> p3
3364 * | || +--------> p2
3365 * | |+------------> p1
3366 * | +-------------> colon
3367 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003368 */
3369
willy tarreau240afa62005-12-17 13:14:35 +01003370 if (*p1 == '$') {
3371 /* skip this one */
3372 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003373 else {
3374 /* first, let's see if we want to capture it */
3375 if (t->proxy->capture_name != NULL &&
3376 t->logs.cli_cookie == NULL &&
3377 (p4 - p1 >= t->proxy->capture_namelen) &&
3378 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3379 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003380
willy tarreau8337c6b2005-12-17 13:41:01 +01003381 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3382 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003383 } else {
3384 if (log_len > t->proxy->capture_len)
3385 log_len = t->proxy->capture_len;
3386 memcpy(t->logs.cli_cookie, p1, log_len);
3387 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003388 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003389 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003390
3391 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3392 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3393 /* Cool... it's the right one */
3394 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003395 char *delim;
3396
3397 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3398 * have the server ID betweek p3 and delim, and the original cookie between
3399 * delim+1 and p4. Otherwise, delim==p4 :
3400 *
3401 * Cookie: NAME=SRV~VALUE;
3402 * | || || | |
3403 * | || || | +--> p4
3404 * | || || +--------> delim
3405 * | || |+-----------> p3
3406 * | || +------------> p2
3407 * | |+----------------> p1
3408 * | +-----------------> colon
3409 * +------------------------> req->h
3410 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003411
willy tarreau0174f312005-12-18 01:02:42 +01003412 if (t->proxy->options & PR_O_COOK_PFX) {
3413 for (delim = p3; delim < p4; delim++)
3414 if (*delim == COOKIE_DELIM)
3415 break;
3416 }
3417 else
3418 delim = p4;
3419
3420
3421 /* Here, we'll look for the first running server which supports the cookie.
3422 * This allows to share a same cookie between several servers, for example
3423 * to dedicate backup servers to specific servers only.
3424 */
3425 while (srv) {
3426 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3427 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3428 /* we found the server and it's usable */
3429 t->flags &= ~SN_CK_MASK;
3430 t->flags |= SN_CK_VALID | SN_DIRECT;
3431 t->srv = srv;
3432 break;
willy tarreau12350152005-12-18 01:03:27 +01003433 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003434 /* we found a server, but it's down */
3435 t->flags &= ~SN_CK_MASK;
3436 t->flags |= SN_CK_DOWN;
3437 }
3438 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003439 srv = srv->next;
3440 }
3441
willy tarreau0174f312005-12-18 01:02:42 +01003442 if (!srv && !(t->flags & SN_CK_DOWN)) {
3443 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003444 t->flags &= ~SN_CK_MASK;
3445 t->flags |= SN_CK_INVALID;
3446 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003447
willy tarreau0174f312005-12-18 01:02:42 +01003448 /* depending on the cookie mode, we may have to either :
3449 * - delete the complete cookie if we're in insert+indirect mode, so that
3450 * the server never sees it ;
3451 * - remove the server id from the cookie value, and tag the cookie as an
3452 * application cookie so that it does not get accidentely removed later,
3453 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003454 */
willy tarreau0174f312005-12-18 01:02:42 +01003455 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3456 buffer_replace2(req, p3, delim + 1, NULL, 0);
3457 p4 -= (delim + 1 - p3);
3458 ptr -= (delim + 1 - p3);
3459 del_cookie = del_colon = NULL;
3460 app_cookies++; /* protect the header from deletion */
3461 }
3462 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003463 (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 +01003464 del_cookie = p1;
3465 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003466 }
willy tarreau12350152005-12-18 01:03:27 +01003467 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003468 /* now we know that we must keep this cookie since it's
3469 * not ours. But if we wanted to delete our cookie
3470 * earlier, we cannot remove the complete header, but we
3471 * can remove the previous block itself.
3472 */
3473 app_cookies++;
3474
3475 if (del_cookie != NULL) {
3476 buffer_replace2(req, del_cookie, p1, NULL, 0);
3477 p4 -= (p1 - del_cookie);
3478 ptr -= (p1 - del_cookie);
3479 del_cookie = del_colon = NULL;
3480 }
willy tarreau240afa62005-12-17 13:14:35 +01003481 }
willy tarreau12350152005-12-18 01:03:27 +01003482
3483 if ((t->proxy->appsession_name != NULL) &&
3484 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3485 /* first, let's see if the cookie is our appcookie*/
3486
3487 /* Cool... it's the right one */
3488
3489 asession_temp = &local_asession;
3490
3491 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3492 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3493 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3494 return 0;
3495 }
3496
3497 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3498 asession_temp->sessid[t->proxy->appsession_len] = 0;
3499 asession_temp->serverid = NULL;
3500
3501 /* only do insert, if lookup fails */
3502 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3503 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3504 Alert("Not enough memory process_cli():asession:calloc().\n");
3505 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3506 return 0;
3507 }
3508
3509 asession_temp->sessid = local_asession.sessid;
3510 asession_temp->serverid = local_asession.serverid;
3511 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3512 }
3513 else{
3514 /* free wasted memory */
3515 pool_free_to(apools.sessid, local_asession.sessid);
3516 }
3517
3518 if (asession_temp->serverid == NULL) {
3519 Alert("Found Application Session without matching server.\n");
3520 } else {
3521 struct server *srv = t->proxy->srv;
3522 while (srv) {
3523 if(strcmp(srv->id, asession_temp->serverid) == 0) {
3524 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3525 /* we found the server and it's usable */
3526 t->flags &= ~SN_CK_MASK;
3527 t->flags |= SN_CK_VALID | SN_DIRECT;
3528 t->srv = srv;
3529 break;
3530 } else {
3531 t->flags &= ~SN_CK_MASK;
3532 t->flags |= SN_CK_DOWN;
3533 }
3534 }
3535 srv = srv->next;
3536 }/* end while(srv) */
3537 }/* end else if server == NULL */
3538
3539 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003540 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003541 }
willy tarreau240afa62005-12-17 13:14:35 +01003542
willy tarreau5cbea6f2005-12-17 12:48:26 +01003543 /* we'll have to look for another cookie ... */
3544 p1 = p4;
3545 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003546
3547 /* There's no more cookie on this line.
3548 * We may have marked the last one(s) for deletion.
3549 * We must do this now in two ways :
3550 * - if there is no app cookie, we simply delete the header ;
3551 * - if there are app cookies, we must delete the end of the
3552 * string properly, including the colon/semi-colon before
3553 * the cookie name.
3554 */
3555 if (del_cookie != NULL) {
3556 if (app_cookies) {
3557 buffer_replace2(req, del_colon, ptr, NULL, 0);
3558 /* WARNING! <ptr> becomes invalid for now. If some code
3559 * below needs to rely on it before the end of the global
3560 * header loop, we need to correct it with this code :
3561 * ptr = del_colon;
3562 */
3563 }
3564 else
3565 delete_header = 1;
3566 }
3567 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003568
3569 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003570 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003571 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003572 }
willy tarreau240afa62005-12-17 13:14:35 +01003573 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3574
willy tarreau5cbea6f2005-12-17 12:48:26 +01003575 req->h = req->lr;
3576 } /* while (req->lr < req->r) */
3577
3578 /* end of header processing (even if incomplete) */
3579
willy tarreauef900ab2005-12-17 12:52:52 +01003580 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3581 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3582 * full. We cannot loop here since event_cli_read will disable it only if
3583 * req->l == rlim-data
3584 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003585 FD_SET(t->cli_fd, StaticReadEvent);
3586 if (t->proxy->clitimeout)
3587 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3588 else
3589 tv_eternity(&t->crexpire);
3590 }
3591
willy tarreaue39cd132005-12-17 13:00:18 +01003592 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003593 * won't be able to free more later, so the session will never terminate.
3594 */
willy tarreaue39cd132005-12-17 13:00:18 +01003595 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003596 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003597 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003598 if (!(t->flags & SN_ERR_MASK))
3599 t->flags |= SN_ERR_PRXCOND;
3600 if (!(t->flags & SN_FINST_MASK))
3601 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003602 return 1;
3603 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003604 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003605 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003606 tv_eternity(&t->crexpire);
3607 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003609 if (!(t->flags & SN_ERR_MASK))
3610 t->flags |= SN_ERR_CLICL;
3611 if (!(t->flags & SN_FINST_MASK))
3612 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003613 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003614 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003615 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3616
3617 /* read timeout : give up with an error message.
3618 */
3619 t->logs.status = 408;
3620 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003621 if (!(t->flags & SN_ERR_MASK))
3622 t->flags |= SN_ERR_CLITO;
3623 if (!(t->flags & SN_FINST_MASK))
3624 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003625 return 1;
3626 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003627
3628 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003629 }
3630 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003631 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003632 /* FIXME: this error handling is partly buggy because we always report
3633 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3634 * or HEADER phase. BTW, it's not logical to expire the client while
3635 * we're waiting for the server to connect.
3636 */
willy tarreau0f7af912005-12-17 12:21:26 +01003637 /* read or write error */
3638 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003639 tv_eternity(&t->crexpire);
3640 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003641 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003642 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003643 if (!(t->flags & SN_ERR_MASK))
3644 t->flags |= SN_ERR_CLICL;
3645 if (!(t->flags & SN_FINST_MASK))
3646 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003647 return 1;
3648 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003649 /* last read, or end of server write */
3650 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003651 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003652 tv_eternity(&t->crexpire);
3653 shutdown(t->cli_fd, SHUT_RD);
3654 t->cli_state = CL_STSHUTR;
3655 return 1;
3656 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003657 /* last server read and buffer empty */
3658 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003659 FD_CLR(t->cli_fd, StaticWriteEvent);
3660 tv_eternity(&t->cwexpire);
3661 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003662 /* We must ensure that the read part is still alive when switching
3663 * to shutw */
3664 FD_SET(t->cli_fd, StaticReadEvent);
3665 if (t->proxy->clitimeout)
3666 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003667 t->cli_state = CL_STSHUTW;
3668 return 1;
3669 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003670 /* read timeout */
3671 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3672 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003673 tv_eternity(&t->crexpire);
3674 shutdown(t->cli_fd, SHUT_RD);
3675 t->cli_state = CL_STSHUTR;
3676 if (!(t->flags & SN_ERR_MASK))
3677 t->flags |= SN_ERR_CLITO;
3678 if (!(t->flags & SN_FINST_MASK))
3679 t->flags |= SN_FINST_D;
3680 return 1;
3681 }
3682 /* write timeout */
3683 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3684 FD_CLR(t->cli_fd, StaticWriteEvent);
3685 tv_eternity(&t->cwexpire);
3686 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003687 /* We must ensure that the read part is still alive when switching
3688 * to shutw */
3689 FD_SET(t->cli_fd, StaticReadEvent);
3690 if (t->proxy->clitimeout)
3691 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3692
willy tarreau036e1ce2005-12-17 13:46:33 +01003693 t->cli_state = CL_STSHUTW;
3694 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003695 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003696 if (!(t->flags & SN_FINST_MASK))
3697 t->flags |= SN_FINST_D;
3698 return 1;
3699 }
willy tarreau0f7af912005-12-17 12:21:26 +01003700
willy tarreauc58fc692005-12-17 14:13:08 +01003701 if (req->l >= req->rlim - req->data) {
3702 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003703 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003704 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003705 FD_CLR(t->cli_fd, StaticReadEvent);
3706 tv_eternity(&t->crexpire);
3707 }
3708 }
3709 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003710 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003711 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3712 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003713 if (!t->proxy->clitimeout ||
3714 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3715 /* If the client has no timeout, or if the server not ready yet, and we
3716 * know for sure that it can expire, then it's cleaner to disable the
3717 * timeout on the client side so that too low values cannot make the
3718 * sessions abort too early.
3719 */
willy tarreau0f7af912005-12-17 12:21:26 +01003720 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003721 else
3722 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003723 }
3724 }
3725
3726 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003727 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003728 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3729 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3730 tv_eternity(&t->cwexpire);
3731 }
3732 }
3733 else { /* buffer not empty */
3734 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3735 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003736 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003737 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003738 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3739 t->crexpire = t->cwexpire;
3740 }
willy tarreau0f7af912005-12-17 12:21:26 +01003741 else
3742 tv_eternity(&t->cwexpire);
3743 }
3744 }
3745 return 0; /* other cases change nothing */
3746 }
3747 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003748 if (t->res_cw == RES_ERROR) {
3749 tv_eternity(&t->cwexpire);
3750 fd_delete(t->cli_fd);
3751 t->cli_state = CL_STCLOSE;
3752 if (!(t->flags & SN_ERR_MASK))
3753 t->flags |= SN_ERR_CLICL;
3754 if (!(t->flags & SN_FINST_MASK))
3755 t->flags |= SN_FINST_D;
3756 return 1;
3757 }
3758 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003759 tv_eternity(&t->cwexpire);
3760 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003761 t->cli_state = CL_STCLOSE;
3762 return 1;
3763 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003764 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3765 tv_eternity(&t->cwexpire);
3766 fd_delete(t->cli_fd);
3767 t->cli_state = CL_STCLOSE;
3768 if (!(t->flags & SN_ERR_MASK))
3769 t->flags |= SN_ERR_CLITO;
3770 if (!(t->flags & SN_FINST_MASK))
3771 t->flags |= SN_FINST_D;
3772 return 1;
3773 }
willy tarreau0f7af912005-12-17 12:21:26 +01003774 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003775 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003776 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3777 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3778 tv_eternity(&t->cwexpire);
3779 }
3780 }
3781 else { /* buffer not empty */
3782 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3783 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003784 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003785 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003786 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3787 t->crexpire = t->cwexpire;
3788 }
willy tarreau0f7af912005-12-17 12:21:26 +01003789 else
3790 tv_eternity(&t->cwexpire);
3791 }
3792 }
3793 return 0;
3794 }
3795 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003796 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003797 tv_eternity(&t->crexpire);
3798 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003799 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003800 if (!(t->flags & SN_ERR_MASK))
3801 t->flags |= SN_ERR_CLICL;
3802 if (!(t->flags & SN_FINST_MASK))
3803 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003804 return 1;
3805 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003806 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3807 tv_eternity(&t->crexpire);
3808 fd_delete(t->cli_fd);
3809 t->cli_state = CL_STCLOSE;
3810 return 1;
3811 }
3812 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3813 tv_eternity(&t->crexpire);
3814 fd_delete(t->cli_fd);
3815 t->cli_state = CL_STCLOSE;
3816 if (!(t->flags & SN_ERR_MASK))
3817 t->flags |= SN_ERR_CLITO;
3818 if (!(t->flags & SN_FINST_MASK))
3819 t->flags |= SN_FINST_D;
3820 return 1;
3821 }
willy tarreauef900ab2005-12-17 12:52:52 +01003822 else if (req->l >= req->rlim - req->data) {
3823 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003824
3825 /* FIXME-20050705: is it possible for a client to maintain a session
3826 * after the timeout by sending more data after it receives a close ?
3827 */
3828
willy tarreau0f7af912005-12-17 12:21:26 +01003829 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003830 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003831 FD_CLR(t->cli_fd, StaticReadEvent);
3832 tv_eternity(&t->crexpire);
3833 }
3834 }
3835 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003836 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003837 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3838 FD_SET(t->cli_fd, StaticReadEvent);
3839 if (t->proxy->clitimeout)
3840 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3841 else
3842 tv_eternity(&t->crexpire);
3843 }
3844 }
3845 return 0;
3846 }
3847 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003848 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003849 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003850 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 +01003851 write(1, trash, len);
3852 }
3853 return 0;
3854 }
3855 return 0;
3856}
3857
3858
3859/*
3860 * manages the server FSM and its socket. It returns 1 if a state has changed
3861 * (and a resync may be needed), 0 else.
3862 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003863int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003864 int s = t->srv_state;
3865 int c = t->cli_state;
3866 struct buffer *req = t->req;
3867 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003868 appsess *asession_temp = NULL;
3869 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003870 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003871
willy tarreau750a4722005-12-17 13:21:24 +01003872#ifdef DEBUG_FULL
3873 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3874#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003875 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3876 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3877 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3878 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003879 if (s == SV_STIDLE) {
3880 if (c == CL_STHEADERS)
3881 return 0; /* stay in idle, waiting for data to reach the client side */
3882 else if (c == CL_STCLOSE ||
3883 c == CL_STSHUTW ||
3884 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3885 tv_eternity(&t->cnexpire);
3886 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003887 if (!(t->flags & SN_ERR_MASK))
3888 t->flags |= SN_ERR_CLICL;
3889 if (!(t->flags & SN_FINST_MASK))
3890 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003891 return 1;
3892 }
3893 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003894 /* initiate a connection to the server */
3895 conn_err = connect_server(t);
3896 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003897 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3898 t->srv_state = SV_STCONN;
3899 }
3900 else { /* try again */
3901 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003902 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003903 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003904 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003905 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3906 t->flags &= ~SN_CK_MASK;
3907 t->flags |= SN_CK_DOWN;
3908 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 }
3910
willy tarreaub1285d52005-12-18 01:20:14 +01003911 conn_err = connect_server(t);
3912 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003913 t->srv_state = SV_STCONN;
3914 break;
3915 }
3916 }
3917 if (t->conn_retries < 0) {
3918 /* if conn_retries < 0 or other error, let's abort */
3919 tv_eternity(&t->cnexpire);
3920 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003921 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003922 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003923 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003924 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01003925 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01003926 if (!(t->flags & SN_FINST_MASK))
3927 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003928 }
3929 }
3930 return 1;
3931 }
3932 }
3933 else if (s == SV_STCONN) { /* connection in progress */
3934 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3935 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3936 return 0; /* nothing changed */
3937 }
3938 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3939 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3940 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003941 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003942 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003943 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003944 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003945 if (t->conn_retries >= 0) {
3946 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003947 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003948 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003949 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3950 t->flags &= ~SN_CK_MASK;
3951 t->flags |= SN_CK_DOWN;
3952 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003953 }
willy tarreaub1285d52005-12-18 01:20:14 +01003954 conn_err = connect_server(t);
3955 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01003956 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003957 }
willy tarreaub1285d52005-12-18 01:20:14 +01003958 else if (t->res_sw == RES_SILENT)
3959 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
3960 else
3961 conn_err = SN_ERR_SRVCL; // it was a connect error.
3962
willy tarreau0f7af912005-12-17 12:21:26 +01003963 /* if conn_retries < 0 or other error, let's abort */
3964 tv_eternity(&t->cnexpire);
3965 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003966 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003967 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003968 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003969 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01003970 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01003971 if (!(t->flags & SN_FINST_MASK))
3972 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003973 return 1;
3974 }
3975 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003976 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003977
willy tarreau0f7af912005-12-17 12:21:26 +01003978 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003979 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003980 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003981 tv_eternity(&t->swexpire);
3982 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003983 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003984 if (t->proxy->srvtimeout) {
3985 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3986 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3987 t->srexpire = t->swexpire;
3988 }
3989 else
3990 tv_eternity(&t->swexpire);
3991 }
willy tarreau0f7af912005-12-17 12:21:26 +01003992
3993 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3994 FD_SET(t->srv_fd, StaticReadEvent);
3995 if (t->proxy->srvtimeout)
3996 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3997 else
3998 tv_eternity(&t->srexpire);
3999
4000 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004001 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004002
4003 /* if the user wants to log as soon as possible, without counting
4004 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004005 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004006 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4007 sess_log(t);
4008 }
willy tarreau0f7af912005-12-17 12:21:26 +01004009 }
willy tarreauef900ab2005-12-17 12:52:52 +01004010 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004011 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004012 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4013 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004014 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004015 return 1;
4016 }
4017 }
4018 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004019 /* now parse the partial (or complete) headers */
4020 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4021 char *ptr;
4022 int delete_header;
4023
4024 ptr = rep->lr;
4025
4026 /* look for the end of the current header */
4027 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4028 ptr++;
4029
4030 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004031 int line, len;
4032
4033 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004034
4035 /* first, we'll block if security checks have caught nasty things */
4036 if (t->flags & SN_CACHEABLE) {
4037 if ((t->flags & SN_CACHE_COOK) &&
4038 (t->flags & SN_SCK_ANY) &&
4039 (t->proxy->options & PR_O_CHK_CACHE)) {
4040
4041 /* we're in presence of a cacheable response containing
4042 * a set-cookie header. We'll block it as requested by
4043 * the 'checkcache' option, and send an alert.
4044 */
4045 tv_eternity(&t->srexpire);
4046 tv_eternity(&t->swexpire);
4047 fd_delete(t->srv_fd);
4048 t->srv_state = SV_STCLOSE;
4049 t->logs.status = 502;
4050 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4051 if (!(t->flags & SN_ERR_MASK))
4052 t->flags |= SN_ERR_PRXCOND;
4053 if (!(t->flags & SN_FINST_MASK))
4054 t->flags |= SN_FINST_H;
4055
4056 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4057 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4058
4059 return 1;
4060 }
4061 }
4062
willy tarreau982249e2005-12-18 00:57:06 +01004063 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4064 if (t->flags & SN_SVDENY) {
4065 tv_eternity(&t->srexpire);
4066 tv_eternity(&t->swexpire);
4067 fd_delete(t->srv_fd);
4068 t->srv_state = SV_STCLOSE;
4069 t->logs.status = 502;
4070 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4071 if (!(t->flags & SN_ERR_MASK))
4072 t->flags |= SN_ERR_PRXCOND;
4073 if (!(t->flags & SN_FINST_MASK))
4074 t->flags |= SN_FINST_H;
4075 return 1;
4076 }
4077
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 /* we'll have something else to do here : add new headers ... */
4079
willy tarreaucd878942005-12-17 13:27:43 +01004080 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4081 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004082 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004083 * insert a set-cookie here, except if we want to insert only on POST
4084 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004085 */
willy tarreau750a4722005-12-17 13:21:24 +01004086 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004087 t->proxy->cookie_name,
4088 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004089
willy tarreau036e1ce2005-12-17 13:46:33 +01004090 t->flags |= SN_SCK_INSERTED;
4091
willy tarreau750a4722005-12-17 13:21:24 +01004092 /* Here, we will tell an eventual cache on the client side that we don't
4093 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4094 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4095 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4096 */
willy tarreau240afa62005-12-17 13:14:35 +01004097 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004098 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4099 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01004100
willy tarreau750a4722005-12-17 13:21:24 +01004101 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004102 }
4103
4104 /* headers to be added */
4105 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004106 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4107 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004108 }
4109
willy tarreau25c4ea52005-12-18 00:49:49 +01004110 /* add a "connection: close" line if needed */
4111 if (t->proxy->options & PR_O_HTTP_CLOSE)
4112 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4113
willy tarreau5cbea6f2005-12-17 12:48:26 +01004114 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004115 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004116 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004117
4118 /* if the user wants to log as soon as possible, without counting
4119 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004120 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004121 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4122 t->logs.bytes = rep->h - rep->data;
4123 sess_log(t);
4124 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004125 break;
4126 }
4127
4128 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4129 if (ptr > rep->r - 2) {
4130 /* this is a partial header, let's wait for more to come */
4131 rep->lr = ptr;
4132 break;
4133 }
4134
4135 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4136 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4137
4138 /* now we know that *ptr is either \r or \n,
4139 * and that there are at least 1 char after it.
4140 */
4141 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4142 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4143 else
4144 rep->lr = ptr + 2; /* \r\n or \n\r */
4145
4146 /*
4147 * now we know that we have a full header ; we can do whatever
4148 * we want with these pointers :
4149 * rep->h = beginning of header
4150 * ptr = end of header (first \r or \n)
4151 * rep->lr = beginning of next line (next rep->h)
4152 * rep->r = end of data (not used at this stage)
4153 */
4154
willy tarreaua1598082005-12-17 13:08:06 +01004155
willy tarreau982249e2005-12-18 00:57:06 +01004156 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004157 t->logs.logwait &= ~LW_RESP;
4158 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004159 switch (t->logs.status) {
4160 case 200:
4161 case 203:
4162 case 206:
4163 case 300:
4164 case 301:
4165 case 410:
4166 /* RFC2616 @13.4:
4167 * "A response received with a status code of
4168 * 200, 203, 206, 300, 301 or 410 MAY be stored
4169 * by a cache (...) unless a cache-control
4170 * directive prohibits caching."
4171 *
4172 * RFC2616 @9.5: POST method :
4173 * "Responses to this method are not cacheable,
4174 * unless the response includes appropriate
4175 * Cache-Control or Expires header fields."
4176 */
4177 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4178 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4179 break;
4180 default:
4181 break;
4182 }
willy tarreau4302f492005-12-18 01:00:37 +01004183 }
4184 else if (t->logs.logwait & LW_RSPHDR) {
4185 struct cap_hdr *h;
4186 int len;
4187 for (h = t->proxy->rsp_cap; h; h = h->next) {
4188 if ((h->namelen + 2 <= ptr - rep->h) &&
4189 (rep->h[h->namelen] == ':') &&
4190 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4191
4192 if (t->rsp_cap[h->index] == NULL)
4193 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4194
4195 len = ptr - (rep->h + h->namelen + 2);
4196 if (len > h->len)
4197 len = h->len;
4198
4199 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4200 t->rsp_cap[h->index][len]=0;
4201 }
4202 }
4203
willy tarreaua1598082005-12-17 13:08:06 +01004204 }
4205
willy tarreau5cbea6f2005-12-17 12:48:26 +01004206 delete_header = 0;
4207
willy tarreau982249e2005-12-18 00:57:06 +01004208 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004209 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004210 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 +01004211 max = ptr - rep->h;
4212 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004213 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 trash[len++] = '\n';
4215 write(1, trash, len);
4216 }
4217
willy tarreau25c4ea52005-12-18 00:49:49 +01004218 /* remove "connection: " if needed */
4219 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4220 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4221 delete_header = 1;
4222 }
4223
willy tarreau5cbea6f2005-12-17 12:48:26 +01004224 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004225 if (!delete_header && t->proxy->rsp_exp != NULL
4226 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004227 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004228 char term;
4229
4230 term = *ptr;
4231 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004232 exp = t->proxy->rsp_exp;
4233 do {
4234 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4235 switch (exp->action) {
4236 case ACT_ALLOW:
4237 if (!(t->flags & SN_SVDENY))
4238 t->flags |= SN_SVALLOW;
4239 break;
4240 case ACT_REPLACE:
4241 if (!(t->flags & SN_SVDENY)) {
4242 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4243 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4244 }
4245 break;
4246 case ACT_REMOVE:
4247 if (!(t->flags & SN_SVDENY))
4248 delete_header = 1;
4249 break;
4250 case ACT_DENY:
4251 if (!(t->flags & SN_SVALLOW))
4252 t->flags |= SN_SVDENY;
4253 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004254 case ACT_PASS: /* we simply don't deny this one */
4255 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004256 }
4257 break;
4258 }
willy tarreaue39cd132005-12-17 13:00:18 +01004259 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004260 *ptr = term; /* restore the string terminator */
4261 }
4262
willy tarreau97f58572005-12-18 00:53:44 +01004263 /* check for cache-control: or pragma: headers */
4264 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4265 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4266 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4267 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4268 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004269 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004270 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4271 else {
4272 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004273 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004274 t->flags &= ~SN_CACHE_COOK;
4275 }
4276 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004277 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004278 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004279 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004280 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4281 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004282 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004283 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004284 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4285 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4286 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4287 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4288 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4289 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004290 }
4291 }
4292 }
4293
willy tarreau5cbea6f2005-12-17 12:48:26 +01004294 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004295 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004296 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004297 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004298 char *p1, *p2, *p3, *p4;
4299
willy tarreau97f58572005-12-18 00:53:44 +01004300 t->flags |= SN_SCK_ANY;
4301
willy tarreau5cbea6f2005-12-17 12:48:26 +01004302 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4303
4304 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004305 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004306 p1++;
4307
4308 if (p1 == ptr || *p1 == ';') /* end of cookie */
4309 break;
4310
4311 /* p1 is at the beginning of the cookie name */
4312 p2 = p1;
4313
4314 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4315 p2++;
4316
4317 if (p2 == ptr || *p2 == ';') /* next cookie */
4318 break;
4319
4320 p3 = p2 + 1; /* skips the '=' sign */
4321 if (p3 == ptr)
4322 break;
4323
4324 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004325 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004326 p4++;
4327
4328 /* here, we have the cookie name between p1 and p2,
4329 * and its value between p3 and p4.
4330 * we can process it.
4331 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004332
4333 /* first, let's see if we want to capture it */
4334 if (t->proxy->capture_name != NULL &&
4335 t->logs.srv_cookie == NULL &&
4336 (p4 - p1 >= t->proxy->capture_namelen) &&
4337 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4338 int log_len = p4 - p1;
4339
4340 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4341 Alert("HTTP logging : out of memory.\n");
4342 }
4343
4344 if (log_len > t->proxy->capture_len)
4345 log_len = t->proxy->capture_len;
4346 memcpy(t->logs.srv_cookie, p1, log_len);
4347 t->logs.srv_cookie[log_len] = 0;
4348 }
4349
4350 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4351 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004352 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004353 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004354
4355 /* If the cookie is in insert mode on a known server, we'll delete
4356 * this occurrence because we'll insert another one later.
4357 * We'll delete it too if the "indirect" option is set and we're in
4358 * a direct access. */
4359 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004360 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004361 /* this header must be deleted */
4362 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004363 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004364 }
4365 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4366 /* replace bytes p3->p4 with the cookie name associated
4367 * with this server since we know it.
4368 */
4369 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004370 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004371 }
willy tarreau0174f312005-12-18 01:02:42 +01004372 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4373 /* insert the cookie name associated with this server
4374 * before existing cookie, and insert a delimitor between them..
4375 */
4376 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4377 p3[t->srv->cklen] = COOKIE_DELIM;
4378 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4379 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004380 break;
4381 }
willy tarreau12350152005-12-18 01:03:27 +01004382
4383 /* first, let's see if the cookie is our appcookie*/
4384 if ((t->proxy->appsession_name != NULL) &&
4385 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4386
4387 /* Cool... it's the right one */
4388
4389 size_t server_id_len = strlen(t->srv->id)+1;
4390 asession_temp = &local_asession;
4391
4392 if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
4393 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4394 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4395 }
4396 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4397 asession_temp->sessid[t->proxy->appsession_len] = 0;
4398 asession_temp->serverid = NULL;
4399
4400 /* only do insert, if lookup fails */
4401 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4402 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4403 Alert("Not enought Memory process_srv():asession:calloc().\n");
4404 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4405 return 0;
4406 }
4407 asession_temp->sessid = local_asession.sessid;
4408 asession_temp->serverid = local_asession.serverid;
4409 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4410 }/* end if(chtbl_lookup()) */
4411 else
4412 {
4413 /* free wasted memory */
4414 pool_free_to(apools.sessid, local_asession.sessid);
4415 } /* end else from if(chtbl_lookup()) */
4416
4417 if(asession_temp->serverid == NULL){
4418 if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
4419 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4420 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4421 }
4422 asession_temp->serverid[0] = '\0';
4423 }
4424
4425 if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
4426
4427 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4428
4429#if defined(DEBUG_HASH)
4430 print_table(&(t->proxy->htbl_proxy));
4431#endif
4432 break;
4433 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004434 else {
4435 // fprintf(stderr,"Ignoring unknown cookie : ");
4436 // write(2, p1, p2-p1);
4437 // fprintf(stderr," = ");
4438 // write(2, p3, p4-p3);
4439 // fprintf(stderr,"\n");
4440 }
4441 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4442 } /* we're now at the end of the cookie value */
4443 } /* end of cookie processing */
4444
willy tarreau97f58572005-12-18 00:53:44 +01004445 /* check for any set-cookie in case we check for cacheability */
4446 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4447 (t->proxy->options & PR_O_CHK_CACHE) &&
4448 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4449 t->flags |= SN_SCK_ANY;
4450 }
4451
willy tarreau5cbea6f2005-12-17 12:48:26 +01004452 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004453 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004454 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004455
willy tarreau5cbea6f2005-12-17 12:48:26 +01004456 rep->h = rep->lr;
4457 } /* while (rep->lr < rep->r) */
4458
4459 /* end of header processing (even if incomplete) */
4460
willy tarreauef900ab2005-12-17 12:52:52 +01004461 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4462 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4463 * full. We cannot loop here since event_srv_read will disable it only if
4464 * rep->l == rlim-data
4465 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004466 FD_SET(t->srv_fd, StaticReadEvent);
4467 if (t->proxy->srvtimeout)
4468 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4469 else
4470 tv_eternity(&t->srexpire);
4471 }
willy tarreau0f7af912005-12-17 12:21:26 +01004472
willy tarreau8337c6b2005-12-17 13:41:01 +01004473 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004474 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004475 tv_eternity(&t->srexpire);
4476 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004477 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004478 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004479 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004480 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004481 if (!(t->flags & SN_ERR_MASK))
4482 t->flags |= SN_ERR_SRVCL;
4483 if (!(t->flags & SN_FINST_MASK))
4484 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004485 return 1;
4486 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004487 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004488 * since we are in header mode, if there's no space left for headers, we
4489 * won't be able to free more later, so the session will never terminate.
4490 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004491 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 +01004492 FD_CLR(t->srv_fd, StaticReadEvent);
4493 tv_eternity(&t->srexpire);
4494 shutdown(t->srv_fd, SHUT_RD);
4495 t->srv_state = SV_STSHUTR;
4496 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004497 }
4498 /* read timeout : return a 504 to the client.
4499 */
4500 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4501 tv_eternity(&t->srexpire);
4502 tv_eternity(&t->swexpire);
4503 fd_delete(t->srv_fd);
4504 t->srv_state = SV_STCLOSE;
4505 t->logs.status = 504;
4506 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004507 if (!(t->flags & SN_ERR_MASK))
4508 t->flags |= SN_ERR_SRVTO;
4509 if (!(t->flags & SN_FINST_MASK))
4510 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004511 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004512
4513 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004514 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004515 /* FIXME!!! here, we don't want to switch to SHUTW if the
4516 * client shuts read too early, because we may still have
4517 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004518 * The side-effect is that if the client completely closes its
4519 * connection during SV_STHEADER, the connection to the server
4520 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004521 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004522 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004523 FD_CLR(t->srv_fd, StaticWriteEvent);
4524 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004525
4526 /* We must ensure that the read part is still alive when switching
4527 * to shutw */
4528 FD_SET(t->srv_fd, StaticReadEvent);
4529 if (t->proxy->srvtimeout)
4530 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4531
willy tarreau0f7af912005-12-17 12:21:26 +01004532 shutdown(t->srv_fd, SHUT_WR);
4533 t->srv_state = SV_STSHUTW;
4534 return 1;
4535 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004536 /* write timeout */
4537 /* FIXME!!! here, we don't want to switch to SHUTW if the
4538 * client shuts read too early, because we may still have
4539 * some work to do on the headers.
4540 */
4541 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4542 FD_CLR(t->srv_fd, StaticWriteEvent);
4543 tv_eternity(&t->swexpire);
4544 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004545 /* We must ensure that the read part is still alive when switching
4546 * to shutw */
4547 FD_SET(t->srv_fd, StaticReadEvent);
4548 if (t->proxy->srvtimeout)
4549 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4550
4551 /* We must ensure that the read part is still alive when switching
4552 * to shutw */
4553 FD_SET(t->srv_fd, StaticReadEvent);
4554 if (t->proxy->srvtimeout)
4555 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4556
willy tarreau036e1ce2005-12-17 13:46:33 +01004557 t->srv_state = SV_STSHUTW;
4558 if (!(t->flags & SN_ERR_MASK))
4559 t->flags |= SN_ERR_SRVTO;
4560 if (!(t->flags & SN_FINST_MASK))
4561 t->flags |= SN_FINST_H;
4562 return 1;
4563 }
willy tarreau0f7af912005-12-17 12:21:26 +01004564
4565 if (req->l == 0) {
4566 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4567 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4568 tv_eternity(&t->swexpire);
4569 }
4570 }
4571 else { /* client buffer not empty */
4572 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4573 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004574 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004575 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004576 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4577 t->srexpire = t->swexpire;
4578 }
willy tarreau0f7af912005-12-17 12:21:26 +01004579 else
4580 tv_eternity(&t->swexpire);
4581 }
4582 }
4583
willy tarreau5cbea6f2005-12-17 12:48:26 +01004584 /* be nice with the client side which would like to send a complete header
4585 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4586 * would read all remaining data at once ! The client should not write past rep->lr
4587 * when the server is in header state.
4588 */
4589 //return header_processed;
4590 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004591 }
4592 else if (s == SV_STDATA) {
4593 /* read or write error */
4594 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004595 tv_eternity(&t->srexpire);
4596 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004597 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004598 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004599 if (!(t->flags & SN_ERR_MASK))
4600 t->flags |= SN_ERR_SRVCL;
4601 if (!(t->flags & SN_FINST_MASK))
4602 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004603 return 1;
4604 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004605 /* last read, or end of client write */
4606 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004607 FD_CLR(t->srv_fd, StaticReadEvent);
4608 tv_eternity(&t->srexpire);
4609 shutdown(t->srv_fd, SHUT_RD);
4610 t->srv_state = SV_STSHUTR;
4611 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004612 }
4613 /* end of client read and no more data to send */
4614 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4615 FD_CLR(t->srv_fd, StaticWriteEvent);
4616 tv_eternity(&t->swexpire);
4617 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004618 /* We must ensure that the read part is still alive when switching
4619 * to shutw */
4620 FD_SET(t->srv_fd, StaticReadEvent);
4621 if (t->proxy->srvtimeout)
4622 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4623
willy tarreaua41a8b42005-12-17 14:02:24 +01004624 t->srv_state = SV_STSHUTW;
4625 return 1;
4626 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004627 /* read timeout */
4628 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4629 FD_CLR(t->srv_fd, StaticReadEvent);
4630 tv_eternity(&t->srexpire);
4631 shutdown(t->srv_fd, SHUT_RD);
4632 t->srv_state = SV_STSHUTR;
4633 if (!(t->flags & SN_ERR_MASK))
4634 t->flags |= SN_ERR_SRVTO;
4635 if (!(t->flags & SN_FINST_MASK))
4636 t->flags |= SN_FINST_D;
4637 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004638 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004639 /* write timeout */
4640 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004641 FD_CLR(t->srv_fd, StaticWriteEvent);
4642 tv_eternity(&t->swexpire);
4643 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004644 /* We must ensure that the read part is still alive when switching
4645 * to shutw */
4646 FD_SET(t->srv_fd, StaticReadEvent);
4647 if (t->proxy->srvtimeout)
4648 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004649 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004650 if (!(t->flags & SN_ERR_MASK))
4651 t->flags |= SN_ERR_SRVTO;
4652 if (!(t->flags & SN_FINST_MASK))
4653 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004654 return 1;
4655 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004656
4657 /* recompute request time-outs */
4658 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004659 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4660 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4661 tv_eternity(&t->swexpire);
4662 }
4663 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004664 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004665 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4666 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004667 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004668 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004669 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4670 t->srexpire = t->swexpire;
4671 }
willy tarreau0f7af912005-12-17 12:21:26 +01004672 else
4673 tv_eternity(&t->swexpire);
4674 }
4675 }
4676
willy tarreaub1ff9db2005-12-17 13:51:03 +01004677 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004678 if (rep->l == BUFSIZE) { /* no room to read more data */
4679 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4680 FD_CLR(t->srv_fd, StaticReadEvent);
4681 tv_eternity(&t->srexpire);
4682 }
4683 }
4684 else {
4685 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4686 FD_SET(t->srv_fd, StaticReadEvent);
4687 if (t->proxy->srvtimeout)
4688 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4689 else
4690 tv_eternity(&t->srexpire);
4691 }
4692 }
4693
4694 return 0; /* other cases change nothing */
4695 }
4696 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004697 if (t->res_sw == RES_ERROR) {
4698 //FD_CLR(t->srv_fd, StaticWriteEvent);
4699 tv_eternity(&t->swexpire);
4700 fd_delete(t->srv_fd);
4701 //close(t->srv_fd);
4702 t->srv_state = SV_STCLOSE;
4703 if (!(t->flags & SN_ERR_MASK))
4704 t->flags |= SN_ERR_SRVCL;
4705 if (!(t->flags & SN_FINST_MASK))
4706 t->flags |= SN_FINST_D;
4707 return 1;
4708 }
4709 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004710 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004711 tv_eternity(&t->swexpire);
4712 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004713 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004714 t->srv_state = SV_STCLOSE;
4715 return 1;
4716 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004717 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4718 //FD_CLR(t->srv_fd, StaticWriteEvent);
4719 tv_eternity(&t->swexpire);
4720 fd_delete(t->srv_fd);
4721 //close(t->srv_fd);
4722 t->srv_state = SV_STCLOSE;
4723 if (!(t->flags & SN_ERR_MASK))
4724 t->flags |= SN_ERR_SRVTO;
4725 if (!(t->flags & SN_FINST_MASK))
4726 t->flags |= SN_FINST_D;
4727 return 1;
4728 }
willy tarreau0f7af912005-12-17 12:21:26 +01004729 else if (req->l == 0) {
4730 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4731 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4732 tv_eternity(&t->swexpire);
4733 }
4734 }
4735 else { /* buffer not empty */
4736 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4737 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004738 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004739 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004740 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4741 t->srexpire = t->swexpire;
4742 }
willy tarreau0f7af912005-12-17 12:21:26 +01004743 else
4744 tv_eternity(&t->swexpire);
4745 }
4746 }
4747 return 0;
4748 }
4749 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004750 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004751 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004752 tv_eternity(&t->srexpire);
4753 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004754 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004755 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004756 if (!(t->flags & SN_ERR_MASK))
4757 t->flags |= SN_ERR_SRVCL;
4758 if (!(t->flags & SN_FINST_MASK))
4759 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004760 return 1;
4761 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004762 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4763 //FD_CLR(t->srv_fd, StaticReadEvent);
4764 tv_eternity(&t->srexpire);
4765 fd_delete(t->srv_fd);
4766 //close(t->srv_fd);
4767 t->srv_state = SV_STCLOSE;
4768 return 1;
4769 }
4770 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4771 //FD_CLR(t->srv_fd, StaticReadEvent);
4772 tv_eternity(&t->srexpire);
4773 fd_delete(t->srv_fd);
4774 //close(t->srv_fd);
4775 t->srv_state = SV_STCLOSE;
4776 if (!(t->flags & SN_ERR_MASK))
4777 t->flags |= SN_ERR_SRVTO;
4778 if (!(t->flags & SN_FINST_MASK))
4779 t->flags |= SN_FINST_D;
4780 return 1;
4781 }
willy tarreau0f7af912005-12-17 12:21:26 +01004782 else if (rep->l == BUFSIZE) { /* no room to read more data */
4783 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4784 FD_CLR(t->srv_fd, StaticReadEvent);
4785 tv_eternity(&t->srexpire);
4786 }
4787 }
4788 else {
4789 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4790 FD_SET(t->srv_fd, StaticReadEvent);
4791 if (t->proxy->srvtimeout)
4792 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4793 else
4794 tv_eternity(&t->srexpire);
4795 }
4796 }
4797 return 0;
4798 }
4799 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004800 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004801 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004802 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 +01004803 write(1, trash, len);
4804 }
4805 return 0;
4806 }
4807 return 0;
4808}
4809
4810
willy tarreau5cbea6f2005-12-17 12:48:26 +01004811/* Processes the client and server jobs of a session task, then
4812 * puts it back to the wait queue in a clean state, or
4813 * cleans up its resources if it must be deleted. Returns
4814 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004815 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816int process_session(struct task *t) {
4817 struct session *s = t->context;
4818 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004819
willy tarreau5cbea6f2005-12-17 12:48:26 +01004820 do {
4821 fsm_resync = 0;
4822 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4823 fsm_resync |= process_cli(s);
4824 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4825 fsm_resync |= process_srv(s);
4826 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4827 } while (fsm_resync);
4828
4829 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004830 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004831 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004832
willy tarreau5cbea6f2005-12-17 12:48:26 +01004833 tv_min(&min1, &s->crexpire, &s->cwexpire);
4834 tv_min(&min2, &s->srexpire, &s->swexpire);
4835 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004836 tv_min(&t->expire, &min1, &min2);
4837
4838 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004839 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004840
willy tarreau5cbea6f2005-12-17 12:48:26 +01004841 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004842 }
4843
willy tarreau5cbea6f2005-12-17 12:48:26 +01004844 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004845 actconn--;
4846
willy tarreau982249e2005-12-18 00:57:06 +01004847 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004848 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004849 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 +01004850 write(1, trash, len);
4851 }
4852
willy tarreau750a4722005-12-17 13:21:24 +01004853 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004854 if (s->rep != NULL)
4855 s->logs.bytes = s->rep->total;
4856
willy tarreau9fe663a2005-12-17 13:02:59 +01004857 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004858 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004859 sess_log(s);
4860
willy tarreau0f7af912005-12-17 12:21:26 +01004861 /* the task MUST not be in the run queue anymore */
4862 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004863 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004864 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004865 return -1; /* rest in peace for eternity */
4866}
4867
4868
4869
4870/*
4871 * manages a server health-check. Returns
4872 * the time the task accepts to wait, or -1 for infinity.
4873 */
4874int process_chk(struct task *t) {
4875 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004876 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004877 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004878
willy tarreauef900ab2005-12-17 12:52:52 +01004879 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004880
4881 if (fd < 0) { /* no check currently running */
4882 //fprintf(stderr, "process_chk: 2\n");
4883 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4884 task_queue(t); /* restore t to its place in the task list */
4885 return tv_remain(&now, &t->expire);
4886 }
4887
4888 /* we'll initiate a new check */
4889 s->result = 0; /* no result yet */
4890 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004891 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004892 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4893 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4894 //fprintf(stderr, "process_chk: 3\n");
4895
willy tarreaua41a8b42005-12-17 14:02:24 +01004896 /* we'll connect to the check port on the server */
4897 sa = s->addr;
4898 sa.sin_port = htons(s->check_port);
4899
willy tarreau0174f312005-12-18 01:02:42 +01004900 /* allow specific binding :
4901 * - server-specific at first
4902 * - proxy-specific next
4903 */
4904 if (s->state & SRV_BIND_SRC) {
4905 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4906 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4907 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4908 s->proxy->id, s->id);
4909 s->result = -1;
4910 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004911 }
willy tarreau0174f312005-12-18 01:02:42 +01004912 else if (s->proxy->options & PR_O_BIND_SRC) {
4913 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4914 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4915 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4916 s->proxy->id);
4917 s->result = -1;
4918 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004919 }
willy tarreau0174f312005-12-18 01:02:42 +01004920
4921 if (!s->result) {
4922 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4923 /* OK, connection in progress or established */
4924
4925 //fprintf(stderr, "process_chk: 4\n");
4926
4927 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4928 fdtab[fd].owner = t;
4929 fdtab[fd].read = &event_srv_chk_r;
4930 fdtab[fd].write = &event_srv_chk_w;
4931 fdtab[fd].state = FD_STCONN; /* connection in progress */
4932 FD_SET(fd, StaticWriteEvent); /* for connect status */
4933 fd_insert(fd);
4934 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4935 tv_delayfrom(&t->expire, &now, s->inter);
4936 task_queue(t); /* restore t to its place in the task list */
4937 return tv_remain(&now, &t->expire);
4938 }
4939 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4940 s->result = -1; /* a real error */
4941 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004942 }
4943 }
willy tarreau08dedbe2005-12-18 01:13:48 +01004944 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004945 }
4946
4947 if (!s->result) { /* nothing done */
4948 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004949 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004950 task_queue(t); /* restore t to its place in the task list */
4951 return tv_remain(&now, &t->expire);
4952 }
4953
4954 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004955 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004956 s->health--; /* still good */
4957 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004958 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004959 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004960 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004961 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004962
willy tarreaudd07e972005-12-18 00:48:48 +01004963 if (find_server(s->proxy) == NULL) {
4964 Alert("Proxy %s has no server available !\n", s->proxy->id);
4965 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4966 }
4967 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004968 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004969 }
4970
4971 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004972 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4973 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004974 }
4975 else {
4976 //fprintf(stderr, "process_chk: 8\n");
4977 /* there was a test running */
4978 if (s->result > 0) { /* good server detected */
4979 //fprintf(stderr, "process_chk: 9\n");
4980 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004981 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004982 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004983 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004984 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004985 }
willy tarreauef900ab2005-12-17 12:52:52 +01004986
willy tarreaue47c8d72005-12-17 12:55:52 +01004987 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004988 s->state |= SRV_RUNNING;
4989 }
willy tarreauef900ab2005-12-17 12:52:52 +01004990 s->curfd = -1; /* no check running anymore */
4991 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004992 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004993 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004994 }
4995 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4996 //fprintf(stderr, "process_chk: 10\n");
4997 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004998 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004999 s->health--; /* still good */
5000 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005001 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005002
willy tarreaudd07e972005-12-18 00:48:48 +01005003 if (s->health == s->rise) {
5004 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005005 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005006
5007 if (find_server(s->proxy) == NULL) {
5008 Alert("Proxy %s has no server available !\n", s->proxy->id);
5009 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5010 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005011 }
willy tarreauef900ab2005-12-17 12:52:52 +01005012
willy tarreau5cbea6f2005-12-17 12:48:26 +01005013 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005014 }
5015 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005016 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005017 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005018 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005019 }
5020 /* if result is 0 and there's no timeout, we have to wait again */
5021 }
5022 //fprintf(stderr, "process_chk: 11\n");
5023 s->result = 0;
5024 task_queue(t); /* restore t to its place in the task list */
5025 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005026}
5027
5028
willy tarreau5cbea6f2005-12-17 12:48:26 +01005029
willy tarreau0f7af912005-12-17 12:21:26 +01005030#if STATTIME > 0
5031int stats(void);
5032#endif
5033
5034/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005035 * This does 4 things :
5036 * - wake up all expired tasks
5037 * - call all runnable tasks
5038 * - call maintain_proxies() to enable/disable the listeners
5039 * - return the delay till next event in ms, -1 = wait indefinitely
5040 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5041 *
willy tarreau0f7af912005-12-17 12:21:26 +01005042 */
5043
willy tarreau1c2ad212005-12-18 01:11:29 +01005044int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005045 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005046 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005047 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005048
willy tarreau1c2ad212005-12-18 01:11:29 +01005049 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005050
willy tarreau1c2ad212005-12-18 01:11:29 +01005051 /* look for expired tasks and add them to the run queue.
5052 */
5053 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5054 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5055 tnext = t->next;
5056 if (t->state & TASK_RUNNING)
5057 continue;
5058
5059 /* wakeup expired entries. It doesn't matter if they are
5060 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005061 */
willy tarreau1c2ad212005-12-18 01:11:29 +01005062 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
5063 task_wakeup(&rq, t);
5064 }
5065 else {
5066 /* first non-runnable task. Use its expiration date as an upper bound */
5067 int temp_time = tv_remain(&now, &t->expire);
5068 if (temp_time)
5069 next_time = temp_time;
5070 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005071 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005072 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005073
willy tarreau1c2ad212005-12-18 01:11:29 +01005074 /* process each task in the run queue now. Each task may be deleted
5075 * since we only use tnext.
5076 */
5077 tnext = rq;
5078 while ((t = tnext) != NULL) {
5079 int temp_time;
5080
5081 tnext = t->rqnext;
5082 task_sleep(&rq, t);
5083 temp_time = t->process(t);
5084 next_time = MINTIME(temp_time, next_time);
5085 }
5086
5087 /* maintain all proxies in a consistent state. This should quickly become a task */
5088 time2 = maintain_proxies();
5089 return MINTIME(time2, next_time);
5090}
5091
5092
5093#if defined(ENABLE_EPOLL)
5094
5095/*
5096 * Main epoll() loop.
5097 */
5098
5099/* does 3 actions :
5100 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5101 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5102 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5103 *
5104 * returns 0 if initialization failed, !0 otherwise.
5105 */
5106
5107int epoll_loop(int action) {
5108 int next_time;
5109 int status;
5110 int fd;
5111
5112 int fds, count;
5113 int pr, pw, sr, sw;
5114 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5115 struct epoll_event ev;
5116
5117 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005118 static struct epoll_event *epoll_events = NULL;
5119 static int epoll_fd;
5120
5121 if (action == POLL_LOOP_ACTION_INIT) {
5122 epoll_fd = epoll_create(global.maxsock + 1);
5123 if (epoll_fd < 0)
5124 return 0;
5125 else {
5126 epoll_events = (struct epoll_event*)
5127 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5128 PrevReadEvent = (fd_set *)
5129 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5130 PrevWriteEvent = (fd_set *)
5131 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005132 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005133 return 1;
5134 }
5135 else if (action == POLL_LOOP_ACTION_CLEAN) {
5136 if (PrevWriteEvent) free(PrevWriteEvent);
5137 if (PrevReadEvent) free(PrevReadEvent);
5138 if (epoll_events) free(epoll_events);
5139 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005140 epoll_fd = 0;
5141 return 1;
5142 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005143
willy tarreau1c2ad212005-12-18 01:11:29 +01005144 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005145
willy tarreau1c2ad212005-12-18 01:11:29 +01005146 tv_now(&now);
5147
5148 while (1) {
5149 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005150
5151 /* stop when there's no connection left and we don't allow them anymore */
5152 if (!actconn && listeners == 0)
5153 break;
5154
willy tarreau0f7af912005-12-17 12:21:26 +01005155#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005156 {
5157 int time2;
5158 time2 = stats();
5159 next_time = MINTIME(time2, next_time);
5160 }
willy tarreau0f7af912005-12-17 12:21:26 +01005161#endif
5162
willy tarreau1c2ad212005-12-18 01:11:29 +01005163 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5164
5165 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5166 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5167
5168 if ((ro^rn) | (wo^wn)) {
5169 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5170#define FDSETS_ARE_INT_ALIGNED
5171#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005172
willy tarreauad90a0c2005-12-18 01:09:15 +01005173#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5174#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005175 pr = (ro >> count) & 1;
5176 pw = (wo >> count) & 1;
5177 sr = (rn >> count) & 1;
5178 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005179#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005180 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5181 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5182 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5183 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005184#endif
5185#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005186 pr = FD_ISSET(fd, PrevReadEvent);
5187 pw = FD_ISSET(fd, PrevWriteEvent);
5188 sr = FD_ISSET(fd, StaticReadEvent);
5189 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005190#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005191 if (!((sr^pr) | (sw^pw)))
5192 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005193
willy tarreau1c2ad212005-12-18 01:11:29 +01005194 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5195 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005196
willy tarreau1c2ad212005-12-18 01:11:29 +01005197 if ((pr | pw)) {
5198 /* the file-descriptor already exists... */
5199 if ((sr | sw)) {
5200 /* ...and it will still exist */
5201 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5202 // perror("epoll_ctl(MOD)");
5203 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005204 }
5205 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005206 /* ...and it will be removed */
5207 if (fdtab[fd].state != FD_STCLOSE &&
5208 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5209 // perror("epoll_ctl(DEL)");
5210 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005211 }
5212 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005213 } else {
5214 /* the file-descriptor did not exist, let's add it */
5215 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5216 // perror("epoll_ctl(ADD)");
5217 // exit(1);
5218 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005219 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005220 }
5221 ((int*)PrevReadEvent)[fds] = rn;
5222 ((int*)PrevWriteEvent)[fds] = wn;
5223 }
5224 }
5225
5226 /* now let's wait for events */
5227 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5228 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005229
willy tarreau1c2ad212005-12-18 01:11:29 +01005230 for (count = 0; count < status; count++) {
5231 fd = epoll_events[count].data.fd;
5232
5233 if (fdtab[fd].state == FD_STCLOSE)
5234 continue;
5235
5236 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5237 fdtab[fd].read(fd);
5238
5239 if (fdtab[fd].state == FD_STCLOSE)
5240 continue;
5241
5242 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5243 fdtab[fd].write(fd);
5244 }
5245 }
5246 return 1;
5247}
5248#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005249
willy tarreauad90a0c2005-12-18 01:09:15 +01005250
willy tarreau5cbea6f2005-12-17 12:48:26 +01005251
willy tarreau1c2ad212005-12-18 01:11:29 +01005252#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005253
willy tarreau1c2ad212005-12-18 01:11:29 +01005254/*
5255 * Main poll() loop.
5256 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005257
willy tarreau1c2ad212005-12-18 01:11:29 +01005258/* does 3 actions :
5259 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5260 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5261 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5262 *
5263 * returns 0 if initialization failed, !0 otherwise.
5264 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005265
willy tarreau1c2ad212005-12-18 01:11:29 +01005266int poll_loop(int action) {
5267 int next_time;
5268 int status;
5269 int fd, nbfd;
5270
5271 int fds, count;
5272 int sr, sw;
5273 unsigned rn, wn; /* read new, write new */
5274
5275 /* private data */
5276 static struct pollfd *poll_events = NULL;
5277
5278 if (action == POLL_LOOP_ACTION_INIT) {
5279 poll_events = (struct pollfd*)
5280 calloc(1, sizeof(struct pollfd) * global.maxsock);
5281 return 1;
5282 }
5283 else if (action == POLL_LOOP_ACTION_CLEAN) {
5284 if (poll_events)
5285 free(poll_events);
5286 return 1;
5287 }
5288
5289 /* OK, it's POLL_LOOP_ACTION_RUN */
5290
5291 tv_now(&now);
5292
5293 while (1) {
5294 next_time = process_runnable_tasks();
5295
5296 /* stop when there's no connection left and we don't allow them anymore */
5297 if (!actconn && listeners == 0)
5298 break;
5299
5300#if STATTIME > 0
5301 {
5302 int time2;
5303 time2 = stats();
5304 next_time = MINTIME(time2, next_time);
5305 }
5306#endif
5307
5308
5309 nbfd = 0;
5310 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5311
5312 rn = ((int*)StaticReadEvent)[fds];
5313 wn = ((int*)StaticWriteEvent)[fds];
5314
5315 if ((rn|wn)) {
5316 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5317#define FDSETS_ARE_INT_ALIGNED
5318#ifdef FDSETS_ARE_INT_ALIGNED
5319
5320#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5321#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5322 sr = (rn >> count) & 1;
5323 sw = (wn >> count) & 1;
5324#else
5325 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5326 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5327#endif
5328#else
5329 sr = FD_ISSET(fd, StaticReadEvent);
5330 sw = FD_ISSET(fd, StaticWriteEvent);
5331#endif
5332 if ((sr|sw)) {
5333 poll_events[nbfd].fd = fd;
5334 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5335 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005336 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005337 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005338 }
5339 }
5340
5341 /* now let's wait for events */
5342 status = poll(poll_events, nbfd, next_time);
5343 tv_now(&now);
5344
5345 for (count = 0; status > 0 && count < nbfd; count++) {
5346 fd = poll_events[count].fd;
5347
5348 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5349 continue;
5350
5351 /* ok, we found one active fd */
5352 status--;
5353
5354 if (fdtab[fd].state == FD_STCLOSE)
5355 continue;
5356
5357 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5358 fdtab[fd].read(fd);
5359
5360 if (fdtab[fd].state == FD_STCLOSE)
5361 continue;
5362
5363 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5364 fdtab[fd].write(fd);
5365 }
5366 }
5367 return 1;
5368}
willy tarreauad90a0c2005-12-18 01:09:15 +01005369#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005370
willy tarreauad90a0c2005-12-18 01:09:15 +01005371
willy tarreauad90a0c2005-12-18 01:09:15 +01005372
willy tarreau1c2ad212005-12-18 01:11:29 +01005373/*
5374 * Main select() loop.
5375 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005376
willy tarreau1c2ad212005-12-18 01:11:29 +01005377/* does 3 actions :
5378 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5379 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5380 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5381 *
5382 * returns 0 if initialization failed, !0 otherwise.
5383 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005384
willy tarreauad90a0c2005-12-18 01:09:15 +01005385
willy tarreau1c2ad212005-12-18 01:11:29 +01005386int select_loop(int action) {
5387 int next_time;
5388 int status;
5389 int fd,i;
5390 struct timeval delta;
5391 int readnotnull, writenotnull;
5392 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005393
willy tarreau1c2ad212005-12-18 01:11:29 +01005394 if (action == POLL_LOOP_ACTION_INIT) {
5395 ReadEvent = (fd_set *)
5396 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5397 WriteEvent = (fd_set *)
5398 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5399 return 1;
5400 }
5401 else if (action == POLL_LOOP_ACTION_CLEAN) {
5402 if (WriteEvent) free(WriteEvent);
5403 if (ReadEvent) free(ReadEvent);
5404 return 1;
5405 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005406
willy tarreau1c2ad212005-12-18 01:11:29 +01005407 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005408
willy tarreau1c2ad212005-12-18 01:11:29 +01005409 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005410
willy tarreau1c2ad212005-12-18 01:11:29 +01005411 while (1) {
5412 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005413
willy tarreau1c2ad212005-12-18 01:11:29 +01005414 /* stop when there's no connection left and we don't allow them anymore */
5415 if (!actconn && listeners == 0)
5416 break;
5417
5418#if STATTIME > 0
5419 {
5420 int time2;
5421 time2 = stats();
5422 next_time = MINTIME(time2, next_time);
5423 }
5424#endif
5425
willy tarreau1c2ad212005-12-18 01:11:29 +01005426 if (next_time > 0) { /* FIXME */
5427 /* Convert to timeval */
5428 /* to avoid eventual select loops due to timer precision */
5429 next_time += SCHEDULER_RESOLUTION;
5430 delta.tv_sec = next_time / 1000;
5431 delta.tv_usec = (next_time % 1000) * 1000;
5432 }
5433 else if (next_time == 0) { /* allow select to return immediately when needed */
5434 delta.tv_sec = delta.tv_usec = 0;
5435 }
5436
5437
5438 /* let's restore fdset state */
5439
5440 readnotnull = 0; writenotnull = 0;
5441 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5442 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5443 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5444 }
5445
5446 // /* just a verification code, needs to be removed for performance */
5447 // for (i=0; i<maxfd; i++) {
5448 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5449 // abort();
5450 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5451 // abort();
5452 //
5453 // }
5454
5455 status = select(maxfd,
5456 readnotnull ? ReadEvent : NULL,
5457 writenotnull ? WriteEvent : NULL,
5458 NULL,
5459 (next_time >= 0) ? &delta : NULL);
5460
5461 /* this is an experiment on the separation of the select work */
5462 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5463 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5464
5465 tv_now(&now);
5466
5467 if (status > 0) { /* must proceed with events */
5468
5469 int fds;
5470 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005471
willy tarreau1c2ad212005-12-18 01:11:29 +01005472 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5473 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5474 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5475
5476 /* if we specify read first, the accepts and zero reads will be
5477 * seen first. Moreover, system buffers will be flushed faster.
5478 */
5479 if (fdtab[fd].state == FD_STCLOSE)
5480 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005481
willy tarreau1c2ad212005-12-18 01:11:29 +01005482 if (FD_ISSET(fd, ReadEvent))
5483 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005484
willy tarreau1c2ad212005-12-18 01:11:29 +01005485 if (FD_ISSET(fd, WriteEvent))
5486 fdtab[fd].write(fd);
5487 }
5488 }
5489 else {
5490 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005491 }
willy tarreau0f7af912005-12-17 12:21:26 +01005492 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005493 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005494}
5495
5496
5497#if STATTIME > 0
5498/*
5499 * Display proxy statistics regularly. It is designed to be called from the
5500 * select_loop().
5501 */
5502int stats(void) {
5503 static int lines;
5504 static struct timeval nextevt;
5505 static struct timeval lastevt;
5506 static struct timeval starttime = {0,0};
5507 unsigned long totaltime, deltatime;
5508 int ret;
5509
willy tarreau750a4722005-12-17 13:21:24 +01005510 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005511 deltatime = (tv_diff(&lastevt, &now)?:1);
5512 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005513
willy tarreau9fe663a2005-12-17 13:02:59 +01005514 if (global.mode & MODE_STATS) {
5515 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005516 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005517 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5518 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005519 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005520 actconn, totalconn,
5521 stats_tsk_new, stats_tsk_good,
5522 stats_tsk_left, stats_tsk_right,
5523 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5524 }
5525 }
5526
5527 tv_delayfrom(&nextevt, &now, STATTIME);
5528
5529 lastevt=now;
5530 }
5531 ret = tv_remain(&now, &nextevt);
5532 return ret;
5533}
5534#endif
5535
5536
5537/*
5538 * this function enables proxies when there are enough free sessions,
5539 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005540 * select_loop(). It returns the time left before next expiration event
5541 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005542 */
5543static int maintain_proxies(void) {
5544 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005545 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005546 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005547
5548 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005549 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005550
5551 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005552 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005553 while (p) {
5554 if (p->nbconn < p->maxconn) {
5555 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005556 for (l = p->listen; l != NULL; l = l->next) {
5557 FD_SET(l->fd, StaticReadEvent);
5558 }
willy tarreau0f7af912005-12-17 12:21:26 +01005559 p->state = PR_STRUN;
5560 }
5561 }
5562 else {
5563 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005564 for (l = p->listen; l != NULL; l = l->next) {
5565 FD_CLR(l->fd, StaticReadEvent);
5566 }
willy tarreau0f7af912005-12-17 12:21:26 +01005567 p->state = PR_STIDLE;
5568 }
5569 }
5570 p = p->next;
5571 }
5572 }
5573 else { /* block all proxies */
5574 while (p) {
5575 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005576 for (l = p->listen; l != NULL; l = l->next) {
5577 FD_CLR(l->fd, StaticReadEvent);
5578 }
willy tarreau0f7af912005-12-17 12:21:26 +01005579 p->state = PR_STIDLE;
5580 }
5581 p = p->next;
5582 }
5583 }
5584
willy tarreau5cbea6f2005-12-17 12:48:26 +01005585 if (stopping) {
5586 p = proxy;
5587 while (p) {
5588 if (p->state != PR_STDISABLED) {
5589 int t;
5590 t = tv_remain(&now, &p->stop_time);
5591 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005592 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005593 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005594
willy tarreaua41a8b42005-12-17 14:02:24 +01005595 for (l = p->listen; l != NULL; l = l->next) {
5596 fd_delete(l->fd);
5597 listeners--;
5598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005599 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005600 }
5601 else {
5602 tleft = MINTIME(t, tleft);
5603 }
5604 }
5605 p = p->next;
5606 }
5607 }
5608 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005609}
5610
5611/*
5612 * this function disables health-check servers so that the process will quickly be ignored
5613 * by load balancers.
5614 */
5615static void soft_stop(void) {
5616 struct proxy *p;
5617
5618 stopping = 1;
5619 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005620 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005621 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005622 if (p->state != PR_STDISABLED) {
5623 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005624 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005625 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005626 }
willy tarreau0f7af912005-12-17 12:21:26 +01005627 p = p->next;
5628 }
5629}
5630
5631/*
5632 * upon SIGUSR1, let's have a soft stop.
5633 */
5634void sig_soft_stop(int sig) {
5635 soft_stop();
5636 signal(sig, SIG_IGN);
5637}
5638
5639
willy tarreau8337c6b2005-12-17 13:41:01 +01005640/*
5641 * this function dumps every server's state when the process receives SIGHUP.
5642 */
5643void sig_dump_state(int sig) {
5644 struct proxy *p = proxy;
5645
5646 Warning("SIGHUP received, dumping servers states.\n");
5647 while (p) {
5648 struct server *s = p->srv;
5649
5650 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5651 while (s) {
5652 if (s->state & SRV_RUNNING) {
5653 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5654 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5655 }
5656 else {
5657 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5658 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5659 }
5660 s = s->next;
5661 }
willy tarreaudd07e972005-12-18 00:48:48 +01005662
5663 if (find_server(p) == NULL) {
5664 Warning("SIGHUP: proxy %s has no server available !\n", p);
5665 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5666 }
5667
willy tarreau8337c6b2005-12-17 13:41:01 +01005668 p = p->next;
5669 }
5670 signal(sig, sig_dump_state);
5671}
5672
willy tarreau0f7af912005-12-17 12:21:26 +01005673void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005674 struct task *t, *tnext;
5675 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005676
willy tarreau5cbea6f2005-12-17 12:48:26 +01005677 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5678 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5679 tnext = t->next;
5680 s = t->context;
5681 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5682 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5683 "req=%d, rep=%d, clifd=%d\n",
5684 s, tv_remain(&now, &t->expire),
5685 s->cli_state,
5686 s->srv_state,
5687 FD_ISSET(s->cli_fd, StaticReadEvent),
5688 FD_ISSET(s->cli_fd, StaticWriteEvent),
5689 FD_ISSET(s->srv_fd, StaticReadEvent),
5690 FD_ISSET(s->srv_fd, StaticWriteEvent),
5691 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5692 );
willy tarreau0f7af912005-12-17 12:21:26 +01005693 }
willy tarreau12350152005-12-18 01:03:27 +01005694}
5695
willy tarreau64a3cc32005-12-18 01:13:11 +01005696#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005697static void fast_stop(void)
5698{
5699 struct proxy *p;
5700 p = proxy;
5701 while (p) {
5702 p->grace = 0;
5703 p = p->next;
5704 }
5705 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005706}
5707
willy tarreau12350152005-12-18 01:03:27 +01005708void sig_int(int sig) {
5709 /* This would normally be a hard stop,
5710 but we want to be sure about deallocation,
5711 and so on, so we do a soft stop with
5712 0 GRACE time
5713 */
5714 fast_stop();
5715 /* If we are killed twice, we decide to die*/
5716 signal(sig, SIG_DFL);
5717}
5718
5719void sig_term(int sig) {
5720 /* This would normally be a hard stop,
5721 but we want to be sure about deallocation,
5722 and so on, so we do a soft stop with
5723 0 GRACE time
5724 */
5725 fast_stop();
5726 /* If we are killed twice, we decide to die*/
5727 signal(sig, SIG_DFL);
5728}
willy tarreau64a3cc32005-12-18 01:13:11 +01005729#endif
willy tarreau12350152005-12-18 01:03:27 +01005730
willy tarreauc1f47532005-12-18 01:08:26 +01005731/* returns the pointer to an error in the replacement string, or NULL if OK */
5732char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005733 struct hdr_exp *exp;
5734
willy tarreauc1f47532005-12-18 01:08:26 +01005735 if (replace != NULL) {
5736 char *err;
5737 err = check_replace_string(replace);
5738 if (err)
5739 return err;
5740 }
5741
willy tarreaue39cd132005-12-17 13:00:18 +01005742 while (*head != NULL)
5743 head = &(*head)->next;
5744
5745 exp = calloc(1, sizeof(struct hdr_exp));
5746
5747 exp->preg = preg;
5748 exp->replace = replace;
5749 exp->action = action;
5750 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005751
5752 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005753}
5754
willy tarreau9fe663a2005-12-17 13:02:59 +01005755
willy tarreau0f7af912005-12-17 12:21:26 +01005756/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005757 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005758 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005759int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005760
willy tarreau9fe663a2005-12-17 13:02:59 +01005761 if (!strcmp(args[0], "global")) { /* new section */
5762 /* no option, nothing special to do */
5763 return 0;
5764 }
5765 else if (!strcmp(args[0], "daemon")) {
5766 global.mode |= MODE_DAEMON;
5767 }
5768 else if (!strcmp(args[0], "debug")) {
5769 global.mode |= MODE_DEBUG;
5770 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005771 else if (!strcmp(args[0], "noepoll")) {
5772 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5773 }
5774 else if (!strcmp(args[0], "nopoll")) {
5775 cfg_polling_mechanism &= ~POLL_USE_POLL;
5776 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005777 else if (!strcmp(args[0], "quiet")) {
5778 global.mode |= MODE_QUIET;
5779 }
5780 else if (!strcmp(args[0], "stats")) {
5781 global.mode |= MODE_STATS;
5782 }
5783 else if (!strcmp(args[0], "uid")) {
5784 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005785 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005786 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005787 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005788 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005789 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005790 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005791 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005792 global.uid = atol(args[1]);
5793 }
5794 else if (!strcmp(args[0], "gid")) {
5795 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005796 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005797 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005798 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005799 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005800 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005801 return -1;
5802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005803 global.gid = atol(args[1]);
5804 }
5805 else if (!strcmp(args[0], "nbproc")) {
5806 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005807 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005808 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005809 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005810 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005811 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005812 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005813 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005814 global.nbproc = atol(args[1]);
5815 }
5816 else if (!strcmp(args[0], "maxconn")) {
5817 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005818 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005819 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005820 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005821 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005822 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005823 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005824 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005825 global.maxconn = atol(args[1]);
5826 }
willy tarreaub1285d52005-12-18 01:20:14 +01005827 else if (!strcmp(args[0], "ulimit-n")) {
5828 if (global.rlimit_nofile != 0) {
5829 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5830 return 0;
5831 }
5832 if (*(args[1]) == 0) {
5833 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
5834 return -1;
5835 }
5836 global.rlimit_nofile = atol(args[1]);
5837 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005838 else if (!strcmp(args[0], "chroot")) {
5839 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005840 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005841 return 0;
5842 }
5843 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005844 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005845 return -1;
5846 }
5847 global.chroot = strdup(args[1]);
5848 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005849 else if (!strcmp(args[0], "pidfile")) {
5850 if (global.pidfile != NULL) {
5851 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5852 return 0;
5853 }
5854 if (*(args[1]) == 0) {
5855 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5856 return -1;
5857 }
5858 global.pidfile = strdup(args[1]);
5859 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005860 else if (!strcmp(args[0], "log")) { /* syslog server address */
5861 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005862 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005863
5864 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005865 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005866 return -1;
5867 }
5868
5869 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5870 if (!strcmp(log_facilities[facility], args[2]))
5871 break;
5872
5873 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005874 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005875 exit(1);
5876 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005877
5878 level = 7; /* max syslog level = debug */
5879 if (*(args[3])) {
5880 while (level >= 0 && strcmp(log_levels[level], args[3]))
5881 level--;
5882 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005883 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005884 exit(1);
5885 }
5886 }
5887
willy tarreau9fe663a2005-12-17 13:02:59 +01005888 sa = str2sa(args[1]);
5889 if (!sa->sin_port)
5890 sa->sin_port = htons(SYSLOG_PORT);
5891
5892 if (global.logfac1 == -1) {
5893 global.logsrv1 = *sa;
5894 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005895 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005896 }
5897 else if (global.logfac2 == -1) {
5898 global.logsrv2 = *sa;
5899 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005900 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005901 }
5902 else {
5903 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5904 return -1;
5905 }
5906
5907 }
5908 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005909 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005910 return -1;
5911 }
5912 return 0;
5913}
5914
5915
willy tarreaua41a8b42005-12-17 14:02:24 +01005916void init_default_instance() {
5917 memset(&defproxy, 0, sizeof(defproxy));
5918 defproxy.mode = PR_MODE_TCP;
5919 defproxy.state = PR_STNEW;
5920 defproxy.maxconn = cfg_maxpconn;
5921 defproxy.conn_retries = CONN_RETRIES;
5922 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
5923}
5924
willy tarreau9fe663a2005-12-17 13:02:59 +01005925/*
5926 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5927 */
5928int cfg_parse_listen(char *file, int linenum, char **args) {
5929 static struct proxy *curproxy = NULL;
5930 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01005931 char *err;
willy tarreau12350152005-12-18 01:03:27 +01005932 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01005933
5934 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005935 if (!*args[1]) {
5936 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5937 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005938 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005939 return -1;
5940 }
5941
5942 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005943 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005944 return -1;
5945 }
5946 curproxy->next = proxy;
5947 proxy = curproxy;
5948 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005949 if (strchr(args[2], ':') != NULL)
5950 curproxy->listen = str2listener(args[2], curproxy->listen);
5951
willy tarreau9fe663a2005-12-17 13:02:59 +01005952 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005953 curproxy->state = defproxy.state;
5954 curproxy->maxconn = defproxy.maxconn;
5955 curproxy->conn_retries = defproxy.conn_retries;
5956 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005957
5958 if (defproxy.check_req)
5959 curproxy->check_req = strdup(defproxy.check_req);
5960 curproxy->check_len = defproxy.check_len;
5961
5962 if (defproxy.cookie_name)
5963 curproxy->cookie_name = strdup(defproxy.cookie_name);
5964 curproxy->cookie_len = defproxy.cookie_len;
5965
5966 if (defproxy.capture_name)
5967 curproxy->capture_name = strdup(defproxy.capture_name);
5968 curproxy->capture_namelen = defproxy.capture_namelen;
5969 curproxy->capture_len = defproxy.capture_len;
5970
5971 if (defproxy.errmsg.msg400)
5972 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5973 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5974
5975 if (defproxy.errmsg.msg403)
5976 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5977 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5978
5979 if (defproxy.errmsg.msg408)
5980 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5981 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5982
5983 if (defproxy.errmsg.msg500)
5984 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5985 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5986
5987 if (defproxy.errmsg.msg502)
5988 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5989 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5990
5991 if (defproxy.errmsg.msg503)
5992 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5993 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5994
5995 if (defproxy.errmsg.msg504)
5996 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5997 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5998
willy tarreaua41a8b42005-12-17 14:02:24 +01005999 curproxy->clitimeout = defproxy.clitimeout;
6000 curproxy->contimeout = defproxy.contimeout;
6001 curproxy->srvtimeout = defproxy.srvtimeout;
6002 curproxy->mode = defproxy.mode;
6003 curproxy->logfac1 = defproxy.logfac1;
6004 curproxy->logsrv1 = defproxy.logsrv1;
6005 curproxy->loglev1 = defproxy.loglev1;
6006 curproxy->logfac2 = defproxy.logfac2;
6007 curproxy->logsrv2 = defproxy.logsrv2;
6008 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006009 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006010 curproxy->grace = defproxy.grace;
6011 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006012 curproxy->mon_net = defproxy.mon_net;
6013 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006014 return 0;
6015 }
6016 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006017 /* some variables may have already been initialized earlier */
6018 if (defproxy.check_req) free(defproxy.check_req);
6019 if (defproxy.cookie_name) free(defproxy.cookie_name);
6020 if (defproxy.capture_name) free(defproxy.capture_name);
6021 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6022 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6023 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6024 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6025 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6026 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6027 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6028
6029 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006030 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006031 return 0;
6032 }
6033 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006034 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006035 return -1;
6036 }
6037
willy tarreaua41a8b42005-12-17 14:02:24 +01006038 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6039 if (curproxy == &defproxy) {
6040 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6041 return -1;
6042 }
6043
6044 if (strchr(args[1], ':') == NULL) {
6045 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6046 file, linenum, args[0]);
6047 return -1;
6048 }
6049 curproxy->listen = str2listener(args[1], curproxy->listen);
6050 return 0;
6051 }
willy tarreaub1285d52005-12-18 01:20:14 +01006052 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6053 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6054 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6055 file, linenum, args[0]);
6056 return -1;
6057 }
6058 /* flush useless bits */
6059 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6060 return 0;
6061 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006062 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006063 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6064 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6065 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6066 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006067 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006068 return -1;
6069 }
6070 }
6071 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
6072 curproxy->state = PR_STDISABLED;
6073 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006074 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6075 curproxy->state = PR_STNEW;
6076 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006077 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6078 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006079// if (curproxy == &defproxy) {
6080// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6081// return -1;
6082// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006083
willy tarreau9fe663a2005-12-17 13:02:59 +01006084 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006085// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6086// file, linenum);
6087// return 0;
6088 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006089 }
6090
6091 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006092 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6093 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006094 return -1;
6095 }
6096 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006097 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006098
6099 cur_arg = 2;
6100 while (*(args[cur_arg])) {
6101 if (!strcmp(args[cur_arg], "rewrite")) {
6102 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006103 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006104 else if (!strcmp(args[cur_arg], "indirect")) {
6105 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006106 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006107 else if (!strcmp(args[cur_arg], "insert")) {
6108 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006109 }
willy tarreau240afa62005-12-17 13:14:35 +01006110 else if (!strcmp(args[cur_arg], "nocache")) {
6111 curproxy->options |= PR_O_COOK_NOC;
6112 }
willy tarreaucd878942005-12-17 13:27:43 +01006113 else if (!strcmp(args[cur_arg], "postonly")) {
6114 curproxy->options |= PR_O_COOK_POST;
6115 }
willy tarreau0174f312005-12-18 01:02:42 +01006116 else if (!strcmp(args[cur_arg], "prefix")) {
6117 curproxy->options |= PR_O_COOK_PFX;
6118 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006119 else {
willy tarreau0174f312005-12-18 01:02:42 +01006120 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006121 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006122 return -1;
6123 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006124 cur_arg++;
6125 }
willy tarreau0174f312005-12-18 01:02:42 +01006126 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6127 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6128 file, linenum);
6129 return -1;
6130 }
6131
6132 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6133 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006134 file, linenum);
6135 return -1;
6136 }
willy tarreau12350152005-12-18 01:03:27 +01006137 }/* end else if (!strcmp(args[0], "cookie")) */
6138 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6139// if (curproxy == &defproxy) {
6140// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6141// return -1;
6142// }
6143
6144 if (curproxy->appsession_name != NULL) {
6145// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6146// file, linenum);
6147// return 0;
6148 free(curproxy->appsession_name);
6149 }
6150
6151 if (*(args[5]) == 0) {
6152 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6153 file, linenum, args[0]);
6154 return -1;
6155 }
6156 have_appsession = 1;
6157 curproxy->appsession_name = strdup(args[1]);
6158 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6159 curproxy->appsession_len = atoi(args[3]);
6160 curproxy->appsession_timeout = atoi(args[5]);
6161 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6162 if (rc) {
6163 Alert("Error Init Appsession Hashtable.\n");
6164 return -1;
6165 }
6166 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006167 else if (!strcmp(args[0], "capture")) {
6168 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6169 // if (curproxy == &defproxy) {
6170 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6171 // return -1;
6172 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006173
willy tarreau4302f492005-12-18 01:00:37 +01006174 if (curproxy->capture_name != NULL) {
6175 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6176 // file, linenum, args[0]);
6177 // return 0;
6178 free(curproxy->capture_name);
6179 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006180
willy tarreau4302f492005-12-18 01:00:37 +01006181 if (*(args[4]) == 0) {
6182 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6183 file, linenum, args[0]);
6184 return -1;
6185 }
6186 curproxy->capture_name = strdup(args[2]);
6187 curproxy->capture_namelen = strlen(curproxy->capture_name);
6188 curproxy->capture_len = atol(args[4]);
6189 if (curproxy->capture_len >= CAPTURE_LEN) {
6190 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6191 file, linenum, CAPTURE_LEN - 1);
6192 curproxy->capture_len = CAPTURE_LEN - 1;
6193 }
6194 curproxy->to_log |= LW_COOKIE;
6195 }
6196 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6197 struct cap_hdr *hdr;
6198
6199 if (curproxy == &defproxy) {
6200 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6201 return -1;
6202 }
6203
6204 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6205 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6206 file, linenum, args[0], args[1]);
6207 return -1;
6208 }
6209
6210 hdr = calloc(sizeof(struct cap_hdr), 1);
6211 hdr->next = curproxy->req_cap;
6212 hdr->name = strdup(args[3]);
6213 hdr->namelen = strlen(args[3]);
6214 hdr->len = atol(args[5]);
6215 hdr->index = curproxy->nb_req_cap++;
6216 curproxy->req_cap = hdr;
6217 curproxy->to_log |= LW_REQHDR;
6218 }
6219 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6220 struct cap_hdr *hdr;
6221
6222 if (curproxy == &defproxy) {
6223 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6224 return -1;
6225 }
6226
6227 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6228 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6229 file, linenum, args[0], args[1]);
6230 return -1;
6231 }
6232 hdr = calloc(sizeof(struct cap_hdr), 1);
6233 hdr->next = curproxy->rsp_cap;
6234 hdr->name = strdup(args[3]);
6235 hdr->namelen = strlen(args[3]);
6236 hdr->len = atol(args[5]);
6237 hdr->index = curproxy->nb_rsp_cap++;
6238 curproxy->rsp_cap = hdr;
6239 curproxy->to_log |= LW_RSPHDR;
6240 }
6241 else {
6242 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006243 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006244 return -1;
6245 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006246 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006247 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006248 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006249 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006250 return 0;
6251 }
6252 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006253 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6254 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006255 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006256 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006257 curproxy->contimeout = atol(args[1]);
6258 }
6259 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006260 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006261 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6262 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006263 return 0;
6264 }
6265 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006266 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6267 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006268 return -1;
6269 }
6270 curproxy->clitimeout = atol(args[1]);
6271 }
6272 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006273 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006274 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006275 return 0;
6276 }
6277 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006278 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6279 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006280 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006281 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006282 curproxy->srvtimeout = atol(args[1]);
6283 }
6284 else if (!strcmp(args[0], "retries")) { /* connection retries */
6285 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006286 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6287 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006288 return -1;
6289 }
6290 curproxy->conn_retries = atol(args[1]);
6291 }
6292 else if (!strcmp(args[0], "option")) {
6293 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006294 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006295 return -1;
6296 }
6297 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006298 /* enable reconnections to dispatch */
6299 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006300#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006301 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006302 /* enable transparent proxy connections */
6303 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006304#endif
6305 else if (!strcmp(args[1], "keepalive"))
6306 /* enable keep-alive */
6307 curproxy->options |= PR_O_KEEPALIVE;
6308 else if (!strcmp(args[1], "forwardfor"))
6309 /* insert x-forwarded-for field */
6310 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006311 else if (!strcmp(args[1], "logasap"))
6312 /* log as soon as possible, without waiting for the session to complete */
6313 curproxy->options |= PR_O_LOGASAP;
6314 else if (!strcmp(args[1], "httpclose"))
6315 /* force connection: close in both directions in HTTP mode */
6316 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006317 else if (!strcmp(args[1], "checkcache"))
6318 /* require examination of cacheability of the 'set-cookie' field */
6319 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006320 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006321 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006322 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006323 else if (!strcmp(args[1], "tcplog"))
6324 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006325 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006326 else if (!strcmp(args[1], "dontlognull")) {
6327 /* don't log empty requests */
6328 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006329 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006330 else if (!strcmp(args[1], "httpchk")) {
6331 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006332 if (curproxy->check_req != NULL) {
6333 free(curproxy->check_req);
6334 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006335 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006336 if (!*args[2]) { /* no argument */
6337 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6338 curproxy->check_len = strlen(DEF_CHECK_REQ);
6339 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006340 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6341 curproxy->check_req = (char *)malloc(reqlen);
6342 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6343 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006344 } else { /* more arguments : METHOD URI [HTTP_VER] */
6345 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6346 if (*args[4])
6347 reqlen += strlen(args[4]);
6348 else
6349 reqlen += strlen("HTTP/1.0");
6350
6351 curproxy->check_req = (char *)malloc(reqlen);
6352 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6353 "%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 +01006354 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006355 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006356 else if (!strcmp(args[1], "persist")) {
6357 /* persist on using the server specified by the cookie, even when it's down */
6358 curproxy->options |= PR_O_PERSIST;
6359 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006360 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006361 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006362 return -1;
6363 }
6364 return 0;
6365 }
6366 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6367 /* enable reconnections to dispatch */
6368 curproxy->options |= PR_O_REDISP;
6369 }
willy tarreaua1598082005-12-17 13:08:06 +01006370#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006371 else if (!strcmp(args[0], "transparent")) {
6372 /* enable transparent proxy connections */
6373 curproxy->options |= PR_O_TRANSP;
6374 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006375#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006376 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6377 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006378 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006379 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006380 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006381 curproxy->maxconn = atol(args[1]);
6382 }
6383 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6384 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006385 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006386 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006387 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006388 curproxy->grace = atol(args[1]);
6389 }
6390 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006391 if (curproxy == &defproxy) {
6392 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6393 return -1;
6394 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006395 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006396 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006397 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006398 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006399 curproxy->dispatch_addr = *str2sa(args[1]);
6400 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006401 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006402 if (*(args[1])) {
6403 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006404 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006405 }
6406 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006407 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006408 return -1;
6409 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006410 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006411 else /* if no option is set, use round-robin by default */
6412 curproxy->options |= PR_O_BALANCE_RR;
6413 }
6414 else if (!strcmp(args[0], "server")) { /* server address */
6415 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006416 char *rport;
6417 char *raddr;
6418 short realport;
6419 int do_check;
6420
6421 if (curproxy == &defproxy) {
6422 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6423 return -1;
6424 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006425
willy tarreaua41a8b42005-12-17 14:02:24 +01006426 if (!*args[2]) {
6427 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006428 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006429 return -1;
6430 }
6431 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6432 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6433 return -1;
6434 }
willy tarreau0174f312005-12-18 01:02:42 +01006435
6436 if (curproxy->srv == NULL)
6437 curproxy->srv = newsrv;
6438 else
6439 curproxy->cursrv->next = newsrv;
6440 curproxy->cursrv = newsrv;
6441
6442 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006443 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006444
6445 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006446 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006447 newsrv->id = strdup(args[1]);
6448
6449 /* several ways to check the port component :
6450 * - IP => port=+0, relative
6451 * - IP: => port=+0, relative
6452 * - IP:N => port=N, absolute
6453 * - IP:+N => port=+N, relative
6454 * - IP:-N => port=-N, relative
6455 */
6456 raddr = strdup(args[2]);
6457 rport = strchr(raddr, ':');
6458 if (rport) {
6459 *rport++ = 0;
6460 realport = atol(rport);
6461 if (!isdigit((int)*rport))
6462 newsrv->state |= SRV_MAPPORTS;
6463 } else {
6464 realport = 0;
6465 newsrv->state |= SRV_MAPPORTS;
6466 }
6467
6468 newsrv->addr = *str2sa(raddr);
6469 newsrv->addr.sin_port = htons(realport);
6470 free(raddr);
6471
willy tarreau9fe663a2005-12-17 13:02:59 +01006472 newsrv->curfd = -1; /* no health-check in progress */
6473 newsrv->inter = DEF_CHKINTR;
6474 newsrv->rise = DEF_RISETIME;
6475 newsrv->fall = DEF_FALLTIME;
6476 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6477 cur_arg = 3;
6478 while (*args[cur_arg]) {
6479 if (!strcmp(args[cur_arg], "cookie")) {
6480 newsrv->cookie = strdup(args[cur_arg + 1]);
6481 newsrv->cklen = strlen(args[cur_arg + 1]);
6482 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006483 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006484 else if (!strcmp(args[cur_arg], "rise")) {
6485 newsrv->rise = atol(args[cur_arg + 1]);
6486 newsrv->health = newsrv->rise;
6487 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006489 else if (!strcmp(args[cur_arg], "fall")) {
6490 newsrv->fall = atol(args[cur_arg + 1]);
6491 cur_arg += 2;
6492 }
6493 else if (!strcmp(args[cur_arg], "inter")) {
6494 newsrv->inter = atol(args[cur_arg + 1]);
6495 cur_arg += 2;
6496 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006497 else if (!strcmp(args[cur_arg], "port")) {
6498 newsrv->check_port = atol(args[cur_arg + 1]);
6499 cur_arg += 2;
6500 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006501 else if (!strcmp(args[cur_arg], "backup")) {
6502 newsrv->state |= SRV_BACKUP;
6503 cur_arg ++;
6504 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006505 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006506 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006507 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006508 }
willy tarreau0174f312005-12-18 01:02:42 +01006509 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6510 if (!*args[cur_arg + 1]) {
6511 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6512 file, linenum, "source");
6513 return -1;
6514 }
6515 newsrv->state |= SRV_BIND_SRC;
6516 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6517 cur_arg += 2;
6518 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006519 else {
willy tarreau0174f312005-12-18 01:02:42 +01006520 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 +01006521 file, linenum, newsrv->id);
6522 return -1;
6523 }
6524 }
6525
6526 if (do_check) {
6527 struct task *t;
6528
6529 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6530 newsrv->check_port = realport; /* by default */
6531 if (!newsrv->check_port) {
6532 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 +01006533 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006534 return -1;
6535 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006536
6537 if ((t = pool_alloc(task)) == NULL) {
6538 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6539 return -1;
6540 }
6541
6542 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6543 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6544 t->state = TASK_IDLE;
6545 t->process = process_chk;
6546 t->context = newsrv;
6547
6548 if (curproxy->state != PR_STDISABLED) {
6549 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6550 task_queue(t);
6551 task_wakeup(&rq, t);
6552 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006553 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006554
willy tarreau9fe663a2005-12-17 13:02:59 +01006555 curproxy->nbservers++;
6556 }
6557 else if (!strcmp(args[0], "log")) { /* syslog server address */
6558 struct sockaddr_in *sa;
6559 int facility;
6560
6561 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6562 curproxy->logfac1 = global.logfac1;
6563 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006564 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006565 curproxy->logfac2 = global.logfac2;
6566 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006567 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006568 }
6569 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006570 int level;
6571
willy tarreau0f7af912005-12-17 12:21:26 +01006572 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6573 if (!strcmp(log_facilities[facility], args[2]))
6574 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006575
willy tarreau0f7af912005-12-17 12:21:26 +01006576 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006577 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006578 exit(1);
6579 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006580
willy tarreau8337c6b2005-12-17 13:41:01 +01006581 level = 7; /* max syslog level = debug */
6582 if (*(args[3])) {
6583 while (level >= 0 && strcmp(log_levels[level], args[3]))
6584 level--;
6585 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006586 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006587 exit(1);
6588 }
6589 }
6590
willy tarreau0f7af912005-12-17 12:21:26 +01006591 sa = str2sa(args[1]);
6592 if (!sa->sin_port)
6593 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006594
willy tarreau0f7af912005-12-17 12:21:26 +01006595 if (curproxy->logfac1 == -1) {
6596 curproxy->logsrv1 = *sa;
6597 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006598 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006599 }
6600 else if (curproxy->logfac2 == -1) {
6601 curproxy->logsrv2 = *sa;
6602 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006603 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006604 }
6605 else {
6606 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006607 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006608 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006609 }
6610 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006611 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 file, linenum);
6613 return -1;
6614 }
6615 }
willy tarreaua1598082005-12-17 13:08:06 +01006616 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006617 if (!*args[1]) {
6618 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006619 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006620 return -1;
6621 }
6622
6623 curproxy->source_addr = *str2sa(args[1]);
6624 curproxy->options |= PR_O_BIND_SRC;
6625 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006626 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6627 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006628 if (curproxy == &defproxy) {
6629 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6630 return -1;
6631 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006632
6633 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006634 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6635 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006636 return -1;
6637 }
6638
6639 preg = calloc(1, sizeof(regex_t));
6640 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006641 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006642 return -1;
6643 }
6644
willy tarreauc1f47532005-12-18 01:08:26 +01006645 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6646 if (err) {
6647 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6648 file, linenum, *err);
6649 return -1;
6650 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006651 }
6652 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6653 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006654 if (curproxy == &defproxy) {
6655 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6656 return -1;
6657 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006658
6659 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006660 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006661 return -1;
6662 }
6663
6664 preg = calloc(1, sizeof(regex_t));
6665 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006666 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006667 return -1;
6668 }
6669
6670 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6671 }
6672 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6673 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006674 if (curproxy == &defproxy) {
6675 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6676 return -1;
6677 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006678
6679 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006680 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006681 return -1;
6682 }
6683
6684 preg = calloc(1, sizeof(regex_t));
6685 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006686 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006687 return -1;
6688 }
6689
6690 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6691 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006692 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6693 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006694 if (curproxy == &defproxy) {
6695 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6696 return -1;
6697 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006698
6699 if (*(args[1]) == 0) {
6700 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6701 return -1;
6702 }
6703
6704 preg = calloc(1, sizeof(regex_t));
6705 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6706 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6707 return -1;
6708 }
6709
6710 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6711 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006712 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6713 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006714 if (curproxy == &defproxy) {
6715 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6716 return -1;
6717 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006718
6719 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006720 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006721 return -1;
6722 }
6723
6724 preg = calloc(1, sizeof(regex_t));
6725 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006726 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006727 return -1;
6728 }
6729
6730 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6731 }
6732 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6733 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006734 if (curproxy == &defproxy) {
6735 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6736 return -1;
6737 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006738
6739 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006740 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6741 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006742 return -1;
6743 }
6744
6745 preg = calloc(1, sizeof(regex_t));
6746 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006747 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006748 return -1;
6749 }
6750
willy tarreauc1f47532005-12-18 01:08:26 +01006751 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6752 if (err) {
6753 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6754 file, linenum, *err);
6755 return -1;
6756 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006757 }
6758 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6759 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006760 if (curproxy == &defproxy) {
6761 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6762 return -1;
6763 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006764
6765 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006766 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006767 return -1;
6768 }
6769
6770 preg = calloc(1, sizeof(regex_t));
6771 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006772 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006773 return -1;
6774 }
6775
6776 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6777 }
6778 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6779 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006780 if (curproxy == &defproxy) {
6781 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6782 return -1;
6783 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006784
6785 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006786 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006787 return -1;
6788 }
6789
6790 preg = calloc(1, sizeof(regex_t));
6791 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006792 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006793 return -1;
6794 }
6795
6796 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6797 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006798 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6799 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006800 if (curproxy == &defproxy) {
6801 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6802 return -1;
6803 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006804
6805 if (*(args[1]) == 0) {
6806 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6807 return -1;
6808 }
6809
6810 preg = calloc(1, sizeof(regex_t));
6811 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6812 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6813 return -1;
6814 }
6815
6816 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6817 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006818 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6819 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006820 if (curproxy == &defproxy) {
6821 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6822 return -1;
6823 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006824
6825 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006826 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006827 return -1;
6828 }
6829
6830 preg = calloc(1, sizeof(regex_t));
6831 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006832 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006833 return -1;
6834 }
6835
6836 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6837 }
6838 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006839 if (curproxy == &defproxy) {
6840 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6841 return -1;
6842 }
6843
willy tarreau9fe663a2005-12-17 13:02:59 +01006844 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006845 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006846 return 0;
6847 }
6848
6849 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006850 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006851 return -1;
6852 }
6853
willy tarreau4302f492005-12-18 01:00:37 +01006854 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6855 }
6856 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6857 regex_t *preg;
6858
6859 if (*(args[1]) == 0 || *(args[2]) == 0) {
6860 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6861 file, linenum, args[0]);
6862 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006863 }
willy tarreau4302f492005-12-18 01:00:37 +01006864
6865 preg = calloc(1, sizeof(regex_t));
6866 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6867 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6868 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006869 }
willy tarreau4302f492005-12-18 01:00:37 +01006870
willy tarreauc1f47532005-12-18 01:08:26 +01006871 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6872 if (err) {
6873 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6874 file, linenum, *err);
6875 return -1;
6876 }
willy tarreau4302f492005-12-18 01:00:37 +01006877 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006878 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6879 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006880 if (curproxy == &defproxy) {
6881 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6882 return -1;
6883 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006884
6885 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006886 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006887 return -1;
6888 }
willy tarreaue39cd132005-12-17 13:00:18 +01006889
willy tarreau9fe663a2005-12-17 13:02:59 +01006890 preg = calloc(1, sizeof(regex_t));
6891 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006892 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006893 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006894 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006895
willy tarreauc1f47532005-12-18 01:08:26 +01006896 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6897 if (err) {
6898 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6899 file, linenum, *err);
6900 return -1;
6901 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006902 }
willy tarreau982249e2005-12-18 00:57:06 +01006903 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6904 regex_t *preg;
6905 if (curproxy == &defproxy) {
6906 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6907 return -1;
6908 }
6909
6910 if (*(args[1]) == 0) {
6911 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6912 return -1;
6913 }
6914
6915 preg = calloc(1, sizeof(regex_t));
6916 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6917 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6918 return -1;
6919 }
6920
willy tarreauc1f47532005-12-18 01:08:26 +01006921 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6922 if (err) {
6923 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6924 file, linenum, *err);
6925 return -1;
6926 }
willy tarreau982249e2005-12-18 00:57:06 +01006927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006928 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01006929 regex_t *preg;
6930 if (curproxy == &defproxy) {
6931 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6932 return -1;
6933 }
willy tarreaue39cd132005-12-17 13:00:18 +01006934
willy tarreaua41a8b42005-12-17 14:02:24 +01006935 if (*(args[1]) == 0 || *(args[2]) == 0) {
6936 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6937 file, linenum, args[0]);
6938 return -1;
6939 }
willy tarreaue39cd132005-12-17 13:00:18 +01006940
willy tarreaua41a8b42005-12-17 14:02:24 +01006941 preg = calloc(1, sizeof(regex_t));
6942 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6943 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6944 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006945 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006946
willy tarreauc1f47532005-12-18 01:08:26 +01006947 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6948 if (err) {
6949 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6950 file, linenum, *err);
6951 return -1;
6952 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006953 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006954 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
6955 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006956 if (curproxy == &defproxy) {
6957 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6958 return -1;
6959 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006960
6961 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006962 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006963 return -1;
6964 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006965
willy tarreau9fe663a2005-12-17 13:02:59 +01006966 preg = calloc(1, sizeof(regex_t));
6967 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006968 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006969 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006970 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006971
willy tarreauc1f47532005-12-18 01:08:26 +01006972 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6973 if (err) {
6974 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6975 file, linenum, *err);
6976 return -1;
6977 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006978 }
willy tarreau982249e2005-12-18 00:57:06 +01006979 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
6980 regex_t *preg;
6981 if (curproxy == &defproxy) {
6982 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6983 return -1;
6984 }
6985
6986 if (*(args[1]) == 0) {
6987 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6988 return -1;
6989 }
6990
6991 preg = calloc(1, sizeof(regex_t));
6992 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6993 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6994 return -1;
6995 }
6996
willy tarreauc1f47532005-12-18 01:08:26 +01006997 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6998 if (err) {
6999 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7000 file, linenum, *err);
7001 return -1;
7002 }
willy tarreau982249e2005-12-18 00:57:06 +01007003 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007004 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007005 if (curproxy == &defproxy) {
7006 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7007 return -1;
7008 }
7009
willy tarreau9fe663a2005-12-17 13:02:59 +01007010 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007011 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007012 return 0;
7013 }
7014
7015 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007016 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 return -1;
7018 }
7019
7020 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7021 }
willy tarreauc1f47532005-12-18 01:08:26 +01007022 else if (!strcmp(args[0], "errorloc") ||
7023 !strcmp(args[0], "errorloc302") ||
7024 !strcmp(args[0], "errorloc303")) { /* error location */
7025 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007026 char *err;
7027
willy tarreaueedaa9f2005-12-17 14:08:03 +01007028 // if (curproxy == &defproxy) {
7029 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7030 // return -1;
7031 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007032
willy tarreau8337c6b2005-12-17 13:41:01 +01007033 if (*(args[2]) == 0) {
7034 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7035 return -1;
7036 }
7037
7038 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007039 if (!strcmp(args[0], "errorloc303")) {
7040 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7041 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7042 } else {
7043 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7044 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7045 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007046
7047 if (errnum == 400) {
7048 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007049 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007050 free(curproxy->errmsg.msg400);
7051 }
7052 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007053 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007054 }
7055 else if (errnum == 403) {
7056 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007057 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007058 free(curproxy->errmsg.msg403);
7059 }
7060 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007061 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007062 }
7063 else if (errnum == 408) {
7064 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007065 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007066 free(curproxy->errmsg.msg408);
7067 }
7068 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007069 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007070 }
7071 else if (errnum == 500) {
7072 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007073 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007074 free(curproxy->errmsg.msg500);
7075 }
7076 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007077 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007078 }
7079 else if (errnum == 502) {
7080 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007081 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007082 free(curproxy->errmsg.msg502);
7083 }
7084 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007085 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007086 }
7087 else if (errnum == 503) {
7088 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007089 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007090 free(curproxy->errmsg.msg503);
7091 }
7092 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007093 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007094 }
7095 else if (errnum == 504) {
7096 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007097 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007098 free(curproxy->errmsg.msg504);
7099 }
7100 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007101 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007102 }
7103 else {
7104 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7105 free(err);
7106 }
7107 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007108 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007109 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007110 return -1;
7111 }
7112 return 0;
7113}
willy tarreaue39cd132005-12-17 13:00:18 +01007114
willy tarreau5cbea6f2005-12-17 12:48:26 +01007115
willy tarreau9fe663a2005-12-17 13:02:59 +01007116/*
7117 * This function reads and parses the configuration file given in the argument.
7118 * returns 0 if OK, -1 if error.
7119 */
7120int readcfgfile(char *file) {
7121 char thisline[256];
7122 char *line;
7123 FILE *f;
7124 int linenum = 0;
7125 char *end;
7126 char *args[MAX_LINE_ARGS];
7127 int arg;
7128 int cfgerr = 0;
7129 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007130
willy tarreau9fe663a2005-12-17 13:02:59 +01007131 struct proxy *curproxy = NULL;
7132 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007133
willy tarreau9fe663a2005-12-17 13:02:59 +01007134 if ((f=fopen(file,"r")) == NULL)
7135 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007136
willy tarreaueedaa9f2005-12-17 14:08:03 +01007137 init_default_instance();
7138
willy tarreau9fe663a2005-12-17 13:02:59 +01007139 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7140 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007141
willy tarreau9fe663a2005-12-17 13:02:59 +01007142 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007143
willy tarreau9fe663a2005-12-17 13:02:59 +01007144 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007145 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007146 line++;
7147
7148 arg = 0;
7149 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007150
willy tarreau9fe663a2005-12-17 13:02:59 +01007151 while (*line && arg < MAX_LINE_ARGS) {
7152 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7153 * C equivalent value. Other combinations left unchanged (eg: \1).
7154 */
7155 if (*line == '\\') {
7156 int skip = 0;
7157 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7158 *line = line[1];
7159 skip = 1;
7160 }
7161 else if (line[1] == 'r') {
7162 *line = '\r';
7163 skip = 1;
7164 }
7165 else if (line[1] == 'n') {
7166 *line = '\n';
7167 skip = 1;
7168 }
7169 else if (line[1] == 't') {
7170 *line = '\t';
7171 skip = 1;
7172 }
willy tarreauc1f47532005-12-18 01:08:26 +01007173 else if (line[1] == 'x') {
7174 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7175 unsigned char hex1, hex2;
7176 hex1 = toupper(line[2]) - '0';
7177 hex2 = toupper(line[3]) - '0';
7178 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7179 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7180 *line = (hex1<<4) + hex2;
7181 skip = 3;
7182 }
7183 else {
7184 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7185 return -1;
7186 }
7187 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007188 if (skip) {
7189 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7190 end -= skip;
7191 }
7192 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007193 }
willy tarreaua1598082005-12-17 13:08:06 +01007194 else if (*line == '#' || *line == '\n' || *line == '\r') {
7195 /* end of string, end of loop */
7196 *line = 0;
7197 break;
7198 }
willy tarreauc29948c2005-12-17 13:10:27 +01007199 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007201 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007202 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007203 line++;
7204 args[++arg] = line;
7205 }
7206 else {
7207 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007208 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007209 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007210
willy tarreau9fe663a2005-12-17 13:02:59 +01007211 /* empty line */
7212 if (!**args)
7213 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007214
willy tarreau9fe663a2005-12-17 13:02:59 +01007215 /* zero out remaining args */
7216 while (++arg < MAX_LINE_ARGS) {
7217 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007218 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007219
willy tarreaua41a8b42005-12-17 14:02:24 +01007220 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007221 confsect = CFG_LISTEN;
7222 else if (!strcmp(args[0], "global")) /* global config */
7223 confsect = CFG_GLOBAL;
7224 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007225
willy tarreau9fe663a2005-12-17 13:02:59 +01007226 switch (confsect) {
7227 case CFG_LISTEN:
7228 if (cfg_parse_listen(file, linenum, args) < 0)
7229 return -1;
7230 break;
7231 case CFG_GLOBAL:
7232 if (cfg_parse_global(file, linenum, args) < 0)
7233 return -1;
7234 break;
7235 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007236 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007237 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007238 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007239
7240
willy tarreau0f7af912005-12-17 12:21:26 +01007241 }
7242 fclose(f);
7243
7244 /*
7245 * Now, check for the integrity of all that we have collected.
7246 */
7247
7248 if ((curproxy = proxy) == NULL) {
7249 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7250 file);
7251 return -1;
7252 }
7253
7254 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007255 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007256 if (curproxy->state == PR_STDISABLED) {
7257 curproxy = curproxy->next;
7258 continue;
7259 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007260 if ((curproxy->mode != PR_MODE_HEALTH) &&
7261 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007262 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007263 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7264 file, curproxy->id);
7265 cfgerr++;
7266 }
7267 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7268 if (curproxy->options & PR_O_TRANSP) {
7269 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7270 file, curproxy->id);
7271 cfgerr++;
7272 }
7273 else if (curproxy->srv == NULL) {
7274 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7275 file, curproxy->id);
7276 cfgerr++;
7277 }
willy tarreaua1598082005-12-17 13:08:06 +01007278 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007279 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7280 file, curproxy->id);
7281 }
7282 }
7283 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007284 if (curproxy->cookie_name != NULL) {
7285 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7286 file, curproxy->id);
7287 }
7288 if ((newsrv = curproxy->srv) != NULL) {
7289 Warning("parsing %s : servers will be ignored for listener %s.\n",
7290 file, curproxy->id);
7291 }
willy tarreaue39cd132005-12-17 13:00:18 +01007292 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007293 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7294 file, curproxy->id);
7295 }
willy tarreaue39cd132005-12-17 13:00:18 +01007296 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007297 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7298 file, curproxy->id);
7299 }
7300 }
7301 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7302 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7303 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7304 file, curproxy->id);
7305 cfgerr++;
7306 }
7307 else {
7308 while (newsrv != NULL) {
7309 /* nothing to check for now */
7310 newsrv = newsrv->next;
7311 }
7312 }
7313 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007314
7315 if (curproxy->options & PR_O_LOGASAP)
7316 curproxy->to_log &= ~LW_BYTES;
7317
willy tarreau8337c6b2005-12-17 13:41:01 +01007318 if (curproxy->errmsg.msg400 == NULL) {
7319 curproxy->errmsg.msg400 = (char *)HTTP_400;
7320 curproxy->errmsg.len400 = strlen(HTTP_400);
7321 }
7322 if (curproxy->errmsg.msg403 == NULL) {
7323 curproxy->errmsg.msg403 = (char *)HTTP_403;
7324 curproxy->errmsg.len403 = strlen(HTTP_403);
7325 }
7326 if (curproxy->errmsg.msg408 == NULL) {
7327 curproxy->errmsg.msg408 = (char *)HTTP_408;
7328 curproxy->errmsg.len408 = strlen(HTTP_408);
7329 }
7330 if (curproxy->errmsg.msg500 == NULL) {
7331 curproxy->errmsg.msg500 = (char *)HTTP_500;
7332 curproxy->errmsg.len500 = strlen(HTTP_500);
7333 }
7334 if (curproxy->errmsg.msg502 == NULL) {
7335 curproxy->errmsg.msg502 = (char *)HTTP_502;
7336 curproxy->errmsg.len502 = strlen(HTTP_502);
7337 }
7338 if (curproxy->errmsg.msg503 == NULL) {
7339 curproxy->errmsg.msg503 = (char *)HTTP_503;
7340 curproxy->errmsg.len503 = strlen(HTTP_503);
7341 }
7342 if (curproxy->errmsg.msg504 == NULL) {
7343 curproxy->errmsg.msg504 = (char *)HTTP_504;
7344 curproxy->errmsg.len504 = strlen(HTTP_504);
7345 }
willy tarreau0f7af912005-12-17 12:21:26 +01007346 curproxy = curproxy->next;
7347 }
7348 if (cfgerr > 0) {
7349 Alert("Errors found in configuration file, aborting.\n");
7350 return -1;
7351 }
7352 else
7353 return 0;
7354}
7355
7356
7357/*
7358 * This function initializes all the necessary variables. It only returns
7359 * if everything is OK. If something fails, it exits.
7360 */
7361void init(int argc, char **argv) {
7362 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007363 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007364 char *old_argv = *argv;
7365 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007366 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007367 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007368
7369 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007370 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007371 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007372 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007373 exit(1);
7374 }
7375
willy tarreau4302f492005-12-18 01:00:37 +01007376 /* initialize the log header encoding map : '{|}"#' should be encoded with
7377 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7378 * URL encoding only requires '"', '#' to be encoded as well as non-
7379 * printable characters above.
7380 */
7381 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7382 memset(url_encode_map, 0, sizeof(url_encode_map));
7383 for (i = 0; i < 32; i++) {
7384 FD_SET(i, hdr_encode_map);
7385 FD_SET(i, url_encode_map);
7386 }
7387 for (i = 127; i < 256; i++) {
7388 FD_SET(i, hdr_encode_map);
7389 FD_SET(i, url_encode_map);
7390 }
7391
7392 tmp = "\"#{|}";
7393 while (*tmp) {
7394 FD_SET(*tmp, hdr_encode_map);
7395 tmp++;
7396 }
7397
7398 tmp = "\"#";
7399 while (*tmp) {
7400 FD_SET(*tmp, url_encode_map);
7401 tmp++;
7402 }
7403
willy tarreau64a3cc32005-12-18 01:13:11 +01007404 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7405#if defined(ENABLE_POLL)
7406 cfg_polling_mechanism |= POLL_USE_POLL;
7407#endif
7408#if defined(ENABLE_EPOLL)
7409 cfg_polling_mechanism |= POLL_USE_EPOLL;
7410#endif
7411
willy tarreau0f7af912005-12-17 12:21:26 +01007412 pid = getpid();
7413 progname = *argv;
7414 while ((tmp = strchr(progname, '/')) != NULL)
7415 progname = tmp + 1;
7416
7417 argc--; argv++;
7418 while (argc > 0) {
7419 char *flag;
7420
7421 if (**argv == '-') {
7422 flag = *argv+1;
7423
7424 /* 1 arg */
7425 if (*flag == 'v') {
7426 display_version();
7427 exit(0);
7428 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007429#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007430 else if (*flag == 'd' && flag[1] == 'e')
7431 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007432#endif
7433#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007434 else if (*flag == 'd' && flag[1] == 'p')
7435 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007436#endif
willy tarreau982249e2005-12-18 00:57:06 +01007437 else if (*flag == 'V')
7438 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007439 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007440 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007441 else if (*flag == 'c')
7442 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007443 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007444 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007445 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007446 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007447#if STATTIME > 0
7448 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007449 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007450 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007451 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007452#endif
7453 else { /* >=2 args */
7454 argv++; argc--;
7455 if (argc == 0)
7456 usage(old_argv);
7457
7458 switch (*flag) {
7459 case 'n' : cfg_maxconn = atol(*argv); break;
7460 case 'N' : cfg_maxpconn = atol(*argv); break;
7461 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007462 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007463 default: usage(old_argv);
7464 }
7465 }
7466 }
7467 else
7468 usage(old_argv);
7469 argv++; argc--;
7470 }
7471
willy tarreau982249e2005-12-18 00:57:06 +01007472 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007473
willy tarreau0f7af912005-12-17 12:21:26 +01007474 if (!cfg_cfgfile)
7475 usage(old_argv);
7476
7477 gethostname(hostname, MAX_HOSTNAME_LEN);
7478
willy tarreau12350152005-12-18 01:03:27 +01007479 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007480 if (readcfgfile(cfg_cfgfile) < 0) {
7481 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7482 exit(1);
7483 }
willy tarreau12350152005-12-18 01:03:27 +01007484 if (have_appsession)
7485 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007486
willy tarreau982249e2005-12-18 00:57:06 +01007487 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007488 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7489 exit(0);
7490 }
7491
willy tarreau9fe663a2005-12-17 13:02:59 +01007492 if (cfg_maxconn > 0)
7493 global.maxconn = cfg_maxconn;
7494
willy tarreaufe2c5c12005-12-17 14:14:34 +01007495 if (cfg_pidfile) {
7496 if (global.pidfile)
7497 free(global.pidfile);
7498 global.pidfile = strdup(cfg_pidfile);
7499 }
7500
willy tarreau9fe663a2005-12-17 13:02:59 +01007501 if (global.maxconn == 0)
7502 global.maxconn = DEFAULT_MAXCONN;
7503
7504 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7505
7506 if (arg_mode & MODE_DEBUG) {
7507 /* command line debug mode inhibits configuration mode */
7508 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7509 }
willy tarreau982249e2005-12-18 00:57:06 +01007510 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7511 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007512
7513 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7514 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7515 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7516 }
7517
7518 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7519 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7520 global.nbproc = 1;
7521 }
7522
7523 if (global.nbproc < 1)
7524 global.nbproc = 1;
7525
willy tarreau0f7af912005-12-17 12:21:26 +01007526 StaticReadEvent = (fd_set *)calloc(1,
7527 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007528 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007529 StaticWriteEvent = (fd_set *)calloc(1,
7530 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007531 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007532
7533 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007534 sizeof(struct fdtab) * (global.maxsock));
7535 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007536 fdtab[i].state = FD_STCLOSE;
7537 }
7538}
7539
7540/*
7541 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7542 */
7543int start_proxies() {
7544 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007545 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007546 int fd;
7547
7548 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007549 if (curproxy->state == PR_STDISABLED)
7550 continue;
7551
willy tarreaua41a8b42005-12-17 14:02:24 +01007552 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7553 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007554 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007555 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7556 curproxy->id);
7557 return -1;
7558 }
willy tarreau0f7af912005-12-17 12:21:26 +01007559
willy tarreaua41a8b42005-12-17 14:02:24 +01007560 if (fd >= global.maxsock) {
7561 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7562 curproxy->id);
7563 close(fd);
7564 return -1;
7565 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007566
willy tarreaua41a8b42005-12-17 14:02:24 +01007567 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7568 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7569 (char *) &one, sizeof(one)) == -1)) {
7570 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7571 curproxy->id);
7572 close(fd);
7573 return -1;
7574 }
willy tarreau0f7af912005-12-17 12:21:26 +01007575
willy tarreaua41a8b42005-12-17 14:02:24 +01007576 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7577 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7578 curproxy->id);
7579 }
willy tarreau0f7af912005-12-17 12:21:26 +01007580
willy tarreaua41a8b42005-12-17 14:02:24 +01007581 if (bind(fd,
7582 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007583 listener->addr.ss_family == AF_INET6 ?
7584 sizeof(struct sockaddr_in6) :
7585 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007586 Alert("cannot bind socket for proxy %s. Aborting.\n",
7587 curproxy->id);
7588 close(fd);
7589 return -1;
7590 }
willy tarreau0f7af912005-12-17 12:21:26 +01007591
willy tarreaua41a8b42005-12-17 14:02:24 +01007592 if (listen(fd, curproxy->maxconn) == -1) {
7593 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7594 curproxy->id);
7595 close(fd);
7596 return -1;
7597 }
willy tarreau0f7af912005-12-17 12:21:26 +01007598
willy tarreaua41a8b42005-12-17 14:02:24 +01007599 /* the function for the accept() event */
7600 fdtab[fd].read = &event_accept;
7601 fdtab[fd].write = NULL; /* never called */
7602 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7603 curproxy->state = PR_STRUN;
7604 fdtab[fd].state = FD_STLISTEN;
7605 FD_SET(fd, StaticReadEvent);
7606 fd_insert(fd);
7607 listeners++;
7608 }
willy tarreaua1598082005-12-17 13:08:06 +01007609 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007610 }
7611 return 0;
7612}
7613
willy tarreau12350152005-12-18 01:03:27 +01007614int match_str(const void *key1, const void *key2){
7615
7616 appsess *temp1,*temp2;
7617 temp1 = (appsess *)key1;
7618 temp2 = (appsess *)key2;
7619
7620 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7621 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7622
7623 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7624}/* end match_str */
7625
7626void destroy(void *data){
7627 appsess *temp1;
7628
7629 //printf("destroy called\n");
7630 temp1 = (appsess *)data;
7631
7632 if (temp1->sessid)
7633 pool_free_to(apools.sessid, temp1->sessid);
7634
7635 if (temp1->serverid)
7636 pool_free_to(apools.serverid, temp1->serverid);
7637
7638 pool_free(appsess, temp1);
7639} /* end destroy */
7640
7641void appsession_cleanup( void )
7642{
7643 struct proxy *p = proxy;
7644
7645 while(p) {
7646 chtbl_destroy(&(p->htbl_proxy));
7647 p = p->next;
7648 }
7649}/* end appsession_cleanup() */
7650
7651void pool_destroy(void **pool)
7652{
7653 void *temp, *next;
7654 next = pool;
7655 while (next) {
7656 temp = next;
7657 next = *(void **)temp;
7658 free(temp);
7659 }
7660}/* end pool_destroy() */
7661
7662void deinit(void){
7663 struct proxy *p = proxy;
7664 struct cap_hdr *h,*h_next;
7665 struct server *s,*s_next;
7666 struct listener *l,*l_next;
7667
7668 while (p) {
7669 if (p->id)
7670 free(p->id);
7671
7672 if (p->check_req)
7673 free(p->check_req);
7674
7675 if (p->cookie_name)
7676 free(p->cookie_name);
7677
7678 if (p->capture_name)
7679 free(p->capture_name);
7680
7681 /* only strup if the user have set in config.
7682 When should we free it?!
7683 if(p->errmsg.msg400) free(p->errmsg.msg400);
7684 if(p->errmsg.msg403) free(p->errmsg.msg403);
7685 if(p->errmsg.msg408) free(p->errmsg.msg408);
7686 if(p->errmsg.msg500) free(p->errmsg.msg500);
7687 if(p->errmsg.msg502) free(p->errmsg.msg502);
7688 if(p->errmsg.msg503) free(p->errmsg.msg503);
7689 if(p->errmsg.msg504) free(p->errmsg.msg504);
7690 */
7691 if (p->appsession_name)
7692 free(p->appsession_name);
7693
7694 h = p->req_cap;
7695 while (h) {
7696 h_next = h->next;
7697 if (h->name)
7698 free(h->name);
7699 pool_destroy(h->pool);
7700 free(h);
7701 h = h_next;
7702 }/* end while(h) */
7703
7704 h = p->rsp_cap;
7705 while (h) {
7706 h_next = h->next;
7707 if (h->name)
7708 free(h->name);
7709
7710 pool_destroy(h->pool);
7711 free(h);
7712 h = h_next;
7713 }/* end while(h) */
7714
7715 s = p->srv;
7716 while (s) {
7717 s_next = s->next;
7718 if(s->id)
7719 free(s->id);
7720
7721 if(s->cookie)
7722 free(s->cookie);
7723
7724 free(s);
7725 s = s_next;
7726 }/* end while(s) */
7727
7728 l = p->listen;
7729 while (l) {
7730 l_next = l->next;
7731 free(l);
7732 l = l_next;
7733 }/* end while(l) */
7734
7735 pool_destroy((void **) p->req_cap_pool);
7736 pool_destroy((void **) p->rsp_cap_pool);
7737 p = p->next;
7738 }/* end while(p) */
7739
7740 if (global.chroot) free(global.chroot);
7741 if (global.pidfile) free(global.pidfile);
7742
willy tarreau12350152005-12-18 01:03:27 +01007743 if (StaticReadEvent) free(StaticReadEvent);
7744 if (StaticWriteEvent) free(StaticWriteEvent);
7745 if (fdtab) free(fdtab);
7746
7747 pool_destroy(pool_session);
7748 pool_destroy(pool_buffer);
7749 pool_destroy(pool_fdtab);
7750 pool_destroy(pool_requri);
7751 pool_destroy(pool_task);
7752 pool_destroy(pool_capture);
7753 pool_destroy(pool_appsess);
7754
7755 if (have_appsession) {
7756 pool_destroy(apools.serverid);
7757 pool_destroy(apools.sessid);
7758 }
7759} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007760
7761int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01007762 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007763 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007764 init(argc, argv);
7765
willy tarreau9fe663a2005-12-17 13:02:59 +01007766 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007767 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007768 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007769 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007770 }
7771
7772 signal(SIGQUIT, dump);
7773 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007774 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007775#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007776 signal(SIGINT, sig_int);
7777 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007778#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007779
7780 /* on very high loads, a sigpipe sometimes happen just between the
7781 * getsockopt() which tells "it's OK to write", and the following write :-(
7782 */
willy tarreau3242e862005-12-17 12:27:53 +01007783#ifndef MSG_NOSIGNAL
7784 signal(SIGPIPE, SIG_IGN);
7785#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007786
7787 if (start_proxies() < 0)
7788 exit(1);
7789
willy tarreaufe2c5c12005-12-17 14:14:34 +01007790 /* open log & pid files before the chroot */
7791 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7792 int pidfd;
7793 unlink(global.pidfile);
7794 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7795 if (pidfd < 0) {
7796 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7797 exit(1);
7798 }
7799 pidfile = fdopen(pidfd, "w");
7800 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007801
7802 /* chroot if needed */
7803 if (global.chroot != NULL) {
7804 if (chroot(global.chroot) == -1) {
7805 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7806 exit(1);
7807 }
7808 chdir("/");
7809 }
7810
willy tarreaub1285d52005-12-18 01:20:14 +01007811 /* ulimits */
7812 if (global.rlimit_nofile) {
7813 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
7814 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
7815 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
7816 }
7817 }
7818
willy tarreau9fe663a2005-12-17 13:02:59 +01007819 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007820 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007821 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7822 exit(1);
7823 }
7824
willy tarreau036e1ce2005-12-17 13:46:33 +01007825 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007826 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7827 exit(1);
7828 }
7829
willy tarreaub1285d52005-12-18 01:20:14 +01007830 /* check ulimits */
7831 limit.rlim_cur = limit.rlim_max = 0;
7832 getrlimit(RLIMIT_NOFILE, &limit);
7833 if (limit.rlim_cur < global.maxsock) {
7834 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",
7835 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
7836 }
7837
willy tarreau9fe663a2005-12-17 13:02:59 +01007838 if (global.mode & MODE_DAEMON) {
7839 int ret = 0;
7840 int proc;
7841
7842 /* the father launches the required number of processes */
7843 for (proc = 0; proc < global.nbproc; proc++) {
7844 ret = fork();
7845 if (ret < 0) {
7846 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7847 exit(1); /* there has been an error */
7848 }
7849 else if (ret == 0) /* child breaks here */
7850 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007851 if (pidfile != NULL) {
7852 fprintf(pidfile, "%d\n", ret);
7853 fflush(pidfile);
7854 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007855 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007856 /* close the pidfile both in children and father */
7857 if (pidfile != NULL)
7858 fclose(pidfile);
7859 free(global.pidfile);
7860
willy tarreau9fe663a2005-12-17 13:02:59 +01007861 if (proc == global.nbproc)
7862 exit(0); /* parent must leave */
7863
willy tarreau750a4722005-12-17 13:21:24 +01007864 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7865 * that we can detach from the TTY. We MUST NOT do it in other cases since
7866 * it would have already be done, and 0-2 would have been affected to listening
7867 * sockets
7868 */
7869 if (!(global.mode & MODE_QUIET)) {
7870 /* detach from the tty */
7871 fclose(stdin); fclose(stdout); fclose(stderr);
7872 close(0); close(1); close(2); /* close all fd's */
7873 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7874 }
willy tarreaua1598082005-12-17 13:08:06 +01007875 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007876 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007877 }
7878
willy tarreau1c2ad212005-12-18 01:11:29 +01007879#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007880 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007881 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
7882 epoll_loop(POLL_LOOP_ACTION_RUN);
7883 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007884 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007885 }
7886 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01007887 Warning("epoll() is not available. Using poll()/select() instead.\n");
7888 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007889 }
7890 }
7891#endif
7892
7893#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007894 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007895 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
7896 poll_loop(POLL_LOOP_ACTION_RUN);
7897 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007898 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007899 }
7900 else {
7901 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01007902 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007903 }
7904 }
7905#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01007906 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007907 if (select_loop(POLL_LOOP_ACTION_INIT)) {
7908 select_loop(POLL_LOOP_ACTION_RUN);
7909 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007910 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01007911 }
7912 }
7913
willy tarreau0f7af912005-12-17 12:21:26 +01007914
willy tarreau12350152005-12-18 01:03:27 +01007915 /* Free all Hash Keys and all Hash elements */
7916 appsession_cleanup();
7917 /* Do some cleanup */
7918 deinit();
7919
willy tarreau0f7af912005-12-17 12:21:26 +01007920 exit(0);
7921}
willy tarreau12350152005-12-18 01:03:27 +01007922
7923#if defined(DEBUG_HASH)
7924static void print_table(const CHTbl *htbl) {
7925
7926 ListElmt *element;
7927 int i;
7928 appsess *asession;
7929
7930 /*****************************************************************************
7931 * *
7932 * Display the chained hash table. *
7933 * *
7934 *****************************************************************************/
7935
7936 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
7937
7938 for (i = 0; i < TBLSIZ; i++) {
7939 fprintf(stdout, "Bucket[%03d]\n", i);
7940
7941 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7942 //fprintf(stdout, "%c", *(char *)list_data(element));
7943 asession = (appsess *)list_data(element);
7944 fprintf(stdout, "ELEM :%s:", asession->sessid);
7945 fprintf(stdout, " Server :%s: \n", asession->serverid);
7946 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
7947 }
7948
7949 fprintf(stdout, "\n");
7950 }
7951 return;
7952} /* end print_table */
7953#endif
7954
7955static int appsession_init(void)
7956{
7957 static int initialized = 0;
7958 int idlen;
7959 struct server *s;
7960 struct proxy *p = proxy;
7961
7962 if (!initialized) {
7963 if (!appsession_task_init()) {
7964 apools.sessid = NULL;
7965 apools.serverid = NULL;
7966 apools.ser_waste = 0;
7967 apools.ser_use = 0;
7968 apools.ser_msize = sizeof(void *);
7969 apools.ses_waste = 0;
7970 apools.ses_use = 0;
7971 apools.ses_msize = sizeof(void *);
7972 while (p) {
7973 s = p->srv;
7974 if (apools.ses_msize < p->appsession_len)
7975 apools.ses_msize = p->appsession_len;
7976 while (s) {
7977 idlen = strlen(s->id);
7978 if (apools.ser_msize < idlen)
7979 apools.ser_msize = idlen;
7980 s = s->next;
7981 }
7982 p = p->next;
7983 }
7984 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
7985 apools.ses_msize ++;
7986 }
7987 else {
7988 fprintf(stderr, "appsession_task_init failed\n");
7989 return -1;
7990 }
7991 initialized ++;
7992 }
7993 return 0;
7994}
7995
7996static int appsession_task_init(void)
7997{
7998 static int initialized = 0;
7999 struct task *t;
8000 if (!initialized) {
8001 if ((t = pool_alloc(task)) == NULL)
8002 return -1;
8003 t->next = t->prev = t->rqnext = NULL;
8004 t->wq = LIST_HEAD(wait_queue);
8005 t->state = TASK_IDLE;
8006 t->context = NULL;
8007 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8008 task_queue(t);
8009 t->process = appsession_refresh;
8010 initialized ++;
8011 }
8012 return 0;
8013}
8014
8015static int appsession_refresh(struct task *t) {
8016 struct proxy *p = proxy;
8017 CHTbl *htbl;
8018 ListElmt *element, *last;
8019 int i;
8020 appsess *asession;
8021 void *data;
8022
8023 while (p) {
8024 if (p->appsession_name != NULL) {
8025 htbl = &p->htbl_proxy;
8026 /* if we ever give up the use of TBLSIZ, we need to change this */
8027 for (i = 0; i < TBLSIZ; i++) {
8028 last = NULL;
8029 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8030 asession = (appsess *)list_data(element);
8031 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8032 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8033 int len;
8034 /*
8035 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8036 */
8037 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8038 asession->sessid, asession->serverid?asession->serverid:"(null)");
8039 write(1, trash, len);
8040 }
8041 /* delete the expired element from within the hash table */
8042 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8043 && (htbl->table[i].destroy != NULL)) {
8044 htbl->table[i].destroy(data);
8045 }
8046 if (last == NULL) {/* patient lost his head, get a new one */
8047 element = list_head(&htbl->table[i]);
8048 if (element == NULL) break; /* no heads left, go to next patient */
8049 }
8050 else
8051 element = last;
8052 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8053 else
8054 last = element;
8055 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8056 }
8057 }
8058 p = p->next;
8059 }
8060 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8061 return TBLCHKINT;
8062} /* end appsession_refresh */
8063