blob: 301ad25e9f0e2c7a495177d33f2b9a4bdb017f4f [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 tarreauc1f47532005-12-18 01:08:26 +010079#define HAPROXY_VERSION "1.2.5"
willy tarreau64a3cc32005-12-18 01:13:11 +010080#define HAPROXY_DATE "2005/04/30"
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 */
324
325#define SN_CK_NONE 0x00000000 /* this session had no cookie */
326#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
327#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
328#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
329#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
330#define SN_CK_SHIFT 6 /* bit shift */
331
332#define SN_ERR_CLITO 0x00000100 /* client time-out */
333#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
334#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
335#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
336#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
337#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
338#define SN_ERR_SHIFT 8 /* bit shift */
339
340#define SN_FINST_R 0x00001000 /* session ended during client request */
341#define SN_FINST_C 0x00002000 /* session ended during server connect */
342#define SN_FINST_H 0x00003000 /* session ended during server headers */
343#define SN_FINST_D 0x00004000 /* session ended during data phase */
344#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
345#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
346#define SN_FINST_SHIFT 12 /* bit shift */
347
348#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
349#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
350#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
351#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
352#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100353#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100354#define SN_SCK_SHIFT 16 /* bit shift */
355
willy tarreau97f58572005-12-18 00:53:44 +0100356#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
357#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
358#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100359
360/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100361#define CL_STHEADERS 0
362#define CL_STDATA 1
363#define CL_STSHUTR 2
364#define CL_STSHUTW 3
365#define CL_STCLOSE 4
366
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100368#define SV_STIDLE 0
369#define SV_STCONN 1
370#define SV_STHEADERS 2
371#define SV_STDATA 3
372#define SV_STSHUTR 4
373#define SV_STSHUTW 5
374#define SV_STCLOSE 6
375
376/* result of an I/O event */
377#define RES_SILENT 0 /* didn't happen */
378#define RES_DATA 1 /* data were sent or received */
379#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
380#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
381
willy tarreau9fe663a2005-12-17 13:02:59 +0100382/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100383#define MODE_DEBUG 1
384#define MODE_STATS 2
385#define MODE_LOG 4
386#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100387#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100388#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100389#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100390
391/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100392#define SRV_RUNNING 1 /* the server is UP */
393#define SRV_BACKUP 2 /* this server is a backup server */
394#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100395#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100396
willy tarreaue39cd132005-12-17 13:00:18 +0100397/* what to do when a header matches a regex */
398#define ACT_ALLOW 0 /* allow the request */
399#define ACT_REPLACE 1 /* replace the matching header */
400#define ACT_REMOVE 2 /* remove the matching header */
401#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100402#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100403
willy tarreau9fe663a2005-12-17 13:02:59 +0100404/* configuration sections */
405#define CFG_NONE 0
406#define CFG_GLOBAL 1
407#define CFG_LISTEN 2
408
willy tarreaua1598082005-12-17 13:08:06 +0100409/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100410#define LW_DATE 1 /* date */
411#define LW_CLIP 2 /* CLient IP */
412#define LW_SVIP 4 /* SerVer IP */
413#define LW_SVID 8 /* server ID */
414#define LW_REQ 16 /* http REQuest */
415#define LW_RESP 32 /* http RESPonse */
416#define LW_PXIP 64 /* proxy IP */
417#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100418#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100419#define LW_COOKIE 512 /* captured cookie */
420#define LW_REQHDR 1024 /* request header(s) */
421#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100422
willy tarreau0f7af912005-12-17 12:21:26 +0100423/*********************************************************************/
424
425#define LIST_HEAD(a) ((void *)(&(a)))
426
427/*********************************************************************/
428
willy tarreau4302f492005-12-18 01:00:37 +0100429struct cap_hdr {
430 struct cap_hdr *next;
431 char *name; /* header name, case insensitive */
432 int namelen; /* length of the header name, to speed-up lookups */
433 int len; /* capture length, not including terminal zero */
434 int index; /* index in the output array */
435 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
436};
437
willy tarreau0f7af912005-12-17 12:21:26 +0100438struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100439 struct hdr_exp *next;
440 regex_t *preg; /* expression to look for */
441 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
442 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100443};
444
445struct buffer {
446 unsigned int l; /* data length */
447 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100448 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100449 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100450 char data[BUFSIZE];
451};
452
453struct server {
454 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100455 int state; /* server state (SRV_*) */
456 int cklen; /* the len of the cookie, to speed up checks */
457 char *cookie; /* the id set in the cookie */
458 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100459 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100460 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100461 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100462 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100463 int rise, fall; /* time in iterations */
464 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100465 int result; /* 0 = connect OK, -1 = connect KO */
466 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100467 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100468};
469
willy tarreau5cbea6f2005-12-17 12:48:26 +0100470/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100471struct task {
472 struct task *next, *prev; /* chaining ... */
473 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100474 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100475 int state; /* task state : IDLE or RUNNING */
476 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100477 int (*process)(struct task *t); /* the function which processes the task */
478 void *context; /* the task's context */
479};
480
481/* WARNING: if new fields are added, they must be initialized in event_accept() */
482struct session {
483 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100484 /* application specific below */
485 struct timeval crexpire; /* expiration date for a client read */
486 struct timeval cwexpire; /* expiration date for a client write */
487 struct timeval srexpire; /* expiration date for a server read */
488 struct timeval swexpire; /* expiration date for a server write */
489 struct timeval cnexpire; /* expiration date for a connect */
490 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
491 struct proxy *proxy; /* the proxy this socket belongs to */
492 int cli_fd; /* the client side fd */
493 int srv_fd; /* the server side fd */
494 int cli_state; /* state of the client side */
495 int srv_state; /* state of the server side */
496 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100498 struct buffer *req; /* request buffer */
499 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100500 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100501 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100502 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100503 char **req_cap; /* array of captured request headers (may be NULL) */
504 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100505 struct {
506 int logwait; /* log fields waiting to be collected : LW_* */
507 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
508 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
509 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
510 long t_data; /* delay before the first data byte from the server ... */
511 unsigned long t_close; /* total session duration */
512 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100513 char *cli_cookie; /* cookie presented by the client, in capture mode */
514 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100515 int status; /* HTTP status from the server, negative if from proxy */
516 long long bytes; /* number of bytes transferred from the server */
517 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100518 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100519};
520
willy tarreaua41a8b42005-12-17 14:02:24 +0100521struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100522 int fd; /* the listen socket */
523 struct sockaddr_storage addr; /* the address we listen to */
524 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100525};
526
527
willy tarreau0f7af912005-12-17 12:21:26 +0100528struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100529 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100530 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100531 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100532 struct server *srv, *cursrv; /* known servers, current server */
533 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100534 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100535 int cookie_len; /* strlen(cookie_name), computed only once */
536 char *appsession_name; /* name of the cookie to look for */
537 int appsession_name_len; /* strlen(appsession_name), computed only once */
538 int appsession_len; /* length of the appsession cookie value to be used */
539 int appsession_timeout;
540 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100541 char *capture_name; /* beginning of the name of the cookie to capture */
542 int capture_namelen; /* length of the cookie name to match */
543 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100544 int clitimeout; /* client I/O timeout (in milliseconds) */
545 int srvtimeout; /* server I/O timeout (in milliseconds) */
546 int contimeout; /* connect timeout (in milliseconds) */
547 char *id; /* proxy id */
548 int nbconn; /* # of active sessions */
549 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100550 int conn_retries; /* maximum number of connect retries */
551 int options; /* PR_O_REDISP, PR_O_TRANSP */
552 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100553 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100554 struct proxy *next;
555 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
556 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100557 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100558 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100559 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100560 int nb_reqadd, nb_rspadd;
561 struct hdr_exp *req_exp; /* regular expressions for request headers */
562 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100563 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
564 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
565 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
566 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100567 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100568 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100569 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
570 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100571 struct {
572 char *msg400; /* message for error 400 */
573 int len400; /* message length for error 400 */
574 char *msg403; /* message for error 403 */
575 int len403; /* message length for error 403 */
576 char *msg408; /* message for error 408 */
577 int len408; /* message length for error 408 */
578 char *msg500; /* message for error 500 */
579 int len500; /* message length for error 500 */
580 char *msg502; /* message for error 502 */
581 int len502; /* message length for error 502 */
582 char *msg503; /* message for error 503 */
583 int len503; /* message length for error 503 */
584 char *msg504; /* message for error 504 */
585 int len504; /* message length for error 504 */
586 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100587};
588
589/* info about one given fd */
590struct fdtab {
591 int (*read)(int fd); /* read function */
592 int (*write)(int fd); /* write function */
593 struct task *owner; /* the session (or proxy) associated with this fd */
594 int state; /* the state of this fd */
595};
596
597/*********************************************************************/
598
willy tarreau0f7af912005-12-17 12:21:26 +0100599int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100600char *cfg_cfgfile = NULL; /* configuration file */
601char *progname = NULL; /* program name */
602int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100603
604/* global options */
605static struct {
606 int uid;
607 int gid;
608 int nbproc;
609 int maxconn;
610 int maxsock; /* max # of sockets */
611 int mode;
612 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100613 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100614 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100615 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100616 struct sockaddr_in logsrv1, logsrv2;
617} global = {
618 logfac1 : -1,
619 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100620 loglev1 : 7, /* max syslog level : debug */
621 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100622 /* others NULL OK */
623};
624
willy tarreau0f7af912005-12-17 12:21:26 +0100625/*********************************************************************/
626
willy tarreau1c2ad212005-12-18 01:11:29 +0100627fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100628 *StaticWriteEvent;
629
willy tarreau64a3cc32005-12-18 01:13:11 +0100630int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100631
willy tarreau0f7af912005-12-17 12:21:26 +0100632void **pool_session = NULL,
633 **pool_buffer = NULL,
634 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100635 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100636 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100637 **pool_capture = NULL,
638 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100639
640struct proxy *proxy = NULL; /* list of all existing proxies */
641struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100642struct task *rq = NULL; /* global run queue */
643struct task wait_queue = { /* global wait queue */
644 prev:LIST_HEAD(wait_queue),
645 next:LIST_HEAD(wait_queue)
646};
willy tarreau0f7af912005-12-17 12:21:26 +0100647
willy tarreau0f7af912005-12-17 12:21:26 +0100648static int totalconn = 0; /* total # of terminated sessions */
649static int actconn = 0; /* # of active sessions */
650static int maxfd = 0; /* # of the highest fd + 1 */
651static int listeners = 0; /* # of listeners */
652static int stopping = 0; /* non zero means stopping in progress */
653static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100654static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100655
656static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100657/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100658static char trash[BUFSIZE];
659
willy tarreaudd07e972005-12-18 00:48:48 +0100660const int zero = 0;
661const int one = 1;
662
willy tarreau0f7af912005-12-17 12:21:26 +0100663/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100664 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100665 */
666
667#define MAX_SYSLOG_LEN 1024
668#define NB_LOG_FACILITIES 24
669const char *log_facilities[NB_LOG_FACILITIES] = {
670 "kern", "user", "mail", "daemon",
671 "auth", "syslog", "lpr", "news",
672 "uucp", "cron", "auth2", "ftp",
673 "ntp", "audit", "alert", "cron2",
674 "local0", "local1", "local2", "local3",
675 "local4", "local5", "local6", "local7"
676};
677
678
679#define NB_LOG_LEVELS 8
680const char *log_levels[NB_LOG_LEVELS] = {
681 "emerg", "alert", "crit", "err",
682 "warning", "notice", "info", "debug"
683};
684
685#define SYSLOG_PORT 514
686
687const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
688 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100689
690const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
691const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
692const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
693const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
694 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
695 unknown, Set-cookie Rewritten */
696
willy tarreau0f7af912005-12-17 12:21:26 +0100697#define MAX_HOSTNAME_LEN 32
698static char hostname[MAX_HOSTNAME_LEN] = "";
699
willy tarreau8337c6b2005-12-17 13:41:01 +0100700const char *HTTP_302 =
701 "HTTP/1.0 302 Found\r\n"
702 "Cache-Control: no-cache\r\n"
703 "Connection: close\r\n"
704 "Location: "; /* not terminated since it will be concatenated with the URL */
705
willy tarreauc1f47532005-12-18 01:08:26 +0100706/* same as 302 except that the browser MUST retry with the GET method */
707const char *HTTP_303 =
708 "HTTP/1.0 303 See Other\r\n"
709 "Cache-Control: no-cache\r\n"
710 "Connection: close\r\n"
711 "Location: "; /* not terminated since it will be concatenated with the URL */
712
willy tarreaua1598082005-12-17 13:08:06 +0100713const char *HTTP_400 =
714 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100715 "Cache-Control: no-cache\r\n"
716 "Connection: close\r\n"
717 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100718 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100719
willy tarreaua1598082005-12-17 13:08:06 +0100720const char *HTTP_403 =
721 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100722 "Cache-Control: no-cache\r\n"
723 "Connection: close\r\n"
724 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100725 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
726
willy tarreau8337c6b2005-12-17 13:41:01 +0100727const char *HTTP_408 =
728 "HTTP/1.0 408 Request Time-out\r\n"
729 "Cache-Control: no-cache\r\n"
730 "Connection: close\r\n"
731 "\r\n"
732 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
733
willy tarreau750a4722005-12-17 13:21:24 +0100734const char *HTTP_500 =
735 "HTTP/1.0 500 Server Error\r\n"
736 "Cache-Control: no-cache\r\n"
737 "Connection: close\r\n"
738 "\r\n"
739 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100740
741const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100742 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100743 "Cache-Control: no-cache\r\n"
744 "Connection: close\r\n"
745 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100746 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
747
748const char *HTTP_503 =
749 "HTTP/1.0 503 Service Unavailable\r\n"
750 "Cache-Control: no-cache\r\n"
751 "Connection: close\r\n"
752 "\r\n"
753 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
754
755const char *HTTP_504 =
756 "HTTP/1.0 504 Gateway Time-out\r\n"
757 "Cache-Control: no-cache\r\n"
758 "Connection: close\r\n"
759 "\r\n"
760 "<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 +0100761
willy tarreau0f7af912005-12-17 12:21:26 +0100762/*********************************************************************/
763/* statistics ******************************************************/
764/*********************************************************************/
765
willy tarreau750a4722005-12-17 13:21:24 +0100766#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100767static int stats_tsk_lsrch, stats_tsk_rsrch,
768 stats_tsk_good, stats_tsk_right, stats_tsk_left,
769 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100770#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100771
772
773/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100774/* debugging *******************************************************/
775/*********************************************************************/
776#ifdef DEBUG_FULL
777static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
778static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
779#endif
780
781/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100782/* function prototypes *********************************************/
783/*********************************************************************/
784
785int event_accept(int fd);
786int event_cli_read(int fd);
787int event_cli_write(int fd);
788int event_srv_read(int fd);
789int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100790int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100791
willy tarreau12350152005-12-18 01:03:27 +0100792static int appsession_task_init(void);
793static int appsession_init(void);
794static int appsession_refresh(struct task *t);
795
willy tarreau0f7af912005-12-17 12:21:26 +0100796/*********************************************************************/
797/* general purpose functions ***************************************/
798/*********************************************************************/
799
800void display_version() {
801 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100802 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100803}
804
805/*
806 * This function prints the command line usage and exits
807 */
808void usage(char *name) {
809 display_version();
810 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100811 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100812#if STATTIME > 0
813 "sl"
814#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100815 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100816 " -v displays version\n"
817 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100818 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100819#if STATTIME > 0
820 " -s enables statistics output\n"
821 " -l enables long statistics format\n"
822#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100823 " -D goes daemon ; implies -q\n"
824 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100825 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100826 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100827 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100828 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100829#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100830 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100831#endif
832#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100833 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100834#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100835 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100836 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100837 exit(1);
838}
839
840
841/*
842 * Displays the message on stderr with the date and pid.
843 */
844void Alert(char *fmt, ...) {
845 va_list argp;
846 struct timeval tv;
847 struct tm *tm;
848
willy tarreau982249e2005-12-18 00:57:06 +0100849 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100850 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100851
willy tarreau5cbea6f2005-12-17 12:48:26 +0100852 gettimeofday(&tv, NULL);
853 tm=localtime(&tv.tv_sec);
854 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100855 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100856 vfprintf(stderr, fmt, argp);
857 fflush(stderr);
858 va_end(argp);
859 }
willy tarreau0f7af912005-12-17 12:21:26 +0100860}
861
862
863/*
864 * Displays the message on stderr with the date and pid.
865 */
866void Warning(char *fmt, ...) {
867 va_list argp;
868 struct timeval tv;
869 struct tm *tm;
870
willy tarreau982249e2005-12-18 00:57:06 +0100871 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100872 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100873
willy tarreau5cbea6f2005-12-17 12:48:26 +0100874 gettimeofday(&tv, NULL);
875 tm=localtime(&tv.tv_sec);
876 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100877 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100878 vfprintf(stderr, fmt, argp);
879 fflush(stderr);
880 va_end(argp);
881 }
882}
883
884/*
885 * Displays the message on <out> only if quiet mode is not set.
886 */
887void qfprintf(FILE *out, char *fmt, ...) {
888 va_list argp;
889
willy tarreau982249e2005-12-18 00:57:06 +0100890 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100891 va_start(argp, fmt);
892 vfprintf(out, fmt, argp);
893 fflush(out);
894 va_end(argp);
895 }
willy tarreau0f7af912005-12-17 12:21:26 +0100896}
897
898
899/*
900 * converts <str> to a struct sockaddr_in* which is locally allocated.
901 * The format is "addr:port", where "addr" can be empty or "*" to indicate
902 * INADDR_ANY.
903 */
904struct sockaddr_in *str2sa(char *str) {
905 static struct sockaddr_in sa;
906 char *c;
907 int port;
908
willy tarreaua1598082005-12-17 13:08:06 +0100909 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100910 str=strdup(str);
911
912 if ((c=strrchr(str,':')) != NULL) {
913 *c++=0;
914 port=atol(c);
915 }
916 else
917 port=0;
918
919 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
920 sa.sin_addr.s_addr = INADDR_ANY;
921 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100922 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100923 struct hostent *he;
924
925 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100926 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100927 }
928 else
929 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
930 }
931 sa.sin_port=htons(port);
932 sa.sin_family=AF_INET;
933
934 free(str);
935 return &sa;
936}
937
willy tarreau9fe663a2005-12-17 13:02:59 +0100938
939/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100940 * converts <str> to a list of listeners which are dynamically allocated.
941 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
942 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
943 * - <port> is a numerical port from 1 to 65535 ;
944 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
945 * This can be repeated as many times as necessary, separated by a coma.
946 * The <tail> argument is a pointer to a current list which should be appended
947 * to the tail of the new list. The pointer to the new list is returned.
948 */
949struct listener *str2listener(char *str, struct listener *tail) {
950 struct listener *l;
951 char *c, *next, *range, *dupstr;
952 int port, end;
953
954 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +0100955
willy tarreaua41a8b42005-12-17 14:02:24 +0100956 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100957 struct sockaddr_storage ss;
958
willy tarreaua41a8b42005-12-17 14:02:24 +0100959 str = next;
960 /* 1) look for the end of the first address */
961 if ((next = strrchr(str, ',')) != NULL) {
962 *next++ = 0;
963 }
964
willy tarreau8a86dbf2005-12-18 00:45:59 +0100965 /* 2) look for the addr/port delimiter, it's the last colon. */
966 if ((range = strrchr(str, ':')) == NULL) {
967 Alert("Missing port number: '%s'\n", str);
968 }
969
970 *range++ = 0;
971
972 if (strrchr(str, ':') != NULL) {
973 /* IPv6 address contains ':' */
974 memset(&ss, 0, sizeof(ss));
975 ss.ss_family = AF_INET6;
976
977 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
978 Alert("Invalid server address: '%s'\n", str);
979 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100980 }
981 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100982 memset(&ss, 0, sizeof(ss));
983 ss.ss_family = AF_INET;
984
985 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
986 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
987 }
988 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
989 struct hostent *he;
990
991 if ((he = gethostbyname(str)) == NULL) {
992 Alert("Invalid server name: '%s'\n", str);
993 }
994 else
995 ((struct sockaddr_in *)&ss)->sin_addr =
996 *(struct in_addr *) *(he->h_addr_list);
997 }
998 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100999
1000 /* 3) look for the port-end delimiter */
1001 if ((c = strchr(range, '-')) != NULL) {
1002 *c++ = 0;
1003 end = atol(c);
1004 }
1005 else {
1006 end = atol(range);
1007 }
1008
1009 for (port = atol(range); port <= end; port++) {
1010 l = (struct listener *)calloc(1, sizeof(struct listener));
1011 l->next = tail;
1012 tail = l;
1013
willy tarreau8a86dbf2005-12-18 00:45:59 +01001014 l->addr = ss;
1015 if (ss.ss_family == AF_INET6)
1016 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1017 else
1018 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1019
willy tarreaua41a8b42005-12-17 14:02:24 +01001020 } /* end for(port) */
1021 } /* end while(next) */
1022 free(dupstr);
1023 return tail;
1024}
1025
willy tarreau4302f492005-12-18 01:00:37 +01001026
1027#define FD_SETS_ARE_BITFIELDS
1028#ifdef FD_SETS_ARE_BITFIELDS
1029/*
1030 * This map is used with all the FD_* macros to check whether a particular bit
1031 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1032 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1033 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1034 * exclusively to the macros.
1035 */
1036fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1037fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1038
1039#else
1040#error "Check if your OS uses bitfields for fd_sets"
1041#endif
1042
1043/* will try to encode the string <string> replacing all characters tagged in
1044 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1045 * prefixed by <escape>, and will store the result between <start> (included
1046 *) and <stop> (excluded), and will always terminate the string with a '\0'
1047 * before <stop>. The position of the '\0' is returned if the conversion
1048 * completes. If bytes are missing between <start> and <stop>, then the
1049 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1050 * cannot even be stored so we return <start> without writing the 0.
1051 * The input string must also be zero-terminated.
1052 */
1053char hextab[16] = "0123456789ABCDEF";
1054char *encode_string(char *start, char *stop,
1055 const char escape, const fd_set *map,
1056 const char *string)
1057{
1058 if (start < stop) {
1059 stop--; /* reserve one byte for the final '\0' */
1060 while (start < stop && *string != 0) {
1061 if (!FD_ISSET((unsigned char)(*string), map))
1062 *start++ = *string;
1063 else {
1064 if (start + 3 >= stop)
1065 break;
1066 *start++ = escape;
1067 *start++ = hextab[(*string >> 4) & 15];
1068 *start++ = hextab[*string & 15];
1069 }
1070 string++;
1071 }
1072 *start = '\0';
1073 }
1074 return start;
1075}
willy tarreaua41a8b42005-12-17 14:02:24 +01001076
1077/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001078 * This function sends a syslog message to both log servers of a proxy,
1079 * or to global log servers if the proxy is NULL.
1080 * It also tries not to waste too much time computing the message header.
1081 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001082 */
1083void send_log(struct proxy *p, int level, char *message, ...) {
1084 static int logfd = -1; /* syslog UDP socket */
1085 static long tvsec = -1; /* to force the string to be initialized */
1086 struct timeval tv;
1087 va_list argp;
1088 static char logmsg[MAX_SYSLOG_LEN];
1089 static char *dataptr = NULL;
1090 int fac_level;
1091 int hdr_len, data_len;
1092 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001093 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001094 int nbloggers = 0;
1095 char *log_ptr;
1096
1097 if (logfd < 0) {
1098 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1099 return;
1100 }
1101
1102 if (level < 0 || progname == NULL || message == NULL)
1103 return;
1104
1105 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001106 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001107 /* this string is rebuild only once a second */
1108 struct tm *tm = localtime(&tv.tv_sec);
1109 tvsec = tv.tv_sec;
1110
willy tarreauc29948c2005-12-17 13:10:27 +01001111 hdr_len = snprintf(logmsg, sizeof(logmsg),
1112 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1113 monthname[tm->tm_mon],
1114 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1115 progname, pid);
1116 /* WARNING: depending upon implementations, snprintf may return
1117 * either -1 or the number of bytes that would be needed to store
1118 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001119 */
willy tarreauc29948c2005-12-17 13:10:27 +01001120 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1121 hdr_len = sizeof(logmsg);
1122
1123 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001124 }
1125
1126 va_start(argp, message);
1127 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001128 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1129 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001130 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001131 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001132
1133 if (p == NULL) {
1134 if (global.logfac1 >= 0) {
1135 sa[nbloggers] = &global.logsrv1;
1136 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001137 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001138 nbloggers++;
1139 }
1140 if (global.logfac2 >= 0) {
1141 sa[nbloggers] = &global.logsrv2;
1142 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001143 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001144 nbloggers++;
1145 }
1146 } else {
1147 if (p->logfac1 >= 0) {
1148 sa[nbloggers] = &p->logsrv1;
1149 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001150 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001151 nbloggers++;
1152 }
1153 if (p->logfac2 >= 0) {
1154 sa[nbloggers] = &p->logsrv2;
1155 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001156 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001157 nbloggers++;
1158 }
1159 }
1160
1161 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001162 /* we can filter the level of the messages that are sent to each logger */
1163 if (level > loglevel[nbloggers])
1164 continue;
1165
willy tarreauc29948c2005-12-17 13:10:27 +01001166 /* For each target, we may have a different facility.
1167 * We can also have a different log level for each message.
1168 * This induces variations in the message header length.
1169 * Since we don't want to recompute it each time, nor copy it every
1170 * time, we only change the facility in the pre-computed header,
1171 * and we change the pointer to the header accordingly.
1172 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001173 fac_level = (facilities[nbloggers] << 3) + level;
1174 log_ptr = logmsg + 3; /* last digit of the log level */
1175 do {
1176 *log_ptr = '0' + fac_level % 10;
1177 fac_level /= 10;
1178 log_ptr--;
1179 } while (fac_level && log_ptr > logmsg);
1180 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001181
willy tarreauc29948c2005-12-17 13:10:27 +01001182 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001183
1184#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001185 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001186 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1187#else
willy tarreauc29948c2005-12-17 13:10:27 +01001188 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001189 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1190#endif
1191 }
willy tarreau0f7af912005-12-17 12:21:26 +01001192}
1193
1194
1195/* sets <tv> to the current time */
1196static inline struct timeval *tv_now(struct timeval *tv) {
1197 if (tv)
1198 gettimeofday(tv, NULL);
1199 return tv;
1200}
1201
1202/*
1203 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1204 */
1205static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1206 if (!tv || !from)
1207 return NULL;
1208 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1209 tv->tv_sec = from->tv_sec + (ms/1000);
1210 while (tv->tv_usec >= 1000000) {
1211 tv->tv_usec -= 1000000;
1212 tv->tv_sec++;
1213 }
1214 return tv;
1215}
1216
1217/*
1218 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1219 */
1220static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001221 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001222 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001223 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001224 return 1;
1225 else if (tv1->tv_usec < tv2->tv_usec)
1226 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001227 else if (tv1->tv_usec > tv2->tv_usec)
1228 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001229 else
1230 return 0;
1231}
1232
1233/*
1234 * returns the absolute difference, in ms, between tv1 and tv2
1235 */
1236unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1237 int cmp;
1238 unsigned long ret;
1239
1240
willy tarreauef900ab2005-12-17 12:52:52 +01001241 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001242 if (!cmp)
1243 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001244 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001245 struct timeval *tmp = tv1;
1246 tv1 = tv2;
1247 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001248 }
willy tarreauef900ab2005-12-17 12:52:52 +01001249 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001250 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001251 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001252 else
willy tarreauef900ab2005-12-17 12:52:52 +01001253 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001254 return (unsigned long) ret;
1255}
1256
1257/*
willy tarreau750a4722005-12-17 13:21:24 +01001258 * returns the difference, in ms, between tv1 and tv2
1259 */
1260static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1261 unsigned long ret;
1262
willy tarreau6e682ce2005-12-17 13:26:49 +01001263 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1264 if (tv2->tv_usec > tv1->tv_usec)
1265 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001266 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001267 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001268 return (unsigned long) ret;
1269}
1270
1271/*
willy tarreau0f7af912005-12-17 12:21:26 +01001272 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1273 */
1274static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001275 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001276 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001277 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001278 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1279 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001280 else
1281 return 0;
1282 }
willy tarreau0f7af912005-12-17 12:21:26 +01001283 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001284 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001285 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001286 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1287 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1288 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001289 else
1290 return 0;
1291}
1292
1293/*
1294 * returns the remaining time between tv1=now and event=tv2
1295 * if tv2 is passed, 0 is returned.
1296 */
1297static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1298 unsigned long ret;
1299
willy tarreau0f7af912005-12-17 12:21:26 +01001300 if (tv_cmp_ms(tv1, tv2) >= 0)
1301 return 0; /* event elapsed */
1302
willy tarreauef900ab2005-12-17 12:52:52 +01001303 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001304 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001305 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001306 else
willy tarreauef900ab2005-12-17 12:52:52 +01001307 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001308 return (unsigned long) ret;
1309}
1310
1311
1312/*
1313 * zeroes a struct timeval
1314 */
1315
1316static inline struct timeval *tv_eternity(struct timeval *tv) {
1317 tv->tv_sec = tv->tv_usec = 0;
1318 return tv;
1319}
1320
1321/*
1322 * returns 1 if tv is null, else 0
1323 */
1324static inline int tv_iseternity(struct timeval *tv) {
1325 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1326 return 1;
1327 else
1328 return 0;
1329}
1330
1331/*
1332 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1333 * considering that 0 is the eternity.
1334 */
1335static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1336 if (tv_iseternity(tv1))
1337 if (tv_iseternity(tv2))
1338 return 0; /* same */
1339 else
1340 return 1; /* tv1 later than tv2 */
1341 else if (tv_iseternity(tv2))
1342 return -1; /* tv2 later than tv1 */
1343
1344 if (tv1->tv_sec > tv2->tv_sec)
1345 return 1;
1346 else if (tv1->tv_sec < tv2->tv_sec)
1347 return -1;
1348 else if (tv1->tv_usec > tv2->tv_usec)
1349 return 1;
1350 else if (tv1->tv_usec < tv2->tv_usec)
1351 return -1;
1352 else
1353 return 0;
1354}
1355
1356/*
1357 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1358 * considering that 0 is the eternity.
1359 */
1360static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1361 if (tv_iseternity(tv1))
1362 if (tv_iseternity(tv2))
1363 return 0; /* same */
1364 else
1365 return 1; /* tv1 later than tv2 */
1366 else if (tv_iseternity(tv2))
1367 return -1; /* tv2 later than tv1 */
1368
willy tarreauefae1842005-12-17 12:51:03 +01001369 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001370 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001371 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001372 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001373 return -1;
1374 else
1375 return 0;
1376 }
1377 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001378 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001379 return 1;
1380 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001381 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001382 return -1;
1383 else
1384 return 0;
1385}
1386
1387/*
1388 * returns the first event between tv1 and tv2 into tvmin.
1389 * a zero tv is ignored. tvmin is returned.
1390 */
1391static inline struct timeval *tv_min(struct timeval *tvmin,
1392 struct timeval *tv1, struct timeval *tv2) {
1393
1394 if (tv_cmp2(tv1, tv2) <= 0)
1395 *tvmin = *tv1;
1396 else
1397 *tvmin = *tv2;
1398
1399 return tvmin;
1400}
1401
1402
1403
1404/***********************************************************/
1405/* fd management ***************************************/
1406/***********************************************************/
1407
1408
1409
willy tarreau5cbea6f2005-12-17 12:48:26 +01001410/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1411 * The file descriptor is also closed.
1412 */
willy tarreau0f7af912005-12-17 12:21:26 +01001413static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001414 FD_CLR(fd, StaticReadEvent);
1415 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001416 close(fd);
1417 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001418
1419 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1420 maxfd--;
1421}
1422
1423/* recomputes the maxfd limit from the fd */
1424static inline void fd_insert(int fd) {
1425 if (fd+1 > maxfd)
1426 maxfd = fd+1;
1427}
1428
1429/*************************************************************/
1430/* task management ***************************************/
1431/*************************************************************/
1432
willy tarreau5cbea6f2005-12-17 12:48:26 +01001433/* puts the task <t> in run queue <q>, and returns <t> */
1434static inline struct task *task_wakeup(struct task **q, struct task *t) {
1435 if (t->state == TASK_RUNNING)
1436 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001437 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001438 t->rqnext = *q;
1439 t->state = TASK_RUNNING;
1440 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001441 }
1442}
1443
willy tarreau5cbea6f2005-12-17 12:48:26 +01001444/* removes the task <t> from the queue <q>
1445 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001446 * set the run queue to point to the next one, and return it
1447 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001448static inline struct task *task_sleep(struct task **q, struct task *t) {
1449 if (t->state == TASK_RUNNING) {
1450 *q = t->rqnext;
1451 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001454}
1455
1456/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001457 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001458 * from the run queue. A pointer to the task itself is returned.
1459 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001460static inline struct task *task_delete(struct task *t) {
1461 t->prev->next = t->next;
1462 t->next->prev = t->prev;
1463 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001464}
1465
1466/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001467 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001468 */
1469static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001470 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001471}
1472
willy tarreau5cbea6f2005-12-17 12:48:26 +01001473/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001474 * may be only moved or left where it was, depending on its timing requirements.
1475 * <task> is returned.
1476 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001477struct task *task_queue(struct task *task) {
1478 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001479 struct task *start_from;
1480
1481 /* first, test if the task was already in a list */
1482 if (task->prev == NULL) {
1483 // start_from = list;
1484 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001485#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001486 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001487#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001488 /* insert the unlinked <task> into the list, searching back from the last entry */
1489 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1490 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001491#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001492 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001493#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001494 }
1495
1496 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1497 // start_from = start_from->next;
1498 // stats_tsk_nsrch++;
1499 // }
1500 }
1501 else if (task->prev == list ||
1502 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1503 start_from = task->next;
1504 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001505#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001506 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001507#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001508 return task; /* it's already in the right place */
1509 }
1510
willy tarreau750a4722005-12-17 13:21:24 +01001511#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001512 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001513#endif
1514
1515 /* if the task is not at the right place, there's little chance that
1516 * it has only shifted a bit, and it will nearly always be queued
1517 * at the end of the list because of constant timeouts
1518 * (observed in real case).
1519 */
1520#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1521 start_from = list->prev; /* assume we'll queue to the end of the list */
1522 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1523 start_from = start_from->prev;
1524#if STATTIME > 0
1525 stats_tsk_lsrch++;
1526#endif
1527 }
1528#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001529 /* insert the unlinked <task> into the list, searching after position <start_from> */
1530 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1531 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001532#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001533 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001534#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001535 }
willy tarreau750a4722005-12-17 13:21:24 +01001536#endif /* WE_REALLY_... */
1537
willy tarreau0f7af912005-12-17 12:21:26 +01001538 /* we need to unlink it now */
1539 task_delete(task);
1540 }
1541 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001542#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001543 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001544#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001545#ifdef LEFT_TO_TOP /* not very good */
1546 start_from = list;
1547 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1548 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001549#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001550 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001551#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001552 }
1553#else
1554 start_from = task->prev->prev; /* valid because of the previous test above */
1555 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1556 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001557#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001558 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001559#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001560 }
1561#endif
1562 /* we need to unlink it now */
1563 task_delete(task);
1564 }
1565 task->prev = start_from;
1566 task->next = start_from->next;
1567 task->next->prev = task;
1568 start_from->next = task;
1569 return task;
1570}
1571
1572
1573/*********************************************************************/
1574/* more specific functions ***************************************/
1575/*********************************************************************/
1576
1577/* some prototypes */
1578static int maintain_proxies(void);
1579
willy tarreau5cbea6f2005-12-17 12:48:26 +01001580/* this either returns the sockname or the original destination address. Code
1581 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1582 */
1583static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001584#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001585 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1586#else
willy tarreaua1598082005-12-17 13:08:06 +01001587#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001588 return getsockname(fd, (struct sockaddr *)sa, salen);
1589#else
1590 return -1;
1591#endif
1592#endif
1593}
1594
1595/*
1596 * frees the context associated to a session. It must have been removed first.
1597 */
1598static inline void session_free(struct session *s) {
1599 if (s->req)
1600 pool_free(buffer, s->req);
1601 if (s->rep)
1602 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001603
1604 if (s->rsp_cap != NULL) {
1605 struct cap_hdr *h;
1606 for (h = s->proxy->rsp_cap; h; h = h->next) {
1607 if (s->rsp_cap[h->index] != NULL)
1608 pool_free_to(h->pool, s->rsp_cap[h->index]);
1609 }
1610 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1611 }
1612 if (s->req_cap != NULL) {
1613 struct cap_hdr *h;
1614 for (h = s->proxy->req_cap; h; h = h->next) {
1615 if (s->req_cap[h->index] != NULL)
1616 pool_free_to(h->pool, s->req_cap[h->index]);
1617 }
1618 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1619 }
1620
willy tarreaua1598082005-12-17 13:08:06 +01001621 if (s->logs.uri)
1622 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001623 if (s->logs.cli_cookie)
1624 pool_free(capture, s->logs.cli_cookie);
1625 if (s->logs.srv_cookie)
1626 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001627
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628 pool_free(session, s);
1629}
1630
willy tarreau0f7af912005-12-17 12:21:26 +01001631
1632/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001633 * This function tries to find a running server for the proxy <px>. A first
1634 * pass looks for active servers, and if none is found, a second pass also
1635 * looks for backup servers.
1636 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1637 */
1638static inline struct server *find_server(struct proxy *px) {
1639 struct server *srv = px->cursrv;
1640 int ignore_backup = 1;
1641
1642 do {
1643 do {
1644 if (srv == NULL)
1645 srv = px->srv;
1646 if (srv->state & SRV_RUNNING
1647 && !((srv->state & SRV_BACKUP) && ignore_backup))
1648 return srv;
1649 srv = srv->next;
1650 } while (srv != px->cursrv);
1651 } while (ignore_backup--);
1652 return NULL;
1653}
1654
1655/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656 * This function initiates a connection to the current server (s->srv) if (s->direct)
1657 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001658 * it's OK, -1 if it's impossible.
1659 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001660int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001661 int fd;
1662
willy tarreau12350152005-12-18 01:03:27 +01001663#ifdef DEBUG_FULL
1664 fprintf(stderr,"connect_server : s=%p\n",s);
1665#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001666
willy tarreaue39cd132005-12-17 13:00:18 +01001667 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001668 s->srv_addr = s->srv->addr;
1669 }
1670 else if (s->proxy->options & PR_O_BALANCE) {
1671 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001672 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001673
willy tarreau8337c6b2005-12-17 13:41:01 +01001674 srv = find_server(s->proxy);
1675
1676 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001677 return -1;
1678
willy tarreau8337c6b2005-12-17 13:41:01 +01001679 s->srv_addr = srv->addr;
1680 s->srv = srv;
1681 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001682 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001683 else /* unknown balancing algorithm */
1684 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001685 }
willy tarreaua1598082005-12-17 13:08:06 +01001686 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001687 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001688 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001689 }
1690 else if (s->proxy->options & PR_O_TRANSP) {
1691 /* in transparent mode, use the original dest addr if no dispatch specified */
1692 int salen = sizeof(struct sockaddr_in);
1693 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1694 qfprintf(stderr, "Cannot get original server address.\n");
1695 return -1;
1696 }
1697 }
willy tarreau0f7af912005-12-17 12:21:26 +01001698
willy tarreaua41a8b42005-12-17 14:02:24 +01001699 /* if this server remaps proxied ports, we'll use
1700 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001701 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001702 struct sockaddr_in sockname;
1703 int namelen;
1704
1705 namelen = sizeof(sockname);
1706 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1707 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1708 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1709 }
1710
willy tarreau0f7af912005-12-17 12:21:26 +01001711 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001712 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001713 return -1;
1714 }
1715
willy tarreau9fe663a2005-12-17 13:02:59 +01001716 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001717 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1718 close(fd);
1719 return -1;
1720 }
1721
willy tarreau0f7af912005-12-17 12:21:26 +01001722 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1723 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001724 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001725 close(fd);
1726 return -1;
1727 }
1728
willy tarreau0174f312005-12-18 01:02:42 +01001729 /* allow specific binding :
1730 * - server-specific at first
1731 * - proxy-specific next
1732 */
1733 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1734 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1735 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1736 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1737 s->proxy->id, s->srv->id);
1738 close(fd);
1739 return -1;
1740 }
1741 }
1742 else if (s->proxy->options & PR_O_BIND_SRC) {
1743 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1744 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1745 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1746 close(fd);
1747 return -1;
1748 }
willy tarreaua1598082005-12-17 13:08:06 +01001749 }
1750
willy tarreau0f7af912005-12-17 12:21:26 +01001751 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1752 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001753 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001754 close(fd);
1755 return -1;
1756 }
1757 else if (errno != EALREADY && errno != EISCONN) {
1758 close(fd);
1759 return -1;
1760 }
1761 }
1762
willy tarreau5cbea6f2005-12-17 12:48:26 +01001763 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001764 fdtab[fd].read = &event_srv_read;
1765 fdtab[fd].write = &event_srv_write;
1766 fdtab[fd].state = FD_STCONN; /* connection in progress */
1767
1768 FD_SET(fd, StaticWriteEvent); /* for connect status */
1769
1770 fd_insert(fd);
1771
1772 if (s->proxy->contimeout)
1773 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1774 else
1775 tv_eternity(&s->cnexpire);
1776 return 0;
1777}
1778
1779/*
1780 * this function is called on a read event from a client socket.
1781 * It returns 0.
1782 */
1783int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001784 struct task *t = fdtab[fd].owner;
1785 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001786 struct buffer *b = s->req;
1787 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001788
willy tarreau12350152005-12-18 01:03:27 +01001789#ifdef DEBUG_FULL
1790 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1791#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001792
willy tarreau0f7af912005-12-17 12:21:26 +01001793 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001794 while (1) {
1795 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1796 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001797 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001798 }
1799 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001800 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001801 }
1802 else {
1803 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001804 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1805 * since it means that the rewrite protection has been removed. This
1806 * implies that the if statement can be removed.
1807 */
1808 if (max > b->rlim - b->data)
1809 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001810 }
1811
1812 if (max == 0) { /* not anymore room to store data */
1813 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001814 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001815 }
1816
willy tarreau3242e862005-12-17 12:27:53 +01001817#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001818 {
1819 int skerr, lskerr;
1820
1821 lskerr = sizeof(skerr);
1822 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1823 if (skerr)
1824 ret = -1;
1825 else
1826 ret = recv(fd, b->r, max, 0);
1827 }
willy tarreau3242e862005-12-17 12:27:53 +01001828#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001829 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001830#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001831 if (ret > 0) {
1832 b->r += ret;
1833 b->l += ret;
1834 s->res_cr = RES_DATA;
1835
1836 if (b->r == b->data + BUFSIZE) {
1837 b->r = b->data; /* wrap around the buffer */
1838 }
willy tarreaua1598082005-12-17 13:08:06 +01001839
1840 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001841 /* we hope to read more data or to get a close on next round */
1842 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001843 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 else if (ret == 0) {
1845 s->res_cr = RES_NULL;
1846 break;
1847 }
1848 else if (errno == EAGAIN) {/* ignore EAGAIN */
1849 break;
1850 }
1851 else {
1852 s->res_cr = RES_ERROR;
1853 fdtab[fd].state = FD_STERROR;
1854 break;
1855 }
1856 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001857 }
1858 else {
1859 s->res_cr = RES_ERROR;
1860 fdtab[fd].state = FD_STERROR;
1861 }
1862
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001864 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001865 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1866 else
1867 tv_eternity(&s->crexpire);
1868
1869 task_wakeup(&rq, t);
1870 }
willy tarreau0f7af912005-12-17 12:21:26 +01001871
willy tarreau0f7af912005-12-17 12:21:26 +01001872 return 0;
1873}
1874
1875
1876/*
1877 * this function is called on a read event from a server socket.
1878 * It returns 0.
1879 */
1880int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001881 struct task *t = fdtab[fd].owner;
1882 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001883 struct buffer *b = s->rep;
1884 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001885
willy tarreau12350152005-12-18 01:03:27 +01001886#ifdef DEBUG_FULL
1887 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1888#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001889
willy tarreau0f7af912005-12-17 12:21:26 +01001890 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001891 while (1) {
1892 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1893 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001894 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001895 }
1896 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001897 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001898 }
1899 else {
1900 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001901 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1902 * since it means that the rewrite protection has been removed. This
1903 * implies that the if statement can be removed.
1904 */
1905 if (max > b->rlim - b->data)
1906 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001907 }
1908
1909 if (max == 0) { /* not anymore room to store data */
1910 FD_CLR(fd, StaticReadEvent);
1911 break;
1912 }
1913
willy tarreau3242e862005-12-17 12:27:53 +01001914#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001915 {
1916 int skerr, lskerr;
1917
1918 lskerr = sizeof(skerr);
1919 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1920 if (skerr)
1921 ret = -1;
1922 else
1923 ret = recv(fd, b->r, max, 0);
1924 }
willy tarreau3242e862005-12-17 12:27:53 +01001925#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001926 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001927#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001928 if (ret > 0) {
1929 b->r += ret;
1930 b->l += ret;
1931 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001932
willy tarreau5cbea6f2005-12-17 12:48:26 +01001933 if (b->r == b->data + BUFSIZE) {
1934 b->r = b->data; /* wrap around the buffer */
1935 }
willy tarreaua1598082005-12-17 13:08:06 +01001936
1937 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001938 /* we hope to read more data or to get a close on next round */
1939 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001940 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001941 else if (ret == 0) {
1942 s->res_sr = RES_NULL;
1943 break;
1944 }
1945 else if (errno == EAGAIN) {/* ignore EAGAIN */
1946 break;
1947 }
1948 else {
1949 s->res_sr = RES_ERROR;
1950 fdtab[fd].state = FD_STERROR;
1951 break;
1952 }
1953 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001954 }
1955 else {
1956 s->res_sr = RES_ERROR;
1957 fdtab[fd].state = FD_STERROR;
1958 }
1959
willy tarreau5cbea6f2005-12-17 12:48:26 +01001960 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001961 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001962 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1963 else
1964 tv_eternity(&s->srexpire);
1965
1966 task_wakeup(&rq, t);
1967 }
willy tarreau0f7af912005-12-17 12:21:26 +01001968
willy tarreau0f7af912005-12-17 12:21:26 +01001969 return 0;
1970}
1971
1972/*
1973 * this function is called on a write event from a client socket.
1974 * It returns 0.
1975 */
1976int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001977 struct task *t = fdtab[fd].owner;
1978 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001979 struct buffer *b = s->rep;
1980 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001981
willy tarreau12350152005-12-18 01:03:27 +01001982#ifdef DEBUG_FULL
1983 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1984#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001985
1986 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001987 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001988 // max = BUFSIZE; BUG !!!!
1989 max = 0;
1990 }
1991 else if (b->r > b->w) {
1992 max = b->r - b->w;
1993 }
1994 else
1995 max = b->data + BUFSIZE - b->w;
1996
willy tarreau0f7af912005-12-17 12:21:26 +01001997 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001998#ifndef MSG_NOSIGNAL
1999 int skerr, lskerr;
2000#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002001
2002 if (max == 0) {
2003 s->res_cw = RES_NULL;
2004 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002005 tv_eternity(&s->cwexpire);
2006 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002007 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002008 }
2009
willy tarreau3242e862005-12-17 12:27:53 +01002010#ifndef MSG_NOSIGNAL
2011 lskerr=sizeof(skerr);
2012 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2013 if (skerr)
2014 ret = -1;
2015 else
2016 ret = send(fd, b->w, max, MSG_DONTWAIT);
2017#else
willy tarreau0f7af912005-12-17 12:21:26 +01002018 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002019#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002020
2021 if (ret > 0) {
2022 b->l -= ret;
2023 b->w += ret;
2024
2025 s->res_cw = RES_DATA;
2026
2027 if (b->w == b->data + BUFSIZE) {
2028 b->w = b->data; /* wrap around the buffer */
2029 }
2030 }
2031 else if (ret == 0) {
2032 /* nothing written, just make as if we were never called */
2033// s->res_cw = RES_NULL;
2034 return 0;
2035 }
2036 else if (errno == EAGAIN) /* ignore EAGAIN */
2037 return 0;
2038 else {
2039 s->res_cw = RES_ERROR;
2040 fdtab[fd].state = FD_STERROR;
2041 }
2042 }
2043 else {
2044 s->res_cw = RES_ERROR;
2045 fdtab[fd].state = FD_STERROR;
2046 }
2047
willy tarreaub1ff9db2005-12-17 13:51:03 +01002048 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002049 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002050 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2051 s->crexpire = s->cwexpire;
2052 }
willy tarreau0f7af912005-12-17 12:21:26 +01002053 else
2054 tv_eternity(&s->cwexpire);
2055
willy tarreau5cbea6f2005-12-17 12:48:26 +01002056 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002057 return 0;
2058}
2059
2060
2061/*
2062 * this function is called on a write event from a server socket.
2063 * It returns 0.
2064 */
2065int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002066 struct task *t = fdtab[fd].owner;
2067 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002068 struct buffer *b = s->req;
2069 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002070
willy tarreau12350152005-12-18 01:03:27 +01002071#ifdef DEBUG_FULL
2072 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2073#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002074
2075 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002076 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002077 // max = BUFSIZE; BUG !!!!
2078 max = 0;
2079 }
2080 else if (b->r > b->w) {
2081 max = b->r - b->w;
2082 }
2083 else
2084 max = b->data + BUFSIZE - b->w;
2085
willy tarreau0f7af912005-12-17 12:21:26 +01002086 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002087#ifndef MSG_NOSIGNAL
2088 int skerr, lskerr;
2089#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002090 if (max == 0) {
2091 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002092 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002093 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002094 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002095 tv_eternity(&s->swexpire);
2096 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002097 return 0;
2098 }
2099
willy tarreauef900ab2005-12-17 12:52:52 +01002100
willy tarreau3242e862005-12-17 12:27:53 +01002101#ifndef MSG_NOSIGNAL
2102 lskerr=sizeof(skerr);
2103 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2104 if (skerr)
2105 ret = -1;
2106 else
2107 ret = send(fd, b->w, max, MSG_DONTWAIT);
2108#else
willy tarreau0f7af912005-12-17 12:21:26 +01002109 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002110#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002111 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002112 if (ret > 0) {
2113 b->l -= ret;
2114 b->w += ret;
2115
2116 s->res_sw = RES_DATA;
2117
2118 if (b->w == b->data + BUFSIZE) {
2119 b->w = b->data; /* wrap around the buffer */
2120 }
2121 }
2122 else if (ret == 0) {
2123 /* nothing written, just make as if we were never called */
2124 // s->res_sw = RES_NULL;
2125 return 0;
2126 }
2127 else if (errno == EAGAIN) /* ignore EAGAIN */
2128 return 0;
2129 else {
2130 s->res_sw = RES_ERROR;
2131 fdtab[fd].state = FD_STERROR;
2132 }
2133 }
2134 else {
2135 s->res_sw = RES_ERROR;
2136 fdtab[fd].state = FD_STERROR;
2137 }
2138
willy tarreaub1ff9db2005-12-17 13:51:03 +01002139 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002140 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002141 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2142 s->srexpire = s->swexpire;
2143 }
willy tarreau0f7af912005-12-17 12:21:26 +01002144 else
2145 tv_eternity(&s->swexpire);
2146
willy tarreau5cbea6f2005-12-17 12:48:26 +01002147 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002148 return 0;
2149}
2150
2151
2152/*
willy tarreaue39cd132005-12-17 13:00:18 +01002153 * returns a message to the client ; the connection is shut down for read,
2154 * and the request is cleared so that no server connection can be initiated.
2155 * The client must be in a valid state for this (HEADER, DATA ...).
2156 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002157 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002158 */
2159void client_retnclose(struct session *s, int len, const char *msg) {
2160 FD_CLR(s->cli_fd, StaticReadEvent);
2161 FD_SET(s->cli_fd, StaticWriteEvent);
2162 tv_eternity(&s->crexpire);
2163 shutdown(s->cli_fd, SHUT_RD);
2164 s->cli_state = CL_STSHUTR;
2165 strcpy(s->rep->data, msg);
2166 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002167 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002168 s->rep->r += len;
2169 s->req->l = 0;
2170}
2171
2172
2173/*
2174 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002175 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002176 */
2177void client_return(struct session *s, int len, const char *msg) {
2178 strcpy(s->rep->data, msg);
2179 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002180 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002181 s->rep->r += len;
2182 s->req->l = 0;
2183}
2184
willy tarreau9fe663a2005-12-17 13:02:59 +01002185/*
2186 * send a log for the session when we have enough info about it
2187 */
2188void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002189 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002190 struct proxy *p = s->proxy;
2191 int log;
2192 char *uri;
2193 char *pxid;
2194 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002195 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002196
2197 /* This is a first attempt at a better logging system.
2198 * For now, we rely on send_log() to provide the date, although it obviously
2199 * is the date of the log and not of the request, and most fields are not
2200 * computed.
2201 */
2202
willy tarreaua1598082005-12-17 13:08:06 +01002203 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002204
willy tarreau8a86dbf2005-12-18 00:45:59 +01002205 if (s->cli_addr.ss_family == AF_INET)
2206 inet_ntop(AF_INET,
2207 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2208 pn, sizeof(pn));
2209 else
2210 inet_ntop(AF_INET6,
2211 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2212 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002213
willy tarreauc1cae632005-12-17 14:12:23 +01002214 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002215 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002216 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002217
willy tarreauc1cae632005-12-17 14:12:23 +01002218 tm = localtime(&s->logs.tv_accept.tv_sec);
2219 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002220 char tmpline[MAX_SYSLOG_LEN], *h;
2221 int hdr;
2222
2223 h = tmpline;
2224 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2225 *(h++) = ' ';
2226 *(h++) = '{';
2227 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2228 if (hdr)
2229 *(h++) = '|';
2230 if (s->req_cap[hdr] != NULL)
2231 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2232 }
2233 *(h++) = '}';
2234 }
2235
2236 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2237 *(h++) = ' ';
2238 *(h++) = '{';
2239 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2240 if (hdr)
2241 *(h++) = '|';
2242 if (s->rsp_cap[hdr] != NULL)
2243 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2244 }
2245 *(h++) = '}';
2246 }
2247
2248 if (h < tmpline + sizeof(tmpline) - 4) {
2249 *(h++) = ' ';
2250 *(h++) = '"';
2251 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2252 *(h++) = '"';
2253 }
2254 *h = '\0';
2255
2256 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%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002257 pn,
2258 (s->cli_addr.ss_family == AF_INET) ?
2259 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2260 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002261 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2262 tm->tm_hour, tm->tm_min, tm->tm_sec,
2263 pxid, srv,
2264 s->logs.t_request,
2265 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2266 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002267 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2268 s->logs.status,
2269 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002270 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2271 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002272 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2273 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2274 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2275 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau4302f492005-12-18 01:00:37 +01002276 tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002277 }
2278 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002279 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002280 pn,
2281 (s->cli_addr.ss_family == AF_INET) ?
2282 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2283 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002284 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2285 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002286 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002287 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002288 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2289 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002290 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002291 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002292 }
2293
2294 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002295}
2296
willy tarreaue39cd132005-12-17 13:00:18 +01002297
2298/*
willy tarreau0f7af912005-12-17 12:21:26 +01002299 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300 * to an accept. It tries to accept as many connections as possible.
2301 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002302 */
2303int event_accept(int fd) {
2304 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 struct session *s;
2306 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002307 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002308
willy tarreau5cbea6f2005-12-17 12:48:26 +01002309 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002310 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 int laddr = sizeof(addr);
2312 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2313 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002314
willy tarreau5cbea6f2005-12-17 12:48:26 +01002315 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2316 Alert("out of memory in event_accept().\n");
2317 FD_CLR(fd, StaticReadEvent);
2318 p->state = PR_STIDLE;
2319 close(cfd);
2320 return 0;
2321 }
willy tarreau0f7af912005-12-17 12:21:26 +01002322
willy tarreau5cbea6f2005-12-17 12:48:26 +01002323 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2324 Alert("out of memory in event_accept().\n");
2325 FD_CLR(fd, StaticReadEvent);
2326 p->state = PR_STIDLE;
2327 close(cfd);
2328 pool_free(session, s);
2329 return 0;
2330 }
willy tarreau0f7af912005-12-17 12:21:26 +01002331
willy tarreau5cbea6f2005-12-17 12:48:26 +01002332 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002333 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002334 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2335 close(cfd);
2336 pool_free(task, t);
2337 pool_free(session, s);
2338 return 0;
2339 }
willy tarreau0f7af912005-12-17 12:21:26 +01002340
willy tarreau5cbea6f2005-12-17 12:48:26 +01002341 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2342 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2343 (char *) &one, sizeof(one)) == -1)) {
2344 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2345 close(cfd);
2346 pool_free(task, t);
2347 pool_free(session, s);
2348 return 0;
2349 }
willy tarreau0f7af912005-12-17 12:21:26 +01002350
willy tarreau9fe663a2005-12-17 13:02:59 +01002351 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2352 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2353 t->state = TASK_IDLE;
2354 t->process = process_session;
2355 t->context = s;
2356
2357 s->task = t;
2358 s->proxy = p;
2359 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2360 s->srv_state = SV_STIDLE;
2361 s->req = s->rep = NULL; /* will be allocated later */
2362 s->flags = 0;
willy tarreau97f58572005-12-18 00:53:44 +01002363
willy tarreau9fe663a2005-12-17 13:02:59 +01002364 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2365 s->cli_fd = cfd;
2366 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002367 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002368 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002369
2370 s->logs.logwait = p->to_log;
2371 s->logs.tv_accept = now;
2372 s->logs.t_request = -1;
2373 s->logs.t_connect = -1;
2374 s->logs.t_data = -1;
2375 s->logs.t_close = 0;
2376 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002377 s->logs.cli_cookie = NULL;
2378 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002379 s->logs.status = -1;
2380 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002381
willy tarreau2f6ba652005-12-17 13:57:42 +01002382 s->uniq_id = totalconn;
2383
willy tarreau4302f492005-12-18 01:00:37 +01002384 if (p->nb_req_cap > 0) {
2385 if ((s->req_cap =
2386 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2387 == NULL) { /* no memory */
2388 close(cfd); /* nothing can be done for this fd without memory */
2389 pool_free(task, t);
2390 pool_free(session, s);
2391 return 0;
2392 }
2393 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2394 }
2395 else
2396 s->req_cap = NULL;
2397
2398 if (p->nb_rsp_cap > 0) {
2399 if ((s->rsp_cap =
2400 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2401 == NULL) { /* no memory */
2402 if (s->req_cap != NULL)
2403 pool_free_to(p->req_cap_pool, s->req_cap);
2404 close(cfd); /* nothing can be done for this fd without memory */
2405 pool_free(task, t);
2406 pool_free(session, s);
2407 return 0;
2408 }
2409 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2410 }
2411 else
2412 s->rsp_cap = NULL;
2413
willy tarreau5cbea6f2005-12-17 12:48:26 +01002414 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2415 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002416 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002417 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002418
willy tarreau5cbea6f2005-12-17 12:48:26 +01002419 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002420 if (addr.ss_family != AF_INET ||
2421 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002422 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002423
willy tarreau9fe663a2005-12-17 13:02:59 +01002424 if (p->to_log) {
2425 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002426 if (s->logs.logwait & LW_CLIP)
2427 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002428 sess_log(s);
2429 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002430 else if (s->cli_addr.ss_family == AF_INET) {
2431 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2432 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2433 sn, sizeof(sn)) &&
2434 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2435 pn, sizeof(pn))) {
2436 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2437 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2438 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2439 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2440 }
2441 }
2442 else {
2443 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2444 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2445 sn, sizeof(sn)) &&
2446 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2447 pn, sizeof(pn))) {
2448 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2449 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2450 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2451 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2452 }
2453 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002454 }
willy tarreau0f7af912005-12-17 12:21:26 +01002455
willy tarreau982249e2005-12-18 00:57:06 +01002456 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002457 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002458 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002459 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002460 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002461 if (addr.ss_family != AF_INET ||
2462 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002463 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002464
willy tarreau8a86dbf2005-12-18 00:45:59 +01002465 if (s->cli_addr.ss_family == AF_INET) {
2466 char pn[INET_ADDRSTRLEN];
2467 inet_ntop(AF_INET,
2468 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2469 pn, sizeof(pn));
2470
2471 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2472 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2473 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2474 }
2475 else {
2476 char pn[INET6_ADDRSTRLEN];
2477 inet_ntop(AF_INET6,
2478 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2479 pn, sizeof(pn));
2480
2481 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2482 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2483 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2484 }
2485
willy tarreauef900ab2005-12-17 12:52:52 +01002486 write(1, trash, len);
2487 }
willy tarreau0f7af912005-12-17 12:21:26 +01002488
willy tarreau5cbea6f2005-12-17 12:48:26 +01002489 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002490 if (s->rsp_cap != NULL)
2491 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2492 if (s->req_cap != NULL)
2493 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002494 close(cfd); /* nothing can be done for this fd without memory */
2495 pool_free(task, t);
2496 pool_free(session, s);
2497 return 0;
2498 }
willy tarreau4302f492005-12-18 01:00:37 +01002499
willy tarreau5cbea6f2005-12-17 12:48:26 +01002500 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002501 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002502 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2503 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002504 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002505 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002506
willy tarreau5cbea6f2005-12-17 12:48:26 +01002507 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2508 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002509 if (s->rsp_cap != NULL)
2510 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2511 if (s->req_cap != NULL)
2512 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002513 close(cfd); /* nothing can be done for this fd without memory */
2514 pool_free(task, t);
2515 pool_free(session, s);
2516 return 0;
2517 }
2518 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002519 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002520 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 +01002521
willy tarreau5cbea6f2005-12-17 12:48:26 +01002522 fdtab[cfd].read = &event_cli_read;
2523 fdtab[cfd].write = &event_cli_write;
2524 fdtab[cfd].owner = t;
2525 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002526
willy tarreau5cbea6f2005-12-17 12:48:26 +01002527 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002528 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2529 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2530 else
2531 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002532 }
2533 else {
2534 FD_SET(cfd, StaticReadEvent);
2535 }
2536
2537 fd_insert(cfd);
2538
2539 tv_eternity(&s->cnexpire);
2540 tv_eternity(&s->srexpire);
2541 tv_eternity(&s->swexpire);
2542 tv_eternity(&s->cwexpire);
2543
2544 if (s->proxy->clitimeout)
2545 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2546 else
2547 tv_eternity(&s->crexpire);
2548
2549 t->expire = s->crexpire;
2550
2551 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002552
2553 if (p->mode != PR_MODE_HEALTH)
2554 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002555
2556 p->nbconn++;
2557 actconn++;
2558 totalconn++;
2559
2560 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2561 } /* end of while (p->nbconn < p->maxconn) */
2562 return 0;
2563}
willy tarreau0f7af912005-12-17 12:21:26 +01002564
willy tarreau0f7af912005-12-17 12:21:26 +01002565
willy tarreau5cbea6f2005-12-17 12:48:26 +01002566/*
2567 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002568 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2569 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 * or -1 if an error occured.
2571 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002572int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002573 struct task *t = fdtab[fd].owner;
2574 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002575
willy tarreau5cbea6f2005-12-17 12:48:26 +01002576 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002577 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002578 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002579 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002580 if (skerr)
2581 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002582 else {
2583 if (s->proxy->options & PR_O_HTTP_CHK) {
2584 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002585 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002586 * so we'll send the request, and won't wake the checker up now.
2587 */
2588#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002589 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002590#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002591 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002592#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002593 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002594 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2595 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2596 return 0;
2597 }
2598 else
2599 s->result = -1;
2600 }
2601 else {
2602 /* good TCP connection is enough */
2603 s->result = 1;
2604 }
2605 }
2606
2607 task_wakeup(&rq, t);
2608 return 0;
2609}
2610
willy tarreau0f7af912005-12-17 12:21:26 +01002611
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002612/*
2613 * This function is used only for server health-checks. It handles
2614 * the server's reply to an HTTP request. It returns 1 if the server replies
2615 * 2xx or 3xx (valid responses), or -1 in other cases.
2616 */
2617int event_srv_chk_r(int fd) {
2618 char reply[64];
2619 int len;
2620 struct task *t = fdtab[fd].owner;
2621 struct server *s = t->context;
2622
2623 int skerr, lskerr;
2624 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002625
2626 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002627#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002628 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2629 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002630 len = recv(fd, reply, sizeof(reply), 0);
2631#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002632 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2633 * but the connection was closed on the remote end. Fortunately, recv still
2634 * works correctly and we don't need to do the getsockopt() on linux.
2635 */
2636 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002637#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002638 if ((len >= sizeof("HTTP/1.0 000")) &&
2639 !memcmp(reply, "HTTP/1.", 7) &&
2640 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2641 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002642
2643 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002644 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002645 return 0;
2646}
2647
2648
2649/*
2650 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2651 * and moves <end> just after the end of <str>.
2652 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2653 * the shift value (positive or negative) is returned.
2654 * If there's no space left, the move is not done.
2655 *
2656 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002657int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002658 int delta;
2659 int len;
2660
2661 len = strlen(str);
2662 delta = len - (end - pos);
2663
2664 if (delta + b->r >= b->data + BUFSIZE)
2665 return 0; /* no space left */
2666
2667 /* first, protect the end of the buffer */
2668 memmove(end + delta, end, b->data + b->l - end);
2669
2670 /* now, copy str over pos */
2671 memcpy(pos, str,len);
2672
willy tarreau5cbea6f2005-12-17 12:48:26 +01002673 /* we only move data after the displaced zone */
2674 if (b->r > pos) b->r += delta;
2675 if (b->w > pos) b->w += delta;
2676 if (b->h > pos) b->h += delta;
2677 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002678 b->l += delta;
2679
2680 return delta;
2681}
2682
willy tarreau8337c6b2005-12-17 13:41:01 +01002683/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002684 * len is 0.
2685 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002686int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002687 int delta;
2688
2689 delta = len - (end - pos);
2690
2691 if (delta + b->r >= b->data + BUFSIZE)
2692 return 0; /* no space left */
2693
2694 /* first, protect the end of the buffer */
2695 memmove(end + delta, end, b->data + b->l - end);
2696
2697 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002698 if (len)
2699 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002700
willy tarreau5cbea6f2005-12-17 12:48:26 +01002701 /* we only move data after the displaced zone */
2702 if (b->r > pos) b->r += delta;
2703 if (b->w > pos) b->w += delta;
2704 if (b->h > pos) b->h += delta;
2705 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002706 b->l += delta;
2707
2708 return delta;
2709}
2710
2711
2712int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2713 char *old_dst = dst;
2714
2715 while (*str) {
2716 if (*str == '\\') {
2717 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002718 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002719 int len, num;
2720
2721 num = *str - '0';
2722 str++;
2723
willy tarreau8a86dbf2005-12-18 00:45:59 +01002724 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002725 len = matches[num].rm_eo - matches[num].rm_so;
2726 memcpy(dst, src + matches[num].rm_so, len);
2727 dst += len;
2728 }
2729
2730 }
2731 else if (*str == 'x') {
2732 unsigned char hex1, hex2;
2733 str++;
2734
willy tarreauc1f47532005-12-18 01:08:26 +01002735 hex1 = toupper(*str++) - '0';
2736 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002737
2738 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2739 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2740 *dst++ = (hex1<<4) + hex2;
2741 }
2742 else
2743 *dst++ = *str++;
2744 }
2745 else
2746 *dst++ = *str++;
2747 }
2748 *dst = 0;
2749 return dst - old_dst;
2750}
2751
willy tarreauc1f47532005-12-18 01:08:26 +01002752static int ishex(char s)
2753{
2754 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
2755}
2756
2757/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
2758char *check_replace_string(char *str)
2759{
2760 char *err = NULL;
2761 while (*str) {
2762 if (*str == '\\') {
2763 err = str; /* in case of a backslash, we return the pointer to it */
2764 str++;
2765 if (!*str)
2766 return err;
2767 else if (isdigit((int)*str))
2768 err = NULL;
2769 else if (*str == 'x') {
2770 str++;
2771 if (!ishex(*str))
2772 return err;
2773 str++;
2774 if (!ishex(*str))
2775 return err;
2776 err = NULL;
2777 }
2778 else {
2779 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
2780 err = NULL;
2781 }
2782 }
2783 str++;
2784 }
2785 return err;
2786}
2787
2788
willy tarreau9fe663a2005-12-17 13:02:59 +01002789
willy tarreau0f7af912005-12-17 12:21:26 +01002790/*
2791 * manages the client FSM and its socket. BTW, it also tries to handle the
2792 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2793 * 0 else.
2794 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002796 int s = t->srv_state;
2797 int c = t->cli_state;
2798 struct buffer *req = t->req;
2799 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01002800 int method_checked = 0;
2801 appsess *asession_temp = NULL;
2802 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01002803
willy tarreau750a4722005-12-17 13:21:24 +01002804#ifdef DEBUG_FULL
2805 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2806#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002807 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2808 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2809 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2810 //);
2811 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002812 /* now parse the partial (or complete) headers */
2813 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2814 char *ptr;
2815 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01002816 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01002817
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002819
willy tarreau0f7af912005-12-17 12:21:26 +01002820 /* look for the end of the current header */
2821 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2822 ptr++;
2823
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002825 int line, len;
2826 /* we can only get here after an end of headers */
2827 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002828
willy tarreaue39cd132005-12-17 13:00:18 +01002829 if (t->flags & SN_CLDENY) {
2830 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002831 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002832 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002833 if (!(t->flags & SN_ERR_MASK))
2834 t->flags |= SN_ERR_PRXCOND;
2835 if (!(t->flags & SN_FINST_MASK))
2836 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002837 return 1;
2838 }
2839
willy tarreau5cbea6f2005-12-17 12:48:26 +01002840 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002841 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2842 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002843 }
willy tarreau0f7af912005-12-17 12:21:26 +01002844
willy tarreau9fe663a2005-12-17 13:02:59 +01002845 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002846 if (t->cli_addr.ss_family == AF_INET) {
2847 unsigned char *pn;
2848 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2849 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2850 pn[0], pn[1], pn[2], pn[3]);
2851 buffer_replace2(req, req->h, req->h, trash, len);
2852 }
2853 else if (t->cli_addr.ss_family == AF_INET6) {
2854 char pn[INET6_ADDRSTRLEN];
2855 inet_ntop(AF_INET6,
2856 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2857 pn, sizeof(pn));
2858 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2859 buffer_replace2(req, req->h, req->h, trash, len);
2860 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002861 }
2862
willy tarreau25c4ea52005-12-18 00:49:49 +01002863 /* add a "connection: close" line if needed */
2864 if (t->proxy->options & PR_O_HTTP_CLOSE)
2865 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2866
willy tarreau982249e2005-12-18 00:57:06 +01002867 if (!memcmp(req->data, "POST ", 5)) {
2868 /* this is a POST request, which is not cacheable by default */
2869 t->flags |= SN_POST;
2870 }
willy tarreaucd878942005-12-17 13:27:43 +01002871
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002873 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002874
willy tarreau750a4722005-12-17 13:21:24 +01002875 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002876 /* FIXME: we'll set the client in a wait state while we try to
2877 * connect to the server. Is this really needed ? wouldn't it be
2878 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002879 //FD_CLR(t->cli_fd, StaticReadEvent);
2880 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002881
2882 /* FIXME: if we break here (as up to 1.1.23), having the client
2883 * shutdown its connection can lead to an abort further.
2884 * it's better to either return 1 or even jump directly to the
2885 * data state which will save one schedule.
2886 */
2887 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002888
2889 if (!t->proxy->clitimeout ||
2890 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2891 /* If the client has no timeout, or if the server is not ready yet,
2892 * and we know for sure that it can expire, then it's cleaner to
2893 * disable the timeout on the client side so that too low values
2894 * cannot make the sessions abort too early.
2895 */
2896 tv_eternity(&t->crexpire);
2897
willy tarreau197e8ec2005-12-17 14:10:59 +01002898 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002899 }
willy tarreau0f7af912005-12-17 12:21:26 +01002900
willy tarreau5cbea6f2005-12-17 12:48:26 +01002901 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2902 if (ptr > req->r - 2) {
2903 /* this is a partial header, let's wait for more to come */
2904 req->lr = ptr;
2905 break;
2906 }
willy tarreau0f7af912005-12-17 12:21:26 +01002907
willy tarreau5cbea6f2005-12-17 12:48:26 +01002908 /* now we know that *ptr is either \r or \n,
2909 * and that there are at least 1 char after it.
2910 */
2911 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2912 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2913 else
2914 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002915
willy tarreau5cbea6f2005-12-17 12:48:26 +01002916 /*
2917 * now we know that we have a full header ; we can do whatever
2918 * we want with these pointers :
2919 * req->h = beginning of header
2920 * ptr = end of header (first \r or \n)
2921 * req->lr = beginning of next line (next rep->h)
2922 * req->r = end of data (not used at this stage)
2923 */
willy tarreau0f7af912005-12-17 12:21:26 +01002924
willy tarreau12350152005-12-18 01:03:27 +01002925 if (!method_checked && (t->proxy->appsession_name != NULL) &&
2926 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
2927 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
2928
2929 /* skip ; */
2930 request_line++;
2931
2932 /* look if we have a jsessionid */
2933
2934 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
2935
2936 /* skip jsessionid= */
2937 request_line += t->proxy->appsession_name_len + 1;
2938
2939 /* First try if we allready have an appsession */
2940 asession_temp = &local_asession;
2941
2942 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2943 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
2944 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
2945 return 0;
2946 }
2947
2948 /* Copy the sessionid */
2949 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
2950 asession_temp->sessid[t->proxy->appsession_len] = 0;
2951 asession_temp->serverid = NULL;
2952
2953 /* only do insert, if lookup fails */
2954 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
2955 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2956 Alert("Not enough memory process_cli():asession:calloc().\n");
2957 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
2958 return 0;
2959 }
2960 asession_temp->sessid = local_asession.sessid;
2961 asession_temp->serverid = local_asession.serverid;
2962 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
2963 } /* end if(chtbl_lookup()) */
2964 else{
2965 /*free wasted memory;*/
2966 pool_free_to(apools.sessid, local_asession.sessid);
2967 }
2968
2969 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
2970 asession_temp->request_count++;
2971
2972#if defined(DEBUG_HASH)
2973 print_table(&(t->proxy->htbl_proxy));
2974#endif
2975
2976 if (asession_temp->serverid == NULL) {
2977 Alert("Found Application Session without matching server.\n");
2978 } else {
2979 struct server *srv = t->proxy->srv;
2980 while (srv) {
2981 if (strcmp(srv->id, asession_temp->serverid) == 0) {
2982 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
2983 /* we found the server and it's usable */
2984 t->flags &= ~SN_CK_MASK;
2985 t->flags |= SN_CK_VALID | SN_DIRECT;
2986 t->srv = srv;
2987 break;
2988 }else {
2989 t->flags &= ~SN_CK_MASK;
2990 t->flags |= SN_CK_DOWN;
2991 }
2992 }/* end if(strcmp()) */
2993 srv = srv->next;
2994 }/* end while(srv) */
2995 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreau12350152005-12-18 01:03:27 +01002996 }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
2997 else {
2998 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
2999 }
willy tarreau598da412005-12-18 01:07:29 +01003000 method_checked = 1;
willy tarreau12350152005-12-18 01:03:27 +01003001 }/* end if(!method_checked ...) */
3002 else{
3003 //printf("No Methode-Header with Session-String\n");
3004 }
3005
willy tarreau8337c6b2005-12-17 13:41:01 +01003006 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003007 /* we have a complete HTTP request that we must log */
3008 int urilen;
3009
willy tarreaua1598082005-12-17 13:08:06 +01003010 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003011 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003012 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003013 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003014 if (!(t->flags & SN_ERR_MASK))
3015 t->flags |= SN_ERR_PRXCOND;
3016 if (!(t->flags & SN_FINST_MASK))
3017 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003018 return 1;
3019 }
3020
3021 urilen = ptr - req->h;
3022 if (urilen >= REQURI_LEN)
3023 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003024 memcpy(t->logs.uri, req->h, urilen);
3025 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003026
willy tarreaua1598082005-12-17 13:08:06 +01003027 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003028 sess_log(t);
3029 }
willy tarreau4302f492005-12-18 01:00:37 +01003030 else if (t->logs.logwait & LW_REQHDR) {
3031 struct cap_hdr *h;
3032 int len;
3033 for (h = t->proxy->req_cap; h; h = h->next) {
3034 if ((h->namelen + 2 <= ptr - req->h) &&
3035 (req->h[h->namelen] == ':') &&
3036 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3037
3038 if (t->req_cap[h->index] == NULL)
3039 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3040
3041 len = ptr - (req->h + h->namelen + 2);
3042 if (len > h->len)
3043 len = h->len;
3044
3045 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3046 t->req_cap[h->index][len]=0;
3047 }
3048 }
3049
3050 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003051
willy tarreau5cbea6f2005-12-17 12:48:26 +01003052 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003053
willy tarreau982249e2005-12-18 00:57:06 +01003054 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003055 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003056 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 +01003057 max = ptr - req->h;
3058 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003059 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003060 trash[len++] = '\n';
3061 write(1, trash, len);
3062 }
willy tarreau0f7af912005-12-17 12:21:26 +01003063
willy tarreau25c4ea52005-12-18 00:49:49 +01003064
3065 /* remove "connection: " if needed */
3066 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3067 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3068 delete_header = 1;
3069 }
3070
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003072 if (!delete_header && t->proxy->req_exp != NULL
3073 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003074 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003075 char term;
3076
3077 term = *ptr;
3078 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003079 exp = t->proxy->req_exp;
3080 do {
3081 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3082 switch (exp->action) {
3083 case ACT_ALLOW:
3084 if (!(t->flags & SN_CLDENY))
3085 t->flags |= SN_CLALLOW;
3086 break;
3087 case ACT_REPLACE:
3088 if (!(t->flags & SN_CLDENY)) {
3089 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3090 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3091 }
3092 break;
3093 case ACT_REMOVE:
3094 if (!(t->flags & SN_CLDENY))
3095 delete_header = 1;
3096 break;
3097 case ACT_DENY:
3098 if (!(t->flags & SN_CLALLOW))
3099 t->flags |= SN_CLDENY;
3100 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003101 case ACT_PASS: /* we simply don't deny this one */
3102 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003103 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003105 }
willy tarreaue39cd132005-12-17 13:00:18 +01003106 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003107 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003108 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109
willy tarreau240afa62005-12-17 13:14:35 +01003110 /* Now look for cookies. Conforming to RFC2109, we have to support
3111 * attributes whose name begin with a '$', and associate them with
3112 * the right cookie, if we want to delete this cookie.
3113 * So there are 3 cases for each cookie read :
3114 * 1) it's a special attribute, beginning with a '$' : ignore it.
3115 * 2) it's a server id cookie that we *MAY* want to delete : save
3116 * some pointers on it (last semi-colon, beginning of cookie...)
3117 * 3) it's an application cookie : we *MAY* have to delete a previous
3118 * "special" cookie.
3119 * At the end of loop, if a "special" cookie remains, we may have to
3120 * remove it. If no application cookie persists in the header, we
3121 * *MUST* delete it
3122 */
willy tarreau12350152005-12-18 01:03:27 +01003123 if (!delete_header &&
3124 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003125 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003126 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003128 char *del_colon, *del_cookie, *colon;
3129 int app_cookies;
3130
willy tarreau5cbea6f2005-12-17 12:48:26 +01003131 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003132 colon = p1;
3133 /* del_cookie == NULL => nothing to be deleted */
3134 del_colon = del_cookie = NULL;
3135 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003136
3137 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003138 /* skip spaces and colons, but keep an eye on these ones */
3139 while (p1 < ptr) {
3140 if (*p1 == ';' || *p1 == ',')
3141 colon = p1;
3142 else if (!isspace((int)*p1))
3143 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003145 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003146
3147 if (p1 == ptr)
3148 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003149
3150 /* p1 is at the beginning of the cookie name */
3151 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003152 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003153 p2++;
3154
3155 if (p2 == ptr)
3156 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003157
3158 p3 = p2 + 1; /* skips the '=' sign */
3159 if (p3 == ptr)
3160 break;
3161
willy tarreau240afa62005-12-17 13:14:35 +01003162 p4 = p3;
3163 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164 p4++;
3165
3166 /* here, we have the cookie name between p1 and p2,
3167 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003168 * we can process it :
3169 *
3170 * Cookie: NAME=VALUE;
3171 * | || || |
3172 * | || || +--> p4
3173 * | || |+-------> p3
3174 * | || +--------> p2
3175 * | |+------------> p1
3176 * | +-------------> colon
3177 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003178 */
3179
willy tarreau240afa62005-12-17 13:14:35 +01003180 if (*p1 == '$') {
3181 /* skip this one */
3182 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003183 else {
3184 /* first, let's see if we want to capture it */
3185 if (t->proxy->capture_name != NULL &&
3186 t->logs.cli_cookie == NULL &&
3187 (p4 - p1 >= t->proxy->capture_namelen) &&
3188 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3189 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003190
willy tarreau8337c6b2005-12-17 13:41:01 +01003191 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3192 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003193 } else {
3194 if (log_len > t->proxy->capture_len)
3195 log_len = t->proxy->capture_len;
3196 memcpy(t->logs.cli_cookie, p1, log_len);
3197 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003198 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003199 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003200
3201 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3202 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3203 /* Cool... it's the right one */
3204 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003205 char *delim;
3206
3207 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3208 * have the server ID betweek p3 and delim, and the original cookie between
3209 * delim+1 and p4. Otherwise, delim==p4 :
3210 *
3211 * Cookie: NAME=SRV~VALUE;
3212 * | || || | |
3213 * | || || | +--> p4
3214 * | || || +--------> delim
3215 * | || |+-----------> p3
3216 * | || +------------> p2
3217 * | |+----------------> p1
3218 * | +-----------------> colon
3219 * +------------------------> req->h
3220 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003221
willy tarreau0174f312005-12-18 01:02:42 +01003222 if (t->proxy->options & PR_O_COOK_PFX) {
3223 for (delim = p3; delim < p4; delim++)
3224 if (*delim == COOKIE_DELIM)
3225 break;
3226 }
3227 else
3228 delim = p4;
3229
3230
3231 /* Here, we'll look for the first running server which supports the cookie.
3232 * This allows to share a same cookie between several servers, for example
3233 * to dedicate backup servers to specific servers only.
3234 */
3235 while (srv) {
3236 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3237 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3238 /* we found the server and it's usable */
3239 t->flags &= ~SN_CK_MASK;
3240 t->flags |= SN_CK_VALID | SN_DIRECT;
3241 t->srv = srv;
3242 break;
willy tarreau12350152005-12-18 01:03:27 +01003243 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003244 /* we found a server, but it's down */
3245 t->flags &= ~SN_CK_MASK;
3246 t->flags |= SN_CK_DOWN;
3247 }
3248 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003249 srv = srv->next;
3250 }
3251
willy tarreau0174f312005-12-18 01:02:42 +01003252 if (!srv && !(t->flags & SN_CK_DOWN)) {
3253 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003254 t->flags &= ~SN_CK_MASK;
3255 t->flags |= SN_CK_INVALID;
3256 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003257
willy tarreau0174f312005-12-18 01:02:42 +01003258 /* depending on the cookie mode, we may have to either :
3259 * - delete the complete cookie if we're in insert+indirect mode, so that
3260 * the server never sees it ;
3261 * - remove the server id from the cookie value, and tag the cookie as an
3262 * application cookie so that it does not get accidentely removed later,
3263 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003264 */
willy tarreau0174f312005-12-18 01:02:42 +01003265 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3266 buffer_replace2(req, p3, delim + 1, NULL, 0);
3267 p4 -= (delim + 1 - p3);
3268 ptr -= (delim + 1 - p3);
3269 del_cookie = del_colon = NULL;
3270 app_cookies++; /* protect the header from deletion */
3271 }
3272 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003273 (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 +01003274 del_cookie = p1;
3275 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003276 }
willy tarreau12350152005-12-18 01:03:27 +01003277 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003278 /* now we know that we must keep this cookie since it's
3279 * not ours. But if we wanted to delete our cookie
3280 * earlier, we cannot remove the complete header, but we
3281 * can remove the previous block itself.
3282 */
3283 app_cookies++;
3284
3285 if (del_cookie != NULL) {
3286 buffer_replace2(req, del_cookie, p1, NULL, 0);
3287 p4 -= (p1 - del_cookie);
3288 ptr -= (p1 - del_cookie);
3289 del_cookie = del_colon = NULL;
3290 }
willy tarreau240afa62005-12-17 13:14:35 +01003291 }
willy tarreau12350152005-12-18 01:03:27 +01003292
3293 if ((t->proxy->appsession_name != NULL) &&
3294 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3295 /* first, let's see if the cookie is our appcookie*/
3296
3297 /* Cool... it's the right one */
3298
3299 asession_temp = &local_asession;
3300
3301 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3302 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3303 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3304 return 0;
3305 }
3306
3307 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3308 asession_temp->sessid[t->proxy->appsession_len] = 0;
3309 asession_temp->serverid = NULL;
3310
3311 /* only do insert, if lookup fails */
3312 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3313 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3314 Alert("Not enough memory process_cli():asession:calloc().\n");
3315 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3316 return 0;
3317 }
3318
3319 asession_temp->sessid = local_asession.sessid;
3320 asession_temp->serverid = local_asession.serverid;
3321 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3322 }
3323 else{
3324 /* free wasted memory */
3325 pool_free_to(apools.sessid, local_asession.sessid);
3326 }
3327
3328 if (asession_temp->serverid == NULL) {
3329 Alert("Found Application Session without matching server.\n");
3330 } else {
3331 struct server *srv = t->proxy->srv;
3332 while (srv) {
3333 if(strcmp(srv->id, asession_temp->serverid) == 0) {
3334 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3335 /* we found the server and it's usable */
3336 t->flags &= ~SN_CK_MASK;
3337 t->flags |= SN_CK_VALID | SN_DIRECT;
3338 t->srv = srv;
3339 break;
3340 } else {
3341 t->flags &= ~SN_CK_MASK;
3342 t->flags |= SN_CK_DOWN;
3343 }
3344 }
3345 srv = srv->next;
3346 }/* end while(srv) */
3347 }/* end else if server == NULL */
3348
3349 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003350 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003351 }
willy tarreau240afa62005-12-17 13:14:35 +01003352
willy tarreau5cbea6f2005-12-17 12:48:26 +01003353 /* we'll have to look for another cookie ... */
3354 p1 = p4;
3355 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003356
3357 /* There's no more cookie on this line.
3358 * We may have marked the last one(s) for deletion.
3359 * We must do this now in two ways :
3360 * - if there is no app cookie, we simply delete the header ;
3361 * - if there are app cookies, we must delete the end of the
3362 * string properly, including the colon/semi-colon before
3363 * the cookie name.
3364 */
3365 if (del_cookie != NULL) {
3366 if (app_cookies) {
3367 buffer_replace2(req, del_colon, ptr, NULL, 0);
3368 /* WARNING! <ptr> becomes invalid for now. If some code
3369 * below needs to rely on it before the end of the global
3370 * header loop, we need to correct it with this code :
3371 * ptr = del_colon;
3372 */
3373 }
3374 else
3375 delete_header = 1;
3376 }
3377 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378
3379 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003380 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003381 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003382 }
willy tarreau240afa62005-12-17 13:14:35 +01003383 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3384
willy tarreau5cbea6f2005-12-17 12:48:26 +01003385 req->h = req->lr;
3386 } /* while (req->lr < req->r) */
3387
3388 /* end of header processing (even if incomplete) */
3389
willy tarreauef900ab2005-12-17 12:52:52 +01003390 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3391 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3392 * full. We cannot loop here since event_cli_read will disable it only if
3393 * req->l == rlim-data
3394 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395 FD_SET(t->cli_fd, StaticReadEvent);
3396 if (t->proxy->clitimeout)
3397 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3398 else
3399 tv_eternity(&t->crexpire);
3400 }
3401
willy tarreaue39cd132005-12-17 13:00:18 +01003402 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003403 * won't be able to free more later, so the session will never terminate.
3404 */
willy tarreaue39cd132005-12-17 13:00:18 +01003405 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003406 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003407 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003408 if (!(t->flags & SN_ERR_MASK))
3409 t->flags |= SN_ERR_PRXCOND;
3410 if (!(t->flags & SN_FINST_MASK))
3411 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003412 return 1;
3413 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003414 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003415 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 tv_eternity(&t->crexpire);
3417 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003418 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003419 if (!(t->flags & SN_ERR_MASK))
3420 t->flags |= SN_ERR_CLICL;
3421 if (!(t->flags & SN_FINST_MASK))
3422 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003423 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003424 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003425 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3426
3427 /* read timeout : give up with an error message.
3428 */
3429 t->logs.status = 408;
3430 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003431 if (!(t->flags & SN_ERR_MASK))
3432 t->flags |= SN_ERR_CLITO;
3433 if (!(t->flags & SN_FINST_MASK))
3434 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003435 return 1;
3436 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003437
3438 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003439 }
3440 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003441 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003442 /* FIXME: this error handling is partly buggy because we always report
3443 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3444 * or HEADER phase. BTW, it's not logical to expire the client while
3445 * we're waiting for the server to connect.
3446 */
willy tarreau0f7af912005-12-17 12:21:26 +01003447 /* read or write error */
3448 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003449 tv_eternity(&t->crexpire);
3450 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003451 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003452 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003453 if (!(t->flags & SN_ERR_MASK))
3454 t->flags |= SN_ERR_CLICL;
3455 if (!(t->flags & SN_FINST_MASK))
3456 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003457 return 1;
3458 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003459 /* last read, or end of server write */
3460 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003461 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003462 tv_eternity(&t->crexpire);
3463 shutdown(t->cli_fd, SHUT_RD);
3464 t->cli_state = CL_STSHUTR;
3465 return 1;
3466 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003467 /* last server read and buffer empty */
3468 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003469 FD_CLR(t->cli_fd, StaticWriteEvent);
3470 tv_eternity(&t->cwexpire);
3471 shutdown(t->cli_fd, SHUT_WR);
3472 t->cli_state = CL_STSHUTW;
3473 return 1;
3474 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003475 /* read timeout */
3476 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3477 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003478 tv_eternity(&t->crexpire);
3479 shutdown(t->cli_fd, SHUT_RD);
3480 t->cli_state = CL_STSHUTR;
3481 if (!(t->flags & SN_ERR_MASK))
3482 t->flags |= SN_ERR_CLITO;
3483 if (!(t->flags & SN_FINST_MASK))
3484 t->flags |= SN_FINST_D;
3485 return 1;
3486 }
3487 /* write timeout */
3488 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3489 FD_CLR(t->cli_fd, StaticWriteEvent);
3490 tv_eternity(&t->cwexpire);
3491 shutdown(t->cli_fd, SHUT_WR);
3492 t->cli_state = CL_STSHUTW;
3493 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003494 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003495 if (!(t->flags & SN_FINST_MASK))
3496 t->flags |= SN_FINST_D;
3497 return 1;
3498 }
willy tarreau0f7af912005-12-17 12:21:26 +01003499
willy tarreauc58fc692005-12-17 14:13:08 +01003500 if (req->l >= req->rlim - req->data) {
3501 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003502 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003503 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003504 FD_CLR(t->cli_fd, StaticReadEvent);
3505 tv_eternity(&t->crexpire);
3506 }
3507 }
3508 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003509 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003510 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3511 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003512 if (!t->proxy->clitimeout ||
3513 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3514 /* If the client has no timeout, or if the server not ready yet, and we
3515 * know for sure that it can expire, then it's cleaner to disable the
3516 * timeout on the client side so that too low values cannot make the
3517 * sessions abort too early.
3518 */
willy tarreau0f7af912005-12-17 12:21:26 +01003519 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003520 else
3521 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003522 }
3523 }
3524
3525 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003526 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003527 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3528 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3529 tv_eternity(&t->cwexpire);
3530 }
3531 }
3532 else { /* buffer not empty */
3533 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3534 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003535 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003536 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003537 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3538 t->crexpire = t->cwexpire;
3539 }
willy tarreau0f7af912005-12-17 12:21:26 +01003540 else
3541 tv_eternity(&t->cwexpire);
3542 }
3543 }
3544 return 0; /* other cases change nothing */
3545 }
3546 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003547 if (t->res_cw == RES_ERROR) {
3548 tv_eternity(&t->cwexpire);
3549 fd_delete(t->cli_fd);
3550 t->cli_state = CL_STCLOSE;
3551 if (!(t->flags & SN_ERR_MASK))
3552 t->flags |= SN_ERR_CLICL;
3553 if (!(t->flags & SN_FINST_MASK))
3554 t->flags |= SN_FINST_D;
3555 return 1;
3556 }
3557 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003558 tv_eternity(&t->cwexpire);
3559 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003560 t->cli_state = CL_STCLOSE;
3561 return 1;
3562 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003563 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3564 tv_eternity(&t->cwexpire);
3565 fd_delete(t->cli_fd);
3566 t->cli_state = CL_STCLOSE;
3567 if (!(t->flags & SN_ERR_MASK))
3568 t->flags |= SN_ERR_CLITO;
3569 if (!(t->flags & SN_FINST_MASK))
3570 t->flags |= SN_FINST_D;
3571 return 1;
3572 }
willy tarreau0f7af912005-12-17 12:21:26 +01003573 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003574 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003575 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3576 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3577 tv_eternity(&t->cwexpire);
3578 }
3579 }
3580 else { /* buffer not empty */
3581 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3582 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003583 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003584 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003585 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3586 t->crexpire = t->cwexpire;
3587 }
willy tarreau0f7af912005-12-17 12:21:26 +01003588 else
3589 tv_eternity(&t->cwexpire);
3590 }
3591 }
3592 return 0;
3593 }
3594 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003595 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003596 tv_eternity(&t->crexpire);
3597 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003598 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003599 if (!(t->flags & SN_ERR_MASK))
3600 t->flags |= SN_ERR_CLICL;
3601 if (!(t->flags & SN_FINST_MASK))
3602 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003603 return 1;
3604 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003605 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3606 tv_eternity(&t->crexpire);
3607 fd_delete(t->cli_fd);
3608 t->cli_state = CL_STCLOSE;
3609 return 1;
3610 }
3611 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3612 tv_eternity(&t->crexpire);
3613 fd_delete(t->cli_fd);
3614 t->cli_state = CL_STCLOSE;
3615 if (!(t->flags & SN_ERR_MASK))
3616 t->flags |= SN_ERR_CLITO;
3617 if (!(t->flags & SN_FINST_MASK))
3618 t->flags |= SN_FINST_D;
3619 return 1;
3620 }
willy tarreauef900ab2005-12-17 12:52:52 +01003621 else if (req->l >= req->rlim - req->data) {
3622 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003623 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003624 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003625 FD_CLR(t->cli_fd, StaticReadEvent);
3626 tv_eternity(&t->crexpire);
3627 }
3628 }
3629 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003630 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003631 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3632 FD_SET(t->cli_fd, StaticReadEvent);
3633 if (t->proxy->clitimeout)
3634 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3635 else
3636 tv_eternity(&t->crexpire);
3637 }
3638 }
3639 return 0;
3640 }
3641 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003642 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003643 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003644 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 +01003645 write(1, trash, len);
3646 }
3647 return 0;
3648 }
3649 return 0;
3650}
3651
3652
3653/*
3654 * manages the server FSM and its socket. It returns 1 if a state has changed
3655 * (and a resync may be needed), 0 else.
3656 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003657int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003658 int s = t->srv_state;
3659 int c = t->cli_state;
3660 struct buffer *req = t->req;
3661 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003662 appsess *asession_temp = NULL;
3663 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003664
willy tarreau750a4722005-12-17 13:21:24 +01003665#ifdef DEBUG_FULL
3666 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3667#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003668 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3669 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3670 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3671 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003672 if (s == SV_STIDLE) {
3673 if (c == CL_STHEADERS)
3674 return 0; /* stay in idle, waiting for data to reach the client side */
3675 else if (c == CL_STCLOSE ||
3676 c == CL_STSHUTW ||
3677 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3678 tv_eternity(&t->cnexpire);
3679 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003680 if (!(t->flags & SN_ERR_MASK))
3681 t->flags |= SN_ERR_CLICL;
3682 if (!(t->flags & SN_FINST_MASK))
3683 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003684 return 1;
3685 }
3686 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003687 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003688 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3689 t->srv_state = SV_STCONN;
3690 }
3691 else { /* try again */
3692 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003693 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003694 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003695 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003696 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3697 t->flags &= ~SN_CK_MASK;
3698 t->flags |= SN_CK_DOWN;
3699 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003700 }
3701
3702 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003703 t->srv_state = SV_STCONN;
3704 break;
3705 }
3706 }
3707 if (t->conn_retries < 0) {
3708 /* if conn_retries < 0 or other error, let's abort */
3709 tv_eternity(&t->cnexpire);
3710 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003711 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003712 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003713 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003714 if (!(t->flags & SN_ERR_MASK))
3715 t->flags |= SN_ERR_SRVCL;
3716 if (!(t->flags & SN_FINST_MASK))
3717 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003718 }
3719 }
3720 return 1;
3721 }
3722 }
3723 else if (s == SV_STCONN) { /* connection in progress */
3724 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3725 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3726 return 0; /* nothing changed */
3727 }
3728 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3729 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3730 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003732 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003733 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003734 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003735 if (t->conn_retries >= 0) {
3736 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003737 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003738 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003739 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3740 t->flags &= ~SN_CK_MASK;
3741 t->flags |= SN_CK_DOWN;
3742 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003743 }
3744 if (connect_server(t) == 0)
3745 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003746 }
3747 /* if conn_retries < 0 or other error, let's abort */
3748 tv_eternity(&t->cnexpire);
3749 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003750 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003751 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003752 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003753 if (!(t->flags & SN_ERR_MASK))
3754 t->flags |= SN_ERR_SRVCL;
3755 if (!(t->flags & SN_FINST_MASK))
3756 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003757 return 1;
3758 }
3759 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003760 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003761
willy tarreau0f7af912005-12-17 12:21:26 +01003762 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003763 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003764 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003765 tv_eternity(&t->swexpire);
3766 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003767 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003768 if (t->proxy->srvtimeout) {
3769 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3770 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3771 t->srexpire = t->swexpire;
3772 }
3773 else
3774 tv_eternity(&t->swexpire);
3775 }
willy tarreau0f7af912005-12-17 12:21:26 +01003776
3777 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3778 FD_SET(t->srv_fd, StaticReadEvent);
3779 if (t->proxy->srvtimeout)
3780 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3781 else
3782 tv_eternity(&t->srexpire);
3783
3784 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003785 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003786
3787 /* if the user wants to log as soon as possible, without counting
3788 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003789 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003790 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3791 sess_log(t);
3792 }
willy tarreau0f7af912005-12-17 12:21:26 +01003793 }
willy tarreauef900ab2005-12-17 12:52:52 +01003794 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003795 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003796 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3797 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003798 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003799 return 1;
3800 }
3801 }
3802 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003803 /* now parse the partial (or complete) headers */
3804 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3805 char *ptr;
3806 int delete_header;
3807
3808 ptr = rep->lr;
3809
3810 /* look for the end of the current header */
3811 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3812 ptr++;
3813
3814 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003815 int line, len;
3816
3817 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01003818
3819 /* first, we'll block if security checks have caught nasty things */
3820 if (t->flags & SN_CACHEABLE) {
3821 if ((t->flags & SN_CACHE_COOK) &&
3822 (t->flags & SN_SCK_ANY) &&
3823 (t->proxy->options & PR_O_CHK_CACHE)) {
3824
3825 /* we're in presence of a cacheable response containing
3826 * a set-cookie header. We'll block it as requested by
3827 * the 'checkcache' option, and send an alert.
3828 */
3829 tv_eternity(&t->srexpire);
3830 tv_eternity(&t->swexpire);
3831 fd_delete(t->srv_fd);
3832 t->srv_state = SV_STCLOSE;
3833 t->logs.status = 502;
3834 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3835 if (!(t->flags & SN_ERR_MASK))
3836 t->flags |= SN_ERR_PRXCOND;
3837 if (!(t->flags & SN_FINST_MASK))
3838 t->flags |= SN_FINST_H;
3839
3840 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3841 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3842
3843 return 1;
3844 }
3845 }
3846
willy tarreau982249e2005-12-18 00:57:06 +01003847 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
3848 if (t->flags & SN_SVDENY) {
3849 tv_eternity(&t->srexpire);
3850 tv_eternity(&t->swexpire);
3851 fd_delete(t->srv_fd);
3852 t->srv_state = SV_STCLOSE;
3853 t->logs.status = 502;
3854 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3855 if (!(t->flags & SN_ERR_MASK))
3856 t->flags |= SN_ERR_PRXCOND;
3857 if (!(t->flags & SN_FINST_MASK))
3858 t->flags |= SN_FINST_H;
3859 return 1;
3860 }
3861
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 /* we'll have something else to do here : add new headers ... */
3863
willy tarreaucd878942005-12-17 13:27:43 +01003864 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3865 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003866 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003867 * insert a set-cookie here, except if we want to insert only on POST
3868 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003869 */
willy tarreau750a4722005-12-17 13:21:24 +01003870 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003871 t->proxy->cookie_name,
3872 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003873
willy tarreau036e1ce2005-12-17 13:46:33 +01003874 t->flags |= SN_SCK_INSERTED;
3875
willy tarreau750a4722005-12-17 13:21:24 +01003876 /* Here, we will tell an eventual cache on the client side that we don't
3877 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3878 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3879 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3880 */
willy tarreau240afa62005-12-17 13:14:35 +01003881 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003882 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3883 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003884
willy tarreau750a4722005-12-17 13:21:24 +01003885 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003886 }
3887
3888 /* headers to be added */
3889 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003890 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3891 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003892 }
3893
willy tarreau25c4ea52005-12-18 00:49:49 +01003894 /* add a "connection: close" line if needed */
3895 if (t->proxy->options & PR_O_HTTP_CLOSE)
3896 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3897
willy tarreau5cbea6f2005-12-17 12:48:26 +01003898 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003899 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003900 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003901
3902 /* if the user wants to log as soon as possible, without counting
3903 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003904 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003905 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3906 t->logs.bytes = rep->h - rep->data;
3907 sess_log(t);
3908 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003909 break;
3910 }
3911
3912 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3913 if (ptr > rep->r - 2) {
3914 /* this is a partial header, let's wait for more to come */
3915 rep->lr = ptr;
3916 break;
3917 }
3918
3919 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3920 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3921
3922 /* now we know that *ptr is either \r or \n,
3923 * and that there are at least 1 char after it.
3924 */
3925 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3926 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3927 else
3928 rep->lr = ptr + 2; /* \r\n or \n\r */
3929
3930 /*
3931 * now we know that we have a full header ; we can do whatever
3932 * we want with these pointers :
3933 * rep->h = beginning of header
3934 * ptr = end of header (first \r or \n)
3935 * rep->lr = beginning of next line (next rep->h)
3936 * rep->r = end of data (not used at this stage)
3937 */
3938
willy tarreaua1598082005-12-17 13:08:06 +01003939
willy tarreau982249e2005-12-18 00:57:06 +01003940 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01003941 t->logs.logwait &= ~LW_RESP;
3942 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01003943 switch (t->logs.status) {
3944 case 200:
3945 case 203:
3946 case 206:
3947 case 300:
3948 case 301:
3949 case 410:
3950 /* RFC2616 @13.4:
3951 * "A response received with a status code of
3952 * 200, 203, 206, 300, 301 or 410 MAY be stored
3953 * by a cache (...) unless a cache-control
3954 * directive prohibits caching."
3955 *
3956 * RFC2616 @9.5: POST method :
3957 * "Responses to this method are not cacheable,
3958 * unless the response includes appropriate
3959 * Cache-Control or Expires header fields."
3960 */
3961 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
3962 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
3963 break;
3964 default:
3965 break;
3966 }
willy tarreau4302f492005-12-18 01:00:37 +01003967 }
3968 else if (t->logs.logwait & LW_RSPHDR) {
3969 struct cap_hdr *h;
3970 int len;
3971 for (h = t->proxy->rsp_cap; h; h = h->next) {
3972 if ((h->namelen + 2 <= ptr - rep->h) &&
3973 (rep->h[h->namelen] == ':') &&
3974 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
3975
3976 if (t->rsp_cap[h->index] == NULL)
3977 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3978
3979 len = ptr - (rep->h + h->namelen + 2);
3980 if (len > h->len)
3981 len = h->len;
3982
3983 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
3984 t->rsp_cap[h->index][len]=0;
3985 }
3986 }
3987
willy tarreaua1598082005-12-17 13:08:06 +01003988 }
3989
willy tarreau5cbea6f2005-12-17 12:48:26 +01003990 delete_header = 0;
3991
willy tarreau982249e2005-12-18 00:57:06 +01003992 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003993 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003994 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 +01003995 max = ptr - rep->h;
3996 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003997 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003998 trash[len++] = '\n';
3999 write(1, trash, len);
4000 }
4001
willy tarreau25c4ea52005-12-18 00:49:49 +01004002 /* remove "connection: " if needed */
4003 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4004 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4005 delete_header = 1;
4006 }
4007
willy tarreau5cbea6f2005-12-17 12:48:26 +01004008 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004009 if (!delete_header && t->proxy->rsp_exp != NULL
4010 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004011 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004012 char term;
4013
4014 term = *ptr;
4015 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004016 exp = t->proxy->rsp_exp;
4017 do {
4018 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4019 switch (exp->action) {
4020 case ACT_ALLOW:
4021 if (!(t->flags & SN_SVDENY))
4022 t->flags |= SN_SVALLOW;
4023 break;
4024 case ACT_REPLACE:
4025 if (!(t->flags & SN_SVDENY)) {
4026 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4027 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4028 }
4029 break;
4030 case ACT_REMOVE:
4031 if (!(t->flags & SN_SVDENY))
4032 delete_header = 1;
4033 break;
4034 case ACT_DENY:
4035 if (!(t->flags & SN_SVALLOW))
4036 t->flags |= SN_SVDENY;
4037 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004038 case ACT_PASS: /* we simply don't deny this one */
4039 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 }
4041 break;
4042 }
willy tarreaue39cd132005-12-17 13:00:18 +01004043 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004044 *ptr = term; /* restore the string terminator */
4045 }
4046
willy tarreau97f58572005-12-18 00:53:44 +01004047 /* check for cache-control: or pragma: headers */
4048 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4049 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4050 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4051 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4052 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004053 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004054 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4055 else {
4056 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004057 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004058 t->flags &= ~SN_CACHE_COOK;
4059 }
4060 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004061 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004062 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004063 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004064 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4065 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004066 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004067 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004068 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4069 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4070 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4071 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4072 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4073 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004074 }
4075 }
4076 }
4077
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004079 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004080 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004081 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004082 char *p1, *p2, *p3, *p4;
4083
willy tarreau97f58572005-12-18 00:53:44 +01004084 t->flags |= SN_SCK_ANY;
4085
willy tarreau5cbea6f2005-12-17 12:48:26 +01004086 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4087
4088 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004089 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004090 p1++;
4091
4092 if (p1 == ptr || *p1 == ';') /* end of cookie */
4093 break;
4094
4095 /* p1 is at the beginning of the cookie name */
4096 p2 = p1;
4097
4098 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4099 p2++;
4100
4101 if (p2 == ptr || *p2 == ';') /* next cookie */
4102 break;
4103
4104 p3 = p2 + 1; /* skips the '=' sign */
4105 if (p3 == ptr)
4106 break;
4107
4108 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004109 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004110 p4++;
4111
4112 /* here, we have the cookie name between p1 and p2,
4113 * and its value between p3 and p4.
4114 * we can process it.
4115 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004116
4117 /* first, let's see if we want to capture it */
4118 if (t->proxy->capture_name != NULL &&
4119 t->logs.srv_cookie == NULL &&
4120 (p4 - p1 >= t->proxy->capture_namelen) &&
4121 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4122 int log_len = p4 - p1;
4123
4124 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4125 Alert("HTTP logging : out of memory.\n");
4126 }
4127
4128 if (log_len > t->proxy->capture_len)
4129 log_len = t->proxy->capture_len;
4130 memcpy(t->logs.srv_cookie, p1, log_len);
4131 t->logs.srv_cookie[log_len] = 0;
4132 }
4133
4134 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4135 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004136 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004137 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004138
4139 /* If the cookie is in insert mode on a known server, we'll delete
4140 * this occurrence because we'll insert another one later.
4141 * We'll delete it too if the "indirect" option is set and we're in
4142 * a direct access. */
4143 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004144 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004145 /* this header must be deleted */
4146 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004147 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004148 }
4149 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4150 /* replace bytes p3->p4 with the cookie name associated
4151 * with this server since we know it.
4152 */
4153 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004154 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004155 }
willy tarreau0174f312005-12-18 01:02:42 +01004156 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4157 /* insert the cookie name associated with this server
4158 * before existing cookie, and insert a delimitor between them..
4159 */
4160 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4161 p3[t->srv->cklen] = COOKIE_DELIM;
4162 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4163 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004164 break;
4165 }
willy tarreau12350152005-12-18 01:03:27 +01004166
4167 /* first, let's see if the cookie is our appcookie*/
4168 if ((t->proxy->appsession_name != NULL) &&
4169 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4170
4171 /* Cool... it's the right one */
4172
4173 size_t server_id_len = strlen(t->srv->id)+1;
4174 asession_temp = &local_asession;
4175
4176 if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
4177 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4178 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4179 }
4180 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4181 asession_temp->sessid[t->proxy->appsession_len] = 0;
4182 asession_temp->serverid = NULL;
4183
4184 /* only do insert, if lookup fails */
4185 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4186 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4187 Alert("Not enought Memory process_srv():asession:calloc().\n");
4188 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4189 return 0;
4190 }
4191 asession_temp->sessid = local_asession.sessid;
4192 asession_temp->serverid = local_asession.serverid;
4193 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4194 }/* end if(chtbl_lookup()) */
4195 else
4196 {
4197 /* free wasted memory */
4198 pool_free_to(apools.sessid, local_asession.sessid);
4199 } /* end else from if(chtbl_lookup()) */
4200
4201 if(asession_temp->serverid == NULL){
4202 if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
4203 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4204 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4205 }
4206 asession_temp->serverid[0] = '\0';
4207 }
4208
4209 if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
4210
4211 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4212
4213#if defined(DEBUG_HASH)
4214 print_table(&(t->proxy->htbl_proxy));
4215#endif
4216 break;
4217 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004218 else {
4219 // fprintf(stderr,"Ignoring unknown cookie : ");
4220 // write(2, p1, p2-p1);
4221 // fprintf(stderr," = ");
4222 // write(2, p3, p4-p3);
4223 // fprintf(stderr,"\n");
4224 }
4225 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4226 } /* we're now at the end of the cookie value */
4227 } /* end of cookie processing */
4228
willy tarreau97f58572005-12-18 00:53:44 +01004229 /* check for any set-cookie in case we check for cacheability */
4230 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4231 (t->proxy->options & PR_O_CHK_CACHE) &&
4232 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4233 t->flags |= SN_SCK_ANY;
4234 }
4235
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004237 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004238 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004239
willy tarreau5cbea6f2005-12-17 12:48:26 +01004240 rep->h = rep->lr;
4241 } /* while (rep->lr < rep->r) */
4242
4243 /* end of header processing (even if incomplete) */
4244
willy tarreauef900ab2005-12-17 12:52:52 +01004245 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4246 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4247 * full. We cannot loop here since event_srv_read will disable it only if
4248 * rep->l == rlim-data
4249 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004250 FD_SET(t->srv_fd, StaticReadEvent);
4251 if (t->proxy->srvtimeout)
4252 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4253 else
4254 tv_eternity(&t->srexpire);
4255 }
willy tarreau0f7af912005-12-17 12:21:26 +01004256
willy tarreau8337c6b2005-12-17 13:41:01 +01004257 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004258 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004259 tv_eternity(&t->srexpire);
4260 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004261 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004262 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004263 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004264 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004265 if (!(t->flags & SN_ERR_MASK))
4266 t->flags |= SN_ERR_SRVCL;
4267 if (!(t->flags & SN_FINST_MASK))
4268 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004269 return 1;
4270 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004271 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004272 * since we are in header mode, if there's no space left for headers, we
4273 * won't be able to free more later, so the session will never terminate.
4274 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004275 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 +01004276 FD_CLR(t->srv_fd, StaticReadEvent);
4277 tv_eternity(&t->srexpire);
4278 shutdown(t->srv_fd, SHUT_RD);
4279 t->srv_state = SV_STSHUTR;
4280 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004281 }
4282 /* read timeout : return a 504 to the client.
4283 */
4284 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4285 tv_eternity(&t->srexpire);
4286 tv_eternity(&t->swexpire);
4287 fd_delete(t->srv_fd);
4288 t->srv_state = SV_STCLOSE;
4289 t->logs.status = 504;
4290 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004291 if (!(t->flags & SN_ERR_MASK))
4292 t->flags |= SN_ERR_SRVTO;
4293 if (!(t->flags & SN_FINST_MASK))
4294 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004295 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004296
4297 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004298 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004299 /* FIXME!!! here, we don't want to switch to SHUTW if the
4300 * client shuts read too early, because we may still have
4301 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004302 * The side-effect is that if the client completely closes its
4303 * connection during SV_STHEADER, the connection to the server
4304 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004305 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004306 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004307 FD_CLR(t->srv_fd, StaticWriteEvent);
4308 tv_eternity(&t->swexpire);
4309 shutdown(t->srv_fd, SHUT_WR);
4310 t->srv_state = SV_STSHUTW;
4311 return 1;
4312 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004313 /* write timeout */
4314 /* FIXME!!! here, we don't want to switch to SHUTW if the
4315 * client shuts read too early, because we may still have
4316 * some work to do on the headers.
4317 */
4318 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4319 FD_CLR(t->srv_fd, StaticWriteEvent);
4320 tv_eternity(&t->swexpire);
4321 shutdown(t->srv_fd, SHUT_WR);
4322 t->srv_state = SV_STSHUTW;
4323 if (!(t->flags & SN_ERR_MASK))
4324 t->flags |= SN_ERR_SRVTO;
4325 if (!(t->flags & SN_FINST_MASK))
4326 t->flags |= SN_FINST_H;
4327 return 1;
4328 }
willy tarreau0f7af912005-12-17 12:21:26 +01004329
4330 if (req->l == 0) {
4331 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4332 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4333 tv_eternity(&t->swexpire);
4334 }
4335 }
4336 else { /* client buffer not empty */
4337 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4338 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004339 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004340 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004341 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4342 t->srexpire = t->swexpire;
4343 }
willy tarreau0f7af912005-12-17 12:21:26 +01004344 else
4345 tv_eternity(&t->swexpire);
4346 }
4347 }
4348
willy tarreau5cbea6f2005-12-17 12:48:26 +01004349 /* be nice with the client side which would like to send a complete header
4350 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4351 * would read all remaining data at once ! The client should not write past rep->lr
4352 * when the server is in header state.
4353 */
4354 //return header_processed;
4355 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004356 }
4357 else if (s == SV_STDATA) {
4358 /* read or write error */
4359 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004360 tv_eternity(&t->srexpire);
4361 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004362 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004363 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004364 if (!(t->flags & SN_ERR_MASK))
4365 t->flags |= SN_ERR_SRVCL;
4366 if (!(t->flags & SN_FINST_MASK))
4367 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004368 return 1;
4369 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004370 /* last read, or end of client write */
4371 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004372 FD_CLR(t->srv_fd, StaticReadEvent);
4373 tv_eternity(&t->srexpire);
4374 shutdown(t->srv_fd, SHUT_RD);
4375 t->srv_state = SV_STSHUTR;
4376 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004377 }
4378 /* end of client read and no more data to send */
4379 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4380 FD_CLR(t->srv_fd, StaticWriteEvent);
4381 tv_eternity(&t->swexpire);
4382 shutdown(t->srv_fd, SHUT_WR);
4383 t->srv_state = SV_STSHUTW;
4384 return 1;
4385 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004386 /* read timeout */
4387 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4388 FD_CLR(t->srv_fd, StaticReadEvent);
4389 tv_eternity(&t->srexpire);
4390 shutdown(t->srv_fd, SHUT_RD);
4391 t->srv_state = SV_STSHUTR;
4392 if (!(t->flags & SN_ERR_MASK))
4393 t->flags |= SN_ERR_SRVTO;
4394 if (!(t->flags & SN_FINST_MASK))
4395 t->flags |= SN_FINST_D;
4396 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004397 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004398 /* write timeout */
4399 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004400 FD_CLR(t->srv_fd, StaticWriteEvent);
4401 tv_eternity(&t->swexpire);
4402 shutdown(t->srv_fd, SHUT_WR);
4403 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004404 if (!(t->flags & SN_ERR_MASK))
4405 t->flags |= SN_ERR_SRVTO;
4406 if (!(t->flags & SN_FINST_MASK))
4407 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004408 return 1;
4409 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004410
4411 /* recompute request time-outs */
4412 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004413 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4414 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4415 tv_eternity(&t->swexpire);
4416 }
4417 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004418 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004419 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4420 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004421 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004422 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004423 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4424 t->srexpire = t->swexpire;
4425 }
willy tarreau0f7af912005-12-17 12:21:26 +01004426 else
4427 tv_eternity(&t->swexpire);
4428 }
4429 }
4430
willy tarreaub1ff9db2005-12-17 13:51:03 +01004431 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004432 if (rep->l == BUFSIZE) { /* no room to read more data */
4433 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4434 FD_CLR(t->srv_fd, StaticReadEvent);
4435 tv_eternity(&t->srexpire);
4436 }
4437 }
4438 else {
4439 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4440 FD_SET(t->srv_fd, StaticReadEvent);
4441 if (t->proxy->srvtimeout)
4442 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4443 else
4444 tv_eternity(&t->srexpire);
4445 }
4446 }
4447
4448 return 0; /* other cases change nothing */
4449 }
4450 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004451 if (t->res_sw == RES_ERROR) {
4452 //FD_CLR(t->srv_fd, StaticWriteEvent);
4453 tv_eternity(&t->swexpire);
4454 fd_delete(t->srv_fd);
4455 //close(t->srv_fd);
4456 t->srv_state = SV_STCLOSE;
4457 if (!(t->flags & SN_ERR_MASK))
4458 t->flags |= SN_ERR_SRVCL;
4459 if (!(t->flags & SN_FINST_MASK))
4460 t->flags |= SN_FINST_D;
4461 return 1;
4462 }
4463 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004464 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004465 tv_eternity(&t->swexpire);
4466 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004467 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004468 t->srv_state = SV_STCLOSE;
4469 return 1;
4470 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004471 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4472 //FD_CLR(t->srv_fd, StaticWriteEvent);
4473 tv_eternity(&t->swexpire);
4474 fd_delete(t->srv_fd);
4475 //close(t->srv_fd);
4476 t->srv_state = SV_STCLOSE;
4477 if (!(t->flags & SN_ERR_MASK))
4478 t->flags |= SN_ERR_SRVTO;
4479 if (!(t->flags & SN_FINST_MASK))
4480 t->flags |= SN_FINST_D;
4481 return 1;
4482 }
willy tarreau0f7af912005-12-17 12:21:26 +01004483 else if (req->l == 0) {
4484 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4485 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4486 tv_eternity(&t->swexpire);
4487 }
4488 }
4489 else { /* buffer not empty */
4490 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4491 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004492 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004493 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004494 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4495 t->srexpire = t->swexpire;
4496 }
willy tarreau0f7af912005-12-17 12:21:26 +01004497 else
4498 tv_eternity(&t->swexpire);
4499 }
4500 }
4501 return 0;
4502 }
4503 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004504 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004505 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004506 tv_eternity(&t->srexpire);
4507 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004508 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004509 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004510 if (!(t->flags & SN_ERR_MASK))
4511 t->flags |= SN_ERR_SRVCL;
4512 if (!(t->flags & SN_FINST_MASK))
4513 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004514 return 1;
4515 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004516 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4517 //FD_CLR(t->srv_fd, StaticReadEvent);
4518 tv_eternity(&t->srexpire);
4519 fd_delete(t->srv_fd);
4520 //close(t->srv_fd);
4521 t->srv_state = SV_STCLOSE;
4522 return 1;
4523 }
4524 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4525 //FD_CLR(t->srv_fd, StaticReadEvent);
4526 tv_eternity(&t->srexpire);
4527 fd_delete(t->srv_fd);
4528 //close(t->srv_fd);
4529 t->srv_state = SV_STCLOSE;
4530 if (!(t->flags & SN_ERR_MASK))
4531 t->flags |= SN_ERR_SRVTO;
4532 if (!(t->flags & SN_FINST_MASK))
4533 t->flags |= SN_FINST_D;
4534 return 1;
4535 }
willy tarreau0f7af912005-12-17 12:21:26 +01004536 else if (rep->l == BUFSIZE) { /* no room to read more data */
4537 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4538 FD_CLR(t->srv_fd, StaticReadEvent);
4539 tv_eternity(&t->srexpire);
4540 }
4541 }
4542 else {
4543 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4544 FD_SET(t->srv_fd, StaticReadEvent);
4545 if (t->proxy->srvtimeout)
4546 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4547 else
4548 tv_eternity(&t->srexpire);
4549 }
4550 }
4551 return 0;
4552 }
4553 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004554 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004555 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004556 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 +01004557 write(1, trash, len);
4558 }
4559 return 0;
4560 }
4561 return 0;
4562}
4563
4564
willy tarreau5cbea6f2005-12-17 12:48:26 +01004565/* Processes the client and server jobs of a session task, then
4566 * puts it back to the wait queue in a clean state, or
4567 * cleans up its resources if it must be deleted. Returns
4568 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004569 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004570int process_session(struct task *t) {
4571 struct session *s = t->context;
4572 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004573
willy tarreau5cbea6f2005-12-17 12:48:26 +01004574 do {
4575 fsm_resync = 0;
4576 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4577 fsm_resync |= process_cli(s);
4578 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4579 fsm_resync |= process_srv(s);
4580 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4581 } while (fsm_resync);
4582
4583 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004584 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004585 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004586
willy tarreau5cbea6f2005-12-17 12:48:26 +01004587 tv_min(&min1, &s->crexpire, &s->cwexpire);
4588 tv_min(&min2, &s->srexpire, &s->swexpire);
4589 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004590 tv_min(&t->expire, &min1, &min2);
4591
4592 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004593 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004594
willy tarreau5cbea6f2005-12-17 12:48:26 +01004595 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004596 }
4597
willy tarreau5cbea6f2005-12-17 12:48:26 +01004598 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004599 actconn--;
4600
willy tarreau982249e2005-12-18 00:57:06 +01004601 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004602 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004603 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 +01004604 write(1, trash, len);
4605 }
4606
willy tarreau750a4722005-12-17 13:21:24 +01004607 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004608 if (s->rep != NULL)
4609 s->logs.bytes = s->rep->total;
4610
willy tarreau9fe663a2005-12-17 13:02:59 +01004611 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004612 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004613 sess_log(s);
4614
willy tarreau0f7af912005-12-17 12:21:26 +01004615 /* the task MUST not be in the run queue anymore */
4616 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004617 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004618 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004619 return -1; /* rest in peace for eternity */
4620}
4621
4622
4623
4624/*
4625 * manages a server health-check. Returns
4626 * the time the task accepts to wait, or -1 for infinity.
4627 */
4628int process_chk(struct task *t) {
4629 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004630 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004631 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004632
willy tarreauef900ab2005-12-17 12:52:52 +01004633 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004634
4635 if (fd < 0) { /* no check currently running */
4636 //fprintf(stderr, "process_chk: 2\n");
4637 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4638 task_queue(t); /* restore t to its place in the task list */
4639 return tv_remain(&now, &t->expire);
4640 }
4641
4642 /* we'll initiate a new check */
4643 s->result = 0; /* no result yet */
4644 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004645 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004646 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4647 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4648 //fprintf(stderr, "process_chk: 3\n");
4649
willy tarreaua41a8b42005-12-17 14:02:24 +01004650 /* we'll connect to the check port on the server */
4651 sa = s->addr;
4652 sa.sin_port = htons(s->check_port);
4653
willy tarreau0174f312005-12-18 01:02:42 +01004654 /* allow specific binding :
4655 * - server-specific at first
4656 * - proxy-specific next
4657 */
4658 if (s->state & SRV_BIND_SRC) {
4659 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4660 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4661 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4662 s->proxy->id, s->id);
4663 s->result = -1;
4664 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004665 }
willy tarreau0174f312005-12-18 01:02:42 +01004666 else if (s->proxy->options & PR_O_BIND_SRC) {
4667 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4668 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4669 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4670 s->proxy->id);
4671 s->result = -1;
4672 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004673 }
willy tarreau0174f312005-12-18 01:02:42 +01004674
4675 if (!s->result) {
4676 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4677 /* OK, connection in progress or established */
4678
4679 //fprintf(stderr, "process_chk: 4\n");
4680
4681 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4682 fdtab[fd].owner = t;
4683 fdtab[fd].read = &event_srv_chk_r;
4684 fdtab[fd].write = &event_srv_chk_w;
4685 fdtab[fd].state = FD_STCONN; /* connection in progress */
4686 FD_SET(fd, StaticWriteEvent); /* for connect status */
4687 fd_insert(fd);
4688 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4689 tv_delayfrom(&t->expire, &now, s->inter);
4690 task_queue(t); /* restore t to its place in the task list */
4691 return tv_remain(&now, &t->expire);
4692 }
4693 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4694 s->result = -1; /* a real error */
4695 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004696 }
4697 }
4698 //fprintf(stderr, "process_chk: 5\n");
4699 close(fd);
4700 }
4701
4702 if (!s->result) { /* nothing done */
4703 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004704 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004705 task_queue(t); /* restore t to its place in the task list */
4706 return tv_remain(&now, &t->expire);
4707 }
4708
4709 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004710 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004711 s->health--; /* still good */
4712 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004713 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004714 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004715 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004716 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004717
willy tarreaudd07e972005-12-18 00:48:48 +01004718 if (find_server(s->proxy) == NULL) {
4719 Alert("Proxy %s has no server available !\n", s->proxy->id);
4720 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4721 }
4722 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004723 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004724 }
4725
4726 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004727 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4728 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004729 }
4730 else {
4731 //fprintf(stderr, "process_chk: 8\n");
4732 /* there was a test running */
4733 if (s->result > 0) { /* good server detected */
4734 //fprintf(stderr, "process_chk: 9\n");
4735 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004736 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004737 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004738 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004739 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004740 }
willy tarreauef900ab2005-12-17 12:52:52 +01004741
willy tarreaue47c8d72005-12-17 12:55:52 +01004742 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004743 s->state |= SRV_RUNNING;
4744 }
willy tarreauef900ab2005-12-17 12:52:52 +01004745 s->curfd = -1; /* no check running anymore */
4746 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004747 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004748 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004749 }
4750 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4751 //fprintf(stderr, "process_chk: 10\n");
4752 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004753 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004754 s->health--; /* still good */
4755 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004756 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01004757
willy tarreaudd07e972005-12-18 00:48:48 +01004758 if (s->health == s->rise) {
4759 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004760 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01004761
4762 if (find_server(s->proxy) == NULL) {
4763 Alert("Proxy %s has no server available !\n", s->proxy->id);
4764 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4765 }
willy tarreau535ae7a2005-12-17 12:58:00 +01004766 }
willy tarreauef900ab2005-12-17 12:52:52 +01004767
willy tarreau5cbea6f2005-12-17 12:48:26 +01004768 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004769 }
4770 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004771 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004772 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004773 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004774 }
4775 /* if result is 0 and there's no timeout, we have to wait again */
4776 }
4777 //fprintf(stderr, "process_chk: 11\n");
4778 s->result = 0;
4779 task_queue(t); /* restore t to its place in the task list */
4780 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004781}
4782
4783
willy tarreau5cbea6f2005-12-17 12:48:26 +01004784
willy tarreau0f7af912005-12-17 12:21:26 +01004785#if STATTIME > 0
4786int stats(void);
4787#endif
4788
4789/*
willy tarreau1c2ad212005-12-18 01:11:29 +01004790 * This does 4 things :
4791 * - wake up all expired tasks
4792 * - call all runnable tasks
4793 * - call maintain_proxies() to enable/disable the listeners
4794 * - return the delay till next event in ms, -1 = wait indefinitely
4795 * Note: this part should be rewritten with the O(ln(n)) scheduler.
4796 *
willy tarreau0f7af912005-12-17 12:21:26 +01004797 */
4798
willy tarreau1c2ad212005-12-18 01:11:29 +01004799int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01004800 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004801 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004802 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004803
willy tarreau1c2ad212005-12-18 01:11:29 +01004804 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004805
willy tarreau1c2ad212005-12-18 01:11:29 +01004806 /* look for expired tasks and add them to the run queue.
4807 */
4808 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4809 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4810 tnext = t->next;
4811 if (t->state & TASK_RUNNING)
4812 continue;
4813
4814 /* wakeup expired entries. It doesn't matter if they are
4815 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01004816 */
willy tarreau1c2ad212005-12-18 01:11:29 +01004817 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
4818 task_wakeup(&rq, t);
4819 }
4820 else {
4821 /* first non-runnable task. Use its expiration date as an upper bound */
4822 int temp_time = tv_remain(&now, &t->expire);
4823 if (temp_time)
4824 next_time = temp_time;
4825 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004826 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004827 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004828
willy tarreau1c2ad212005-12-18 01:11:29 +01004829 /* process each task in the run queue now. Each task may be deleted
4830 * since we only use tnext.
4831 */
4832 tnext = rq;
4833 while ((t = tnext) != NULL) {
4834 int temp_time;
4835
4836 tnext = t->rqnext;
4837 task_sleep(&rq, t);
4838 temp_time = t->process(t);
4839 next_time = MINTIME(temp_time, next_time);
4840 }
4841
4842 /* maintain all proxies in a consistent state. This should quickly become a task */
4843 time2 = maintain_proxies();
4844 return MINTIME(time2, next_time);
4845}
4846
4847
4848#if defined(ENABLE_EPOLL)
4849
4850/*
4851 * Main epoll() loop.
4852 */
4853
4854/* does 3 actions :
4855 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
4856 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
4857 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
4858 *
4859 * returns 0 if initialization failed, !0 otherwise.
4860 */
4861
4862int epoll_loop(int action) {
4863 int next_time;
4864 int status;
4865 int fd;
4866
4867 int fds, count;
4868 int pr, pw, sr, sw;
4869 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
4870 struct epoll_event ev;
4871
4872 /* private data */
4873 static int last_maxfd = 0;
4874 static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
4875 static struct epoll_event *epoll_events = NULL;
4876 static int epoll_fd;
4877
4878 if (action == POLL_LOOP_ACTION_INIT) {
4879 epoll_fd = epoll_create(global.maxsock + 1);
4880 if (epoll_fd < 0)
4881 return 0;
4882 else {
4883 epoll_events = (struct epoll_event*)
4884 calloc(1, sizeof(struct epoll_event) * global.maxsock);
4885 PrevReadEvent = (fd_set *)
4886 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
4887 PrevWriteEvent = (fd_set *)
4888 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004889 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004890 return 1;
4891 }
4892 else if (action == POLL_LOOP_ACTION_CLEAN) {
4893 if (PrevWriteEvent) free(PrevWriteEvent);
4894 if (PrevReadEvent) free(PrevReadEvent);
4895 if (epoll_events) free(epoll_events);
4896 close(epoll_fd);
4897 last_maxfd = 0;
4898 epoll_fd = 0;
4899 return 1;
4900 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004901
willy tarreau1c2ad212005-12-18 01:11:29 +01004902 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004903
willy tarreau1c2ad212005-12-18 01:11:29 +01004904 tv_now(&now);
4905
4906 while (1) {
4907 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01004908
4909 /* stop when there's no connection left and we don't allow them anymore */
4910 if (!actconn && listeners == 0)
4911 break;
4912
willy tarreau0f7af912005-12-17 12:21:26 +01004913#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01004914 {
4915 int time2;
4916 time2 = stats();
4917 next_time = MINTIME(time2, next_time);
4918 }
willy tarreau0f7af912005-12-17 12:21:26 +01004919#endif
4920
willy tarreau0f7af912005-12-17 12:21:26 +01004921
willy tarreau1c2ad212005-12-18 01:11:29 +01004922 /*
4923 * We'll first check if some fds have been closed recently, in which case
4924 * we'll have to remove them from the previous epoll set. It's
4925 * unnecessary to call epoll_ctl(DEL) because close() automatically
4926 * removes the fds from the epoll set.
4927 */
4928 for (fd = maxfd; fd < last_maxfd; fd++) {
4929 ev.data.fd = fd;
4930 FD_CLR(fd, PrevReadEvent);
4931 FD_CLR(fd, PrevWriteEvent);
4932 }
4933 last_maxfd = maxfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004934
willy tarreau1c2ad212005-12-18 01:11:29 +01004935 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
4936
4937 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
4938 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
4939
4940 if ((ro^rn) | (wo^wn)) {
4941 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
4942#define FDSETS_ARE_INT_ALIGNED
4943#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01004944
willy tarreauad90a0c2005-12-18 01:09:15 +01004945#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
4946#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01004947 pr = (ro >> count) & 1;
4948 pw = (wo >> count) & 1;
4949 sr = (rn >> count) & 1;
4950 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01004951#else
willy tarreau1c2ad212005-12-18 01:11:29 +01004952 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
4953 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
4954 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
4955 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01004956#endif
4957#else
willy tarreau1c2ad212005-12-18 01:11:29 +01004958 pr = FD_ISSET(fd, PrevReadEvent);
4959 pw = FD_ISSET(fd, PrevWriteEvent);
4960 sr = FD_ISSET(fd, StaticReadEvent);
4961 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01004962#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01004963 if (!((sr^pr) | (sw^pw)))
4964 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01004965
willy tarreau1c2ad212005-12-18 01:11:29 +01004966 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
4967 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01004968
willy tarreau1c2ad212005-12-18 01:11:29 +01004969 if ((pr | pw)) {
4970 /* the file-descriptor already exists... */
4971 if ((sr | sw)) {
4972 /* ...and it will still exist */
4973 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
4974 // perror("epoll_ctl(MOD)");
4975 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01004976 }
4977 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01004978 /* ...and it will be removed */
4979 if (fdtab[fd].state != FD_STCLOSE &&
4980 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
4981 // perror("epoll_ctl(DEL)");
4982 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01004983 }
4984 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004985 } else {
4986 /* the file-descriptor did not exist, let's add it */
4987 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
4988 // perror("epoll_ctl(ADD)");
4989 // exit(1);
4990 }
willy tarreauad90a0c2005-12-18 01:09:15 +01004991 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004992 }
4993 ((int*)PrevReadEvent)[fds] = rn;
4994 ((int*)PrevWriteEvent)[fds] = wn;
4995 }
4996 }
4997
4998 /* now let's wait for events */
4999 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5000 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005001
willy tarreau1c2ad212005-12-18 01:11:29 +01005002 for (count = 0; count < status; count++) {
5003 fd = epoll_events[count].data.fd;
5004
5005 if (fdtab[fd].state == FD_STCLOSE)
5006 continue;
5007
5008 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5009 fdtab[fd].read(fd);
5010
5011 if (fdtab[fd].state == FD_STCLOSE)
5012 continue;
5013
5014 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5015 fdtab[fd].write(fd);
5016 }
5017 }
5018 return 1;
5019}
5020#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005021
willy tarreauad90a0c2005-12-18 01:09:15 +01005022
willy tarreau5cbea6f2005-12-17 12:48:26 +01005023
willy tarreau1c2ad212005-12-18 01:11:29 +01005024#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005025
willy tarreau1c2ad212005-12-18 01:11:29 +01005026/*
5027 * Main poll() loop.
5028 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005029
willy tarreau1c2ad212005-12-18 01:11:29 +01005030/* does 3 actions :
5031 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5032 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5033 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5034 *
5035 * returns 0 if initialization failed, !0 otherwise.
5036 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005037
willy tarreau1c2ad212005-12-18 01:11:29 +01005038int poll_loop(int action) {
5039 int next_time;
5040 int status;
5041 int fd, nbfd;
5042
5043 int fds, count;
5044 int sr, sw;
5045 unsigned rn, wn; /* read new, write new */
5046
5047 /* private data */
5048 static struct pollfd *poll_events = NULL;
5049
5050 if (action == POLL_LOOP_ACTION_INIT) {
5051 poll_events = (struct pollfd*)
5052 calloc(1, sizeof(struct pollfd) * global.maxsock);
5053 return 1;
5054 }
5055 else if (action == POLL_LOOP_ACTION_CLEAN) {
5056 if (poll_events)
5057 free(poll_events);
5058 return 1;
5059 }
5060
5061 /* OK, it's POLL_LOOP_ACTION_RUN */
5062
5063 tv_now(&now);
5064
5065 while (1) {
5066 next_time = process_runnable_tasks();
5067
5068 /* stop when there's no connection left and we don't allow them anymore */
5069 if (!actconn && listeners == 0)
5070 break;
5071
5072#if STATTIME > 0
5073 {
5074 int time2;
5075 time2 = stats();
5076 next_time = MINTIME(time2, next_time);
5077 }
5078#endif
5079
5080
5081 nbfd = 0;
5082 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5083
5084 rn = ((int*)StaticReadEvent)[fds];
5085 wn = ((int*)StaticWriteEvent)[fds];
5086
5087 if ((rn|wn)) {
5088 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5089#define FDSETS_ARE_INT_ALIGNED
5090#ifdef FDSETS_ARE_INT_ALIGNED
5091
5092#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5093#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5094 sr = (rn >> count) & 1;
5095 sw = (wn >> count) & 1;
5096#else
5097 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5098 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5099#endif
5100#else
5101 sr = FD_ISSET(fd, StaticReadEvent);
5102 sw = FD_ISSET(fd, StaticWriteEvent);
5103#endif
5104 if ((sr|sw)) {
5105 poll_events[nbfd].fd = fd;
5106 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5107 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005108 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005109 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005110 }
5111 }
5112
5113 /* now let's wait for events */
5114 status = poll(poll_events, nbfd, next_time);
5115 tv_now(&now);
5116
5117 for (count = 0; status > 0 && count < nbfd; count++) {
5118 fd = poll_events[count].fd;
5119
5120 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5121 continue;
5122
5123 /* ok, we found one active fd */
5124 status--;
5125
5126 if (fdtab[fd].state == FD_STCLOSE)
5127 continue;
5128
5129 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5130 fdtab[fd].read(fd);
5131
5132 if (fdtab[fd].state == FD_STCLOSE)
5133 continue;
5134
5135 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5136 fdtab[fd].write(fd);
5137 }
5138 }
5139 return 1;
5140}
willy tarreauad90a0c2005-12-18 01:09:15 +01005141#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005142
willy tarreauad90a0c2005-12-18 01:09:15 +01005143
willy tarreauad90a0c2005-12-18 01:09:15 +01005144
willy tarreau1c2ad212005-12-18 01:11:29 +01005145/*
5146 * Main select() loop.
5147 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005148
willy tarreau1c2ad212005-12-18 01:11:29 +01005149/* does 3 actions :
5150 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5151 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5152 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5153 *
5154 * returns 0 if initialization failed, !0 otherwise.
5155 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005156
willy tarreauad90a0c2005-12-18 01:09:15 +01005157
willy tarreau1c2ad212005-12-18 01:11:29 +01005158int select_loop(int action) {
5159 int next_time;
5160 int status;
5161 int fd,i;
5162 struct timeval delta;
5163 int readnotnull, writenotnull;
5164 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005165
willy tarreau1c2ad212005-12-18 01:11:29 +01005166 if (action == POLL_LOOP_ACTION_INIT) {
5167 ReadEvent = (fd_set *)
5168 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5169 WriteEvent = (fd_set *)
5170 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5171 return 1;
5172 }
5173 else if (action == POLL_LOOP_ACTION_CLEAN) {
5174 if (WriteEvent) free(WriteEvent);
5175 if (ReadEvent) free(ReadEvent);
5176 return 1;
5177 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005178
willy tarreau1c2ad212005-12-18 01:11:29 +01005179 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005180
willy tarreau1c2ad212005-12-18 01:11:29 +01005181 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005182
willy tarreau1c2ad212005-12-18 01:11:29 +01005183 while (1) {
5184 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005185
willy tarreau1c2ad212005-12-18 01:11:29 +01005186 /* stop when there's no connection left and we don't allow them anymore */
5187 if (!actconn && listeners == 0)
5188 break;
5189
5190#if STATTIME > 0
5191 {
5192 int time2;
5193 time2 = stats();
5194 next_time = MINTIME(time2, next_time);
5195 }
5196#endif
5197
willy tarreau1c2ad212005-12-18 01:11:29 +01005198 if (next_time > 0) { /* FIXME */
5199 /* Convert to timeval */
5200 /* to avoid eventual select loops due to timer precision */
5201 next_time += SCHEDULER_RESOLUTION;
5202 delta.tv_sec = next_time / 1000;
5203 delta.tv_usec = (next_time % 1000) * 1000;
5204 }
5205 else if (next_time == 0) { /* allow select to return immediately when needed */
5206 delta.tv_sec = delta.tv_usec = 0;
5207 }
5208
5209
5210 /* let's restore fdset state */
5211
5212 readnotnull = 0; writenotnull = 0;
5213 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5214 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5215 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5216 }
5217
5218 // /* just a verification code, needs to be removed for performance */
5219 // for (i=0; i<maxfd; i++) {
5220 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5221 // abort();
5222 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5223 // abort();
5224 //
5225 // }
5226
5227 status = select(maxfd,
5228 readnotnull ? ReadEvent : NULL,
5229 writenotnull ? WriteEvent : NULL,
5230 NULL,
5231 (next_time >= 0) ? &delta : NULL);
5232
5233 /* this is an experiment on the separation of the select work */
5234 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5235 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5236
5237 tv_now(&now);
5238
5239 if (status > 0) { /* must proceed with events */
5240
5241 int fds;
5242 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005243
willy tarreau1c2ad212005-12-18 01:11:29 +01005244 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5245 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5246 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5247
5248 /* if we specify read first, the accepts and zero reads will be
5249 * seen first. Moreover, system buffers will be flushed faster.
5250 */
5251 if (fdtab[fd].state == FD_STCLOSE)
5252 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005253
willy tarreau1c2ad212005-12-18 01:11:29 +01005254 if (FD_ISSET(fd, ReadEvent))
5255 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005256
willy tarreau1c2ad212005-12-18 01:11:29 +01005257 if (FD_ISSET(fd, WriteEvent))
5258 fdtab[fd].write(fd);
5259 }
5260 }
5261 else {
5262 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005263 }
willy tarreau0f7af912005-12-17 12:21:26 +01005264 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005265 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005266}
5267
5268
5269#if STATTIME > 0
5270/*
5271 * Display proxy statistics regularly. It is designed to be called from the
5272 * select_loop().
5273 */
5274int stats(void) {
5275 static int lines;
5276 static struct timeval nextevt;
5277 static struct timeval lastevt;
5278 static struct timeval starttime = {0,0};
5279 unsigned long totaltime, deltatime;
5280 int ret;
5281
willy tarreau750a4722005-12-17 13:21:24 +01005282 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005283 deltatime = (tv_diff(&lastevt, &now)?:1);
5284 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005285
willy tarreau9fe663a2005-12-17 13:02:59 +01005286 if (global.mode & MODE_STATS) {
5287 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005288 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005289 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5290 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005291 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005292 actconn, totalconn,
5293 stats_tsk_new, stats_tsk_good,
5294 stats_tsk_left, stats_tsk_right,
5295 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5296 }
5297 }
5298
5299 tv_delayfrom(&nextevt, &now, STATTIME);
5300
5301 lastevt=now;
5302 }
5303 ret = tv_remain(&now, &nextevt);
5304 return ret;
5305}
5306#endif
5307
5308
5309/*
5310 * this function enables proxies when there are enough free sessions,
5311 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005312 * select_loop(). It returns the time left before next expiration event
5313 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005314 */
5315static int maintain_proxies(void) {
5316 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005317 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005318 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005319
5320 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005321 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005322
5323 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005324 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005325 while (p) {
5326 if (p->nbconn < p->maxconn) {
5327 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005328 for (l = p->listen; l != NULL; l = l->next) {
5329 FD_SET(l->fd, StaticReadEvent);
5330 }
willy tarreau0f7af912005-12-17 12:21:26 +01005331 p->state = PR_STRUN;
5332 }
5333 }
5334 else {
5335 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005336 for (l = p->listen; l != NULL; l = l->next) {
5337 FD_CLR(l->fd, StaticReadEvent);
5338 }
willy tarreau0f7af912005-12-17 12:21:26 +01005339 p->state = PR_STIDLE;
5340 }
5341 }
5342 p = p->next;
5343 }
5344 }
5345 else { /* block all proxies */
5346 while (p) {
5347 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005348 for (l = p->listen; l != NULL; l = l->next) {
5349 FD_CLR(l->fd, StaticReadEvent);
5350 }
willy tarreau0f7af912005-12-17 12:21:26 +01005351 p->state = PR_STIDLE;
5352 }
5353 p = p->next;
5354 }
5355 }
5356
willy tarreau5cbea6f2005-12-17 12:48:26 +01005357 if (stopping) {
5358 p = proxy;
5359 while (p) {
5360 if (p->state != PR_STDISABLED) {
5361 int t;
5362 t = tv_remain(&now, &p->stop_time);
5363 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005364 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005365 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005366
willy tarreaua41a8b42005-12-17 14:02:24 +01005367 for (l = p->listen; l != NULL; l = l->next) {
5368 fd_delete(l->fd);
5369 listeners--;
5370 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005371 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005372 }
5373 else {
5374 tleft = MINTIME(t, tleft);
5375 }
5376 }
5377 p = p->next;
5378 }
5379 }
5380 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005381}
5382
5383/*
5384 * this function disables health-check servers so that the process will quickly be ignored
5385 * by load balancers.
5386 */
5387static void soft_stop(void) {
5388 struct proxy *p;
5389
5390 stopping = 1;
5391 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005392 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005393 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005394 if (p->state != PR_STDISABLED) {
5395 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005396 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005397 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005398 }
willy tarreau0f7af912005-12-17 12:21:26 +01005399 p = p->next;
5400 }
5401}
5402
5403/*
5404 * upon SIGUSR1, let's have a soft stop.
5405 */
5406void sig_soft_stop(int sig) {
5407 soft_stop();
5408 signal(sig, SIG_IGN);
5409}
5410
5411
willy tarreau8337c6b2005-12-17 13:41:01 +01005412/*
5413 * this function dumps every server's state when the process receives SIGHUP.
5414 */
5415void sig_dump_state(int sig) {
5416 struct proxy *p = proxy;
5417
5418 Warning("SIGHUP received, dumping servers states.\n");
5419 while (p) {
5420 struct server *s = p->srv;
5421
5422 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5423 while (s) {
5424 if (s->state & SRV_RUNNING) {
5425 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5426 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5427 }
5428 else {
5429 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5430 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5431 }
5432 s = s->next;
5433 }
willy tarreaudd07e972005-12-18 00:48:48 +01005434
5435 if (find_server(p) == NULL) {
5436 Warning("SIGHUP: proxy %s has no server available !\n", p);
5437 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5438 }
5439
willy tarreau8337c6b2005-12-17 13:41:01 +01005440 p = p->next;
5441 }
5442 signal(sig, sig_dump_state);
5443}
5444
willy tarreau0f7af912005-12-17 12:21:26 +01005445void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005446 struct task *t, *tnext;
5447 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005448
willy tarreau5cbea6f2005-12-17 12:48:26 +01005449 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5450 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5451 tnext = t->next;
5452 s = t->context;
5453 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5454 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5455 "req=%d, rep=%d, clifd=%d\n",
5456 s, tv_remain(&now, &t->expire),
5457 s->cli_state,
5458 s->srv_state,
5459 FD_ISSET(s->cli_fd, StaticReadEvent),
5460 FD_ISSET(s->cli_fd, StaticWriteEvent),
5461 FD_ISSET(s->srv_fd, StaticReadEvent),
5462 FD_ISSET(s->srv_fd, StaticWriteEvent),
5463 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5464 );
willy tarreau0f7af912005-12-17 12:21:26 +01005465 }
willy tarreau12350152005-12-18 01:03:27 +01005466}
5467
willy tarreau64a3cc32005-12-18 01:13:11 +01005468#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005469static void fast_stop(void)
5470{
5471 struct proxy *p;
5472 p = proxy;
5473 while (p) {
5474 p->grace = 0;
5475 p = p->next;
5476 }
5477 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005478}
5479
willy tarreau12350152005-12-18 01:03:27 +01005480void sig_int(int sig) {
5481 /* This would normally be a hard stop,
5482 but we want to be sure about deallocation,
5483 and so on, so we do a soft stop with
5484 0 GRACE time
5485 */
5486 fast_stop();
5487 /* If we are killed twice, we decide to die*/
5488 signal(sig, SIG_DFL);
5489}
5490
5491void sig_term(int sig) {
5492 /* This would normally be a hard stop,
5493 but we want to be sure about deallocation,
5494 and so on, so we do a soft stop with
5495 0 GRACE time
5496 */
5497 fast_stop();
5498 /* If we are killed twice, we decide to die*/
5499 signal(sig, SIG_DFL);
5500}
willy tarreau64a3cc32005-12-18 01:13:11 +01005501#endif
willy tarreau12350152005-12-18 01:03:27 +01005502
willy tarreauc1f47532005-12-18 01:08:26 +01005503/* returns the pointer to an error in the replacement string, or NULL if OK */
5504char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005505 struct hdr_exp *exp;
5506
willy tarreauc1f47532005-12-18 01:08:26 +01005507 if (replace != NULL) {
5508 char *err;
5509 err = check_replace_string(replace);
5510 if (err)
5511 return err;
5512 }
5513
willy tarreaue39cd132005-12-17 13:00:18 +01005514 while (*head != NULL)
5515 head = &(*head)->next;
5516
5517 exp = calloc(1, sizeof(struct hdr_exp));
5518
5519 exp->preg = preg;
5520 exp->replace = replace;
5521 exp->action = action;
5522 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005523
5524 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005525}
5526
willy tarreau9fe663a2005-12-17 13:02:59 +01005527
willy tarreau0f7af912005-12-17 12:21:26 +01005528/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005529 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005530 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005531int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005532
willy tarreau9fe663a2005-12-17 13:02:59 +01005533 if (!strcmp(args[0], "global")) { /* new section */
5534 /* no option, nothing special to do */
5535 return 0;
5536 }
5537 else if (!strcmp(args[0], "daemon")) {
5538 global.mode |= MODE_DAEMON;
5539 }
5540 else if (!strcmp(args[0], "debug")) {
5541 global.mode |= MODE_DEBUG;
5542 }
willy tarreau64a3cc32005-12-18 01:13:11 +01005543 else if (!strcmp(args[0], "noepoll")) {
5544 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
5545 }
5546 else if (!strcmp(args[0], "nopoll")) {
5547 cfg_polling_mechanism &= ~POLL_USE_POLL;
5548 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005549 else if (!strcmp(args[0], "quiet")) {
5550 global.mode |= MODE_QUIET;
5551 }
5552 else if (!strcmp(args[0], "stats")) {
5553 global.mode |= MODE_STATS;
5554 }
5555 else if (!strcmp(args[0], "uid")) {
5556 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005557 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005558 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005559 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005560 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005561 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005562 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005563 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005564 global.uid = atol(args[1]);
5565 }
5566 else if (!strcmp(args[0], "gid")) {
5567 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005568 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005569 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005570 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005571 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005572 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005573 return -1;
5574 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005575 global.gid = atol(args[1]);
5576 }
5577 else if (!strcmp(args[0], "nbproc")) {
5578 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005579 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005580 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005582 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005583 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005584 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005585 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005586 global.nbproc = atol(args[1]);
5587 }
5588 else if (!strcmp(args[0], "maxconn")) {
5589 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005590 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005591 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005592 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005593 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005594 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005595 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005596 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005597 global.maxconn = atol(args[1]);
5598 }
5599 else if (!strcmp(args[0], "chroot")) {
5600 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005601 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005602 return 0;
5603 }
5604 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005605 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005606 return -1;
5607 }
5608 global.chroot = strdup(args[1]);
5609 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005610 else if (!strcmp(args[0], "pidfile")) {
5611 if (global.pidfile != NULL) {
5612 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5613 return 0;
5614 }
5615 if (*(args[1]) == 0) {
5616 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5617 return -1;
5618 }
5619 global.pidfile = strdup(args[1]);
5620 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005621 else if (!strcmp(args[0], "log")) { /* syslog server address */
5622 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005623 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005624
5625 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005626 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005627 return -1;
5628 }
5629
5630 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5631 if (!strcmp(log_facilities[facility], args[2]))
5632 break;
5633
5634 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005635 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005636 exit(1);
5637 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005638
5639 level = 7; /* max syslog level = debug */
5640 if (*(args[3])) {
5641 while (level >= 0 && strcmp(log_levels[level], args[3]))
5642 level--;
5643 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005644 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005645 exit(1);
5646 }
5647 }
5648
willy tarreau9fe663a2005-12-17 13:02:59 +01005649 sa = str2sa(args[1]);
5650 if (!sa->sin_port)
5651 sa->sin_port = htons(SYSLOG_PORT);
5652
5653 if (global.logfac1 == -1) {
5654 global.logsrv1 = *sa;
5655 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005656 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005657 }
5658 else if (global.logfac2 == -1) {
5659 global.logsrv2 = *sa;
5660 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005661 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005662 }
5663 else {
5664 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5665 return -1;
5666 }
5667
5668 }
5669 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005670 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005671 return -1;
5672 }
5673 return 0;
5674}
5675
5676
willy tarreaua41a8b42005-12-17 14:02:24 +01005677void init_default_instance() {
5678 memset(&defproxy, 0, sizeof(defproxy));
5679 defproxy.mode = PR_MODE_TCP;
5680 defproxy.state = PR_STNEW;
5681 defproxy.maxconn = cfg_maxpconn;
5682 defproxy.conn_retries = CONN_RETRIES;
5683 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
5684}
5685
willy tarreau9fe663a2005-12-17 13:02:59 +01005686/*
5687 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5688 */
5689int cfg_parse_listen(char *file, int linenum, char **args) {
5690 static struct proxy *curproxy = NULL;
5691 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01005692 char *err;
willy tarreau12350152005-12-18 01:03:27 +01005693 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01005694
5695 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005696 if (!*args[1]) {
5697 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5698 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005699 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005700 return -1;
5701 }
5702
5703 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005704 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005705 return -1;
5706 }
5707 curproxy->next = proxy;
5708 proxy = curproxy;
5709 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005710 if (strchr(args[2], ':') != NULL)
5711 curproxy->listen = str2listener(args[2], curproxy->listen);
5712
willy tarreau9fe663a2005-12-17 13:02:59 +01005713 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005714 curproxy->state = defproxy.state;
5715 curproxy->maxconn = defproxy.maxconn;
5716 curproxy->conn_retries = defproxy.conn_retries;
5717 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005718
5719 if (defproxy.check_req)
5720 curproxy->check_req = strdup(defproxy.check_req);
5721 curproxy->check_len = defproxy.check_len;
5722
5723 if (defproxy.cookie_name)
5724 curproxy->cookie_name = strdup(defproxy.cookie_name);
5725 curproxy->cookie_len = defproxy.cookie_len;
5726
5727 if (defproxy.capture_name)
5728 curproxy->capture_name = strdup(defproxy.capture_name);
5729 curproxy->capture_namelen = defproxy.capture_namelen;
5730 curproxy->capture_len = defproxy.capture_len;
5731
5732 if (defproxy.errmsg.msg400)
5733 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5734 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5735
5736 if (defproxy.errmsg.msg403)
5737 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5738 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5739
5740 if (defproxy.errmsg.msg408)
5741 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5742 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5743
5744 if (defproxy.errmsg.msg500)
5745 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5746 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5747
5748 if (defproxy.errmsg.msg502)
5749 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5750 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5751
5752 if (defproxy.errmsg.msg503)
5753 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5754 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5755
5756 if (defproxy.errmsg.msg504)
5757 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5758 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5759
willy tarreaua41a8b42005-12-17 14:02:24 +01005760 curproxy->clitimeout = defproxy.clitimeout;
5761 curproxy->contimeout = defproxy.contimeout;
5762 curproxy->srvtimeout = defproxy.srvtimeout;
5763 curproxy->mode = defproxy.mode;
5764 curproxy->logfac1 = defproxy.logfac1;
5765 curproxy->logsrv1 = defproxy.logsrv1;
5766 curproxy->loglev1 = defproxy.loglev1;
5767 curproxy->logfac2 = defproxy.logfac2;
5768 curproxy->logsrv2 = defproxy.logsrv2;
5769 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01005770 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01005771 curproxy->grace = defproxy.grace;
5772 curproxy->source_addr = defproxy.source_addr;
5773 return 0;
5774 }
5775 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005776 /* some variables may have already been initialized earlier */
5777 if (defproxy.check_req) free(defproxy.check_req);
5778 if (defproxy.cookie_name) free(defproxy.cookie_name);
5779 if (defproxy.capture_name) free(defproxy.capture_name);
5780 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
5781 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
5782 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
5783 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
5784 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
5785 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
5786 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
5787
5788 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01005789 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01005790 return 0;
5791 }
5792 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005793 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005794 return -1;
5795 }
5796
willy tarreaua41a8b42005-12-17 14:02:24 +01005797 if (!strcmp(args[0], "bind")) { /* new listen addresses */
5798 if (curproxy == &defproxy) {
5799 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5800 return -1;
5801 }
5802
5803 if (strchr(args[1], ':') == NULL) {
5804 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
5805 file, linenum, args[0]);
5806 return -1;
5807 }
5808 curproxy->listen = str2listener(args[1], curproxy->listen);
5809 return 0;
5810 }
5811 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01005812 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
5813 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
5814 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
5815 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005816 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005817 return -1;
5818 }
5819 }
5820 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
5821 curproxy->state = PR_STDISABLED;
5822 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005823 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
5824 curproxy->state = PR_STNEW;
5825 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005826 else if (!strcmp(args[0], "cookie")) { /* cookie name */
5827 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005828// if (curproxy == &defproxy) {
5829// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5830// return -1;
5831// }
willy tarreaua41a8b42005-12-17 14:02:24 +01005832
willy tarreau9fe663a2005-12-17 13:02:59 +01005833 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005834// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5835// file, linenum);
5836// return 0;
5837 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005838 }
5839
5840 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005841 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
5842 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005843 return -1;
5844 }
5845 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005846 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005847
5848 cur_arg = 2;
5849 while (*(args[cur_arg])) {
5850 if (!strcmp(args[cur_arg], "rewrite")) {
5851 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01005852 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005853 else if (!strcmp(args[cur_arg], "indirect")) {
5854 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01005855 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005856 else if (!strcmp(args[cur_arg], "insert")) {
5857 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01005858 }
willy tarreau240afa62005-12-17 13:14:35 +01005859 else if (!strcmp(args[cur_arg], "nocache")) {
5860 curproxy->options |= PR_O_COOK_NOC;
5861 }
willy tarreaucd878942005-12-17 13:27:43 +01005862 else if (!strcmp(args[cur_arg], "postonly")) {
5863 curproxy->options |= PR_O_COOK_POST;
5864 }
willy tarreau0174f312005-12-18 01:02:42 +01005865 else if (!strcmp(args[cur_arg], "prefix")) {
5866 curproxy->options |= PR_O_COOK_PFX;
5867 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005868 else {
willy tarreau0174f312005-12-18 01:02:42 +01005869 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005870 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005871 return -1;
5872 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005873 cur_arg++;
5874 }
willy tarreau0174f312005-12-18 01:02:42 +01005875 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
5876 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
5877 file, linenum);
5878 return -1;
5879 }
5880
5881 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
5882 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005883 file, linenum);
5884 return -1;
5885 }
willy tarreau12350152005-12-18 01:03:27 +01005886 }/* end else if (!strcmp(args[0], "cookie")) */
5887 else if (!strcmp(args[0], "appsession")) { /* cookie name */
5888// if (curproxy == &defproxy) {
5889// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5890// return -1;
5891// }
5892
5893 if (curproxy->appsession_name != NULL) {
5894// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5895// file, linenum);
5896// return 0;
5897 free(curproxy->appsession_name);
5898 }
5899
5900 if (*(args[5]) == 0) {
5901 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
5902 file, linenum, args[0]);
5903 return -1;
5904 }
5905 have_appsession = 1;
5906 curproxy->appsession_name = strdup(args[1]);
5907 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
5908 curproxy->appsession_len = atoi(args[3]);
5909 curproxy->appsession_timeout = atoi(args[5]);
5910 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
5911 if (rc) {
5912 Alert("Error Init Appsession Hashtable.\n");
5913 return -1;
5914 }
5915 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01005916 else if (!strcmp(args[0], "capture")) {
5917 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
5918 // if (curproxy == &defproxy) {
5919 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5920 // return -1;
5921 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005922
willy tarreau4302f492005-12-18 01:00:37 +01005923 if (curproxy->capture_name != NULL) {
5924 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5925 // file, linenum, args[0]);
5926 // return 0;
5927 free(curproxy->capture_name);
5928 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005929
willy tarreau4302f492005-12-18 01:00:37 +01005930 if (*(args[4]) == 0) {
5931 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
5932 file, linenum, args[0]);
5933 return -1;
5934 }
5935 curproxy->capture_name = strdup(args[2]);
5936 curproxy->capture_namelen = strlen(curproxy->capture_name);
5937 curproxy->capture_len = atol(args[4]);
5938 if (curproxy->capture_len >= CAPTURE_LEN) {
5939 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
5940 file, linenum, CAPTURE_LEN - 1);
5941 curproxy->capture_len = CAPTURE_LEN - 1;
5942 }
5943 curproxy->to_log |= LW_COOKIE;
5944 }
5945 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
5946 struct cap_hdr *hdr;
5947
5948 if (curproxy == &defproxy) {
5949 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5950 return -1;
5951 }
5952
5953 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5954 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5955 file, linenum, args[0], args[1]);
5956 return -1;
5957 }
5958
5959 hdr = calloc(sizeof(struct cap_hdr), 1);
5960 hdr->next = curproxy->req_cap;
5961 hdr->name = strdup(args[3]);
5962 hdr->namelen = strlen(args[3]);
5963 hdr->len = atol(args[5]);
5964 hdr->index = curproxy->nb_req_cap++;
5965 curproxy->req_cap = hdr;
5966 curproxy->to_log |= LW_REQHDR;
5967 }
5968 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
5969 struct cap_hdr *hdr;
5970
5971 if (curproxy == &defproxy) {
5972 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5973 return -1;
5974 }
5975
5976 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5977 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5978 file, linenum, args[0], args[1]);
5979 return -1;
5980 }
5981 hdr = calloc(sizeof(struct cap_hdr), 1);
5982 hdr->next = curproxy->rsp_cap;
5983 hdr->name = strdup(args[3]);
5984 hdr->namelen = strlen(args[3]);
5985 hdr->len = atol(args[5]);
5986 hdr->index = curproxy->nb_rsp_cap++;
5987 curproxy->rsp_cap = hdr;
5988 curproxy->to_log |= LW_RSPHDR;
5989 }
5990 else {
5991 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005992 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005993 return -1;
5994 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005995 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005996 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005997 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005998 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005999 return 0;
6000 }
6001 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006002 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6003 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006004 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006005 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006006 curproxy->contimeout = atol(args[1]);
6007 }
6008 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006009 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006010 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6011 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006012 return 0;
6013 }
6014 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006015 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6016 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006017 return -1;
6018 }
6019 curproxy->clitimeout = atol(args[1]);
6020 }
6021 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006022 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006023 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006024 return 0;
6025 }
6026 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006027 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6028 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006029 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006030 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006031 curproxy->srvtimeout = atol(args[1]);
6032 }
6033 else if (!strcmp(args[0], "retries")) { /* connection retries */
6034 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006035 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6036 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006037 return -1;
6038 }
6039 curproxy->conn_retries = atol(args[1]);
6040 }
6041 else if (!strcmp(args[0], "option")) {
6042 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006043 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006044 return -1;
6045 }
6046 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006047 /* enable reconnections to dispatch */
6048 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006049#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006050 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006051 /* enable transparent proxy connections */
6052 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006053#endif
6054 else if (!strcmp(args[1], "keepalive"))
6055 /* enable keep-alive */
6056 curproxy->options |= PR_O_KEEPALIVE;
6057 else if (!strcmp(args[1], "forwardfor"))
6058 /* insert x-forwarded-for field */
6059 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006060 else if (!strcmp(args[1], "logasap"))
6061 /* log as soon as possible, without waiting for the session to complete */
6062 curproxy->options |= PR_O_LOGASAP;
6063 else if (!strcmp(args[1], "httpclose"))
6064 /* force connection: close in both directions in HTTP mode */
6065 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006066 else if (!strcmp(args[1], "checkcache"))
6067 /* require examination of cacheability of the 'set-cookie' field */
6068 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006069 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006070 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006071 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006072 else if (!strcmp(args[1], "tcplog"))
6073 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006074 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006075 else if (!strcmp(args[1], "dontlognull")) {
6076 /* don't log empty requests */
6077 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006078 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006079 else if (!strcmp(args[1], "httpchk")) {
6080 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006081 if (curproxy->check_req != NULL) {
6082 free(curproxy->check_req);
6083 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006084 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006085 if (!*args[2]) { /* no argument */
6086 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6087 curproxy->check_len = strlen(DEF_CHECK_REQ);
6088 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006089 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6090 curproxy->check_req = (char *)malloc(reqlen);
6091 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6092 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006093 } else { /* more arguments : METHOD URI [HTTP_VER] */
6094 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6095 if (*args[4])
6096 reqlen += strlen(args[4]);
6097 else
6098 reqlen += strlen("HTTP/1.0");
6099
6100 curproxy->check_req = (char *)malloc(reqlen);
6101 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6102 "%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 +01006103 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006104 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006105 else if (!strcmp(args[1], "persist")) {
6106 /* persist on using the server specified by the cookie, even when it's down */
6107 curproxy->options |= PR_O_PERSIST;
6108 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006109 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006110 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006111 return -1;
6112 }
6113 return 0;
6114 }
6115 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6116 /* enable reconnections to dispatch */
6117 curproxy->options |= PR_O_REDISP;
6118 }
willy tarreaua1598082005-12-17 13:08:06 +01006119#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006120 else if (!strcmp(args[0], "transparent")) {
6121 /* enable transparent proxy connections */
6122 curproxy->options |= PR_O_TRANSP;
6123 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006124#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006125 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6126 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006127 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006128 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006129 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006130 curproxy->maxconn = atol(args[1]);
6131 }
6132 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6133 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006134 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006135 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006136 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006137 curproxy->grace = atol(args[1]);
6138 }
6139 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006140 if (curproxy == &defproxy) {
6141 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6142 return -1;
6143 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006144 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006145 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006146 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006147 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006148 curproxy->dispatch_addr = *str2sa(args[1]);
6149 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006150 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006151 if (*(args[1])) {
6152 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006153 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006154 }
6155 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006156 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006157 return -1;
6158 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006159 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006160 else /* if no option is set, use round-robin by default */
6161 curproxy->options |= PR_O_BALANCE_RR;
6162 }
6163 else if (!strcmp(args[0], "server")) { /* server address */
6164 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006165 char *rport;
6166 char *raddr;
6167 short realport;
6168 int do_check;
6169
6170 if (curproxy == &defproxy) {
6171 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6172 return -1;
6173 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006174
willy tarreaua41a8b42005-12-17 14:02:24 +01006175 if (!*args[2]) {
6176 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006177 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006178 return -1;
6179 }
6180 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6181 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6182 return -1;
6183 }
willy tarreau0174f312005-12-18 01:02:42 +01006184
6185 if (curproxy->srv == NULL)
6186 curproxy->srv = newsrv;
6187 else
6188 curproxy->cursrv->next = newsrv;
6189 curproxy->cursrv = newsrv;
6190
6191 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006192 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006193
6194 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006195 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006196 newsrv->id = strdup(args[1]);
6197
6198 /* several ways to check the port component :
6199 * - IP => port=+0, relative
6200 * - IP: => port=+0, relative
6201 * - IP:N => port=N, absolute
6202 * - IP:+N => port=+N, relative
6203 * - IP:-N => port=-N, relative
6204 */
6205 raddr = strdup(args[2]);
6206 rport = strchr(raddr, ':');
6207 if (rport) {
6208 *rport++ = 0;
6209 realport = atol(rport);
6210 if (!isdigit((int)*rport))
6211 newsrv->state |= SRV_MAPPORTS;
6212 } else {
6213 realport = 0;
6214 newsrv->state |= SRV_MAPPORTS;
6215 }
6216
6217 newsrv->addr = *str2sa(raddr);
6218 newsrv->addr.sin_port = htons(realport);
6219 free(raddr);
6220
willy tarreau9fe663a2005-12-17 13:02:59 +01006221 newsrv->curfd = -1; /* no health-check in progress */
6222 newsrv->inter = DEF_CHKINTR;
6223 newsrv->rise = DEF_RISETIME;
6224 newsrv->fall = DEF_FALLTIME;
6225 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6226 cur_arg = 3;
6227 while (*args[cur_arg]) {
6228 if (!strcmp(args[cur_arg], "cookie")) {
6229 newsrv->cookie = strdup(args[cur_arg + 1]);
6230 newsrv->cklen = strlen(args[cur_arg + 1]);
6231 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006232 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006233 else if (!strcmp(args[cur_arg], "rise")) {
6234 newsrv->rise = atol(args[cur_arg + 1]);
6235 newsrv->health = newsrv->rise;
6236 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006237 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006238 else if (!strcmp(args[cur_arg], "fall")) {
6239 newsrv->fall = atol(args[cur_arg + 1]);
6240 cur_arg += 2;
6241 }
6242 else if (!strcmp(args[cur_arg], "inter")) {
6243 newsrv->inter = atol(args[cur_arg + 1]);
6244 cur_arg += 2;
6245 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006246 else if (!strcmp(args[cur_arg], "port")) {
6247 newsrv->check_port = atol(args[cur_arg + 1]);
6248 cur_arg += 2;
6249 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006250 else if (!strcmp(args[cur_arg], "backup")) {
6251 newsrv->state |= SRV_BACKUP;
6252 cur_arg ++;
6253 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006254 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006255 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006256 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006257 }
willy tarreau0174f312005-12-18 01:02:42 +01006258 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6259 if (!*args[cur_arg + 1]) {
6260 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6261 file, linenum, "source");
6262 return -1;
6263 }
6264 newsrv->state |= SRV_BIND_SRC;
6265 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6266 cur_arg += 2;
6267 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006268 else {
willy tarreau0174f312005-12-18 01:02:42 +01006269 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 +01006270 file, linenum, newsrv->id);
6271 return -1;
6272 }
6273 }
6274
6275 if (do_check) {
6276 struct task *t;
6277
6278 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6279 newsrv->check_port = realport; /* by default */
6280 if (!newsrv->check_port) {
6281 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 +01006282 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006283 return -1;
6284 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006285
6286 if ((t = pool_alloc(task)) == NULL) {
6287 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6288 return -1;
6289 }
6290
6291 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6292 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6293 t->state = TASK_IDLE;
6294 t->process = process_chk;
6295 t->context = newsrv;
6296
6297 if (curproxy->state != PR_STDISABLED) {
6298 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6299 task_queue(t);
6300 task_wakeup(&rq, t);
6301 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006302 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006303
willy tarreau9fe663a2005-12-17 13:02:59 +01006304 curproxy->nbservers++;
6305 }
6306 else if (!strcmp(args[0], "log")) { /* syslog server address */
6307 struct sockaddr_in *sa;
6308 int facility;
6309
6310 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6311 curproxy->logfac1 = global.logfac1;
6312 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006313 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006314 curproxy->logfac2 = global.logfac2;
6315 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006316 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006317 }
6318 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006319 int level;
6320
willy tarreau0f7af912005-12-17 12:21:26 +01006321 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6322 if (!strcmp(log_facilities[facility], args[2]))
6323 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006324
willy tarreau0f7af912005-12-17 12:21:26 +01006325 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006326 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006327 exit(1);
6328 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006329
willy tarreau8337c6b2005-12-17 13:41:01 +01006330 level = 7; /* max syslog level = debug */
6331 if (*(args[3])) {
6332 while (level >= 0 && strcmp(log_levels[level], args[3]))
6333 level--;
6334 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006335 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006336 exit(1);
6337 }
6338 }
6339
willy tarreau0f7af912005-12-17 12:21:26 +01006340 sa = str2sa(args[1]);
6341 if (!sa->sin_port)
6342 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006343
willy tarreau0f7af912005-12-17 12:21:26 +01006344 if (curproxy->logfac1 == -1) {
6345 curproxy->logsrv1 = *sa;
6346 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006347 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006348 }
6349 else if (curproxy->logfac2 == -1) {
6350 curproxy->logsrv2 = *sa;
6351 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006352 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006353 }
6354 else {
6355 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006356 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006357 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006358 }
6359 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006360 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006361 file, linenum);
6362 return -1;
6363 }
6364 }
willy tarreaua1598082005-12-17 13:08:06 +01006365 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006366 if (!*args[1]) {
6367 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006368 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006369 return -1;
6370 }
6371
6372 curproxy->source_addr = *str2sa(args[1]);
6373 curproxy->options |= PR_O_BIND_SRC;
6374 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006375 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6376 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006377 if (curproxy == &defproxy) {
6378 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6379 return -1;
6380 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006381
6382 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006383 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6384 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006385 return -1;
6386 }
6387
6388 preg = calloc(1, sizeof(regex_t));
6389 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006390 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006391 return -1;
6392 }
6393
willy tarreauc1f47532005-12-18 01:08:26 +01006394 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6395 if (err) {
6396 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6397 file, linenum, *err);
6398 return -1;
6399 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006400 }
6401 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6402 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006403 if (curproxy == &defproxy) {
6404 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6405 return -1;
6406 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006407
6408 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006409 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006410 return -1;
6411 }
6412
6413 preg = calloc(1, sizeof(regex_t));
6414 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006415 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006416 return -1;
6417 }
6418
6419 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6420 }
6421 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6422 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006423 if (curproxy == &defproxy) {
6424 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6425 return -1;
6426 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006427
6428 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006429 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006430 return -1;
6431 }
6432
6433 preg = calloc(1, sizeof(regex_t));
6434 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006435 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006436 return -1;
6437 }
6438
6439 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6440 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006441 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6442 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006443 if (curproxy == &defproxy) {
6444 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6445 return -1;
6446 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006447
6448 if (*(args[1]) == 0) {
6449 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6450 return -1;
6451 }
6452
6453 preg = calloc(1, sizeof(regex_t));
6454 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6455 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6456 return -1;
6457 }
6458
6459 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6460 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006461 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6462 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006463 if (curproxy == &defproxy) {
6464 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6465 return -1;
6466 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006467
6468 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006469 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006470 return -1;
6471 }
6472
6473 preg = calloc(1, sizeof(regex_t));
6474 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006475 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006476 return -1;
6477 }
6478
6479 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6480 }
6481 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6482 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006483 if (curproxy == &defproxy) {
6484 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6485 return -1;
6486 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006487
6488 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006489 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6490 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006491 return -1;
6492 }
6493
6494 preg = calloc(1, sizeof(regex_t));
6495 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006496 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006497 return -1;
6498 }
6499
willy tarreauc1f47532005-12-18 01:08:26 +01006500 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6501 if (err) {
6502 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6503 file, linenum, *err);
6504 return -1;
6505 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006506 }
6507 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6508 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006509 if (curproxy == &defproxy) {
6510 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6511 return -1;
6512 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006513
6514 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006515 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006516 return -1;
6517 }
6518
6519 preg = calloc(1, sizeof(regex_t));
6520 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006521 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006522 return -1;
6523 }
6524
6525 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6526 }
6527 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6528 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006529 if (curproxy == &defproxy) {
6530 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6531 return -1;
6532 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006533
6534 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006535 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006536 return -1;
6537 }
6538
6539 preg = calloc(1, sizeof(regex_t));
6540 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006541 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006542 return -1;
6543 }
6544
6545 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6546 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006547 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6548 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006549 if (curproxy == &defproxy) {
6550 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6551 return -1;
6552 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006553
6554 if (*(args[1]) == 0) {
6555 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6556 return -1;
6557 }
6558
6559 preg = calloc(1, sizeof(regex_t));
6560 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6561 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6562 return -1;
6563 }
6564
6565 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6566 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006567 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6568 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006569 if (curproxy == &defproxy) {
6570 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6571 return -1;
6572 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006573
6574 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006575 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006576 return -1;
6577 }
6578
6579 preg = calloc(1, sizeof(regex_t));
6580 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006581 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006582 return -1;
6583 }
6584
6585 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6586 }
6587 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006588 if (curproxy == &defproxy) {
6589 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6590 return -1;
6591 }
6592
willy tarreau9fe663a2005-12-17 13:02:59 +01006593 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006594 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006595 return 0;
6596 }
6597
6598 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006599 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006600 return -1;
6601 }
6602
willy tarreau4302f492005-12-18 01:00:37 +01006603 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6604 }
6605 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6606 regex_t *preg;
6607
6608 if (*(args[1]) == 0 || *(args[2]) == 0) {
6609 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6610 file, linenum, args[0]);
6611 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006612 }
willy tarreau4302f492005-12-18 01:00:37 +01006613
6614 preg = calloc(1, sizeof(regex_t));
6615 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6616 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6617 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006618 }
willy tarreau4302f492005-12-18 01:00:37 +01006619
willy tarreauc1f47532005-12-18 01:08:26 +01006620 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6621 if (err) {
6622 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6623 file, linenum, *err);
6624 return -1;
6625 }
willy tarreau4302f492005-12-18 01:00:37 +01006626 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006627 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6628 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006629 if (curproxy == &defproxy) {
6630 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6631 return -1;
6632 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006633
6634 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006635 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006636 return -1;
6637 }
willy tarreaue39cd132005-12-17 13:00:18 +01006638
willy tarreau9fe663a2005-12-17 13:02:59 +01006639 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;
willy tarreau0f7af912005-12-17 12:21:26 +01006643 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006644
willy tarreauc1f47532005-12-18 01:08:26 +01006645 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, 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 }
willy tarreau982249e2005-12-18 00:57:06 +01006652 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6653 regex_t *preg;
6654 if (curproxy == &defproxy) {
6655 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6656 return -1;
6657 }
6658
6659 if (*(args[1]) == 0) {
6660 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6661 return -1;
6662 }
6663
6664 preg = calloc(1, sizeof(regex_t));
6665 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6666 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6667 return -1;
6668 }
6669
willy tarreauc1f47532005-12-18 01:08:26 +01006670 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6671 if (err) {
6672 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6673 file, linenum, *err);
6674 return -1;
6675 }
willy tarreau982249e2005-12-18 00:57:06 +01006676 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006677 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01006678 regex_t *preg;
6679 if (curproxy == &defproxy) {
6680 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6681 return -1;
6682 }
willy tarreaue39cd132005-12-17 13:00:18 +01006683
willy tarreaua41a8b42005-12-17 14:02:24 +01006684 if (*(args[1]) == 0 || *(args[2]) == 0) {
6685 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6686 file, linenum, args[0]);
6687 return -1;
6688 }
willy tarreaue39cd132005-12-17 13:00:18 +01006689
willy tarreaua41a8b42005-12-17 14:02:24 +01006690 preg = calloc(1, sizeof(regex_t));
6691 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6692 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6693 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006694 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006695
willy tarreauc1f47532005-12-18 01:08:26 +01006696 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6697 if (err) {
6698 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6699 file, linenum, *err);
6700 return -1;
6701 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006702 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006703 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
6704 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006705 if (curproxy == &defproxy) {
6706 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6707 return -1;
6708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006709
6710 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006711 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006712 return -1;
6713 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006714
willy tarreau9fe663a2005-12-17 13:02:59 +01006715 preg = calloc(1, sizeof(regex_t));
6716 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006717 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006718 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006719 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006720
willy tarreauc1f47532005-12-18 01:08:26 +01006721 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6722 if (err) {
6723 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6724 file, linenum, *err);
6725 return -1;
6726 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006727 }
willy tarreau982249e2005-12-18 00:57:06 +01006728 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
6729 regex_t *preg;
6730 if (curproxy == &defproxy) {
6731 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6732 return -1;
6733 }
6734
6735 if (*(args[1]) == 0) {
6736 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6737 return -1;
6738 }
6739
6740 preg = calloc(1, sizeof(regex_t));
6741 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6742 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6743 return -1;
6744 }
6745
willy tarreauc1f47532005-12-18 01:08:26 +01006746 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6747 if (err) {
6748 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6749 file, linenum, *err);
6750 return -1;
6751 }
willy tarreau982249e2005-12-18 00:57:06 +01006752 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006753 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006754 if (curproxy == &defproxy) {
6755 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6756 return -1;
6757 }
6758
willy tarreau9fe663a2005-12-17 13:02:59 +01006759 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006760 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006761 return 0;
6762 }
6763
6764 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006765 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006766 return -1;
6767 }
6768
6769 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
6770 }
willy tarreauc1f47532005-12-18 01:08:26 +01006771 else if (!strcmp(args[0], "errorloc") ||
6772 !strcmp(args[0], "errorloc302") ||
6773 !strcmp(args[0], "errorloc303")) { /* error location */
6774 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006775 char *err;
6776
willy tarreaueedaa9f2005-12-17 14:08:03 +01006777 // if (curproxy == &defproxy) {
6778 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6779 // return -1;
6780 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006781
willy tarreau8337c6b2005-12-17 13:41:01 +01006782 if (*(args[2]) == 0) {
6783 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
6784 return -1;
6785 }
6786
6787 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01006788 if (!strcmp(args[0], "errorloc303")) {
6789 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
6790 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
6791 } else {
6792 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
6793 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
6794 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006795
6796 if (errnum == 400) {
6797 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006798 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006799 free(curproxy->errmsg.msg400);
6800 }
6801 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006802 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006803 }
6804 else if (errnum == 403) {
6805 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006806 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006807 free(curproxy->errmsg.msg403);
6808 }
6809 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006810 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006811 }
6812 else if (errnum == 408) {
6813 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006814 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006815 free(curproxy->errmsg.msg408);
6816 }
6817 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006818 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006819 }
6820 else if (errnum == 500) {
6821 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006822 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006823 free(curproxy->errmsg.msg500);
6824 }
6825 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006826 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006827 }
6828 else if (errnum == 502) {
6829 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006830 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006831 free(curproxy->errmsg.msg502);
6832 }
6833 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006834 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006835 }
6836 else if (errnum == 503) {
6837 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006838 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006839 free(curproxy->errmsg.msg503);
6840 }
6841 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006842 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006843 }
6844 else if (errnum == 504) {
6845 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006846 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006847 free(curproxy->errmsg.msg504);
6848 }
6849 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006850 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006851 }
6852 else {
6853 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
6854 free(err);
6855 }
6856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006857 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006858 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01006859 return -1;
6860 }
6861 return 0;
6862}
willy tarreaue39cd132005-12-17 13:00:18 +01006863
willy tarreau5cbea6f2005-12-17 12:48:26 +01006864
willy tarreau9fe663a2005-12-17 13:02:59 +01006865/*
6866 * This function reads and parses the configuration file given in the argument.
6867 * returns 0 if OK, -1 if error.
6868 */
6869int readcfgfile(char *file) {
6870 char thisline[256];
6871 char *line;
6872 FILE *f;
6873 int linenum = 0;
6874 char *end;
6875 char *args[MAX_LINE_ARGS];
6876 int arg;
6877 int cfgerr = 0;
6878 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01006879
willy tarreau9fe663a2005-12-17 13:02:59 +01006880 struct proxy *curproxy = NULL;
6881 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006882
willy tarreau9fe663a2005-12-17 13:02:59 +01006883 if ((f=fopen(file,"r")) == NULL)
6884 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006885
willy tarreaueedaa9f2005-12-17 14:08:03 +01006886 init_default_instance();
6887
willy tarreau9fe663a2005-12-17 13:02:59 +01006888 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
6889 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006890
willy tarreau9fe663a2005-12-17 13:02:59 +01006891 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006892
willy tarreau9fe663a2005-12-17 13:02:59 +01006893 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01006894 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01006895 line++;
6896
6897 arg = 0;
6898 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01006899
willy tarreau9fe663a2005-12-17 13:02:59 +01006900 while (*line && arg < MAX_LINE_ARGS) {
6901 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
6902 * C equivalent value. Other combinations left unchanged (eg: \1).
6903 */
6904 if (*line == '\\') {
6905 int skip = 0;
6906 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
6907 *line = line[1];
6908 skip = 1;
6909 }
6910 else if (line[1] == 'r') {
6911 *line = '\r';
6912 skip = 1;
6913 }
6914 else if (line[1] == 'n') {
6915 *line = '\n';
6916 skip = 1;
6917 }
6918 else if (line[1] == 't') {
6919 *line = '\t';
6920 skip = 1;
6921 }
willy tarreauc1f47532005-12-18 01:08:26 +01006922 else if (line[1] == 'x') {
6923 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
6924 unsigned char hex1, hex2;
6925 hex1 = toupper(line[2]) - '0';
6926 hex2 = toupper(line[3]) - '0';
6927 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
6928 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
6929 *line = (hex1<<4) + hex2;
6930 skip = 3;
6931 }
6932 else {
6933 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
6934 return -1;
6935 }
6936 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006937 if (skip) {
6938 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
6939 end -= skip;
6940 }
6941 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006942 }
willy tarreaua1598082005-12-17 13:08:06 +01006943 else if (*line == '#' || *line == '\n' || *line == '\r') {
6944 /* end of string, end of loop */
6945 *line = 0;
6946 break;
6947 }
willy tarreauc29948c2005-12-17 13:10:27 +01006948 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01006950 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01006951 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01006952 line++;
6953 args[++arg] = line;
6954 }
6955 else {
6956 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006957 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006958 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006959
willy tarreau9fe663a2005-12-17 13:02:59 +01006960 /* empty line */
6961 if (!**args)
6962 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01006963
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 /* zero out remaining args */
6965 while (++arg < MAX_LINE_ARGS) {
6966 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006967 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006968
willy tarreaua41a8b42005-12-17 14:02:24 +01006969 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01006970 confsect = CFG_LISTEN;
6971 else if (!strcmp(args[0], "global")) /* global config */
6972 confsect = CFG_GLOBAL;
6973 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006974
willy tarreau9fe663a2005-12-17 13:02:59 +01006975 switch (confsect) {
6976 case CFG_LISTEN:
6977 if (cfg_parse_listen(file, linenum, args) < 0)
6978 return -1;
6979 break;
6980 case CFG_GLOBAL:
6981 if (cfg_parse_global(file, linenum, args) < 0)
6982 return -1;
6983 break;
6984 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01006985 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006986 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006988
6989
willy tarreau0f7af912005-12-17 12:21:26 +01006990 }
6991 fclose(f);
6992
6993 /*
6994 * Now, check for the integrity of all that we have collected.
6995 */
6996
6997 if ((curproxy = proxy) == NULL) {
6998 Alert("parsing %s : no <listen> line. Nothing to do !\n",
6999 file);
7000 return -1;
7001 }
7002
7003 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007004 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01007005 if (curproxy->state == PR_STDISABLED) {
7006 curproxy = curproxy->next;
7007 continue;
7008 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007009 if ((curproxy->mode != PR_MODE_HEALTH) &&
7010 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007011 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007012 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7013 file, curproxy->id);
7014 cfgerr++;
7015 }
7016 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7017 if (curproxy->options & PR_O_TRANSP) {
7018 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7019 file, curproxy->id);
7020 cfgerr++;
7021 }
7022 else if (curproxy->srv == NULL) {
7023 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7024 file, curproxy->id);
7025 cfgerr++;
7026 }
willy tarreaua1598082005-12-17 13:08:06 +01007027 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007028 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7029 file, curproxy->id);
7030 }
7031 }
7032 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007033 if (curproxy->cookie_name != NULL) {
7034 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7035 file, curproxy->id);
7036 }
7037 if ((newsrv = curproxy->srv) != NULL) {
7038 Warning("parsing %s : servers will be ignored for listener %s.\n",
7039 file, curproxy->id);
7040 }
willy tarreaue39cd132005-12-17 13:00:18 +01007041 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007042 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7043 file, curproxy->id);
7044 }
willy tarreaue39cd132005-12-17 13:00:18 +01007045 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007046 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7047 file, curproxy->id);
7048 }
7049 }
7050 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7051 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7052 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7053 file, curproxy->id);
7054 cfgerr++;
7055 }
7056 else {
7057 while (newsrv != NULL) {
7058 /* nothing to check for now */
7059 newsrv = newsrv->next;
7060 }
7061 }
7062 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007063
7064 if (curproxy->options & PR_O_LOGASAP)
7065 curproxy->to_log &= ~LW_BYTES;
7066
willy tarreau8337c6b2005-12-17 13:41:01 +01007067 if (curproxy->errmsg.msg400 == NULL) {
7068 curproxy->errmsg.msg400 = (char *)HTTP_400;
7069 curproxy->errmsg.len400 = strlen(HTTP_400);
7070 }
7071 if (curproxy->errmsg.msg403 == NULL) {
7072 curproxy->errmsg.msg403 = (char *)HTTP_403;
7073 curproxy->errmsg.len403 = strlen(HTTP_403);
7074 }
7075 if (curproxy->errmsg.msg408 == NULL) {
7076 curproxy->errmsg.msg408 = (char *)HTTP_408;
7077 curproxy->errmsg.len408 = strlen(HTTP_408);
7078 }
7079 if (curproxy->errmsg.msg500 == NULL) {
7080 curproxy->errmsg.msg500 = (char *)HTTP_500;
7081 curproxy->errmsg.len500 = strlen(HTTP_500);
7082 }
7083 if (curproxy->errmsg.msg502 == NULL) {
7084 curproxy->errmsg.msg502 = (char *)HTTP_502;
7085 curproxy->errmsg.len502 = strlen(HTTP_502);
7086 }
7087 if (curproxy->errmsg.msg503 == NULL) {
7088 curproxy->errmsg.msg503 = (char *)HTTP_503;
7089 curproxy->errmsg.len503 = strlen(HTTP_503);
7090 }
7091 if (curproxy->errmsg.msg504 == NULL) {
7092 curproxy->errmsg.msg504 = (char *)HTTP_504;
7093 curproxy->errmsg.len504 = strlen(HTTP_504);
7094 }
willy tarreau0f7af912005-12-17 12:21:26 +01007095 curproxy = curproxy->next;
7096 }
7097 if (cfgerr > 0) {
7098 Alert("Errors found in configuration file, aborting.\n");
7099 return -1;
7100 }
7101 else
7102 return 0;
7103}
7104
7105
7106/*
7107 * This function initializes all the necessary variables. It only returns
7108 * if everything is OK. If something fails, it exits.
7109 */
7110void init(int argc, char **argv) {
7111 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007112 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007113 char *old_argv = *argv;
7114 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007115 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007116 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007117
7118 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007119 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007120 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007121 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007122 exit(1);
7123 }
7124
willy tarreau4302f492005-12-18 01:00:37 +01007125 /* initialize the log header encoding map : '{|}"#' should be encoded with
7126 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7127 * URL encoding only requires '"', '#' to be encoded as well as non-
7128 * printable characters above.
7129 */
7130 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7131 memset(url_encode_map, 0, sizeof(url_encode_map));
7132 for (i = 0; i < 32; i++) {
7133 FD_SET(i, hdr_encode_map);
7134 FD_SET(i, url_encode_map);
7135 }
7136 for (i = 127; i < 256; i++) {
7137 FD_SET(i, hdr_encode_map);
7138 FD_SET(i, url_encode_map);
7139 }
7140
7141 tmp = "\"#{|}";
7142 while (*tmp) {
7143 FD_SET(*tmp, hdr_encode_map);
7144 tmp++;
7145 }
7146
7147 tmp = "\"#";
7148 while (*tmp) {
7149 FD_SET(*tmp, url_encode_map);
7150 tmp++;
7151 }
7152
willy tarreau64a3cc32005-12-18 01:13:11 +01007153 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7154#if defined(ENABLE_POLL)
7155 cfg_polling_mechanism |= POLL_USE_POLL;
7156#endif
7157#if defined(ENABLE_EPOLL)
7158 cfg_polling_mechanism |= POLL_USE_EPOLL;
7159#endif
7160
willy tarreau0f7af912005-12-17 12:21:26 +01007161 pid = getpid();
7162 progname = *argv;
7163 while ((tmp = strchr(progname, '/')) != NULL)
7164 progname = tmp + 1;
7165
7166 argc--; argv++;
7167 while (argc > 0) {
7168 char *flag;
7169
7170 if (**argv == '-') {
7171 flag = *argv+1;
7172
7173 /* 1 arg */
7174 if (*flag == 'v') {
7175 display_version();
7176 exit(0);
7177 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007178#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007179 else if (*flag == 'd' && flag[1] == 'e')
7180 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007181#endif
7182#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007183 else if (*flag == 'd' && flag[1] == 'p')
7184 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007185#endif
willy tarreau982249e2005-12-18 00:57:06 +01007186 else if (*flag == 'V')
7187 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007188 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007189 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007190 else if (*flag == 'c')
7191 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007192 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007193 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007194 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007196#if STATTIME > 0
7197 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007198 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007199 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007200 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007201#endif
7202 else { /* >=2 args */
7203 argv++; argc--;
7204 if (argc == 0)
7205 usage(old_argv);
7206
7207 switch (*flag) {
7208 case 'n' : cfg_maxconn = atol(*argv); break;
7209 case 'N' : cfg_maxpconn = atol(*argv); break;
7210 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007211 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007212 default: usage(old_argv);
7213 }
7214 }
7215 }
7216 else
7217 usage(old_argv);
7218 argv++; argc--;
7219 }
7220
willy tarreau982249e2005-12-18 00:57:06 +01007221 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007222
willy tarreau0f7af912005-12-17 12:21:26 +01007223 if (!cfg_cfgfile)
7224 usage(old_argv);
7225
7226 gethostname(hostname, MAX_HOSTNAME_LEN);
7227
willy tarreau12350152005-12-18 01:03:27 +01007228 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007229 if (readcfgfile(cfg_cfgfile) < 0) {
7230 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7231 exit(1);
7232 }
willy tarreau12350152005-12-18 01:03:27 +01007233 if (have_appsession)
7234 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007235
willy tarreau982249e2005-12-18 00:57:06 +01007236 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007237 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7238 exit(0);
7239 }
7240
willy tarreau9fe663a2005-12-17 13:02:59 +01007241 if (cfg_maxconn > 0)
7242 global.maxconn = cfg_maxconn;
7243
willy tarreaufe2c5c12005-12-17 14:14:34 +01007244 if (cfg_pidfile) {
7245 if (global.pidfile)
7246 free(global.pidfile);
7247 global.pidfile = strdup(cfg_pidfile);
7248 }
7249
willy tarreau9fe663a2005-12-17 13:02:59 +01007250 if (global.maxconn == 0)
7251 global.maxconn = DEFAULT_MAXCONN;
7252
7253 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7254
7255 if (arg_mode & MODE_DEBUG) {
7256 /* command line debug mode inhibits configuration mode */
7257 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7258 }
willy tarreau982249e2005-12-18 00:57:06 +01007259 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7260 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007261
7262 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7263 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7264 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7265 }
7266
7267 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7268 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7269 global.nbproc = 1;
7270 }
7271
7272 if (global.nbproc < 1)
7273 global.nbproc = 1;
7274
willy tarreau0f7af912005-12-17 12:21:26 +01007275 StaticReadEvent = (fd_set *)calloc(1,
7276 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007277 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007278 StaticWriteEvent = (fd_set *)calloc(1,
7279 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007280 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007281
7282 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007283 sizeof(struct fdtab) * (global.maxsock));
7284 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007285 fdtab[i].state = FD_STCLOSE;
7286 }
7287}
7288
7289/*
7290 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7291 */
7292int start_proxies() {
7293 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007294 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007295 int fd;
7296
7297 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007298 if (curproxy->state == PR_STDISABLED)
7299 continue;
7300
willy tarreaua41a8b42005-12-17 14:02:24 +01007301 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7302 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007303 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007304 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7305 curproxy->id);
7306 return -1;
7307 }
willy tarreau0f7af912005-12-17 12:21:26 +01007308
willy tarreaua41a8b42005-12-17 14:02:24 +01007309 if (fd >= global.maxsock) {
7310 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7311 curproxy->id);
7312 close(fd);
7313 return -1;
7314 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007315
willy tarreaua41a8b42005-12-17 14:02:24 +01007316 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7317 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7318 (char *) &one, sizeof(one)) == -1)) {
7319 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7320 curproxy->id);
7321 close(fd);
7322 return -1;
7323 }
willy tarreau0f7af912005-12-17 12:21:26 +01007324
willy tarreaua41a8b42005-12-17 14:02:24 +01007325 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7326 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7327 curproxy->id);
7328 }
willy tarreau0f7af912005-12-17 12:21:26 +01007329
willy tarreaua41a8b42005-12-17 14:02:24 +01007330 if (bind(fd,
7331 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007332 listener->addr.ss_family == AF_INET6 ?
7333 sizeof(struct sockaddr_in6) :
7334 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007335 Alert("cannot bind socket for proxy %s. Aborting.\n",
7336 curproxy->id);
7337 close(fd);
7338 return -1;
7339 }
willy tarreau0f7af912005-12-17 12:21:26 +01007340
willy tarreaua41a8b42005-12-17 14:02:24 +01007341 if (listen(fd, curproxy->maxconn) == -1) {
7342 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7343 curproxy->id);
7344 close(fd);
7345 return -1;
7346 }
willy tarreau0f7af912005-12-17 12:21:26 +01007347
willy tarreaua41a8b42005-12-17 14:02:24 +01007348 /* the function for the accept() event */
7349 fdtab[fd].read = &event_accept;
7350 fdtab[fd].write = NULL; /* never called */
7351 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7352 curproxy->state = PR_STRUN;
7353 fdtab[fd].state = FD_STLISTEN;
7354 FD_SET(fd, StaticReadEvent);
7355 fd_insert(fd);
7356 listeners++;
7357 }
willy tarreaua1598082005-12-17 13:08:06 +01007358 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007359 }
7360 return 0;
7361}
7362
willy tarreau12350152005-12-18 01:03:27 +01007363int match_str(const void *key1, const void *key2){
7364
7365 appsess *temp1,*temp2;
7366 temp1 = (appsess *)key1;
7367 temp2 = (appsess *)key2;
7368
7369 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7370 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7371
7372 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7373}/* end match_str */
7374
7375void destroy(void *data){
7376 appsess *temp1;
7377
7378 //printf("destroy called\n");
7379 temp1 = (appsess *)data;
7380
7381 if (temp1->sessid)
7382 pool_free_to(apools.sessid, temp1->sessid);
7383
7384 if (temp1->serverid)
7385 pool_free_to(apools.serverid, temp1->serverid);
7386
7387 pool_free(appsess, temp1);
7388} /* end destroy */
7389
7390void appsession_cleanup( void )
7391{
7392 struct proxy *p = proxy;
7393
7394 while(p) {
7395 chtbl_destroy(&(p->htbl_proxy));
7396 p = p->next;
7397 }
7398}/* end appsession_cleanup() */
7399
7400void pool_destroy(void **pool)
7401{
7402 void *temp, *next;
7403 next = pool;
7404 while (next) {
7405 temp = next;
7406 next = *(void **)temp;
7407 free(temp);
7408 }
7409}/* end pool_destroy() */
7410
7411void deinit(void){
7412 struct proxy *p = proxy;
7413 struct cap_hdr *h,*h_next;
7414 struct server *s,*s_next;
7415 struct listener *l,*l_next;
7416
7417 while (p) {
7418 if (p->id)
7419 free(p->id);
7420
7421 if (p->check_req)
7422 free(p->check_req);
7423
7424 if (p->cookie_name)
7425 free(p->cookie_name);
7426
7427 if (p->capture_name)
7428 free(p->capture_name);
7429
7430 /* only strup if the user have set in config.
7431 When should we free it?!
7432 if(p->errmsg.msg400) free(p->errmsg.msg400);
7433 if(p->errmsg.msg403) free(p->errmsg.msg403);
7434 if(p->errmsg.msg408) free(p->errmsg.msg408);
7435 if(p->errmsg.msg500) free(p->errmsg.msg500);
7436 if(p->errmsg.msg502) free(p->errmsg.msg502);
7437 if(p->errmsg.msg503) free(p->errmsg.msg503);
7438 if(p->errmsg.msg504) free(p->errmsg.msg504);
7439 */
7440 if (p->appsession_name)
7441 free(p->appsession_name);
7442
7443 h = p->req_cap;
7444 while (h) {
7445 h_next = h->next;
7446 if (h->name)
7447 free(h->name);
7448 pool_destroy(h->pool);
7449 free(h);
7450 h = h_next;
7451 }/* end while(h) */
7452
7453 h = p->rsp_cap;
7454 while (h) {
7455 h_next = h->next;
7456 if (h->name)
7457 free(h->name);
7458
7459 pool_destroy(h->pool);
7460 free(h);
7461 h = h_next;
7462 }/* end while(h) */
7463
7464 s = p->srv;
7465 while (s) {
7466 s_next = s->next;
7467 if(s->id)
7468 free(s->id);
7469
7470 if(s->cookie)
7471 free(s->cookie);
7472
7473 free(s);
7474 s = s_next;
7475 }/* end while(s) */
7476
7477 l = p->listen;
7478 while (l) {
7479 l_next = l->next;
7480 free(l);
7481 l = l_next;
7482 }/* end while(l) */
7483
7484 pool_destroy((void **) p->req_cap_pool);
7485 pool_destroy((void **) p->rsp_cap_pool);
7486 p = p->next;
7487 }/* end while(p) */
7488
7489 if (global.chroot) free(global.chroot);
7490 if (global.pidfile) free(global.pidfile);
7491
willy tarreau12350152005-12-18 01:03:27 +01007492 if (StaticReadEvent) free(StaticReadEvent);
7493 if (StaticWriteEvent) free(StaticWriteEvent);
7494 if (fdtab) free(fdtab);
7495
7496 pool_destroy(pool_session);
7497 pool_destroy(pool_buffer);
7498 pool_destroy(pool_fdtab);
7499 pool_destroy(pool_requri);
7500 pool_destroy(pool_task);
7501 pool_destroy(pool_capture);
7502 pool_destroy(pool_appsess);
7503
7504 if (have_appsession) {
7505 pool_destroy(apools.serverid);
7506 pool_destroy(apools.sessid);
7507 }
7508} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007509
7510int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01007511 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007512 init(argc, argv);
7513
willy tarreau9fe663a2005-12-17 13:02:59 +01007514 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007515 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007516 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007517 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007518 }
7519
7520 signal(SIGQUIT, dump);
7521 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007522 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01007523#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01007524 signal(SIGINT, sig_int);
7525 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01007526#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007527
7528 /* on very high loads, a sigpipe sometimes happen just between the
7529 * getsockopt() which tells "it's OK to write", and the following write :-(
7530 */
willy tarreau3242e862005-12-17 12:27:53 +01007531#ifndef MSG_NOSIGNAL
7532 signal(SIGPIPE, SIG_IGN);
7533#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007534
7535 if (start_proxies() < 0)
7536 exit(1);
7537
willy tarreaufe2c5c12005-12-17 14:14:34 +01007538 /* open log & pid files before the chroot */
7539 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7540 int pidfd;
7541 unlink(global.pidfile);
7542 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7543 if (pidfd < 0) {
7544 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7545 exit(1);
7546 }
7547 pidfile = fdopen(pidfd, "w");
7548 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007549
7550 /* chroot if needed */
7551 if (global.chroot != NULL) {
7552 if (chroot(global.chroot) == -1) {
7553 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7554 exit(1);
7555 }
7556 chdir("/");
7557 }
7558
7559 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007560 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007561 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7562 exit(1);
7563 }
7564
willy tarreau036e1ce2005-12-17 13:46:33 +01007565 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007566 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7567 exit(1);
7568 }
7569
7570 if (global.mode & MODE_DAEMON) {
7571 int ret = 0;
7572 int proc;
7573
7574 /* the father launches the required number of processes */
7575 for (proc = 0; proc < global.nbproc; proc++) {
7576 ret = fork();
7577 if (ret < 0) {
7578 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7579 exit(1); /* there has been an error */
7580 }
7581 else if (ret == 0) /* child breaks here */
7582 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007583 if (pidfile != NULL) {
7584 fprintf(pidfile, "%d\n", ret);
7585 fflush(pidfile);
7586 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007587 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007588 /* close the pidfile both in children and father */
7589 if (pidfile != NULL)
7590 fclose(pidfile);
7591 free(global.pidfile);
7592
willy tarreau9fe663a2005-12-17 13:02:59 +01007593 if (proc == global.nbproc)
7594 exit(0); /* parent must leave */
7595
willy tarreau750a4722005-12-17 13:21:24 +01007596 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7597 * that we can detach from the TTY. We MUST NOT do it in other cases since
7598 * it would have already be done, and 0-2 would have been affected to listening
7599 * sockets
7600 */
7601 if (!(global.mode & MODE_QUIET)) {
7602 /* detach from the tty */
7603 fclose(stdin); fclose(stdout); fclose(stderr);
7604 close(0); close(1); close(2); /* close all fd's */
7605 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7606 }
willy tarreaua1598082005-12-17 13:08:06 +01007607 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007608 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007609 }
7610
willy tarreau1c2ad212005-12-18 01:11:29 +01007611#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007612 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007613 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
7614 epoll_loop(POLL_LOOP_ACTION_RUN);
7615 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007616 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007617 }
7618 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01007619 Warning("epoll() is not available. Using poll()/select() instead.\n");
7620 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007621 }
7622 }
7623#endif
7624
7625#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007626 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007627 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
7628 poll_loop(POLL_LOOP_ACTION_RUN);
7629 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007630 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007631 }
7632 else {
7633 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01007634 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007635 }
7636 }
7637#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01007638 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01007639 if (select_loop(POLL_LOOP_ACTION_INIT)) {
7640 select_loop(POLL_LOOP_ACTION_RUN);
7641 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01007642 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01007643 }
7644 }
7645
willy tarreau0f7af912005-12-17 12:21:26 +01007646
willy tarreau12350152005-12-18 01:03:27 +01007647 /* Free all Hash Keys and all Hash elements */
7648 appsession_cleanup();
7649 /* Do some cleanup */
7650 deinit();
7651
willy tarreau0f7af912005-12-17 12:21:26 +01007652 exit(0);
7653}
willy tarreau12350152005-12-18 01:03:27 +01007654
7655#if defined(DEBUG_HASH)
7656static void print_table(const CHTbl *htbl) {
7657
7658 ListElmt *element;
7659 int i;
7660 appsess *asession;
7661
7662 /*****************************************************************************
7663 * *
7664 * Display the chained hash table. *
7665 * *
7666 *****************************************************************************/
7667
7668 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
7669
7670 for (i = 0; i < TBLSIZ; i++) {
7671 fprintf(stdout, "Bucket[%03d]\n", i);
7672
7673 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7674 //fprintf(stdout, "%c", *(char *)list_data(element));
7675 asession = (appsess *)list_data(element);
7676 fprintf(stdout, "ELEM :%s:", asession->sessid);
7677 fprintf(stdout, " Server :%s: \n", asession->serverid);
7678 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
7679 }
7680
7681 fprintf(stdout, "\n");
7682 }
7683 return;
7684} /* end print_table */
7685#endif
7686
7687static int appsession_init(void)
7688{
7689 static int initialized = 0;
7690 int idlen;
7691 struct server *s;
7692 struct proxy *p = proxy;
7693
7694 if (!initialized) {
7695 if (!appsession_task_init()) {
7696 apools.sessid = NULL;
7697 apools.serverid = NULL;
7698 apools.ser_waste = 0;
7699 apools.ser_use = 0;
7700 apools.ser_msize = sizeof(void *);
7701 apools.ses_waste = 0;
7702 apools.ses_use = 0;
7703 apools.ses_msize = sizeof(void *);
7704 while (p) {
7705 s = p->srv;
7706 if (apools.ses_msize < p->appsession_len)
7707 apools.ses_msize = p->appsession_len;
7708 while (s) {
7709 idlen = strlen(s->id);
7710 if (apools.ser_msize < idlen)
7711 apools.ser_msize = idlen;
7712 s = s->next;
7713 }
7714 p = p->next;
7715 }
7716 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
7717 apools.ses_msize ++;
7718 }
7719 else {
7720 fprintf(stderr, "appsession_task_init failed\n");
7721 return -1;
7722 }
7723 initialized ++;
7724 }
7725 return 0;
7726}
7727
7728static int appsession_task_init(void)
7729{
7730 static int initialized = 0;
7731 struct task *t;
7732 if (!initialized) {
7733 if ((t = pool_alloc(task)) == NULL)
7734 return -1;
7735 t->next = t->prev = t->rqnext = NULL;
7736 t->wq = LIST_HEAD(wait_queue);
7737 t->state = TASK_IDLE;
7738 t->context = NULL;
7739 tv_delayfrom(&t->expire, &now, TBLCHKINT);
7740 task_queue(t);
7741 t->process = appsession_refresh;
7742 initialized ++;
7743 }
7744 return 0;
7745}
7746
7747static int appsession_refresh(struct task *t) {
7748 struct proxy *p = proxy;
7749 CHTbl *htbl;
7750 ListElmt *element, *last;
7751 int i;
7752 appsess *asession;
7753 void *data;
7754
7755 while (p) {
7756 if (p->appsession_name != NULL) {
7757 htbl = &p->htbl_proxy;
7758 /* if we ever give up the use of TBLSIZ, we need to change this */
7759 for (i = 0; i < TBLSIZ; i++) {
7760 last = NULL;
7761 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7762 asession = (appsess *)list_data(element);
7763 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
7764 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
7765 int len;
7766 /*
7767 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
7768 */
7769 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
7770 asession->sessid, asession->serverid?asession->serverid:"(null)");
7771 write(1, trash, len);
7772 }
7773 /* delete the expired element from within the hash table */
7774 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
7775 && (htbl->table[i].destroy != NULL)) {
7776 htbl->table[i].destroy(data);
7777 }
7778 if (last == NULL) {/* patient lost his head, get a new one */
7779 element = list_head(&htbl->table[i]);
7780 if (element == NULL) break; /* no heads left, go to next patient */
7781 }
7782 else
7783 element = last;
7784 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
7785 else
7786 last = element;
7787 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
7788 }
7789 }
7790 p = p->next;
7791 }
7792 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
7793 return TBLCHKINT;
7794} /* end appsession_refresh */
7795