blob: c136ac6524d8c083295695a8d8e1f5db5f41bde8 [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 tarreau726618c2006-01-29 22:42:06 +01003 * 2000-2006 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
willy tarreau0f7af912005-12-17 12:21:26 +010055#include <syslog.h>
willy tarreau77bc8542005-12-18 01:31:43 +010056
57#ifdef USE_PCRE
58#include <pcre.h>
59#include <pcreposix.h>
60#else
61#include <regex.h>
62#endif
63
willy tarreaua1598082005-12-17 13:08:06 +010064#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010065#include <linux/netfilter_ipv4.h>
66#endif
willy tarreau0f7af912005-12-17 12:21:26 +010067
willy tarreau12350152005-12-18 01:03:27 +010068#if defined(__dietlibc__)
69#include <strings.h>
70#endif
71
willy tarreau1c2ad212005-12-18 01:11:29 +010072#if defined(ENABLE_POLL)
73#include <sys/poll.h>
74#endif
75
76#if defined(ENABLE_EPOLL)
77#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010078#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010079#else
80#include "include/epoll.h"
81#endif
82#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010083
willy tarreau598da412005-12-18 01:07:29 +010084#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010085
willy tarreau065f1c02006-01-29 22:10:07 +010086#define HAPROXY_VERSION "1.2.8"
87#define HAPROXY_DATE "2006/01/29"
willy tarreau0f7af912005-12-17 12:21:26 +010088
89/* this is for libc5 for example */
90#ifndef TCP_NODELAY
91#define TCP_NODELAY 1
92#endif
93
94#ifndef SHUT_RD
95#define SHUT_RD 0
96#endif
97
98#ifndef SHUT_WR
99#define SHUT_WR 1
100#endif
101
willy tarreau0174f312005-12-18 01:02:42 +0100102/*
103 * BUFSIZE defines the size of a read and write buffer. It is the maximum
104 * amount of bytes which can be stored by the proxy for each session. However,
105 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
106 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
107 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
108 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
109 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
110 */
111#ifndef BUFSIZE
112#define BUFSIZE 16384
113#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100114
115// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100116#ifndef MAXREWRITE
117#define MAXREWRITE (BUFSIZE / 2)
118#endif
119
willy tarreau9fe663a2005-12-17 13:02:59 +0100120#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100121#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100122
willy tarreau5cbea6f2005-12-17 12:48:26 +0100123// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100124#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100125
willy tarreaue39cd132005-12-17 13:00:18 +0100126// max # of added headers per request
127#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100128
129// max # of matches per regexp
130#define MAX_MATCH 10
131
willy tarreau0174f312005-12-18 01:02:42 +0100132// cookie delimitor in "prefix" mode. This character is inserted between the
133// persistence cookie and the original value. The '~' is allowed by RFC2965,
134// and should not be too common in server names.
135#ifndef COOKIE_DELIM
136#define COOKIE_DELIM '~'
137#endif
138
willy tarreau0f7af912005-12-17 12:21:26 +0100139#define CONN_RETRIES 3
140
willy tarreau5cbea6f2005-12-17 12:48:26 +0100141#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100142#define DEF_CHKINTR 2000
143#define DEF_FALLTIME 3
144#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100145#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100146
willy tarreau9fe663a2005-12-17 13:02:59 +0100147/* default connections limit */
148#define DEFAULT_MAXCONN 2000
149
willy tarreau0f7af912005-12-17 12:21:26 +0100150/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
151#define INTBITS 5
152
153/* show stats this every millisecond, 0 to disable */
154#ifndef STATTIME
155#define STATTIME 2000
156#endif
157
willy tarreau5cbea6f2005-12-17 12:48:26 +0100158/* this reduces the number of calls to select() by choosing appropriate
159 * sheduler precision in milliseconds. It should be near the minimum
160 * time that is needed by select() to collect all events. All timeouts
161 * are rounded up by adding this value prior to pass it to select().
162 */
163#define SCHEDULER_RESOLUTION 9
164
willy tarreaub952e1d2005-12-18 01:31:20 +0100165#define TIME_ETERNITY -1
166/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
willy tarreau0f7af912005-12-17 12:21:26 +0100167#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
168#define SETNOW(a) (*a=now)
169
willy tarreau9da061b2005-12-17 12:29:56 +0100170/****** string-specific macros and functions ******/
171/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
172#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
173
174/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
175#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
176
willy tarreau0174f312005-12-18 01:02:42 +0100177/* returns 1 only if only zero or one bit is set in X, which means that X is a
178 * power of 2, and 0 otherwise */
179#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100180/*
181 * copies at most <size-1> chars from <src> to <dst>. Last char is always
182 * set to 0, unless <size> is 0. The number of chars copied is returned
183 * (excluding the terminating zero).
184 * This code has been optimized for size and speed : on x86, it's 45 bytes
185 * long, uses only registers, and consumes only 4 cycles per char.
186 */
willy tarreau750a4722005-12-17 13:21:24 +0100187int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100188 char *orig = dst;
189 if (size) {
190 while (--size && (*dst = *src)) {
191 src++; dst++;
192 }
193 *dst = 0;
194 }
195 return dst - orig;
196}
willy tarreau9da061b2005-12-17 12:29:56 +0100197
willy tarreau4302f492005-12-18 01:00:37 +0100198/*
199 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
200 * dynamically allocated. In the first case, <__pool> is updated to point to
201 * the next element in the list.
202 */
203#define pool_alloc_from(__pool, __len) ({ \
204 void *__p; \
205 if ((__p = (__pool)) == NULL) \
206 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
207 else { \
208 __pool = *(void **)(__pool); \
209 } \
210 __p; \
211})
212
213/*
214 * Puts a memory area back to the corresponding pool.
215 * Items are chained directly through a pointer that
216 * is written in the beginning of the memory area, so
217 * there's no need for any carrier cell. This implies
218 * that each memory area is at least as big as one
219 * pointer.
220 */
221#define pool_free_to(__pool, __ptr) ({ \
222 *(void **)(__ptr) = (void *)(__pool); \
223 __pool = (void *)(__ptr); \
224})
225
226
willy tarreau0f7af912005-12-17 12:21:26 +0100227#define MEM_OPTIM
228#ifdef MEM_OPTIM
229/*
230 * Returns a pointer to type <type> taken from the
231 * pool <pool_type> or dynamically allocated. In the
232 * first case, <pool_type> is updated to point to the
233 * next element in the list.
234 */
235#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100236 void *__p; \
237 if ((__p = pool_##type) == NULL) \
238 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100239 else { \
240 pool_##type = *(void **)pool_##type; \
241 } \
willy tarreau4302f492005-12-18 01:00:37 +0100242 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100243})
244
245/*
246 * Puts a memory area back to the corresponding pool.
247 * Items are chained directly through a pointer that
248 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100249 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100250 * that each memory area is at least as big as one
251 * pointer.
252 */
253#define pool_free(type, ptr) ({ \
254 *(void **)ptr = (void *)pool_##type; \
255 pool_##type = (void *)ptr; \
256})
257
258#else
259#define pool_alloc(type) (calloc(1,sizeof_##type));
260#define pool_free(type, ptr) (free(ptr));
261#endif /* MEM_OPTIM */
262
willy tarreau5cbea6f2005-12-17 12:48:26 +0100263#define sizeof_task sizeof(struct task)
264#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100265#define sizeof_buffer sizeof(struct buffer)
266#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau9fe663a2005-12-17 13:02:59 +0100267#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100268#define sizeof_capture CAPTURE_LEN
willy tarreau64a3cc32005-12-18 01:13:11 +0100269#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau12350152005-12-18 01:03:27 +0100270#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100271
willy tarreau5cbea6f2005-12-17 12:48:26 +0100272/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100273#define FD_STCLOSE 0
274#define FD_STLISTEN 1
275#define FD_STCONN 2
276#define FD_STREADY 3
277#define FD_STERROR 4
278
willy tarreau5cbea6f2005-12-17 12:48:26 +0100279/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100280#define TASK_IDLE 0
281#define TASK_RUNNING 1
282
willy tarreau5cbea6f2005-12-17 12:48:26 +0100283/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100284#define PR_STNEW 0
285#define PR_STIDLE 1
286#define PR_STRUN 2
willy tarreaudbd3bef2006-01-20 19:35:18 +0100287#define PR_STSTOPPED 3
288#define PR_STPAUSED 4
willy tarreau0f7af912005-12-17 12:21:26 +0100289
willy tarreau5cbea6f2005-12-17 12:48:26 +0100290/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define PR_MODE_TCP 0
292#define PR_MODE_HTTP 1
293#define PR_MODE_HEALTH 2
294
willy tarreau1c2ad212005-12-18 01:11:29 +0100295/* possible actions for the *poll() loops */
296#define POLL_LOOP_ACTION_INIT 0
297#define POLL_LOOP_ACTION_RUN 1
298#define POLL_LOOP_ACTION_CLEAN 2
299
willy tarreau64a3cc32005-12-18 01:13:11 +0100300/* poll mechanisms available */
301#define POLL_USE_SELECT (1<<0)
302#define POLL_USE_POLL (1<<1)
303#define POLL_USE_EPOLL (1<<2)
304
willy tarreau5cbea6f2005-12-17 12:48:26 +0100305/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100306#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
307#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
308#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
309#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
310#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
311#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
312#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
313#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100314#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100315#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
316#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
317#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
318#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
319#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
320#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
321#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
322#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
323#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
324#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
325#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreaub952e1d2005-12-18 01:31:20 +0100326#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
327#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328
willy tarreaue39cd132005-12-17 13:00:18 +0100329/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100330#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
331#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
332#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
333#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
334#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
335#define SN_POST 0x00000020 /* the request was an HTTP POST */
willy tarreaub1285d52005-12-18 01:20:14 +0100336#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
willy tarreau036e1ce2005-12-17 13:46:33 +0100337
338#define SN_CK_NONE 0x00000000 /* this session had no cookie */
339#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
340#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
341#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
342#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
343#define SN_CK_SHIFT 6 /* bit shift */
344
willy tarreaub1285d52005-12-18 01:20:14 +0100345#define SN_ERR_NONE 0x00000000
willy tarreau036e1ce2005-12-17 13:46:33 +0100346#define SN_ERR_CLITO 0x00000100 /* client time-out */
347#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
348#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
349#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
350#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
willy tarreaub1285d52005-12-18 01:20:14 +0100351#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
352#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
willy tarreau036e1ce2005-12-17 13:46:33 +0100353#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
354#define SN_ERR_SHIFT 8 /* bit shift */
355
356#define SN_FINST_R 0x00001000 /* session ended during client request */
357#define SN_FINST_C 0x00002000 /* session ended during server connect */
358#define SN_FINST_H 0x00003000 /* session ended during server headers */
359#define SN_FINST_D 0x00004000 /* session ended during data phase */
360#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
361#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
362#define SN_FINST_SHIFT 12 /* bit shift */
363
364#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
365#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
366#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
367#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
368#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100369#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100370#define SN_SCK_SHIFT 16 /* bit shift */
371
willy tarreau97f58572005-12-18 00:53:44 +0100372#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
373#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
374#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100375
376/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100377#define CL_STHEADERS 0
378#define CL_STDATA 1
379#define CL_STSHUTR 2
380#define CL_STSHUTW 3
381#define CL_STCLOSE 4
382
willy tarreau5cbea6f2005-12-17 12:48:26 +0100383/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100384#define SV_STIDLE 0
385#define SV_STCONN 1
386#define SV_STHEADERS 2
387#define SV_STDATA 3
388#define SV_STSHUTR 4
389#define SV_STSHUTW 5
390#define SV_STCLOSE 6
391
392/* result of an I/O event */
393#define RES_SILENT 0 /* didn't happen */
394#define RES_DATA 1 /* data were sent or received */
395#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
396#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
397
willy tarreau9fe663a2005-12-17 13:02:59 +0100398/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100399#define MODE_DEBUG 1
400#define MODE_STATS 2
401#define MODE_LOG 4
402#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100403#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100404#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100405#define MODE_VERBOSE 64
willy tarreaud0fb4652005-12-18 01:32:04 +0100406#define MODE_STARTING 128
willy tarreau5cbea6f2005-12-17 12:48:26 +0100407
408/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100409#define SRV_RUNNING 1 /* the server is UP */
410#define SRV_BACKUP 2 /* this server is a backup server */
411#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100412#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100413
willy tarreaue39cd132005-12-17 13:00:18 +0100414/* what to do when a header matches a regex */
415#define ACT_ALLOW 0 /* allow the request */
416#define ACT_REPLACE 1 /* replace the matching header */
417#define ACT_REMOVE 2 /* remove the matching header */
418#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100419#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100420
willy tarreau9fe663a2005-12-17 13:02:59 +0100421/* configuration sections */
422#define CFG_NONE 0
423#define CFG_GLOBAL 1
424#define CFG_LISTEN 2
425
willy tarreaua1598082005-12-17 13:08:06 +0100426/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100427#define LW_DATE 1 /* date */
428#define LW_CLIP 2 /* CLient IP */
429#define LW_SVIP 4 /* SerVer IP */
430#define LW_SVID 8 /* server ID */
431#define LW_REQ 16 /* http REQuest */
432#define LW_RESP 32 /* http RESPonse */
433#define LW_PXIP 64 /* proxy IP */
434#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100435#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100436#define LW_COOKIE 512 /* captured cookie */
437#define LW_REQHDR 1024 /* request header(s) */
438#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100439
willy tarreau0f7af912005-12-17 12:21:26 +0100440/*********************************************************************/
441
442#define LIST_HEAD(a) ((void *)(&(a)))
443
444/*********************************************************************/
445
willy tarreau4302f492005-12-18 01:00:37 +0100446struct cap_hdr {
447 struct cap_hdr *next;
448 char *name; /* header name, case insensitive */
449 int namelen; /* length of the header name, to speed-up lookups */
450 int len; /* capture length, not including terminal zero */
451 int index; /* index in the output array */
452 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
453};
454
willy tarreau0f7af912005-12-17 12:21:26 +0100455struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100456 struct hdr_exp *next;
457 regex_t *preg; /* expression to look for */
458 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
459 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100460};
461
462struct buffer {
463 unsigned int l; /* data length */
464 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100465 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100466 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100467 char data[BUFSIZE];
468};
469
470struct server {
471 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100472 int state; /* server state (SRV_*) */
473 int cklen; /* the len of the cookie, to speed up checks */
474 char *cookie; /* the id set in the cookie */
475 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100476 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100477 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100478 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100479 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100480 int rise, fall; /* time in iterations */
481 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100482 int result; /* 0 = connect OK, -1 = connect KO */
483 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100484 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100485};
486
willy tarreau5cbea6f2005-12-17 12:48:26 +0100487/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100488struct task {
489 struct task *next, *prev; /* chaining ... */
490 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100491 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100492 int state; /* task state : IDLE or RUNNING */
493 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100494 int (*process)(struct task *t); /* the function which processes the task */
495 void *context; /* the task's context */
496};
497
498/* WARNING: if new fields are added, they must be initialized in event_accept() */
499struct session {
500 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100501 /* application specific below */
502 struct timeval crexpire; /* expiration date for a client read */
503 struct timeval cwexpire; /* expiration date for a client write */
504 struct timeval srexpire; /* expiration date for a server read */
505 struct timeval swexpire; /* expiration date for a server write */
506 struct timeval cnexpire; /* expiration date for a connect */
507 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
508 struct proxy *proxy; /* the proxy this socket belongs to */
509 int cli_fd; /* the client side fd */
510 int srv_fd; /* the server side fd */
511 int cli_state; /* state of the client side */
512 int srv_state; /* state of the server side */
513 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100514 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100515 struct buffer *req; /* request buffer */
516 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100517 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100518 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100519 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100520 char **req_cap; /* array of captured request headers (may be NULL) */
521 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100522 struct {
523 int logwait; /* log fields waiting to be collected : LW_* */
524 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
525 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
526 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
527 long t_data; /* delay before the first data byte from the server ... */
528 unsigned long t_close; /* total session duration */
529 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100530 char *cli_cookie; /* cookie presented by the client, in capture mode */
531 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100532 int status; /* HTTP status from the server, negative if from proxy */
533 long long bytes; /* number of bytes transferred from the server */
534 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100535 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100536};
537
willy tarreaua41a8b42005-12-17 14:02:24 +0100538struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100539 int fd; /* the listen socket */
540 struct sockaddr_storage addr; /* the address we listen to */
541 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100542};
543
544
willy tarreau0f7af912005-12-17 12:21:26 +0100545struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100546 struct listener *listen; /* the listen addresses and sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100547 struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
willy tarreau0f7af912005-12-17 12:21:26 +0100548 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100549 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100550 struct server *srv, *cursrv; /* known servers, current server */
551 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100552 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100553 int cookie_len; /* strlen(cookie_name), computed only once */
554 char *appsession_name; /* name of the cookie to look for */
555 int appsession_name_len; /* strlen(appsession_name), computed only once */
556 int appsession_len; /* length of the appsession cookie value to be used */
557 int appsession_timeout;
558 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100559 char *capture_name; /* beginning of the name of the cookie to capture */
560 int capture_namelen; /* length of the cookie name to match */
561 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100562 int clitimeout; /* client I/O timeout (in milliseconds) */
563 int srvtimeout; /* server I/O timeout (in milliseconds) */
564 int contimeout; /* connect timeout (in milliseconds) */
565 char *id; /* proxy id */
566 int nbconn; /* # of active sessions */
567 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100568 int conn_retries; /* maximum number of connect retries */
willy tarreaub952e1d2005-12-18 01:31:20 +0100569 int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100570 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100571 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100572 struct proxy *next;
573 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
willy tarreau5dffb602005-12-18 01:15:23 +0100574 signed char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100575 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100576 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100577 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100578 int nb_reqadd, nb_rspadd;
579 struct hdr_exp *req_exp; /* regular expressions for request headers */
580 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100581 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
582 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
583 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
584 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100585 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100586 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100587 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
588 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100589 struct {
590 char *msg400; /* message for error 400 */
591 int len400; /* message length for error 400 */
592 char *msg403; /* message for error 403 */
593 int len403; /* message length for error 403 */
594 char *msg408; /* message for error 408 */
595 int len408; /* message length for error 408 */
596 char *msg500; /* message for error 500 */
597 int len500; /* message length for error 500 */
598 char *msg502; /* message for error 502 */
599 int len502; /* message length for error 502 */
600 char *msg503; /* message for error 503 */
601 int len503; /* message length for error 503 */
602 char *msg504; /* message for error 504 */
603 int len504; /* message length for error 504 */
604 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100605};
606
607/* info about one given fd */
608struct fdtab {
609 int (*read)(int fd); /* read function */
610 int (*write)(int fd); /* write function */
611 struct task *owner; /* the session (or proxy) associated with this fd */
612 int state; /* the state of this fd */
613};
614
615/*********************************************************************/
616
willy tarreaub952e1d2005-12-18 01:31:20 +0100617int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100618char *cfg_cfgfile = NULL; /* configuration file */
619char *progname = NULL; /* program name */
620int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100621
622/* global options */
623static struct {
624 int uid;
625 int gid;
626 int nbproc;
627 int maxconn;
628 int maxsock; /* max # of sockets */
willy tarreaub1285d52005-12-18 01:20:14 +0100629 int rlimit_nofile; /* default ulimit-n value : 0=unset */
willy tarreau9fe663a2005-12-17 13:02:59 +0100630 int mode;
631 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100632 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100633 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100634 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100635 struct sockaddr_in logsrv1, logsrv2;
636} global = {
637 logfac1 : -1,
638 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100639 loglev1 : 7, /* max syslog level : debug */
640 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100641 /* others NULL OK */
642};
643
willy tarreau0f7af912005-12-17 12:21:26 +0100644/*********************************************************************/
645
willy tarreau1c2ad212005-12-18 01:11:29 +0100646fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100647 *StaticWriteEvent;
648
willy tarreau64a3cc32005-12-18 01:13:11 +0100649int cfg_polling_mechanism = 0; /* POLL_USE_{SELECT|POLL|EPOLL} */
willy tarreauad90a0c2005-12-18 01:09:15 +0100650
willy tarreau0f7af912005-12-17 12:21:26 +0100651void **pool_session = NULL,
652 **pool_buffer = NULL,
653 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100654 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100655 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100656 **pool_capture = NULL,
657 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100658
659struct proxy *proxy = NULL; /* list of all existing proxies */
660struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100661struct task *rq = NULL; /* global run queue */
662struct task wait_queue = { /* global wait queue */
663 prev:LIST_HEAD(wait_queue),
664 next:LIST_HEAD(wait_queue)
665};
willy tarreau0f7af912005-12-17 12:21:26 +0100666
willy tarreau0f7af912005-12-17 12:21:26 +0100667static int totalconn = 0; /* total # of terminated sessions */
668static int actconn = 0; /* # of active sessions */
669static int maxfd = 0; /* # of the highest fd + 1 */
670static int listeners = 0; /* # of listeners */
671static int stopping = 0; /* non zero means stopping in progress */
672static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100673static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100674
willy tarreau08dedbe2005-12-18 01:13:48 +0100675#if defined(ENABLE_EPOLL)
676/* FIXME: this is dirty, but at the moment, there's no other solution to remove
677 * the old FDs from outside the loop. Perhaps we should export a global 'poll'
678 * structure with pointers to functions such as init_fd() and close_fd(), plus
679 * a private structure with several pointers to places such as below.
680 */
681
682static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
683#endif
684
willy tarreau0f7af912005-12-17 12:21:26 +0100685static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100686/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100687static char trash[BUFSIZE];
688
willy tarreaudd07e972005-12-18 00:48:48 +0100689const int zero = 0;
690const int one = 1;
691
willy tarreau0f7af912005-12-17 12:21:26 +0100692/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100693 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100694 */
695
696#define MAX_SYSLOG_LEN 1024
697#define NB_LOG_FACILITIES 24
698const char *log_facilities[NB_LOG_FACILITIES] = {
699 "kern", "user", "mail", "daemon",
700 "auth", "syslog", "lpr", "news",
701 "uucp", "cron", "auth2", "ftp",
702 "ntp", "audit", "alert", "cron2",
703 "local0", "local1", "local2", "local3",
704 "local4", "local5", "local6", "local7"
705};
706
707
708#define NB_LOG_LEVELS 8
709const char *log_levels[NB_LOG_LEVELS] = {
710 "emerg", "alert", "crit", "err",
711 "warning", "notice", "info", "debug"
712};
713
714#define SYSLOG_PORT 514
715
716const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
717 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100718
willy tarreaub1285d52005-12-18 01:20:14 +0100719const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
willy tarreau036e1ce2005-12-17 13:46:33 +0100720const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
721const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
722const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
723 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
724 unknown, Set-cookie Rewritten */
725
willy tarreau0f7af912005-12-17 12:21:26 +0100726#define MAX_HOSTNAME_LEN 32
727static char hostname[MAX_HOSTNAME_LEN] = "";
728
willy tarreau8337c6b2005-12-17 13:41:01 +0100729const char *HTTP_302 =
730 "HTTP/1.0 302 Found\r\n"
731 "Cache-Control: no-cache\r\n"
732 "Connection: close\r\n"
733 "Location: "; /* not terminated since it will be concatenated with the URL */
734
willy tarreauc1f47532005-12-18 01:08:26 +0100735/* same as 302 except that the browser MUST retry with the GET method */
736const char *HTTP_303 =
737 "HTTP/1.0 303 See Other\r\n"
738 "Cache-Control: no-cache\r\n"
739 "Connection: close\r\n"
740 "Location: "; /* not terminated since it will be concatenated with the URL */
741
willy tarreaua1598082005-12-17 13:08:06 +0100742const char *HTTP_400 =
743 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100744 "Cache-Control: no-cache\r\n"
745 "Connection: close\r\n"
746 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100747 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100748
willy tarreaua1598082005-12-17 13:08:06 +0100749const char *HTTP_403 =
750 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100751 "Cache-Control: no-cache\r\n"
752 "Connection: close\r\n"
753 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100754 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
755
willy tarreau8337c6b2005-12-17 13:41:01 +0100756const char *HTTP_408 =
757 "HTTP/1.0 408 Request Time-out\r\n"
758 "Cache-Control: no-cache\r\n"
759 "Connection: close\r\n"
760 "\r\n"
761 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
762
willy tarreau750a4722005-12-17 13:21:24 +0100763const char *HTTP_500 =
764 "HTTP/1.0 500 Server Error\r\n"
765 "Cache-Control: no-cache\r\n"
766 "Connection: close\r\n"
767 "\r\n"
768 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100769
770const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100771 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100772 "Cache-Control: no-cache\r\n"
773 "Connection: close\r\n"
774 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100775 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
776
777const char *HTTP_503 =
778 "HTTP/1.0 503 Service Unavailable\r\n"
779 "Cache-Control: no-cache\r\n"
780 "Connection: close\r\n"
781 "\r\n"
782 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
783
784const char *HTTP_504 =
785 "HTTP/1.0 504 Gateway Time-out\r\n"
786 "Cache-Control: no-cache\r\n"
787 "Connection: close\r\n"
788 "\r\n"
789 "<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 +0100790
willy tarreau0f7af912005-12-17 12:21:26 +0100791/*********************************************************************/
792/* statistics ******************************************************/
793/*********************************************************************/
794
willy tarreau750a4722005-12-17 13:21:24 +0100795#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100796static int stats_tsk_lsrch, stats_tsk_rsrch,
797 stats_tsk_good, stats_tsk_right, stats_tsk_left,
798 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100799#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100800
801
802/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100803/* debugging *******************************************************/
804/*********************************************************************/
805#ifdef DEBUG_FULL
806static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
807static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
808#endif
809
810/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100811/* function prototypes *********************************************/
812/*********************************************************************/
813
814int event_accept(int fd);
815int event_cli_read(int fd);
816int event_cli_write(int fd);
817int event_srv_read(int fd);
818int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100819int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100820
willy tarreau12350152005-12-18 01:03:27 +0100821static int appsession_task_init(void);
822static int appsession_init(void);
823static int appsession_refresh(struct task *t);
824
willy tarreau0f7af912005-12-17 12:21:26 +0100825/*********************************************************************/
826/* general purpose functions ***************************************/
827/*********************************************************************/
828
829void display_version() {
830 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau726618c2006-01-29 22:42:06 +0100831 printf("Copyright 2000-2006 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100832}
833
834/*
835 * This function prints the command line usage and exits
836 */
837void usage(char *name) {
838 display_version();
839 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100840 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100841#if STATTIME > 0
842 "sl"
843#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100844 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100845 " -v displays version\n"
846 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100847 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100848#if STATTIME > 0
849 " -s enables statistics output\n"
850 " -l enables long statistics format\n"
851#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100852 " -D goes daemon ; implies -q\n"
853 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100854 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100855 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100856 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100857 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100858#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100859 " -de disables epoll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100860#endif
861#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +0100862 " -dp disables poll() usage even when available\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100863#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100864 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100865 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100866 exit(1);
867}
868
869
870/*
willy tarreaud0fb4652005-12-18 01:32:04 +0100871 * Displays the message on stderr with the date and pid. Overrides the quiet
872 * mode during startup.
willy tarreau0f7af912005-12-17 12:21:26 +0100873 */
874void Alert(char *fmt, ...) {
875 va_list argp;
876 struct timeval tv;
877 struct tm *tm;
878
willy tarreaud0fb4652005-12-18 01:32:04 +0100879 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100880 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100881
willy tarreau5cbea6f2005-12-17 12:48:26 +0100882 gettimeofday(&tv, NULL);
883 tm=localtime(&tv.tv_sec);
884 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100885 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100886 vfprintf(stderr, fmt, argp);
887 fflush(stderr);
888 va_end(argp);
889 }
willy tarreau0f7af912005-12-17 12:21:26 +0100890}
891
892
893/*
894 * Displays the message on stderr with the date and pid.
895 */
896void Warning(char *fmt, ...) {
897 va_list argp;
898 struct timeval tv;
899 struct tm *tm;
900
willy tarreau982249e2005-12-18 00:57:06 +0100901 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100902 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100903
willy tarreau5cbea6f2005-12-17 12:48:26 +0100904 gettimeofday(&tv, NULL);
905 tm=localtime(&tv.tv_sec);
906 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100907 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100908 vfprintf(stderr, fmt, argp);
909 fflush(stderr);
910 va_end(argp);
911 }
912}
913
914/*
915 * Displays the message on <out> only if quiet mode is not set.
916 */
917void qfprintf(FILE *out, char *fmt, ...) {
918 va_list argp;
919
willy tarreau982249e2005-12-18 00:57:06 +0100920 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100921 va_start(argp, fmt);
922 vfprintf(out, fmt, argp);
923 fflush(out);
924 va_end(argp);
925 }
willy tarreau0f7af912005-12-17 12:21:26 +0100926}
927
928
929/*
930 * converts <str> to a struct sockaddr_in* which is locally allocated.
931 * The format is "addr:port", where "addr" can be empty or "*" to indicate
932 * INADDR_ANY.
933 */
934struct sockaddr_in *str2sa(char *str) {
935 static struct sockaddr_in sa;
936 char *c;
937 int port;
938
willy tarreaua1598082005-12-17 13:08:06 +0100939 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100940 str=strdup(str);
941
942 if ((c=strrchr(str,':')) != NULL) {
943 *c++=0;
944 port=atol(c);
945 }
946 else
947 port=0;
948
949 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
950 sa.sin_addr.s_addr = INADDR_ANY;
951 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100952 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100953 struct hostent *he;
954
955 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100956 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100957 }
958 else
959 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
960 }
961 sa.sin_port=htons(port);
962 sa.sin_family=AF_INET;
963
964 free(str);
965 return &sa;
966}
967
willy tarreaub1285d52005-12-18 01:20:14 +0100968/*
969 * converts <str> to a two struct in_addr* which are locally allocated.
970 * The format is "addr[/mask]", where "addr" cannot be empty, and mask
971 * is optionnal and either in the dotted or CIDR notation.
972 * Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
973 */
974int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
975 char *c;
976 unsigned long len;
977
978 memset(mask, 0, sizeof(*mask));
979 memset(addr, 0, sizeof(*addr));
980 str=strdup(str);
981
982 if ((c = strrchr(str, '/')) != NULL) {
983 *c++ = 0;
984 /* c points to the mask */
985 if (strchr(c, '.') != NULL) { /* dotted notation */
986 if (!inet_pton(AF_INET, c, mask))
987 return 0;
988 }
989 else { /* mask length */
990 char *err;
991 len = strtol(c, &err, 10);
992 if (!*c || (err && *err) || (unsigned)len > 32)
993 return 0;
994 if (len)
995 mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
996 else
997 mask->s_addr = 0;
998 }
999 }
1000 else {
1001 mask->s_addr = 0xFFFFFFFF;
1002 }
1003 if (!inet_pton(AF_INET, str, addr)) {
1004 struct hostent *he;
1005
1006 if ((he = gethostbyname(str)) == NULL) {
1007 return 0;
1008 }
1009 else
1010 *addr = *(struct in_addr *) *(he->h_addr_list);
1011 }
1012 free(str);
1013 return 1;
1014}
1015
willy tarreau9fe663a2005-12-17 13:02:59 +01001016
1017/*
willy tarreaua41a8b42005-12-17 14:02:24 +01001018 * converts <str> to a list of listeners which are dynamically allocated.
1019 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
1020 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
1021 * - <port> is a numerical port from 1 to 65535 ;
1022 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
1023 * This can be repeated as many times as necessary, separated by a coma.
1024 * The <tail> argument is a pointer to a current list which should be appended
1025 * to the tail of the new list. The pointer to the new list is returned.
1026 */
1027struct listener *str2listener(char *str, struct listener *tail) {
1028 struct listener *l;
1029 char *c, *next, *range, *dupstr;
1030 int port, end;
1031
1032 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +01001033
willy tarreaua41a8b42005-12-17 14:02:24 +01001034 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001035 struct sockaddr_storage ss;
1036
willy tarreaua41a8b42005-12-17 14:02:24 +01001037 str = next;
1038 /* 1) look for the end of the first address */
1039 if ((next = strrchr(str, ',')) != NULL) {
1040 *next++ = 0;
1041 }
1042
willy tarreau8a86dbf2005-12-18 00:45:59 +01001043 /* 2) look for the addr/port delimiter, it's the last colon. */
1044 if ((range = strrchr(str, ':')) == NULL) {
1045 Alert("Missing port number: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001046 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001047 }
1048
1049 *range++ = 0;
1050
1051 if (strrchr(str, ':') != NULL) {
1052 /* IPv6 address contains ':' */
1053 memset(&ss, 0, sizeof(ss));
1054 ss.ss_family = AF_INET6;
1055
1056 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
1057 Alert("Invalid server address: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001058 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001059 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001060 }
1061 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +01001062 memset(&ss, 0, sizeof(ss));
1063 ss.ss_family = AF_INET;
1064
1065 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
1066 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
1067 }
1068 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
1069 struct hostent *he;
1070
1071 if ((he = gethostbyname(str)) == NULL) {
1072 Alert("Invalid server name: '%s'\n", str);
willy tarreaud0fb4652005-12-18 01:32:04 +01001073 goto fail;
willy tarreau8a86dbf2005-12-18 00:45:59 +01001074 }
1075 else
1076 ((struct sockaddr_in *)&ss)->sin_addr =
1077 *(struct in_addr *) *(he->h_addr_list);
1078 }
1079 }
willy tarreaua41a8b42005-12-17 14:02:24 +01001080
1081 /* 3) look for the port-end delimiter */
1082 if ((c = strchr(range, '-')) != NULL) {
1083 *c++ = 0;
1084 end = atol(c);
1085 }
1086 else {
1087 end = atol(range);
1088 }
1089
willy tarreaud0fb4652005-12-18 01:32:04 +01001090 port = atol(range);
1091
1092 if (port < 1 || port > 65535) {
1093 Alert("Invalid port '%d' specified for address '%s'.\n", port, str);
1094 goto fail;
1095 }
1096
1097 if (end < 1 || end > 65535) {
1098 Alert("Invalid port '%d' specified for address '%s'.\n", end, str);
1099 goto fail;
1100 }
1101
1102 for (; port <= end; port++) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001103 l = (struct listener *)calloc(1, sizeof(struct listener));
1104 l->next = tail;
1105 tail = l;
1106
willy tarreau8a86dbf2005-12-18 00:45:59 +01001107 l->addr = ss;
1108 if (ss.ss_family == AF_INET6)
1109 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1110 else
1111 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1112
willy tarreaua41a8b42005-12-17 14:02:24 +01001113 } /* end for(port) */
1114 } /* end while(next) */
1115 free(dupstr);
1116 return tail;
willy tarreaud0fb4652005-12-18 01:32:04 +01001117 fail:
1118 free(dupstr);
1119 return NULL;
willy tarreaua41a8b42005-12-17 14:02:24 +01001120}
1121
willy tarreau4302f492005-12-18 01:00:37 +01001122
1123#define FD_SETS_ARE_BITFIELDS
1124#ifdef FD_SETS_ARE_BITFIELDS
1125/*
1126 * This map is used with all the FD_* macros to check whether a particular bit
1127 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1128 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1129 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1130 * exclusively to the macros.
1131 */
1132fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1133fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1134
1135#else
1136#error "Check if your OS uses bitfields for fd_sets"
1137#endif
1138
1139/* will try to encode the string <string> replacing all characters tagged in
1140 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1141 * prefixed by <escape>, and will store the result between <start> (included
1142 *) and <stop> (excluded), and will always terminate the string with a '\0'
1143 * before <stop>. The position of the '\0' is returned if the conversion
1144 * completes. If bytes are missing between <start> and <stop>, then the
1145 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1146 * cannot even be stored so we return <start> without writing the 0.
1147 * The input string must also be zero-terminated.
1148 */
1149char hextab[16] = "0123456789ABCDEF";
1150char *encode_string(char *start, char *stop,
1151 const char escape, const fd_set *map,
1152 const char *string)
1153{
1154 if (start < stop) {
1155 stop--; /* reserve one byte for the final '\0' */
1156 while (start < stop && *string != 0) {
1157 if (!FD_ISSET((unsigned char)(*string), map))
1158 *start++ = *string;
1159 else {
1160 if (start + 3 >= stop)
1161 break;
1162 *start++ = escape;
1163 *start++ = hextab[(*string >> 4) & 15];
1164 *start++ = hextab[*string & 15];
1165 }
1166 string++;
1167 }
1168 *start = '\0';
1169 }
1170 return start;
1171}
willy tarreaua41a8b42005-12-17 14:02:24 +01001172
1173/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001174 * This function sends a syslog message to both log servers of a proxy,
1175 * or to global log servers if the proxy is NULL.
1176 * It also tries not to waste too much time computing the message header.
1177 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001178 */
1179void send_log(struct proxy *p, int level, char *message, ...) {
1180 static int logfd = -1; /* syslog UDP socket */
1181 static long tvsec = -1; /* to force the string to be initialized */
1182 struct timeval tv;
1183 va_list argp;
1184 static char logmsg[MAX_SYSLOG_LEN];
1185 static char *dataptr = NULL;
1186 int fac_level;
1187 int hdr_len, data_len;
1188 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001189 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001190 int nbloggers = 0;
1191 char *log_ptr;
1192
1193 if (logfd < 0) {
1194 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1195 return;
1196 }
1197
1198 if (level < 0 || progname == NULL || message == NULL)
1199 return;
1200
1201 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001202 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001203 /* this string is rebuild only once a second */
1204 struct tm *tm = localtime(&tv.tv_sec);
1205 tvsec = tv.tv_sec;
1206
willy tarreauc29948c2005-12-17 13:10:27 +01001207 hdr_len = snprintf(logmsg, sizeof(logmsg),
1208 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1209 monthname[tm->tm_mon],
1210 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1211 progname, pid);
1212 /* WARNING: depending upon implementations, snprintf may return
1213 * either -1 or the number of bytes that would be needed to store
1214 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001215 */
willy tarreauc29948c2005-12-17 13:10:27 +01001216 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1217 hdr_len = sizeof(logmsg);
1218
1219 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001220 }
1221
1222 va_start(argp, message);
1223 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001224 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1225 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001226 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001227 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001228
1229 if (p == NULL) {
1230 if (global.logfac1 >= 0) {
1231 sa[nbloggers] = &global.logsrv1;
1232 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001233 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001234 nbloggers++;
1235 }
1236 if (global.logfac2 >= 0) {
1237 sa[nbloggers] = &global.logsrv2;
1238 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001239 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001240 nbloggers++;
1241 }
1242 } else {
1243 if (p->logfac1 >= 0) {
1244 sa[nbloggers] = &p->logsrv1;
1245 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001246 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001247 nbloggers++;
1248 }
1249 if (p->logfac2 >= 0) {
1250 sa[nbloggers] = &p->logsrv2;
1251 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001252 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001253 nbloggers++;
1254 }
1255 }
1256
1257 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001258 /* we can filter the level of the messages that are sent to each logger */
1259 if (level > loglevel[nbloggers])
1260 continue;
1261
willy tarreauc29948c2005-12-17 13:10:27 +01001262 /* For each target, we may have a different facility.
1263 * We can also have a different log level for each message.
1264 * This induces variations in the message header length.
1265 * Since we don't want to recompute it each time, nor copy it every
1266 * time, we only change the facility in the pre-computed header,
1267 * and we change the pointer to the header accordingly.
1268 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001269 fac_level = (facilities[nbloggers] << 3) + level;
1270 log_ptr = logmsg + 3; /* last digit of the log level */
1271 do {
1272 *log_ptr = '0' + fac_level % 10;
1273 fac_level /= 10;
1274 log_ptr--;
1275 } while (fac_level && log_ptr > logmsg);
1276 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001277
willy tarreauc29948c2005-12-17 13:10:27 +01001278 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001279
1280#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001281 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001282 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1283#else
willy tarreauc29948c2005-12-17 13:10:27 +01001284 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001285 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1286#endif
1287 }
willy tarreau0f7af912005-12-17 12:21:26 +01001288}
1289
1290
1291/* sets <tv> to the current time */
1292static inline struct timeval *tv_now(struct timeval *tv) {
1293 if (tv)
1294 gettimeofday(tv, NULL);
1295 return tv;
1296}
1297
1298/*
1299 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1300 */
1301static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1302 if (!tv || !from)
1303 return NULL;
1304 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1305 tv->tv_sec = from->tv_sec + (ms/1000);
1306 while (tv->tv_usec >= 1000000) {
1307 tv->tv_usec -= 1000000;
1308 tv->tv_sec++;
1309 }
1310 return tv;
1311}
1312
1313/*
1314 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001315 * Must not be used when either argument is eternity. Use tv_cmp2() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001316 */
1317static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001318 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001319 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001320 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001321 return 1;
1322 else if (tv1->tv_usec < tv2->tv_usec)
1323 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001324 else if (tv1->tv_usec > tv2->tv_usec)
1325 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001326 else
1327 return 0;
1328}
1329
1330/*
1331 * returns the absolute difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001332 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001333 */
1334unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1335 int cmp;
1336 unsigned long ret;
1337
1338
willy tarreauef900ab2005-12-17 12:52:52 +01001339 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001340 if (!cmp)
1341 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001342 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001343 struct timeval *tmp = tv1;
1344 tv1 = tv2;
1345 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001346 }
willy tarreauef900ab2005-12-17 12:52:52 +01001347 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001348 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001349 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001350 else
willy tarreauef900ab2005-12-17 12:52:52 +01001351 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001352 return (unsigned long) ret;
1353}
1354
1355/*
willy tarreau750a4722005-12-17 13:21:24 +01001356 * returns the difference, in ms, between tv1 and tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001357 * Must not be used when either argument is eternity.
willy tarreau750a4722005-12-17 13:21:24 +01001358 */
1359static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1360 unsigned long ret;
1361
willy tarreau6e682ce2005-12-17 13:26:49 +01001362 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1363 if (tv2->tv_usec > tv1->tv_usec)
1364 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001365 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001366 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001367 return (unsigned long) ret;
1368}
1369
1370/*
willy tarreau0f7af912005-12-17 12:21:26 +01001371 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
willy tarreaub952e1d2005-12-18 01:31:20 +01001372 * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
willy tarreau0f7af912005-12-17 12:21:26 +01001373 */
1374static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001375 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001376 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001377 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001378 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1379 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001380 else
1381 return 0;
1382 }
willy tarreau0f7af912005-12-17 12:21:26 +01001383 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001384 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001385 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001386 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1387 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1388 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001389 else
1390 return 0;
1391}
1392
1393/*
1394 * returns the remaining time between tv1=now and event=tv2
1395 * if tv2 is passed, 0 is returned.
willy tarreaub952e1d2005-12-18 01:31:20 +01001396 * Must not be used when either argument is eternity.
willy tarreau0f7af912005-12-17 12:21:26 +01001397 */
1398static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1399 unsigned long ret;
1400
willy tarreau0f7af912005-12-17 12:21:26 +01001401 if (tv_cmp_ms(tv1, tv2) >= 0)
1402 return 0; /* event elapsed */
1403
willy tarreauef900ab2005-12-17 12:52:52 +01001404 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001405 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001406 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001407 else
willy tarreauef900ab2005-12-17 12:52:52 +01001408 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001409 return (unsigned long) ret;
1410}
1411
1412
1413/*
1414 * zeroes a struct timeval
1415 */
1416
1417static inline struct timeval *tv_eternity(struct timeval *tv) {
1418 tv->tv_sec = tv->tv_usec = 0;
1419 return tv;
1420}
1421
1422/*
1423 * returns 1 if tv is null, else 0
1424 */
1425static inline int tv_iseternity(struct timeval *tv) {
1426 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1427 return 1;
1428 else
1429 return 0;
1430}
1431
1432/*
1433 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1434 * considering that 0 is the eternity.
1435 */
1436static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1437 if (tv_iseternity(tv1))
1438 if (tv_iseternity(tv2))
1439 return 0; /* same */
1440 else
1441 return 1; /* tv1 later than tv2 */
1442 else if (tv_iseternity(tv2))
1443 return -1; /* tv2 later than tv1 */
1444
1445 if (tv1->tv_sec > tv2->tv_sec)
1446 return 1;
1447 else if (tv1->tv_sec < tv2->tv_sec)
1448 return -1;
1449 else if (tv1->tv_usec > tv2->tv_usec)
1450 return 1;
1451 else if (tv1->tv_usec < tv2->tv_usec)
1452 return -1;
1453 else
1454 return 0;
1455}
1456
1457/*
1458 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1459 * considering that 0 is the eternity.
1460 */
1461static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1462 if (tv_iseternity(tv1))
1463 if (tv_iseternity(tv2))
1464 return 0; /* same */
1465 else
1466 return 1; /* tv1 later than tv2 */
1467 else if (tv_iseternity(tv2))
1468 return -1; /* tv2 later than tv1 */
1469
willy tarreauefae1842005-12-17 12:51:03 +01001470 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001471 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001472 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001473 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001474 return -1;
1475 else
1476 return 0;
1477 }
1478 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001479 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001480 return 1;
1481 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001482 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001483 return -1;
1484 else
1485 return 0;
1486}
1487
1488/*
willy tarreaub952e1d2005-12-18 01:31:20 +01001489 * returns the remaining time between tv1=now and event=tv2
1490 * if tv2 is passed, 0 is returned.
1491 * Returns TIME_ETERNITY if tv2 is eternity.
1492 */
1493static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
1494 unsigned long ret;
1495
1496 if (tv_iseternity(tv2))
1497 return TIME_ETERNITY;
1498
1499 if (tv_cmp_ms(tv1, tv2) >= 0)
1500 return 0; /* event elapsed */
1501
1502 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1503 if (tv2->tv_usec > tv1->tv_usec)
1504 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
1505 else
1506 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
1507 return (unsigned long) ret;
1508}
1509
1510/*
willy tarreau0f7af912005-12-17 12:21:26 +01001511 * returns the first event between tv1 and tv2 into tvmin.
1512 * a zero tv is ignored. tvmin is returned.
1513 */
1514static inline struct timeval *tv_min(struct timeval *tvmin,
1515 struct timeval *tv1, struct timeval *tv2) {
1516
1517 if (tv_cmp2(tv1, tv2) <= 0)
1518 *tvmin = *tv1;
1519 else
1520 *tvmin = *tv2;
1521
1522 return tvmin;
1523}
1524
1525
1526
1527/***********************************************************/
1528/* fd management ***************************************/
1529/***********************************************************/
1530
1531
1532
willy tarreau5cbea6f2005-12-17 12:48:26 +01001533/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1534 * The file descriptor is also closed.
1535 */
willy tarreau0f7af912005-12-17 12:21:26 +01001536static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001537 FD_CLR(fd, StaticReadEvent);
1538 FD_CLR(fd, StaticWriteEvent);
willy tarreau08dedbe2005-12-18 01:13:48 +01001539#if defined(ENABLE_EPOLL)
1540 if (PrevReadEvent) {
1541 FD_CLR(fd, PrevReadEvent);
1542 FD_CLR(fd, PrevWriteEvent);
1543 }
1544#endif
1545
willy tarreau5cbea6f2005-12-17 12:48:26 +01001546 close(fd);
1547 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001548
1549 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1550 maxfd--;
1551}
1552
1553/* recomputes the maxfd limit from the fd */
1554static inline void fd_insert(int fd) {
1555 if (fd+1 > maxfd)
1556 maxfd = fd+1;
1557}
1558
1559/*************************************************************/
1560/* task management ***************************************/
1561/*************************************************************/
1562
willy tarreau5cbea6f2005-12-17 12:48:26 +01001563/* puts the task <t> in run queue <q>, and returns <t> */
1564static inline struct task *task_wakeup(struct task **q, struct task *t) {
1565 if (t->state == TASK_RUNNING)
1566 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001567 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001568 t->rqnext = *q;
1569 t->state = TASK_RUNNING;
1570 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001571 }
1572}
1573
willy tarreau5cbea6f2005-12-17 12:48:26 +01001574/* removes the task <t> from the queue <q>
1575 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001576 * set the run queue to point to the next one, and return it
1577 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001578static inline struct task *task_sleep(struct task **q, struct task *t) {
1579 if (t->state == TASK_RUNNING) {
1580 *q = t->rqnext;
1581 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001582 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001583 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001584}
1585
1586/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001587 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001588 * from the run queue. A pointer to the task itself is returned.
1589 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001590static inline struct task *task_delete(struct task *t) {
1591 t->prev->next = t->next;
1592 t->next->prev = t->prev;
1593 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001594}
1595
1596/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001597 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001598 */
1599static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001601}
1602
willy tarreau5cbea6f2005-12-17 12:48:26 +01001603/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001604 * may be only moved or left where it was, depending on its timing requirements.
1605 * <task> is returned.
1606 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001607struct task *task_queue(struct task *task) {
1608 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001609 struct task *start_from;
1610
1611 /* first, test if the task was already in a list */
1612 if (task->prev == NULL) {
1613 // start_from = list;
1614 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001615#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001616 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001617#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001618 /* insert the unlinked <task> into the list, searching back from the last entry */
1619 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1620 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001621#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001622 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001623#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001624 }
1625
1626 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1627 // start_from = start_from->next;
1628 // stats_tsk_nsrch++;
1629 // }
1630 }
1631 else if (task->prev == list ||
1632 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1633 start_from = task->next;
1634 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001635#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001636 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001637#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001638 return task; /* it's already in the right place */
1639 }
1640
willy tarreau750a4722005-12-17 13:21:24 +01001641#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001642 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001643#endif
1644
1645 /* if the task is not at the right place, there's little chance that
1646 * it has only shifted a bit, and it will nearly always be queued
1647 * at the end of the list because of constant timeouts
1648 * (observed in real case).
1649 */
1650#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1651 start_from = list->prev; /* assume we'll queue to the end of the list */
1652 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1653 start_from = start_from->prev;
1654#if STATTIME > 0
1655 stats_tsk_lsrch++;
1656#endif
1657 }
1658#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001659 /* insert the unlinked <task> into the list, searching after position <start_from> */
1660 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1661 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001662#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001663 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001664#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001665 }
willy tarreau750a4722005-12-17 13:21:24 +01001666#endif /* WE_REALLY_... */
1667
willy tarreau0f7af912005-12-17 12:21:26 +01001668 /* we need to unlink it now */
1669 task_delete(task);
1670 }
1671 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001672#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001673 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001674#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001675#ifdef LEFT_TO_TOP /* not very good */
1676 start_from = list;
1677 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1678 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001679#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001680 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001681#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001682 }
1683#else
1684 start_from = task->prev->prev; /* valid because of the previous test above */
1685 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1686 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001687#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001688 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001689#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001690 }
1691#endif
1692 /* we need to unlink it now */
1693 task_delete(task);
1694 }
1695 task->prev = start_from;
1696 task->next = start_from->next;
1697 task->next->prev = task;
1698 start_from->next = task;
1699 return task;
1700}
1701
1702
1703/*********************************************************************/
1704/* more specific functions ***************************************/
1705/*********************************************************************/
1706
1707/* some prototypes */
1708static int maintain_proxies(void);
1709
willy tarreaub952e1d2005-12-18 01:31:20 +01001710/* This either returns the sockname or the original destination address. Code
willy tarreau5cbea6f2005-12-17 12:48:26 +01001711 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1712 */
willy tarreauc5f73ed2005-12-18 01:26:38 +01001713static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001714#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001715 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1716#else
willy tarreaua1598082005-12-17 13:08:06 +01001717#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001718 return getsockname(fd, (struct sockaddr *)sa, salen);
1719#else
1720 return -1;
1721#endif
1722#endif
1723}
1724
1725/*
1726 * frees the context associated to a session. It must have been removed first.
1727 */
1728static inline void session_free(struct session *s) {
1729 if (s->req)
1730 pool_free(buffer, s->req);
1731 if (s->rep)
1732 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001733
1734 if (s->rsp_cap != NULL) {
1735 struct cap_hdr *h;
1736 for (h = s->proxy->rsp_cap; h; h = h->next) {
1737 if (s->rsp_cap[h->index] != NULL)
1738 pool_free_to(h->pool, s->rsp_cap[h->index]);
1739 }
1740 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1741 }
1742 if (s->req_cap != NULL) {
1743 struct cap_hdr *h;
1744 for (h = s->proxy->req_cap; h; h = h->next) {
1745 if (s->req_cap[h->index] != NULL)
1746 pool_free_to(h->pool, s->req_cap[h->index]);
1747 }
1748 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1749 }
1750
willy tarreaua1598082005-12-17 13:08:06 +01001751 if (s->logs.uri)
1752 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001753 if (s->logs.cli_cookie)
1754 pool_free(capture, s->logs.cli_cookie);
1755 if (s->logs.srv_cookie)
1756 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001757
willy tarreau5cbea6f2005-12-17 12:48:26 +01001758 pool_free(session, s);
1759}
1760
willy tarreau0f7af912005-12-17 12:21:26 +01001761
1762/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001763 * This function tries to find a running server for the proxy <px>. A first
1764 * pass looks for active servers, and if none is found, a second pass also
1765 * looks for backup servers.
1766 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1767 */
1768static inline struct server *find_server(struct proxy *px) {
1769 struct server *srv = px->cursrv;
1770 int ignore_backup = 1;
1771
1772 do {
1773 do {
1774 if (srv == NULL)
1775 srv = px->srv;
1776 if (srv->state & SRV_RUNNING
1777 && !((srv->state & SRV_BACKUP) && ignore_backup))
1778 return srv;
1779 srv = srv->next;
1780 } while (srv != px->cursrv);
1781 } while (ignore_backup--);
1782 return NULL;
1783}
1784
1785/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001786 * This function initiates a connection to the current server (s->srv) if (s->direct)
willy tarreaub1285d52005-12-18 01:20:14 +01001787 * is set, or to the dispatch server if (s->direct) is 0.
1788 * It can return one of :
1789 * - SN_ERR_NONE if everything's OK
1790 * - SN_ERR_SRVTO if there are no more servers
1791 * - SN_ERR_SRVCL if the connection was refused by the server
1792 * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
1793 * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
1794 * - SN_ERR_INTERNAL for any other purely internal errors
1795 * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
willy tarreau0f7af912005-12-17 12:21:26 +01001796 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001797int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001798 int fd;
1799
willy tarreau12350152005-12-18 01:03:27 +01001800#ifdef DEBUG_FULL
1801 fprintf(stderr,"connect_server : s=%p\n",s);
1802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001803
willy tarreaue39cd132005-12-17 13:00:18 +01001804 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001805 s->srv_addr = s->srv->addr;
1806 }
1807 else if (s->proxy->options & PR_O_BALANCE) {
1808 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001809 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001810
willy tarreau8337c6b2005-12-17 13:41:01 +01001811 srv = find_server(s->proxy);
1812
1813 if (srv == NULL) /* no server left */
willy tarreaub1285d52005-12-18 01:20:14 +01001814 return SN_ERR_SRVTO;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001815
willy tarreau8337c6b2005-12-17 13:41:01 +01001816 s->srv_addr = srv->addr;
1817 s->srv = srv;
1818 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001819 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001820 else /* unknown balancing algorithm */
willy tarreaub1285d52005-12-18 01:20:14 +01001821 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001822 }
willy tarreaua1598082005-12-17 13:08:06 +01001823 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001824 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001825 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001826 }
1827 else if (s->proxy->options & PR_O_TRANSP) {
1828 /* in transparent mode, use the original dest addr if no dispatch specified */
willy tarreaub952e1d2005-12-18 01:31:20 +01001829 socklen_t salen = sizeof(s->srv_addr);
1830
willy tarreau5cbea6f2005-12-17 12:48:26 +01001831 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1832 qfprintf(stderr, "Cannot get original server address.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001833 return SN_ERR_INTERNAL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 }
1835 }
willy tarreau0f7af912005-12-17 12:21:26 +01001836
willy tarreaua41a8b42005-12-17 14:02:24 +01001837 /* if this server remaps proxied ports, we'll use
1838 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001839 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001840 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01001841 socklen_t namelen = sizeof(sockname);
willy tarreaua41a8b42005-12-17 14:02:24 +01001842
willy tarreaub952e1d2005-12-18 01:31:20 +01001843 if (!(s->proxy->options & PR_O_TRANSP) ||
1844 get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreaua41a8b42005-12-17 14:02:24 +01001845 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1846 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1847 }
1848
willy tarreau0f7af912005-12-17 12:21:26 +01001849 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001850 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreaub1285d52005-12-18 01:20:14 +01001851
1852 if (errno == ENFILE)
1853 send_log(s->proxy, LOG_EMERG,
1854 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
1855 s->proxy->id, maxfd);
1856 else if (errno == EMFILE)
1857 send_log(s->proxy, LOG_EMERG,
1858 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
1859 s->proxy->id, maxfd);
1860 else if (errno == ENOBUFS || errno == ENOMEM)
1861 send_log(s->proxy, LOG_EMERG,
1862 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
1863 s->proxy->id, maxfd);
1864 /* this is a resource error */
1865 return SN_ERR_RESOURCE;
willy tarreau0f7af912005-12-17 12:21:26 +01001866 }
1867
willy tarreau9fe663a2005-12-17 13:02:59 +01001868 if (fd >= global.maxsock) {
willy tarreaub1285d52005-12-18 01:20:14 +01001869 /* do not log anything there, it's a normal condition when this option
1870 * is used to serialize connections to a server !
1871 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001872 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1873 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001874 return SN_ERR_PRXCOND; /* it is a configuration limit */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001875 }
1876
willy tarreau0f7af912005-12-17 12:21:26 +01001877 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1878 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001879 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001880 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001881 return SN_ERR_INTERNAL;
willy tarreau0f7af912005-12-17 12:21:26 +01001882 }
1883
willy tarreaub952e1d2005-12-18 01:31:20 +01001884 if (s->proxy->options & PR_O_TCP_SRV_KA)
1885 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
1886
willy tarreau0174f312005-12-18 01:02:42 +01001887 /* allow specific binding :
1888 * - server-specific at first
1889 * - proxy-specific next
1890 */
1891 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1892 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1893 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1894 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1895 s->proxy->id, s->srv->id);
1896 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001897 send_log(s->proxy, LOG_EMERG,
1898 "Cannot bind to source address before connect() for server %s/%s.\n",
1899 s->proxy->id, s->srv->id);
1900 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001901 }
1902 }
1903 else if (s->proxy->options & PR_O_BIND_SRC) {
1904 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1905 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1906 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1907 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001908 send_log(s->proxy, LOG_EMERG,
1909 "Cannot bind to source address before connect() for server %s/%s.\n",
1910 s->proxy->id, s->srv->id);
1911 return SN_ERR_RESOURCE;
willy tarreau0174f312005-12-18 01:02:42 +01001912 }
willy tarreaua1598082005-12-17 13:08:06 +01001913 }
1914
willy tarreaub1285d52005-12-18 01:20:14 +01001915 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
1916 (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
1917
1918 if (errno == EAGAIN || errno == EADDRINUSE) {
1919 char *msg;
1920 if (errno == EAGAIN) /* no free ports left, try again later */
1921 msg = "no free ports";
1922 else
1923 msg = "local address already in use";
1924
1925 qfprintf(stderr,"Cannot connect: %s.\n",msg);
willy tarreau0f7af912005-12-17 12:21:26 +01001926 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001927 send_log(s->proxy, LOG_EMERG,
1928 "Connect() failed for server %s/%s: %s.\n",
1929 s->proxy->id, s->srv->id, msg);
1930 return SN_ERR_RESOURCE;
1931 } else if (errno == ETIMEDOUT) {
willy tarreaub952e1d2005-12-18 01:31:20 +01001932 //qfprintf(stderr,"Connect(): ETIMEDOUT");
willy tarreau0f7af912005-12-17 12:21:26 +01001933 close(fd);
willy tarreaub1285d52005-12-18 01:20:14 +01001934 return SN_ERR_SRVTO;
1935 } else {
1936 // (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
willy tarreaub952e1d2005-12-18 01:31:20 +01001937 //qfprintf(stderr,"Connect(): %d", errno);
willy tarreaub1285d52005-12-18 01:20:14 +01001938 close(fd);
1939 return SN_ERR_SRVCL;
willy tarreau0f7af912005-12-17 12:21:26 +01001940 }
1941 }
1942
willy tarreau5cbea6f2005-12-17 12:48:26 +01001943 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001944 fdtab[fd].read = &event_srv_read;
1945 fdtab[fd].write = &event_srv_write;
1946 fdtab[fd].state = FD_STCONN; /* connection in progress */
1947
1948 FD_SET(fd, StaticWriteEvent); /* for connect status */
1949
1950 fd_insert(fd);
1951
1952 if (s->proxy->contimeout)
1953 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1954 else
1955 tv_eternity(&s->cnexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01001956 return SN_ERR_NONE; /* connection is OK */
willy tarreau0f7af912005-12-17 12:21:26 +01001957}
1958
1959/*
1960 * this function is called on a read event from a client socket.
1961 * It returns 0.
1962 */
1963int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001964 struct task *t = fdtab[fd].owner;
1965 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001966 struct buffer *b = s->req;
1967 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001968
willy tarreau12350152005-12-18 01:03:27 +01001969#ifdef DEBUG_FULL
1970 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1971#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001972
willy tarreau0f7af912005-12-17 12:21:26 +01001973 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01001974#ifdef FILL_BUFFERS
1975 while (1)
1976#else
1977 do
1978#endif
1979 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001980 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1981 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001982 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001983 }
1984 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001985 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001986 }
1987 else {
1988 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001989 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1990 * since it means that the rewrite protection has been removed. This
1991 * implies that the if statement can be removed.
1992 */
1993 if (max > b->rlim - b->data)
1994 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001995 }
1996
1997 if (max == 0) { /* not anymore room to store data */
1998 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001999 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002000 }
2001
willy tarreau3242e862005-12-17 12:27:53 +01002002#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002004 int skerr;
2005 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002006
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2008 if (skerr)
2009 ret = -1;
2010 else
2011 ret = recv(fd, b->r, max, 0);
2012 }
willy tarreau3242e862005-12-17 12:27:53 +01002013#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002015#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002016 if (ret > 0) {
2017 b->r += ret;
2018 b->l += ret;
2019 s->res_cr = RES_DATA;
2020
2021 if (b->r == b->data + BUFSIZE) {
2022 b->r = b->data; /* wrap around the buffer */
2023 }
willy tarreaua1598082005-12-17 13:08:06 +01002024
2025 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002026 /* we hope to read more data or to get a close on next round */
2027 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002028 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 else if (ret == 0) {
2030 s->res_cr = RES_NULL;
2031 break;
2032 }
2033 else if (errno == EAGAIN) {/* ignore EAGAIN */
2034 break;
2035 }
2036 else {
2037 s->res_cr = RES_ERROR;
2038 fdtab[fd].state = FD_STERROR;
2039 break;
2040 }
2041 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002042#ifndef FILL_BUFFERS
2043 while (0);
2044#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002045 }
2046 else {
2047 s->res_cr = RES_ERROR;
2048 fdtab[fd].state = FD_STERROR;
2049 }
2050
willy tarreau5cbea6f2005-12-17 12:48:26 +01002051 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002052 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2054 else
2055 tv_eternity(&s->crexpire);
2056
2057 task_wakeup(&rq, t);
2058 }
willy tarreau0f7af912005-12-17 12:21:26 +01002059
willy tarreau0f7af912005-12-17 12:21:26 +01002060 return 0;
2061}
2062
2063
2064/*
2065 * this function is called on a read event from a server socket.
2066 * It returns 0.
2067 */
2068int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002069 struct task *t = fdtab[fd].owner;
2070 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002071 struct buffer *b = s->rep;
2072 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002073
willy tarreau12350152005-12-18 01:03:27 +01002074#ifdef DEBUG_FULL
2075 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
2076#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002077
willy tarreau0f7af912005-12-17 12:21:26 +01002078 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5dffb602005-12-18 01:15:23 +01002079#ifdef FILL_BUFFERS
2080 while (1)
2081#else
2082 do
2083#endif
2084 {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002085 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
2086 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01002087 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002088 }
2089 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01002090 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002091 }
2092 else {
2093 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01002094 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
2095 * since it means that the rewrite protection has been removed. This
2096 * implies that the if statement can be removed.
2097 */
2098 if (max > b->rlim - b->data)
2099 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002100 }
2101
2102 if (max == 0) { /* not anymore room to store data */
2103 FD_CLR(fd, StaticReadEvent);
2104 break;
2105 }
2106
willy tarreau3242e862005-12-17 12:27:53 +01002107#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01002108 {
willy tarreaub952e1d2005-12-18 01:31:20 +01002109 int skerr;
2110 socklen_t lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002111
willy tarreau5cbea6f2005-12-17 12:48:26 +01002112 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2113 if (skerr)
2114 ret = -1;
2115 else
2116 ret = recv(fd, b->r, max, 0);
2117 }
willy tarreau3242e862005-12-17 12:27:53 +01002118#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01002119 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002120#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002121 if (ret > 0) {
2122 b->r += ret;
2123 b->l += ret;
2124 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01002125
willy tarreau5cbea6f2005-12-17 12:48:26 +01002126 if (b->r == b->data + BUFSIZE) {
2127 b->r = b->data; /* wrap around the buffer */
2128 }
willy tarreaua1598082005-12-17 13:08:06 +01002129
2130 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002131 /* we hope to read more data or to get a close on next round */
2132 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002133 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002134 else if (ret == 0) {
2135 s->res_sr = RES_NULL;
2136 break;
2137 }
2138 else if (errno == EAGAIN) {/* ignore EAGAIN */
2139 break;
2140 }
2141 else {
2142 s->res_sr = RES_ERROR;
2143 fdtab[fd].state = FD_STERROR;
2144 break;
2145 }
2146 } /* while(1) */
willy tarreau5dffb602005-12-18 01:15:23 +01002147#ifndef FILL_BUFFERS
2148 while (0);
2149#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002150 }
2151 else {
2152 s->res_sr = RES_ERROR;
2153 fdtab[fd].state = FD_STERROR;
2154 }
2155
willy tarreau5cbea6f2005-12-17 12:48:26 +01002156 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01002157 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002158 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
2159 else
2160 tv_eternity(&s->srexpire);
2161
2162 task_wakeup(&rq, t);
2163 }
willy tarreau0f7af912005-12-17 12:21:26 +01002164
willy tarreau0f7af912005-12-17 12:21:26 +01002165 return 0;
2166}
2167
2168/*
2169 * this function is called on a write event from a client socket.
2170 * It returns 0.
2171 */
2172int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002173 struct task *t = fdtab[fd].owner;
2174 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002175 struct buffer *b = s->rep;
2176 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002177
willy tarreau12350152005-12-18 01:03:27 +01002178#ifdef DEBUG_FULL
2179 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
2180#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002181
2182 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002183 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002184 // max = BUFSIZE; BUG !!!!
2185 max = 0;
2186 }
2187 else if (b->r > b->w) {
2188 max = b->r - b->w;
2189 }
2190 else
2191 max = b->data + BUFSIZE - b->w;
2192
willy tarreau0f7af912005-12-17 12:21:26 +01002193 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002194 if (max == 0) {
2195 s->res_cw = RES_NULL;
2196 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002197 tv_eternity(&s->cwexpire);
2198 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002199 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002200 }
2201
willy tarreau3242e862005-12-17 12:27:53 +01002202#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002203 {
2204 int skerr;
2205 socklen_t lskerr = sizeof(skerr);
2206
2207 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2208 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002209 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002210 else
willy tarreau3242e862005-12-17 12:27:53 +01002211 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002212 }
willy tarreau3242e862005-12-17 12:27:53 +01002213#else
willy tarreau0f7af912005-12-17 12:21:26 +01002214 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002215#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002216
2217 if (ret > 0) {
2218 b->l -= ret;
2219 b->w += ret;
2220
2221 s->res_cw = RES_DATA;
2222
2223 if (b->w == b->data + BUFSIZE) {
2224 b->w = b->data; /* wrap around the buffer */
2225 }
2226 }
2227 else if (ret == 0) {
2228 /* nothing written, just make as if we were never called */
2229// s->res_cw = RES_NULL;
2230 return 0;
2231 }
2232 else if (errno == EAGAIN) /* ignore EAGAIN */
2233 return 0;
2234 else {
2235 s->res_cw = RES_ERROR;
2236 fdtab[fd].state = FD_STERROR;
2237 }
2238 }
2239 else {
2240 s->res_cw = RES_ERROR;
2241 fdtab[fd].state = FD_STERROR;
2242 }
2243
willy tarreaub1ff9db2005-12-17 13:51:03 +01002244 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002245 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002246 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2247 s->crexpire = s->cwexpire;
2248 }
willy tarreau0f7af912005-12-17 12:21:26 +01002249 else
2250 tv_eternity(&s->cwexpire);
2251
willy tarreau5cbea6f2005-12-17 12:48:26 +01002252 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002253 return 0;
2254}
2255
2256
2257/*
2258 * this function is called on a write event from a server socket.
2259 * It returns 0.
2260 */
2261int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002262 struct task *t = fdtab[fd].owner;
2263 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002264 struct buffer *b = s->req;
2265 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002266
willy tarreau12350152005-12-18 01:03:27 +01002267#ifdef DEBUG_FULL
2268 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2269#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002270
2271 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002272 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002273 // max = BUFSIZE; BUG !!!!
2274 max = 0;
2275 }
2276 else if (b->r > b->w) {
2277 max = b->r - b->w;
2278 }
2279 else
2280 max = b->data + BUFSIZE - b->w;
2281
willy tarreau0f7af912005-12-17 12:21:26 +01002282 if (fdtab[fd].state != FD_STERROR) {
willy tarreauef900ab2005-12-17 12:52:52 +01002283 if (max == 0) {
2284 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau48b06592005-12-18 01:37:12 +01002285 if (s->srv_state == SV_STCONN) {
2286 int skerr;
2287 socklen_t lskerr = sizeof(skerr);
2288 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2289 if (skerr) {
2290 s->res_sw = RES_ERROR;
2291 fdtab[fd].state = FD_STERROR;
2292 task_wakeup(&rq, t);
2293 tv_eternity(&s->swexpire);
2294 FD_CLR(fd, StaticWriteEvent);
2295 return 0;
2296 }
2297 }
2298
willy tarreau0f7af912005-12-17 12:21:26 +01002299 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002300 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002301 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002302 tv_eternity(&s->swexpire);
2303 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002304 return 0;
2305 }
2306
willy tarreau3242e862005-12-17 12:27:53 +01002307#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002308 {
2309 int skerr;
2310 socklen_t lskerr = sizeof(skerr);
2311 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2312 if (skerr)
willy tarreau3242e862005-12-17 12:27:53 +01002313 ret = -1;
willy tarreaub952e1d2005-12-18 01:31:20 +01002314 else
willy tarreau3242e862005-12-17 12:27:53 +01002315 ret = send(fd, b->w, max, MSG_DONTWAIT);
willy tarreaub952e1d2005-12-18 01:31:20 +01002316 }
willy tarreau3242e862005-12-17 12:27:53 +01002317#else
willy tarreau0f7af912005-12-17 12:21:26 +01002318 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002319#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002320 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002321 if (ret > 0) {
2322 b->l -= ret;
2323 b->w += ret;
2324
2325 s->res_sw = RES_DATA;
2326
2327 if (b->w == b->data + BUFSIZE) {
2328 b->w = b->data; /* wrap around the buffer */
2329 }
2330 }
2331 else if (ret == 0) {
2332 /* nothing written, just make as if we were never called */
2333 // s->res_sw = RES_NULL;
2334 return 0;
2335 }
2336 else if (errno == EAGAIN) /* ignore EAGAIN */
2337 return 0;
2338 else {
2339 s->res_sw = RES_ERROR;
2340 fdtab[fd].state = FD_STERROR;
2341 }
2342 }
2343 else {
2344 s->res_sw = RES_ERROR;
2345 fdtab[fd].state = FD_STERROR;
2346 }
2347
willy tarreaub1ff9db2005-12-17 13:51:03 +01002348 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002349 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002350 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2351 s->srexpire = s->swexpire;
2352 }
willy tarreau0f7af912005-12-17 12:21:26 +01002353 else
2354 tv_eternity(&s->swexpire);
2355
willy tarreau5cbea6f2005-12-17 12:48:26 +01002356 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002357 return 0;
2358}
2359
2360
2361/*
willy tarreaue39cd132005-12-17 13:00:18 +01002362 * returns a message to the client ; the connection is shut down for read,
2363 * and the request is cleared so that no server connection can be initiated.
2364 * The client must be in a valid state for this (HEADER, DATA ...).
2365 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002366 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002367 */
2368void client_retnclose(struct session *s, int len, const char *msg) {
2369 FD_CLR(s->cli_fd, StaticReadEvent);
2370 FD_SET(s->cli_fd, StaticWriteEvent);
2371 tv_eternity(&s->crexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01002372 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaue39cd132005-12-17 13:00:18 +01002373 shutdown(s->cli_fd, SHUT_RD);
2374 s->cli_state = CL_STSHUTR;
2375 strcpy(s->rep->data, msg);
2376 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002377 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002378 s->rep->r += len;
2379 s->req->l = 0;
2380}
2381
2382
2383/*
2384 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002385 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002386 */
2387void client_return(struct session *s, int len, const char *msg) {
2388 strcpy(s->rep->data, msg);
2389 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002390 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002391 s->rep->r += len;
2392 s->req->l = 0;
2393}
2394
willy tarreau9fe663a2005-12-17 13:02:59 +01002395/*
2396 * send a log for the session when we have enough info about it
2397 */
2398void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002399 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002400 struct proxy *p = s->proxy;
2401 int log;
2402 char *uri;
2403 char *pxid;
2404 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002405 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002406
2407 /* This is a first attempt at a better logging system.
2408 * For now, we rely on send_log() to provide the date, although it obviously
2409 * is the date of the log and not of the request, and most fields are not
2410 * computed.
2411 */
2412
willy tarreaua1598082005-12-17 13:08:06 +01002413 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002414
willy tarreau8a86dbf2005-12-18 00:45:59 +01002415 if (s->cli_addr.ss_family == AF_INET)
2416 inet_ntop(AF_INET,
2417 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2418 pn, sizeof(pn));
2419 else
2420 inet_ntop(AF_INET6,
2421 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2422 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002423
willy tarreauc1cae632005-12-17 14:12:23 +01002424 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002425 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002426 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002427
willy tarreauc1cae632005-12-17 14:12:23 +01002428 tm = localtime(&s->logs.tv_accept.tv_sec);
2429 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002430 char tmpline[MAX_SYSLOG_LEN], *h;
2431 int hdr;
2432
2433 h = tmpline;
2434 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2435 *(h++) = ' ';
2436 *(h++) = '{';
2437 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2438 if (hdr)
2439 *(h++) = '|';
2440 if (s->req_cap[hdr] != NULL)
2441 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2442 }
2443 *(h++) = '}';
2444 }
2445
2446 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2447 *(h++) = ' ';
2448 *(h++) = '{';
2449 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2450 if (hdr)
2451 *(h++) = '|';
2452 if (s->rsp_cap[hdr] != NULL)
2453 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2454 }
2455 *(h++) = '}';
2456 }
2457
2458 if (h < tmpline + sizeof(tmpline) - 4) {
2459 *(h++) = ' ';
2460 *(h++) = '"';
2461 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2462 *(h++) = '"';
2463 }
2464 *h = '\0';
2465
willy tarreau0fe39652005-12-18 01:25:24 +01002466 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c %d/%d%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002467 pn,
2468 (s->cli_addr.ss_family == AF_INET) ?
2469 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2470 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002471 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2472 tm->tm_hour, tm->tm_min, tm->tm_sec,
2473 pxid, srv,
2474 s->logs.t_request,
2475 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2476 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002477 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2478 s->logs.status,
2479 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002480 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2481 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002482 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2483 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2484 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2485 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau0fe39652005-12-18 01:25:24 +01002486 p->nbconn, actconn, tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002487 }
2488 else {
willy tarreau0fe39652005-12-18 01:25:24 +01002489 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c %d/%d\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002490 pn,
2491 (s->cli_addr.ss_family == AF_INET) ?
2492 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2493 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002494 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2495 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002496 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002497 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002498 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2499 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002500 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreau0fe39652005-12-18 01:25:24 +01002501 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2502 p->nbconn, actconn);
willy tarreaua1598082005-12-17 13:08:06 +01002503 }
2504
2505 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002506}
2507
willy tarreaue39cd132005-12-17 13:00:18 +01002508
2509/*
willy tarreau0f7af912005-12-17 12:21:26 +01002510 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002511 * to an accept. It tries to accept as many connections as possible.
2512 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002513 */
2514int event_accept(int fd) {
2515 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002516 struct session *s;
2517 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002518 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002519
willy tarreau5cbea6f2005-12-17 12:48:26 +01002520 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002521 struct sockaddr_storage addr;
willy tarreauc5f73ed2005-12-18 01:26:38 +01002522 socklen_t laddr = sizeof(addr);
willy tarreaub952e1d2005-12-18 01:31:20 +01002523
willy tarreaub1285d52005-12-18 01:20:14 +01002524 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
2525 switch (errno) {
2526 case EAGAIN:
2527 case EINTR:
2528 case ECONNABORTED:
2529 return 0; /* nothing more to accept */
2530 case ENFILE:
2531 send_log(p, LOG_EMERG,
2532 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
2533 p->id, maxfd);
2534 return 0;
2535 case EMFILE:
2536 send_log(p, LOG_EMERG,
2537 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
2538 p->id, maxfd);
2539 return 0;
2540 case ENOBUFS:
2541 case ENOMEM:
2542 send_log(p, LOG_EMERG,
2543 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
2544 p->id, maxfd);
2545 return 0;
2546 default:
2547 return 0;
2548 }
2549 }
willy tarreau0f7af912005-12-17 12:21:26 +01002550
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2552 Alert("out of memory in event_accept().\n");
2553 FD_CLR(fd, StaticReadEvent);
2554 p->state = PR_STIDLE;
2555 close(cfd);
2556 return 0;
2557 }
willy tarreau0f7af912005-12-17 12:21:26 +01002558
willy tarreaub1285d52005-12-18 01:20:14 +01002559 /* if this session comes from a known monitoring system, we want to ignore
2560 * it as soon as possible, which means closing it immediately for TCP.
2561 */
2562 s->flags = 0;
2563 if (addr.ss_family == AF_INET &&
2564 p->mon_mask.s_addr &&
2565 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
2566 if (p->mode == PR_MODE_TCP) {
2567 close(cfd);
2568 pool_free(session, s);
2569 continue;
2570 }
2571 s->flags |= SN_MONITOR;
2572 }
2573
willy tarreau5cbea6f2005-12-17 12:48:26 +01002574 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2575 Alert("out of memory in event_accept().\n");
2576 FD_CLR(fd, StaticReadEvent);
2577 p->state = PR_STIDLE;
2578 close(cfd);
2579 pool_free(session, s);
2580 return 0;
2581 }
willy tarreau0f7af912005-12-17 12:21:26 +01002582
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002584 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2586 close(cfd);
2587 pool_free(task, t);
2588 pool_free(session, s);
2589 return 0;
2590 }
willy tarreau0f7af912005-12-17 12:21:26 +01002591
willy tarreau5cbea6f2005-12-17 12:48:26 +01002592 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2593 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2594 (char *) &one, sizeof(one)) == -1)) {
2595 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2596 close(cfd);
2597 pool_free(task, t);
2598 pool_free(session, s);
2599 return 0;
2600 }
willy tarreau0f7af912005-12-17 12:21:26 +01002601
willy tarreaub952e1d2005-12-18 01:31:20 +01002602 if (p->options & PR_O_TCP_CLI_KA)
2603 setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
2604
willy tarreau9fe663a2005-12-17 13:02:59 +01002605 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2606 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2607 t->state = TASK_IDLE;
2608 t->process = process_session;
2609 t->context = s;
2610
2611 s->task = t;
2612 s->proxy = p;
2613 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2614 s->srv_state = SV_STIDLE;
2615 s->req = s->rep = NULL; /* will be allocated later */
willy tarreau97f58572005-12-18 00:53:44 +01002616
willy tarreau9fe663a2005-12-17 13:02:59 +01002617 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2618 s->cli_fd = cfd;
2619 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002620 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002621 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002622
willy tarreaub1285d52005-12-18 01:20:14 +01002623 if (s->flags & SN_MONITOR)
2624 s->logs.logwait = 0;
2625 else
2626 s->logs.logwait = p->to_log;
2627
willy tarreaua1598082005-12-17 13:08:06 +01002628 s->logs.tv_accept = now;
2629 s->logs.t_request = -1;
2630 s->logs.t_connect = -1;
2631 s->logs.t_data = -1;
2632 s->logs.t_close = 0;
2633 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002634 s->logs.cli_cookie = NULL;
2635 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002636 s->logs.status = -1;
2637 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002638
willy tarreau2f6ba652005-12-17 13:57:42 +01002639 s->uniq_id = totalconn;
2640
willy tarreau4302f492005-12-18 01:00:37 +01002641 if (p->nb_req_cap > 0) {
2642 if ((s->req_cap =
2643 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2644 == NULL) { /* no memory */
2645 close(cfd); /* nothing can be done for this fd without memory */
2646 pool_free(task, t);
2647 pool_free(session, s);
2648 return 0;
2649 }
2650 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2651 }
2652 else
2653 s->req_cap = NULL;
2654
2655 if (p->nb_rsp_cap > 0) {
2656 if ((s->rsp_cap =
2657 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2658 == NULL) { /* no memory */
2659 if (s->req_cap != NULL)
2660 pool_free_to(p->req_cap_pool, s->req_cap);
2661 close(cfd); /* nothing can be done for this fd without memory */
2662 pool_free(task, t);
2663 pool_free(session, s);
2664 return 0;
2665 }
2666 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2667 }
2668 else
2669 s->rsp_cap = NULL;
2670
willy tarreau5cbea6f2005-12-17 12:48:26 +01002671 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2672 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002673 struct sockaddr_storage sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002674 socklen_t namelen = sizeof(sockname);
willy tarreau0f7af912005-12-17 12:21:26 +01002675
willy tarreau8a86dbf2005-12-18 00:45:59 +01002676 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002677 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002678 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002679 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002680
willy tarreau9fe663a2005-12-17 13:02:59 +01002681 if (p->to_log) {
2682 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002683 if (s->logs.logwait & LW_CLIP)
2684 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002685 sess_log(s);
2686 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002687 else if (s->cli_addr.ss_family == AF_INET) {
2688 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2689 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2690 sn, sizeof(sn)) &&
2691 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2692 pn, sizeof(pn))) {
2693 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2694 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2695 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2696 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2697 }
2698 }
2699 else {
2700 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2701 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2702 sn, sizeof(sn)) &&
2703 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2704 pn, sizeof(pn))) {
2705 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2706 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2707 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2708 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2709 }
2710 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002711 }
willy tarreau0f7af912005-12-17 12:21:26 +01002712
willy tarreau982249e2005-12-18 00:57:06 +01002713 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002714 struct sockaddr_in sockname;
willy tarreaub952e1d2005-12-18 01:31:20 +01002715 socklen_t namelen = sizeof(sockname);
willy tarreauef900ab2005-12-17 12:52:52 +01002716 int len;
willy tarreau8a86dbf2005-12-18 00:45:59 +01002717 if (addr.ss_family != AF_INET ||
willy tarreaub952e1d2005-12-18 01:31:20 +01002718 !(s->proxy->options & PR_O_TRANSP) ||
willy tarreau8a86dbf2005-12-18 00:45:59 +01002719 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002720 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002721
willy tarreau8a86dbf2005-12-18 00:45:59 +01002722 if (s->cli_addr.ss_family == AF_INET) {
2723 char pn[INET_ADDRSTRLEN];
2724 inet_ntop(AF_INET,
2725 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2726 pn, sizeof(pn));
2727
2728 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2729 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2730 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2731 }
2732 else {
2733 char pn[INET6_ADDRSTRLEN];
2734 inet_ntop(AF_INET6,
2735 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2736 pn, sizeof(pn));
2737
2738 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2739 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2740 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2741 }
2742
willy tarreauef900ab2005-12-17 12:52:52 +01002743 write(1, trash, len);
2744 }
willy tarreau0f7af912005-12-17 12:21:26 +01002745
willy tarreau5cbea6f2005-12-17 12:48:26 +01002746 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002747 if (s->rsp_cap != NULL)
2748 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2749 if (s->req_cap != NULL)
2750 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002751 close(cfd); /* nothing can be done for this fd without memory */
2752 pool_free(task, t);
2753 pool_free(session, s);
2754 return 0;
2755 }
willy tarreau4302f492005-12-18 01:00:37 +01002756
willy tarreau5cbea6f2005-12-17 12:48:26 +01002757 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002758 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002759 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2760 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002761 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002762 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002763
willy tarreau5cbea6f2005-12-17 12:48:26 +01002764 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2765 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002766 if (s->rsp_cap != NULL)
2767 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2768 if (s->req_cap != NULL)
2769 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 close(cfd); /* nothing can be done for this fd without memory */
2771 pool_free(task, t);
2772 pool_free(session, s);
2773 return 0;
2774 }
2775 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002776 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002777 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 +01002778
willy tarreau5cbea6f2005-12-17 12:48:26 +01002779 fdtab[cfd].read = &event_cli_read;
2780 fdtab[cfd].write = &event_cli_write;
2781 fdtab[cfd].owner = t;
2782 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002783
willy tarreaub1285d52005-12-18 01:20:14 +01002784 if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
2785 (p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
2786 /* Either we got a request from a monitoring system on an HTTP instance,
2787 * or we're in health check mode with the 'httpchk' option enabled. In
2788 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
2789 */
2790 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2791 else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
2792 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002793 }
2794 else {
2795 FD_SET(cfd, StaticReadEvent);
2796 }
2797
willy tarreaub952e1d2005-12-18 01:31:20 +01002798#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
2799 if (PrevReadEvent) {
2800 assert(!(FD_ISSET(cfd, PrevReadEvent)));
2801 assert(!(FD_ISSET(cfd, PrevWriteEvent)));
2802 }
2803#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01002804 fd_insert(cfd);
2805
2806 tv_eternity(&s->cnexpire);
2807 tv_eternity(&s->srexpire);
2808 tv_eternity(&s->swexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01002809 tv_eternity(&s->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002810 tv_eternity(&s->cwexpire);
2811
willy tarreaub1285d52005-12-18 01:20:14 +01002812 if (s->proxy->clitimeout) {
2813 if (FD_ISSET(cfd, StaticReadEvent))
2814 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2815 if (FD_ISSET(cfd, StaticWriteEvent))
2816 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
2817 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818
willy tarreaub1285d52005-12-18 01:20:14 +01002819 tv_min(&t->expire, &s->crexpire, &s->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002820
2821 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002822
2823 if (p->mode != PR_MODE_HEALTH)
2824 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002825
2826 p->nbconn++;
2827 actconn++;
2828 totalconn++;
2829
willy tarreaub952e1d2005-12-18 01:31:20 +01002830 // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002831 } /* end of while (p->nbconn < p->maxconn) */
2832 return 0;
2833}
willy tarreau0f7af912005-12-17 12:21:26 +01002834
willy tarreau0f7af912005-12-17 12:21:26 +01002835
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836/*
2837 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002838 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2839 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002840 * or -1 if an error occured.
2841 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002842int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002843 struct task *t = fdtab[fd].owner;
2844 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002845
willy tarreauc5f73ed2005-12-18 01:26:38 +01002846 int skerr;
willy tarreaub952e1d2005-12-18 01:31:20 +01002847 socklen_t lskerr = sizeof(skerr);
2848
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002850 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002851 if (skerr)
2852 s->result = -1;
willy tarreaua4a583a2005-12-18 01:39:19 +01002853 else if (s->result != -1) {
2854 /* we don't want to mark 'UP' a server on which we detected an error earlier */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002855 if (s->proxy->options & PR_O_HTTP_CHK) {
2856 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002857 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002858 * so we'll send the request, and won't wake the checker up now.
2859 */
2860#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002861 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002862#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002863 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002864#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002865 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002866 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2867 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2868 return 0;
2869 }
2870 else
2871 s->result = -1;
2872 }
2873 else {
2874 /* good TCP connection is enough */
2875 s->result = 1;
2876 }
2877 }
2878
2879 task_wakeup(&rq, t);
2880 return 0;
2881}
2882
willy tarreau0f7af912005-12-17 12:21:26 +01002883
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002884/*
2885 * This function is used only for server health-checks. It handles
2886 * the server's reply to an HTTP request. It returns 1 if the server replies
2887 * 2xx or 3xx (valid responses), or -1 in other cases.
2888 */
2889int event_srv_chk_r(int fd) {
2890 char reply[64];
willy tarreaua4a583a2005-12-18 01:39:19 +01002891 int len, result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002892 struct task *t = fdtab[fd].owner;
2893 struct server *s = t->context;
2894
willy tarreaua4a583a2005-12-18 01:39:19 +01002895 result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002896#ifndef MSG_NOSIGNAL
willy tarreaub952e1d2005-12-18 01:31:20 +01002897 {
2898 int skerr;
2899 socklen_t lskerr = sizeof(skerr);
2900
2901 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2902 if (!skerr)
2903 len = recv(fd, reply, sizeof(reply), 0);
2904 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002905#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002906 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2907 * but the connection was closed on the remote end. Fortunately, recv still
2908 * works correctly and we don't need to do the getsockopt() on linux.
2909 */
2910 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002911#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002912 if ((len >= sizeof("HTTP/1.0 000")) &&
2913 !memcmp(reply, "HTTP/1.", 7) &&
2914 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
willy tarreaua4a583a2005-12-18 01:39:19 +01002915 result = 1;
2916
2917 if (s->result != -1)
2918 s->result = result;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002919
2920 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002921 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002922 return 0;
2923}
2924
2925
2926/*
2927 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2928 * and moves <end> just after the end of <str>.
2929 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2930 * the shift value (positive or negative) is returned.
2931 * If there's no space left, the move is not done.
2932 *
2933 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002934int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002935 int delta;
2936 int len;
2937
2938 len = strlen(str);
2939 delta = len - (end - pos);
2940
2941 if (delta + b->r >= b->data + BUFSIZE)
2942 return 0; /* no space left */
2943
2944 /* first, protect the end of the buffer */
2945 memmove(end + delta, end, b->data + b->l - end);
2946
2947 /* now, copy str over pos */
2948 memcpy(pos, str,len);
2949
willy tarreau5cbea6f2005-12-17 12:48:26 +01002950 /* we only move data after the displaced zone */
2951 if (b->r > pos) b->r += delta;
2952 if (b->w > pos) b->w += delta;
2953 if (b->h > pos) b->h += delta;
2954 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002955 b->l += delta;
2956
2957 return delta;
2958}
2959
willy tarreau8337c6b2005-12-17 13:41:01 +01002960/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002961 * len is 0.
2962 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002963int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002964 int delta;
2965
2966 delta = len - (end - pos);
2967
2968 if (delta + b->r >= b->data + BUFSIZE)
2969 return 0; /* no space left */
2970
Willy TARREAUe78ae262006-01-08 01:24:12 +01002971 if (b->data + b->l < end)
2972 /* The data has been stolen, we could have crashed. Maybe we should abort() ? */
2973 return 0;
2974
willy tarreau0f7af912005-12-17 12:21:26 +01002975 /* first, protect the end of the buffer */
2976 memmove(end + delta, end, b->data + b->l - end);
2977
2978 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002979 if (len)
2980 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002981
willy tarreau5cbea6f2005-12-17 12:48:26 +01002982 /* we only move data after the displaced zone */
2983 if (b->r > pos) b->r += delta;
2984 if (b->w > pos) b->w += delta;
2985 if (b->h > pos) b->h += delta;
2986 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002987 b->l += delta;
2988
2989 return delta;
2990}
2991
2992
2993int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2994 char *old_dst = dst;
2995
2996 while (*str) {
2997 if (*str == '\\') {
2998 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002999 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003000 int len, num;
3001
3002 num = *str - '0';
3003 str++;
3004
willy tarreau8a86dbf2005-12-18 00:45:59 +01003005 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01003006 len = matches[num].rm_eo - matches[num].rm_so;
3007 memcpy(dst, src + matches[num].rm_so, len);
3008 dst += len;
3009 }
3010
3011 }
3012 else if (*str == 'x') {
3013 unsigned char hex1, hex2;
3014 str++;
3015
willy tarreauc1f47532005-12-18 01:08:26 +01003016 hex1 = toupper(*str++) - '0';
3017 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01003018
3019 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3020 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3021 *dst++ = (hex1<<4) + hex2;
3022 }
3023 else
3024 *dst++ = *str++;
3025 }
3026 else
3027 *dst++ = *str++;
3028 }
3029 *dst = 0;
3030 return dst - old_dst;
3031}
3032
willy tarreauc1f47532005-12-18 01:08:26 +01003033static int ishex(char s)
3034{
3035 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
3036}
3037
3038/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
3039char *check_replace_string(char *str)
3040{
3041 char *err = NULL;
3042 while (*str) {
3043 if (*str == '\\') {
3044 err = str; /* in case of a backslash, we return the pointer to it */
3045 str++;
3046 if (!*str)
3047 return err;
3048 else if (isdigit((int)*str))
3049 err = NULL;
3050 else if (*str == 'x') {
3051 str++;
3052 if (!ishex(*str))
3053 return err;
3054 str++;
3055 if (!ishex(*str))
3056 return err;
3057 err = NULL;
3058 }
3059 else {
3060 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
3061 err = NULL;
3062 }
3063 }
3064 str++;
3065 }
3066 return err;
3067}
3068
3069
willy tarreau9fe663a2005-12-17 13:02:59 +01003070
willy tarreau0f7af912005-12-17 12:21:26 +01003071/*
3072 * manages the client FSM and its socket. BTW, it also tries to handle the
3073 * cookie. It returns 1 if a state has changed (and a resync may be needed),
3074 * 0 else.
3075 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003077 int s = t->srv_state;
3078 int c = t->cli_state;
3079 struct buffer *req = t->req;
3080 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003081 int method_checked = 0;
3082 appsess *asession_temp = NULL;
3083 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003084
willy tarreau750a4722005-12-17 13:21:24 +01003085#ifdef DEBUG_FULL
willy tarreaub1285d52005-12-18 01:20:14 +01003086 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
3087 cli_stnames[c], srv_stnames[s],
3088 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3089 t->crexpire.tv_sec, t->crexpire.tv_usec,
3090 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
willy tarreau750a4722005-12-17 13:21:24 +01003091#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003092 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3093 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3094 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3095 //);
3096 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 /* now parse the partial (or complete) headers */
3098 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
3099 char *ptr;
3100 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01003101 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01003102
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01003104
willy tarreau0f7af912005-12-17 12:21:26 +01003105 /* look for the end of the current header */
3106 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
3107 ptr++;
3108
willy tarreau5cbea6f2005-12-17 12:48:26 +01003109 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003110 int line, len;
3111 /* we can only get here after an end of headers */
3112 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreaue39cd132005-12-17 13:00:18 +01003114 if (t->flags & SN_CLDENY) {
3115 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01003116 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01003117 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01003118 if (!(t->flags & SN_ERR_MASK))
3119 t->flags |= SN_ERR_PRXCOND;
3120 if (!(t->flags & SN_FINST_MASK))
3121 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003122 return 1;
3123 }
3124
willy tarreau5cbea6f2005-12-17 12:48:26 +01003125 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003126 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
3127 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003128 }
willy tarreau0f7af912005-12-17 12:21:26 +01003129
willy tarreau9fe663a2005-12-17 13:02:59 +01003130 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01003131 if (t->cli_addr.ss_family == AF_INET) {
3132 unsigned char *pn;
3133 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
3134 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
3135 pn[0], pn[1], pn[2], pn[3]);
3136 buffer_replace2(req, req->h, req->h, trash, len);
3137 }
3138 else if (t->cli_addr.ss_family == AF_INET6) {
3139 char pn[INET6_ADDRSTRLEN];
3140 inet_ntop(AF_INET6,
3141 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
3142 pn, sizeof(pn));
3143 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
3144 buffer_replace2(req, req->h, req->h, trash, len);
3145 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003146 }
3147
willy tarreau25c4ea52005-12-18 00:49:49 +01003148 /* add a "connection: close" line if needed */
3149 if (t->proxy->options & PR_O_HTTP_CLOSE)
3150 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
3151
willy tarreau982249e2005-12-18 00:57:06 +01003152 if (!memcmp(req->data, "POST ", 5)) {
3153 /* this is a POST request, which is not cacheable by default */
3154 t->flags |= SN_POST;
3155 }
willy tarreaucd878942005-12-17 13:27:43 +01003156
willy tarreau5cbea6f2005-12-17 12:48:26 +01003157 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003158 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01003159
willy tarreau750a4722005-12-17 13:21:24 +01003160 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003161 /* FIXME: we'll set the client in a wait state while we try to
3162 * connect to the server. Is this really needed ? wouldn't it be
3163 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01003164 //FD_CLR(t->cli_fd, StaticReadEvent);
3165 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01003166
3167 /* FIXME: if we break here (as up to 1.1.23), having the client
3168 * shutdown its connection can lead to an abort further.
3169 * it's better to either return 1 or even jump directly to the
3170 * data state which will save one schedule.
3171 */
3172 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01003173
3174 if (!t->proxy->clitimeout ||
3175 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3176 /* If the client has no timeout, or if the server is not ready yet,
3177 * and we know for sure that it can expire, then it's cleaner to
3178 * disable the timeout on the client side so that too low values
3179 * cannot make the sessions abort too early.
willy tarreaub1285d52005-12-18 01:20:14 +01003180 *
3181 * FIXME-20050705: the server needs a way to re-enable this time-out
3182 * when it switches its state, otherwise a client can stay connected
3183 * indefinitely. This now seems to be OK.
willy tarreauc58fc692005-12-17 14:13:08 +01003184 */
3185 tv_eternity(&t->crexpire);
3186
willy tarreau197e8ec2005-12-17 14:10:59 +01003187 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003188 }
willy tarreau0f7af912005-12-17 12:21:26 +01003189
willy tarreau5cbea6f2005-12-17 12:48:26 +01003190 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3191 if (ptr > req->r - 2) {
3192 /* this is a partial header, let's wait for more to come */
3193 req->lr = ptr;
3194 break;
3195 }
willy tarreau0f7af912005-12-17 12:21:26 +01003196
willy tarreau5cbea6f2005-12-17 12:48:26 +01003197 /* now we know that *ptr is either \r or \n,
3198 * and that there are at least 1 char after it.
3199 */
3200 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3201 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3202 else
3203 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01003204
willy tarreau5cbea6f2005-12-17 12:48:26 +01003205 /*
3206 * now we know that we have a full header ; we can do whatever
3207 * we want with these pointers :
3208 * req->h = beginning of header
3209 * ptr = end of header (first \r or \n)
3210 * req->lr = beginning of next line (next rep->h)
3211 * req->r = end of data (not used at this stage)
3212 */
willy tarreau0f7af912005-12-17 12:21:26 +01003213
willy tarreau12350152005-12-18 01:03:27 +01003214 if (!method_checked && (t->proxy->appsession_name != NULL) &&
3215 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
3216 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
3217
3218 /* skip ; */
3219 request_line++;
3220
3221 /* look if we have a jsessionid */
3222
3223 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
3224
3225 /* skip jsessionid= */
3226 request_line += t->proxy->appsession_name_len + 1;
3227
3228 /* First try if we allready have an appsession */
3229 asession_temp = &local_asession;
3230
3231 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3232 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3233 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3234 return 0;
3235 }
3236
3237 /* Copy the sessionid */
3238 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
3239 asession_temp->sessid[t->proxy->appsession_len] = 0;
3240 asession_temp->serverid = NULL;
3241
3242 /* only do insert, if lookup fails */
3243 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
3244 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3245 Alert("Not enough memory process_cli():asession:calloc().\n");
3246 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3247 return 0;
3248 }
3249 asession_temp->sessid = local_asession.sessid;
3250 asession_temp->serverid = local_asession.serverid;
3251 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01003252 } /* end if (chtbl_lookup()) */
3253 else {
willy tarreau12350152005-12-18 01:03:27 +01003254 /*free wasted memory;*/
3255 pool_free_to(apools.sessid, local_asession.sessid);
3256 }
3257
3258 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
3259 asession_temp->request_count++;
3260
3261#if defined(DEBUG_HASH)
3262 print_table(&(t->proxy->htbl_proxy));
3263#endif
3264
3265 if (asession_temp->serverid == NULL) {
3266 Alert("Found Application Session without matching server.\n");
3267 } else {
3268 struct server *srv = t->proxy->srv;
3269 while (srv) {
3270 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3271 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3272 /* we found the server and it's usable */
3273 t->flags &= ~SN_CK_MASK;
3274 t->flags |= SN_CK_VALID | SN_DIRECT;
3275 t->srv = srv;
3276 break;
willy tarreaub952e1d2005-12-18 01:31:20 +01003277 } else {
willy tarreau12350152005-12-18 01:03:27 +01003278 t->flags &= ~SN_CK_MASK;
3279 t->flags |= SN_CK_DOWN;
3280 }
willy tarreaub952e1d2005-12-18 01:31:20 +01003281 } /* end if (strcmp()) */
willy tarreau12350152005-12-18 01:03:27 +01003282 srv = srv->next;
3283 }/* end while(srv) */
3284 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreaub952e1d2005-12-18 01:31:20 +01003285 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
willy tarreau12350152005-12-18 01:03:27 +01003286 else {
3287 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
3288 }
willy tarreau598da412005-12-18 01:07:29 +01003289 method_checked = 1;
willy tarreaub952e1d2005-12-18 01:31:20 +01003290 } /* end if (!method_checked ...) */
willy tarreau12350152005-12-18 01:03:27 +01003291 else{
3292 //printf("No Methode-Header with Session-String\n");
3293 }
3294
willy tarreau8337c6b2005-12-17 13:41:01 +01003295 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003296 /* we have a complete HTTP request that we must log */
3297 int urilen;
3298
willy tarreaua1598082005-12-17 13:08:06 +01003299 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003300 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003301 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003302 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003303 if (!(t->flags & SN_ERR_MASK))
3304 t->flags |= SN_ERR_PRXCOND;
3305 if (!(t->flags & SN_FINST_MASK))
3306 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003307 return 1;
3308 }
3309
3310 urilen = ptr - req->h;
3311 if (urilen >= REQURI_LEN)
3312 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003313 memcpy(t->logs.uri, req->h, urilen);
3314 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003315
willy tarreaua1598082005-12-17 13:08:06 +01003316 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003317 sess_log(t);
3318 }
willy tarreau4302f492005-12-18 01:00:37 +01003319 else if (t->logs.logwait & LW_REQHDR) {
3320 struct cap_hdr *h;
3321 int len;
3322 for (h = t->proxy->req_cap; h; h = h->next) {
3323 if ((h->namelen + 2 <= ptr - req->h) &&
3324 (req->h[h->namelen] == ':') &&
3325 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3326
3327 if (t->req_cap[h->index] == NULL)
3328 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3329
3330 len = ptr - (req->h + h->namelen + 2);
3331 if (len > h->len)
3332 len = h->len;
3333
3334 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3335 t->req_cap[h->index][len]=0;
3336 }
3337 }
3338
3339 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003340
willy tarreau5cbea6f2005-12-17 12:48:26 +01003341 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003342
willy tarreau982249e2005-12-18 00:57:06 +01003343 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003344 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003345 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 +01003346 max = ptr - req->h;
3347 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003348 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349 trash[len++] = '\n';
3350 write(1, trash, len);
3351 }
willy tarreau0f7af912005-12-17 12:21:26 +01003352
willy tarreau25c4ea52005-12-18 00:49:49 +01003353
3354 /* remove "connection: " if needed */
3355 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3356 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3357 delete_header = 1;
3358 }
3359
willy tarreau5cbea6f2005-12-17 12:48:26 +01003360 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003361 if (!delete_header && t->proxy->req_exp != NULL
3362 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003363 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003364 char term;
3365
3366 term = *ptr;
3367 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003368 exp = t->proxy->req_exp;
3369 do {
3370 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3371 switch (exp->action) {
3372 case ACT_ALLOW:
3373 if (!(t->flags & SN_CLDENY))
3374 t->flags |= SN_CLALLOW;
3375 break;
3376 case ACT_REPLACE:
3377 if (!(t->flags & SN_CLDENY)) {
3378 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3379 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3380 }
3381 break;
3382 case ACT_REMOVE:
3383 if (!(t->flags & SN_CLDENY))
3384 delete_header = 1;
3385 break;
3386 case ACT_DENY:
3387 if (!(t->flags & SN_CLALLOW))
3388 t->flags |= SN_CLDENY;
3389 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003390 case ACT_PASS: /* we simply don't deny this one */
3391 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003392 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003393 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003394 }
willy tarreaue39cd132005-12-17 13:00:18 +01003395 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003396 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003397 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003398
willy tarreau240afa62005-12-17 13:14:35 +01003399 /* Now look for cookies. Conforming to RFC2109, we have to support
3400 * attributes whose name begin with a '$', and associate them with
3401 * the right cookie, if we want to delete this cookie.
3402 * So there are 3 cases for each cookie read :
3403 * 1) it's a special attribute, beginning with a '$' : ignore it.
3404 * 2) it's a server id cookie that we *MAY* want to delete : save
3405 * some pointers on it (last semi-colon, beginning of cookie...)
3406 * 3) it's an application cookie : we *MAY* have to delete a previous
3407 * "special" cookie.
3408 * At the end of loop, if a "special" cookie remains, we may have to
3409 * remove it. If no application cookie persists in the header, we
3410 * *MUST* delete it
3411 */
willy tarreau12350152005-12-18 01:03:27 +01003412 if (!delete_header &&
3413 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003414 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003415 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003416 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003417 char *del_colon, *del_cookie, *colon;
3418 int app_cookies;
3419
willy tarreau5cbea6f2005-12-17 12:48:26 +01003420 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003421 colon = p1;
3422 /* del_cookie == NULL => nothing to be deleted */
3423 del_colon = del_cookie = NULL;
3424 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003425
3426 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003427 /* skip spaces and colons, but keep an eye on these ones */
3428 while (p1 < ptr) {
3429 if (*p1 == ';' || *p1 == ',')
3430 colon = p1;
3431 else if (!isspace((int)*p1))
3432 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003433 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003434 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003435
3436 if (p1 == ptr)
3437 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003438
3439 /* p1 is at the beginning of the cookie name */
3440 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003441 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003442 p2++;
3443
3444 if (p2 == ptr)
3445 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003446
3447 p3 = p2 + 1; /* skips the '=' sign */
3448 if (p3 == ptr)
3449 break;
3450
willy tarreau240afa62005-12-17 13:14:35 +01003451 p4 = p3;
3452 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 p4++;
3454
3455 /* here, we have the cookie name between p1 and p2,
3456 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003457 * we can process it :
3458 *
3459 * Cookie: NAME=VALUE;
3460 * | || || |
3461 * | || || +--> p4
3462 * | || |+-------> p3
3463 * | || +--------> p2
3464 * | |+------------> p1
3465 * | +-------------> colon
3466 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003467 */
3468
willy tarreau240afa62005-12-17 13:14:35 +01003469 if (*p1 == '$') {
3470 /* skip this one */
3471 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003472 else {
3473 /* first, let's see if we want to capture it */
3474 if (t->proxy->capture_name != NULL &&
3475 t->logs.cli_cookie == NULL &&
3476 (p4 - p1 >= t->proxy->capture_namelen) &&
3477 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3478 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003479
willy tarreau8337c6b2005-12-17 13:41:01 +01003480 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3481 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003482 } else {
3483 if (log_len > t->proxy->capture_len)
3484 log_len = t->proxy->capture_len;
3485 memcpy(t->logs.cli_cookie, p1, log_len);
3486 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003487 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003488 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003489
3490 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3491 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3492 /* Cool... it's the right one */
3493 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003494 char *delim;
3495
3496 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3497 * have the server ID betweek p3 and delim, and the original cookie between
3498 * delim+1 and p4. Otherwise, delim==p4 :
3499 *
3500 * Cookie: NAME=SRV~VALUE;
3501 * | || || | |
3502 * | || || | +--> p4
3503 * | || || +--------> delim
3504 * | || |+-----------> p3
3505 * | || +------------> p2
3506 * | |+----------------> p1
3507 * | +-----------------> colon
3508 * +------------------------> req->h
3509 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003510
willy tarreau0174f312005-12-18 01:02:42 +01003511 if (t->proxy->options & PR_O_COOK_PFX) {
3512 for (delim = p3; delim < p4; delim++)
3513 if (*delim == COOKIE_DELIM)
3514 break;
3515 }
3516 else
3517 delim = p4;
3518
3519
3520 /* Here, we'll look for the first running server which supports the cookie.
3521 * This allows to share a same cookie between several servers, for example
3522 * to dedicate backup servers to specific servers only.
3523 */
3524 while (srv) {
3525 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3526 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3527 /* we found the server and it's usable */
3528 t->flags &= ~SN_CK_MASK;
3529 t->flags |= SN_CK_VALID | SN_DIRECT;
3530 t->srv = srv;
3531 break;
willy tarreau12350152005-12-18 01:03:27 +01003532 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003533 /* we found a server, but it's down */
3534 t->flags &= ~SN_CK_MASK;
3535 t->flags |= SN_CK_DOWN;
3536 }
3537 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003538 srv = srv->next;
3539 }
3540
willy tarreau0174f312005-12-18 01:02:42 +01003541 if (!srv && !(t->flags & SN_CK_DOWN)) {
3542 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003543 t->flags &= ~SN_CK_MASK;
3544 t->flags |= SN_CK_INVALID;
3545 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003546
willy tarreau0174f312005-12-18 01:02:42 +01003547 /* depending on the cookie mode, we may have to either :
3548 * - delete the complete cookie if we're in insert+indirect mode, so that
3549 * the server never sees it ;
3550 * - remove the server id from the cookie value, and tag the cookie as an
3551 * application cookie so that it does not get accidentely removed later,
3552 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003553 */
willy tarreau0174f312005-12-18 01:02:42 +01003554 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3555 buffer_replace2(req, p3, delim + 1, NULL, 0);
3556 p4 -= (delim + 1 - p3);
3557 ptr -= (delim + 1 - p3);
3558 del_cookie = del_colon = NULL;
3559 app_cookies++; /* protect the header from deletion */
3560 }
3561 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003562 (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 +01003563 del_cookie = p1;
3564 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003565 }
willy tarreau12350152005-12-18 01:03:27 +01003566 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003567 /* now we know that we must keep this cookie since it's
3568 * not ours. But if we wanted to delete our cookie
3569 * earlier, we cannot remove the complete header, but we
3570 * can remove the previous block itself.
3571 */
3572 app_cookies++;
3573
3574 if (del_cookie != NULL) {
3575 buffer_replace2(req, del_cookie, p1, NULL, 0);
3576 p4 -= (p1 - del_cookie);
3577 ptr -= (p1 - del_cookie);
3578 del_cookie = del_colon = NULL;
3579 }
willy tarreau240afa62005-12-17 13:14:35 +01003580 }
willy tarreau12350152005-12-18 01:03:27 +01003581
3582 if ((t->proxy->appsession_name != NULL) &&
3583 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3584 /* first, let's see if the cookie is our appcookie*/
3585
3586 /* Cool... it's the right one */
3587
3588 asession_temp = &local_asession;
3589
3590 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3591 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3592 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3593 return 0;
3594 }
3595
3596 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3597 asession_temp->sessid[t->proxy->appsession_len] = 0;
3598 asession_temp->serverid = NULL;
3599
3600 /* only do insert, if lookup fails */
3601 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3602 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3603 Alert("Not enough memory process_cli():asession:calloc().\n");
3604 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3605 return 0;
3606 }
3607
3608 asession_temp->sessid = local_asession.sessid;
3609 asession_temp->serverid = local_asession.serverid;
3610 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3611 }
3612 else{
3613 /* free wasted memory */
3614 pool_free_to(apools.sessid, local_asession.sessid);
3615 }
3616
3617 if (asession_temp->serverid == NULL) {
3618 Alert("Found Application Session without matching server.\n");
3619 } else {
3620 struct server *srv = t->proxy->srv;
3621 while (srv) {
willy tarreaub952e1d2005-12-18 01:31:20 +01003622 if (strcmp(srv->id, asession_temp->serverid) == 0) {
willy tarreau12350152005-12-18 01:03:27 +01003623 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3624 /* we found the server and it's usable */
3625 t->flags &= ~SN_CK_MASK;
3626 t->flags |= SN_CK_VALID | SN_DIRECT;
3627 t->srv = srv;
3628 break;
3629 } else {
3630 t->flags &= ~SN_CK_MASK;
3631 t->flags |= SN_CK_DOWN;
3632 }
3633 }
3634 srv = srv->next;
3635 }/* end while(srv) */
3636 }/* end else if server == NULL */
3637
3638 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003639 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003640 }
willy tarreau240afa62005-12-17 13:14:35 +01003641
willy tarreau5cbea6f2005-12-17 12:48:26 +01003642 /* we'll have to look for another cookie ... */
3643 p1 = p4;
3644 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003645
3646 /* There's no more cookie on this line.
3647 * We may have marked the last one(s) for deletion.
3648 * We must do this now in two ways :
3649 * - if there is no app cookie, we simply delete the header ;
3650 * - if there are app cookies, we must delete the end of the
3651 * string properly, including the colon/semi-colon before
3652 * the cookie name.
3653 */
3654 if (del_cookie != NULL) {
3655 if (app_cookies) {
3656 buffer_replace2(req, del_colon, ptr, NULL, 0);
3657 /* WARNING! <ptr> becomes invalid for now. If some code
3658 * below needs to rely on it before the end of the global
3659 * header loop, we need to correct it with this code :
3660 * ptr = del_colon;
3661 */
3662 }
3663 else
3664 delete_header = 1;
3665 }
3666 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003667
3668 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003669 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003670 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003671 }
willy tarreau240afa62005-12-17 13:14:35 +01003672 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3673
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 req->h = req->lr;
3675 } /* while (req->lr < req->r) */
3676
3677 /* end of header processing (even if incomplete) */
3678
willy tarreauef900ab2005-12-17 12:52:52 +01003679 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3680 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3681 * full. We cannot loop here since event_cli_read will disable it only if
3682 * req->l == rlim-data
3683 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003684 FD_SET(t->cli_fd, StaticReadEvent);
3685 if (t->proxy->clitimeout)
3686 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3687 else
3688 tv_eternity(&t->crexpire);
3689 }
3690
willy tarreaue39cd132005-12-17 13:00:18 +01003691 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003692 * won't be able to free more later, so the session will never terminate.
3693 */
willy tarreaue39cd132005-12-17 13:00:18 +01003694 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003695 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003696 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003697 if (!(t->flags & SN_ERR_MASK))
3698 t->flags |= SN_ERR_PRXCOND;
3699 if (!(t->flags & SN_FINST_MASK))
3700 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003701 return 1;
3702 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003703 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003704 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003705 tv_eternity(&t->crexpire);
3706 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003707 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003708 if (!(t->flags & SN_ERR_MASK))
3709 t->flags |= SN_ERR_CLICL;
3710 if (!(t->flags & SN_FINST_MASK))
3711 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003712 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003713 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003714 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3715
3716 /* read timeout : give up with an error message.
3717 */
3718 t->logs.status = 408;
3719 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003720 if (!(t->flags & SN_ERR_MASK))
3721 t->flags |= SN_ERR_CLITO;
3722 if (!(t->flags & SN_FINST_MASK))
3723 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003724 return 1;
3725 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726
3727 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003728 }
3729 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003730 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003731 /* FIXME: this error handling is partly buggy because we always report
3732 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3733 * or HEADER phase. BTW, it's not logical to expire the client while
3734 * we're waiting for the server to connect.
3735 */
willy tarreau0f7af912005-12-17 12:21:26 +01003736 /* read or write error */
3737 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003738 tv_eternity(&t->crexpire);
3739 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003740 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003741 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003742 if (!(t->flags & SN_ERR_MASK))
3743 t->flags |= SN_ERR_CLICL;
3744 if (!(t->flags & SN_FINST_MASK))
3745 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003746 return 1;
3747 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003748 /* last read, or end of server write */
3749 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003750 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003751 tv_eternity(&t->crexpire);
3752 shutdown(t->cli_fd, SHUT_RD);
3753 t->cli_state = CL_STSHUTR;
3754 return 1;
3755 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003756 /* last server read and buffer empty */
3757 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003758 FD_CLR(t->cli_fd, StaticWriteEvent);
3759 tv_eternity(&t->cwexpire);
3760 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003761 /* We must ensure that the read part is still alive when switching
3762 * to shutw */
3763 FD_SET(t->cli_fd, StaticReadEvent);
3764 if (t->proxy->clitimeout)
3765 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003766 t->cli_state = CL_STSHUTW;
willy tarreaub952e1d2005-12-18 01:31:20 +01003767 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01003768 return 1;
3769 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003770 /* read timeout */
3771 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3772 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003773 tv_eternity(&t->crexpire);
3774 shutdown(t->cli_fd, SHUT_RD);
3775 t->cli_state = CL_STSHUTR;
3776 if (!(t->flags & SN_ERR_MASK))
3777 t->flags |= SN_ERR_CLITO;
3778 if (!(t->flags & SN_FINST_MASK))
3779 t->flags |= SN_FINST_D;
3780 return 1;
3781 }
3782 /* write timeout */
3783 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3784 FD_CLR(t->cli_fd, StaticWriteEvent);
3785 tv_eternity(&t->cwexpire);
3786 shutdown(t->cli_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01003787 /* We must ensure that the read part is still alive when switching
3788 * to shutw */
3789 FD_SET(t->cli_fd, StaticReadEvent);
3790 if (t->proxy->clitimeout)
3791 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3792
willy tarreau036e1ce2005-12-17 13:46:33 +01003793 t->cli_state = CL_STSHUTW;
3794 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003795 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003796 if (!(t->flags & SN_FINST_MASK))
3797 t->flags |= SN_FINST_D;
3798 return 1;
3799 }
willy tarreau0f7af912005-12-17 12:21:26 +01003800
willy tarreauc58fc692005-12-17 14:13:08 +01003801 if (req->l >= req->rlim - req->data) {
3802 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003803 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003804 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003805 FD_CLR(t->cli_fd, StaticReadEvent);
3806 tv_eternity(&t->crexpire);
3807 }
3808 }
3809 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003810 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003811 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3812 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003813 if (!t->proxy->clitimeout ||
3814 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3815 /* If the client has no timeout, or if the server not ready yet, and we
3816 * know for sure that it can expire, then it's cleaner to disable the
3817 * timeout on the client side so that too low values cannot make the
3818 * sessions abort too early.
3819 */
willy tarreau0f7af912005-12-17 12:21:26 +01003820 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003821 else
3822 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003823 }
3824 }
3825
3826 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003827 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003828 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3829 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3830 tv_eternity(&t->cwexpire);
3831 }
3832 }
3833 else { /* buffer not empty */
3834 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3835 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003836 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003837 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003838 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3839 t->crexpire = t->cwexpire;
3840 }
willy tarreau0f7af912005-12-17 12:21:26 +01003841 else
3842 tv_eternity(&t->cwexpire);
3843 }
3844 }
3845 return 0; /* other cases change nothing */
3846 }
3847 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003848 if (t->res_cw == RES_ERROR) {
3849 tv_eternity(&t->cwexpire);
3850 fd_delete(t->cli_fd);
3851 t->cli_state = CL_STCLOSE;
3852 if (!(t->flags & SN_ERR_MASK))
3853 t->flags |= SN_ERR_CLICL;
3854 if (!(t->flags & SN_FINST_MASK))
3855 t->flags |= SN_FINST_D;
3856 return 1;
3857 }
3858 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003859 tv_eternity(&t->cwexpire);
3860 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003861 t->cli_state = CL_STCLOSE;
3862 return 1;
3863 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003864 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3865 tv_eternity(&t->cwexpire);
3866 fd_delete(t->cli_fd);
3867 t->cli_state = CL_STCLOSE;
3868 if (!(t->flags & SN_ERR_MASK))
3869 t->flags |= SN_ERR_CLITO;
3870 if (!(t->flags & SN_FINST_MASK))
3871 t->flags |= SN_FINST_D;
3872 return 1;
3873 }
willy tarreau0f7af912005-12-17 12:21:26 +01003874 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003875 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003876 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3877 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3878 tv_eternity(&t->cwexpire);
3879 }
3880 }
3881 else { /* buffer not empty */
3882 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3883 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003884 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003885 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003886 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3887 t->crexpire = t->cwexpire;
3888 }
willy tarreau0f7af912005-12-17 12:21:26 +01003889 else
3890 tv_eternity(&t->cwexpire);
3891 }
3892 }
3893 return 0;
3894 }
3895 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003896 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003897 tv_eternity(&t->crexpire);
3898 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003899 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003900 if (!(t->flags & SN_ERR_MASK))
3901 t->flags |= SN_ERR_CLICL;
3902 if (!(t->flags & SN_FINST_MASK))
3903 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003904 return 1;
3905 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003906 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3907 tv_eternity(&t->crexpire);
3908 fd_delete(t->cli_fd);
3909 t->cli_state = CL_STCLOSE;
3910 return 1;
3911 }
3912 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3913 tv_eternity(&t->crexpire);
3914 fd_delete(t->cli_fd);
3915 t->cli_state = CL_STCLOSE;
3916 if (!(t->flags & SN_ERR_MASK))
3917 t->flags |= SN_ERR_CLITO;
3918 if (!(t->flags & SN_FINST_MASK))
3919 t->flags |= SN_FINST_D;
3920 return 1;
3921 }
willy tarreauef900ab2005-12-17 12:52:52 +01003922 else if (req->l >= req->rlim - req->data) {
3923 /* no room to read more data */
willy tarreaub1285d52005-12-18 01:20:14 +01003924
3925 /* FIXME-20050705: is it possible for a client to maintain a session
3926 * after the timeout by sending more data after it receives a close ?
3927 */
3928
willy tarreau0f7af912005-12-17 12:21:26 +01003929 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003930 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003931 FD_CLR(t->cli_fd, StaticReadEvent);
3932 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003933 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01003934 }
3935 }
3936 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003937 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003938 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3939 FD_SET(t->cli_fd, StaticReadEvent);
3940 if (t->proxy->clitimeout)
3941 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3942 else
3943 tv_eternity(&t->crexpire);
willy tarreaub952e1d2005-12-18 01:31:20 +01003944 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01003945 }
3946 }
3947 return 0;
3948 }
3949 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003950 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003951 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003952 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 +01003953 write(1, trash, len);
3954 }
3955 return 0;
3956 }
3957 return 0;
3958}
3959
3960
3961/*
3962 * manages the server FSM and its socket. It returns 1 if a state has changed
3963 * (and a resync may be needed), 0 else.
3964 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003965int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003966 int s = t->srv_state;
3967 int c = t->cli_state;
3968 struct buffer *req = t->req;
3969 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003970 appsess *asession_temp = NULL;
3971 appsess local_asession;
willy tarreaub1285d52005-12-18 01:20:14 +01003972 int conn_err;
willy tarreau0f7af912005-12-17 12:21:26 +01003973
willy tarreau750a4722005-12-17 13:21:24 +01003974#ifdef DEBUG_FULL
3975 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3976#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003977 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3978 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3979 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3980 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003981 if (s == SV_STIDLE) {
3982 if (c == CL_STHEADERS)
3983 return 0; /* stay in idle, waiting for data to reach the client side */
3984 else if (c == CL_STCLOSE ||
3985 c == CL_STSHUTW ||
3986 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3987 tv_eternity(&t->cnexpire);
3988 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003989 if (!(t->flags & SN_ERR_MASK))
3990 t->flags |= SN_ERR_CLICL;
3991 if (!(t->flags & SN_FINST_MASK))
3992 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003993 return 1;
3994 }
3995 else { /* go to SV_STCONN */
willy tarreaub1285d52005-12-18 01:20:14 +01003996 /* initiate a connection to the server */
3997 conn_err = connect_server(t);
3998 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003999 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
4000 t->srv_state = SV_STCONN;
4001 }
4002 else { /* try again */
4003 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004005 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004006 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004007 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4008 t->flags &= ~SN_CK_MASK;
4009 t->flags |= SN_CK_DOWN;
4010 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004011 }
4012
willy tarreaub1285d52005-12-18 01:20:14 +01004013 conn_err = connect_server(t);
4014 if (conn_err == SN_ERR_NONE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004015 t->srv_state = SV_STCONN;
4016 break;
4017 }
4018 }
4019 if (t->conn_retries < 0) {
4020 /* if conn_retries < 0 or other error, let's abort */
4021 tv_eternity(&t->cnexpire);
4022 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004023 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004024 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004025 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004026 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004027 t->flags |= conn_err; /* report the precise connect() error */
willy tarreau036e1ce2005-12-17 13:46:33 +01004028 if (!(t->flags & SN_FINST_MASK))
4029 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004030 }
4031 }
4032 return 1;
4033 }
4034 }
4035 else if (s == SV_STCONN) { /* connection in progress */
4036 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
4037 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
4038 return 0; /* nothing changed */
4039 }
4040 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
4041 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
4042 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004043 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004044 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004045 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004046 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004047 if (t->conn_retries >= 0) {
4048 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004049 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004050 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01004051 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
4052 t->flags &= ~SN_CK_MASK;
4053 t->flags |= SN_CK_DOWN;
4054 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004055 }
willy tarreaub1285d52005-12-18 01:20:14 +01004056 conn_err = connect_server(t);
4057 if (conn_err == SN_ERR_NONE)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004058 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01004059 }
willy tarreaub1285d52005-12-18 01:20:14 +01004060 else if (t->res_sw == RES_SILENT)
4061 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
4062 else
4063 conn_err = SN_ERR_SRVCL; // it was a connect error.
4064
willy tarreau0f7af912005-12-17 12:21:26 +01004065 /* if conn_retries < 0 or other error, let's abort */
4066 tv_eternity(&t->cnexpire);
4067 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01004068 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01004069 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01004070 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01004071 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1285d52005-12-18 01:20:14 +01004072 t->flags |= conn_err;
willy tarreau036e1ce2005-12-17 13:46:33 +01004073 if (!(t->flags & SN_FINST_MASK))
4074 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01004075 return 1;
4076 }
4077 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01004078 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004079
willy tarreau0f7af912005-12-17 12:21:26 +01004080 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004081 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004082 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004083 tv_eternity(&t->swexpire);
4084 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01004085 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004086 if (t->proxy->srvtimeout) {
4087 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
4088 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4089 t->srexpire = t->swexpire;
4090 }
4091 else
4092 tv_eternity(&t->swexpire);
4093 }
willy tarreau0f7af912005-12-17 12:21:26 +01004094
4095 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
4096 FD_SET(t->srv_fd, StaticReadEvent);
4097 if (t->proxy->srvtimeout)
4098 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4099 else
4100 tv_eternity(&t->srexpire);
4101
4102 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004103 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01004104
4105 /* if the user wants to log as soon as possible, without counting
4106 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004107 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004108 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
4109 sess_log(t);
4110 }
willy tarreau0f7af912005-12-17 12:21:26 +01004111 }
willy tarreauef900ab2005-12-17 12:52:52 +01004112 else {
willy tarreau0f7af912005-12-17 12:21:26 +01004113 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01004114 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
4115 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004116 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004117 return 1;
4118 }
4119 }
4120 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004121 /* now parse the partial (or complete) headers */
4122 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
4123 char *ptr;
4124 int delete_header;
4125
4126 ptr = rep->lr;
4127
4128 /* look for the end of the current header */
4129 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
4130 ptr++;
4131
4132 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004133 int line, len;
4134
4135 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01004136
4137 /* first, we'll block if security checks have caught nasty things */
4138 if (t->flags & SN_CACHEABLE) {
4139 if ((t->flags & SN_CACHE_COOK) &&
4140 (t->flags & SN_SCK_ANY) &&
4141 (t->proxy->options & PR_O_CHK_CACHE)) {
4142
4143 /* we're in presence of a cacheable response containing
4144 * a set-cookie header. We'll block it as requested by
4145 * the 'checkcache' option, and send an alert.
4146 */
4147 tv_eternity(&t->srexpire);
4148 tv_eternity(&t->swexpire);
4149 fd_delete(t->srv_fd);
4150 t->srv_state = SV_STCLOSE;
4151 t->logs.status = 502;
4152 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4153 if (!(t->flags & SN_ERR_MASK))
4154 t->flags |= SN_ERR_PRXCOND;
4155 if (!(t->flags & SN_FINST_MASK))
4156 t->flags |= SN_FINST_H;
4157
4158 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4159 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
4160
4161 return 1;
4162 }
4163 }
4164
willy tarreau982249e2005-12-18 00:57:06 +01004165 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
4166 if (t->flags & SN_SVDENY) {
4167 tv_eternity(&t->srexpire);
4168 tv_eternity(&t->swexpire);
4169 fd_delete(t->srv_fd);
4170 t->srv_state = SV_STCLOSE;
4171 t->logs.status = 502;
4172 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
4173 if (!(t->flags & SN_ERR_MASK))
4174 t->flags |= SN_ERR_PRXCOND;
4175 if (!(t->flags & SN_FINST_MASK))
4176 t->flags |= SN_FINST_H;
4177 return 1;
4178 }
4179
willy tarreau5cbea6f2005-12-17 12:48:26 +01004180 /* we'll have something else to do here : add new headers ... */
4181
willy tarreaucd878942005-12-17 13:27:43 +01004182 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
4183 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004184 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01004185 * insert a set-cookie here, except if we want to insert only on POST
4186 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004187 */
willy tarreau750a4722005-12-17 13:21:24 +01004188 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01004189 t->proxy->cookie_name,
4190 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01004191
willy tarreau036e1ce2005-12-17 13:46:33 +01004192 t->flags |= SN_SCK_INSERTED;
4193
willy tarreau750a4722005-12-17 13:21:24 +01004194 /* Here, we will tell an eventual cache on the client side that we don't
4195 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4196 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4197 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4198 */
willy tarreau240afa62005-12-17 13:14:35 +01004199 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01004200 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
4201 len += sprintf(trash + len, "Cache-control: private\r\n");
Willy TARREAUe78ae262006-01-08 01:24:12 +01004202
4203 if (rep->data + rep->l < rep->h)
4204 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
4205 *(int *)0 = 0;
willy tarreau750a4722005-12-17 13:21:24 +01004206 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004207 }
4208
4209 /* headers to be added */
4210 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01004211 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
4212 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004213 }
4214
willy tarreau25c4ea52005-12-18 00:49:49 +01004215 /* add a "connection: close" line if needed */
4216 if (t->proxy->options & PR_O_HTTP_CLOSE)
4217 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
4218
willy tarreau5cbea6f2005-12-17 12:48:26 +01004219 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01004220 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01004221 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01004222
4223 /* if the user wants to log as soon as possible, without counting
4224 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01004225 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01004226 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4227 t->logs.bytes = rep->h - rep->data;
4228 sess_log(t);
4229 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004230 break;
4231 }
4232
4233 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
4234 if (ptr > rep->r - 2) {
4235 /* this is a partial header, let's wait for more to come */
4236 rep->lr = ptr;
4237 break;
4238 }
4239
4240 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
4241 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
4242
4243 /* now we know that *ptr is either \r or \n,
4244 * and that there are at least 1 char after it.
4245 */
4246 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
4247 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
4248 else
4249 rep->lr = ptr + 2; /* \r\n or \n\r */
4250
4251 /*
4252 * now we know that we have a full header ; we can do whatever
4253 * we want with these pointers :
4254 * rep->h = beginning of header
4255 * ptr = end of header (first \r or \n)
4256 * rep->lr = beginning of next line (next rep->h)
4257 * rep->r = end of data (not used at this stage)
4258 */
4259
willy tarreaua1598082005-12-17 13:08:06 +01004260
willy tarreau982249e2005-12-18 00:57:06 +01004261 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01004262 t->logs.logwait &= ~LW_RESP;
4263 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01004264 switch (t->logs.status) {
4265 case 200:
4266 case 203:
4267 case 206:
4268 case 300:
4269 case 301:
4270 case 410:
4271 /* RFC2616 @13.4:
4272 * "A response received with a status code of
4273 * 200, 203, 206, 300, 301 or 410 MAY be stored
4274 * by a cache (...) unless a cache-control
4275 * directive prohibits caching."
4276 *
4277 * RFC2616 @9.5: POST method :
4278 * "Responses to this method are not cacheable,
4279 * unless the response includes appropriate
4280 * Cache-Control or Expires header fields."
4281 */
4282 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
4283 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
4284 break;
4285 default:
4286 break;
4287 }
willy tarreau4302f492005-12-18 01:00:37 +01004288 }
4289 else if (t->logs.logwait & LW_RSPHDR) {
4290 struct cap_hdr *h;
4291 int len;
4292 for (h = t->proxy->rsp_cap; h; h = h->next) {
4293 if ((h->namelen + 2 <= ptr - rep->h) &&
4294 (rep->h[h->namelen] == ':') &&
4295 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
4296
4297 if (t->rsp_cap[h->index] == NULL)
4298 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
4299
4300 len = ptr - (rep->h + h->namelen + 2);
4301 if (len > h->len)
4302 len = h->len;
4303
4304 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
4305 t->rsp_cap[h->index][len]=0;
4306 }
4307 }
4308
willy tarreaua1598082005-12-17 13:08:06 +01004309 }
4310
willy tarreau5cbea6f2005-12-17 12:48:26 +01004311 delete_header = 0;
4312
willy tarreau982249e2005-12-18 00:57:06 +01004313 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004314 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01004315 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 +01004316 max = ptr - rep->h;
4317 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01004318 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004319 trash[len++] = '\n';
4320 write(1, trash, len);
4321 }
4322
willy tarreau25c4ea52005-12-18 00:49:49 +01004323 /* remove "connection: " if needed */
4324 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4325 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4326 delete_header = 1;
4327 }
4328
willy tarreau5cbea6f2005-12-17 12:48:26 +01004329 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004330 if (!delete_header && t->proxy->rsp_exp != NULL
4331 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004332 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004333 char term;
4334
4335 term = *ptr;
4336 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004337 exp = t->proxy->rsp_exp;
4338 do {
4339 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4340 switch (exp->action) {
4341 case ACT_ALLOW:
4342 if (!(t->flags & SN_SVDENY))
4343 t->flags |= SN_SVALLOW;
4344 break;
4345 case ACT_REPLACE:
4346 if (!(t->flags & SN_SVDENY)) {
4347 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4348 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4349 }
4350 break;
4351 case ACT_REMOVE:
4352 if (!(t->flags & SN_SVDENY))
4353 delete_header = 1;
4354 break;
4355 case ACT_DENY:
4356 if (!(t->flags & SN_SVALLOW))
4357 t->flags |= SN_SVDENY;
4358 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004359 case ACT_PASS: /* we simply don't deny this one */
4360 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004361 }
4362 break;
4363 }
willy tarreaue39cd132005-12-17 13:00:18 +01004364 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004365 *ptr = term; /* restore the string terminator */
4366 }
4367
willy tarreau97f58572005-12-18 00:53:44 +01004368 /* check for cache-control: or pragma: headers */
4369 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4370 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4371 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4372 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4373 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004374 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004375 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4376 else {
4377 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004378 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004379 t->flags &= ~SN_CACHE_COOK;
4380 }
4381 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004382 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004383 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004384 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004385 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4386 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004387 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004388 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004389 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4390 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4391 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4392 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4393 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4394 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004395 }
4396 }
4397 }
4398
willy tarreau5cbea6f2005-12-17 12:48:26 +01004399 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004400 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004401 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004402 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004403 char *p1, *p2, *p3, *p4;
4404
willy tarreau97f58572005-12-18 00:53:44 +01004405 t->flags |= SN_SCK_ANY;
4406
willy tarreau5cbea6f2005-12-17 12:48:26 +01004407 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4408
4409 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004410 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004411 p1++;
4412
4413 if (p1 == ptr || *p1 == ';') /* end of cookie */
4414 break;
4415
4416 /* p1 is at the beginning of the cookie name */
4417 p2 = p1;
4418
4419 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4420 p2++;
4421
4422 if (p2 == ptr || *p2 == ';') /* next cookie */
4423 break;
4424
4425 p3 = p2 + 1; /* skips the '=' sign */
4426 if (p3 == ptr)
4427 break;
4428
4429 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004430 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004431 p4++;
4432
4433 /* here, we have the cookie name between p1 and p2,
4434 * and its value between p3 and p4.
4435 * we can process it.
4436 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004437
4438 /* first, let's see if we want to capture it */
4439 if (t->proxy->capture_name != NULL &&
4440 t->logs.srv_cookie == NULL &&
4441 (p4 - p1 >= t->proxy->capture_namelen) &&
4442 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4443 int log_len = p4 - p1;
4444
4445 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4446 Alert("HTTP logging : out of memory.\n");
4447 }
4448
4449 if (log_len > t->proxy->capture_len)
4450 log_len = t->proxy->capture_len;
4451 memcpy(t->logs.srv_cookie, p1, log_len);
4452 t->logs.srv_cookie[log_len] = 0;
4453 }
4454
4455 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4456 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004457 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004458 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004459
4460 /* If the cookie is in insert mode on a known server, we'll delete
4461 * this occurrence because we'll insert another one later.
4462 * We'll delete it too if the "indirect" option is set and we're in
4463 * a direct access. */
4464 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004465 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004466 /* this header must be deleted */
4467 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004468 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004469 }
4470 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4471 /* replace bytes p3->p4 with the cookie name associated
4472 * with this server since we know it.
4473 */
4474 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004475 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004476 }
willy tarreau0174f312005-12-18 01:02:42 +01004477 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4478 /* insert the cookie name associated with this server
4479 * before existing cookie, and insert a delimitor between them..
4480 */
4481 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4482 p3[t->srv->cklen] = COOKIE_DELIM;
4483 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4484 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004485 break;
4486 }
willy tarreau12350152005-12-18 01:03:27 +01004487
4488 /* first, let's see if the cookie is our appcookie*/
4489 if ((t->proxy->appsession_name != NULL) &&
4490 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4491
4492 /* Cool... it's the right one */
4493
willy tarreaub952e1d2005-12-18 01:31:20 +01004494 size_t server_id_len = strlen(t->srv->id) + 1;
willy tarreau12350152005-12-18 01:03:27 +01004495 asession_temp = &local_asession;
4496
willy tarreaub952e1d2005-12-18 01:31:20 +01004497 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004498 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4499 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4500 }
4501 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4502 asession_temp->sessid[t->proxy->appsession_len] = 0;
4503 asession_temp->serverid = NULL;
4504
4505 /* only do insert, if lookup fails */
4506 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4507 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4508 Alert("Not enought Memory process_srv():asession:calloc().\n");
4509 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4510 return 0;
4511 }
4512 asession_temp->sessid = local_asession.sessid;
4513 asession_temp->serverid = local_asession.serverid;
4514 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
willy tarreaub952e1d2005-12-18 01:31:20 +01004515 }/* end if (chtbl_lookup()) */
4516 else {
willy tarreau12350152005-12-18 01:03:27 +01004517 /* free wasted memory */
4518 pool_free_to(apools.sessid, local_asession.sessid);
willy tarreaub952e1d2005-12-18 01:31:20 +01004519 } /* end else from if (chtbl_lookup()) */
willy tarreau12350152005-12-18 01:03:27 +01004520
willy tarreaub952e1d2005-12-18 01:31:20 +01004521 if (asession_temp->serverid == NULL) {
4522 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
willy tarreau12350152005-12-18 01:03:27 +01004523 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4524 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4525 }
4526 asession_temp->serverid[0] = '\0';
4527 }
4528
willy tarreaub952e1d2005-12-18 01:31:20 +01004529 if (asession_temp->serverid[0] == '\0')
4530 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
willy tarreau12350152005-12-18 01:03:27 +01004531
4532 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4533
4534#if defined(DEBUG_HASH)
4535 print_table(&(t->proxy->htbl_proxy));
4536#endif
4537 break;
4538 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004539 else {
4540 // fprintf(stderr,"Ignoring unknown cookie : ");
4541 // write(2, p1, p2-p1);
4542 // fprintf(stderr," = ");
4543 // write(2, p3, p4-p3);
4544 // fprintf(stderr,"\n");
4545 }
4546 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4547 } /* we're now at the end of the cookie value */
4548 } /* end of cookie processing */
4549
willy tarreau97f58572005-12-18 00:53:44 +01004550 /* check for any set-cookie in case we check for cacheability */
4551 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4552 (t->proxy->options & PR_O_CHK_CACHE) &&
4553 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4554 t->flags |= SN_SCK_ANY;
4555 }
4556
willy tarreau5cbea6f2005-12-17 12:48:26 +01004557 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004558 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004559 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004560
willy tarreau5cbea6f2005-12-17 12:48:26 +01004561 rep->h = rep->lr;
4562 } /* while (rep->lr < rep->r) */
4563
4564 /* end of header processing (even if incomplete) */
4565
willy tarreauef900ab2005-12-17 12:52:52 +01004566 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4567 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4568 * full. We cannot loop here since event_srv_read will disable it only if
4569 * rep->l == rlim-data
4570 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004571 FD_SET(t->srv_fd, StaticReadEvent);
4572 if (t->proxy->srvtimeout)
4573 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4574 else
4575 tv_eternity(&t->srexpire);
4576 }
willy tarreau0f7af912005-12-17 12:21:26 +01004577
willy tarreau8337c6b2005-12-17 13:41:01 +01004578 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004579 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004580 tv_eternity(&t->srexpire);
4581 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004582 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004583 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004584 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004585 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004586 if (!(t->flags & SN_ERR_MASK))
4587 t->flags |= SN_ERR_SRVCL;
4588 if (!(t->flags & SN_FINST_MASK))
4589 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004590 return 1;
4591 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004592 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004593 * since we are in header mode, if there's no space left for headers, we
4594 * won't be able to free more later, so the session will never terminate.
4595 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004596 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 +01004597 FD_CLR(t->srv_fd, StaticReadEvent);
4598 tv_eternity(&t->srexpire);
4599 shutdown(t->srv_fd, SHUT_RD);
4600 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004601 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004602 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004603 }
4604 /* read timeout : return a 504 to the client.
4605 */
4606 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4607 tv_eternity(&t->srexpire);
4608 tv_eternity(&t->swexpire);
4609 fd_delete(t->srv_fd);
4610 t->srv_state = SV_STCLOSE;
4611 t->logs.status = 504;
4612 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004613 if (!(t->flags & SN_ERR_MASK))
4614 t->flags |= SN_ERR_SRVTO;
4615 if (!(t->flags & SN_FINST_MASK))
4616 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004617 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004618
4619 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004620 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004621 /* FIXME!!! here, we don't want to switch to SHUTW if the
4622 * client shuts read too early, because we may still have
4623 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004624 * The side-effect is that if the client completely closes its
4625 * connection during SV_STHEADER, the connection to the server
4626 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004627 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004628 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004629 FD_CLR(t->srv_fd, StaticWriteEvent);
4630 tv_eternity(&t->swexpire);
willy tarreaub1285d52005-12-18 01:20:14 +01004631
4632 /* We must ensure that the read part is still alive when switching
4633 * to shutw */
4634 FD_SET(t->srv_fd, StaticReadEvent);
4635 if (t->proxy->srvtimeout)
4636 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4637
willy tarreau0f7af912005-12-17 12:21:26 +01004638 shutdown(t->srv_fd, SHUT_WR);
4639 t->srv_state = SV_STSHUTW;
4640 return 1;
4641 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004642 /* write timeout */
4643 /* FIXME!!! here, we don't want to switch to SHUTW if the
4644 * client shuts read too early, because we may still have
4645 * some work to do on the headers.
4646 */
4647 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4648 FD_CLR(t->srv_fd, StaticWriteEvent);
4649 tv_eternity(&t->swexpire);
4650 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004651 /* We must ensure that the read part is still alive when switching
4652 * to shutw */
4653 FD_SET(t->srv_fd, StaticReadEvent);
4654 if (t->proxy->srvtimeout)
4655 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4656
4657 /* We must ensure that the read part is still alive when switching
4658 * to shutw */
4659 FD_SET(t->srv_fd, StaticReadEvent);
4660 if (t->proxy->srvtimeout)
4661 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4662
willy tarreau036e1ce2005-12-17 13:46:33 +01004663 t->srv_state = SV_STSHUTW;
4664 if (!(t->flags & SN_ERR_MASK))
4665 t->flags |= SN_ERR_SRVTO;
4666 if (!(t->flags & SN_FINST_MASK))
4667 t->flags |= SN_FINST_H;
4668 return 1;
4669 }
willy tarreau0f7af912005-12-17 12:21:26 +01004670
4671 if (req->l == 0) {
4672 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4673 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4674 tv_eternity(&t->swexpire);
4675 }
4676 }
4677 else { /* client buffer not empty */
4678 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4679 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004680 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004681 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004682 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4683 t->srexpire = t->swexpire;
4684 }
willy tarreau0f7af912005-12-17 12:21:26 +01004685 else
4686 tv_eternity(&t->swexpire);
4687 }
4688 }
4689
willy tarreau5cbea6f2005-12-17 12:48:26 +01004690 /* be nice with the client side which would like to send a complete header
4691 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4692 * would read all remaining data at once ! The client should not write past rep->lr
4693 * when the server is in header state.
4694 */
4695 //return header_processed;
4696 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004697 }
4698 else if (s == SV_STDATA) {
4699 /* read or write error */
4700 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004701 tv_eternity(&t->srexpire);
4702 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004703 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004704 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004705 if (!(t->flags & SN_ERR_MASK))
4706 t->flags |= SN_ERR_SRVCL;
4707 if (!(t->flags & SN_FINST_MASK))
4708 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004709 return 1;
4710 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004711 /* last read, or end of client write */
4712 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004713 FD_CLR(t->srv_fd, StaticReadEvent);
4714 tv_eternity(&t->srexpire);
4715 shutdown(t->srv_fd, SHUT_RD);
4716 t->srv_state = SV_STSHUTR;
willy tarreaub952e1d2005-12-18 01:31:20 +01004717 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
willy tarreau0f7af912005-12-17 12:21:26 +01004718 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004719 }
4720 /* end of client read and no more data to send */
4721 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4722 FD_CLR(t->srv_fd, StaticWriteEvent);
4723 tv_eternity(&t->swexpire);
4724 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004725 /* We must ensure that the read part is still alive when switching
4726 * to shutw */
4727 FD_SET(t->srv_fd, StaticReadEvent);
4728 if (t->proxy->srvtimeout)
4729 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4730
willy tarreaua41a8b42005-12-17 14:02:24 +01004731 t->srv_state = SV_STSHUTW;
4732 return 1;
4733 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004734 /* read timeout */
4735 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4736 FD_CLR(t->srv_fd, StaticReadEvent);
4737 tv_eternity(&t->srexpire);
4738 shutdown(t->srv_fd, SHUT_RD);
4739 t->srv_state = SV_STSHUTR;
4740 if (!(t->flags & SN_ERR_MASK))
4741 t->flags |= SN_ERR_SRVTO;
4742 if (!(t->flags & SN_FINST_MASK))
4743 t->flags |= SN_FINST_D;
4744 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004745 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004746 /* write timeout */
4747 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004748 FD_CLR(t->srv_fd, StaticWriteEvent);
4749 tv_eternity(&t->swexpire);
4750 shutdown(t->srv_fd, SHUT_WR);
willy tarreaub1285d52005-12-18 01:20:14 +01004751 /* We must ensure that the read part is still alive when switching
4752 * to shutw */
4753 FD_SET(t->srv_fd, StaticReadEvent);
4754 if (t->proxy->srvtimeout)
4755 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01004756 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004757 if (!(t->flags & SN_ERR_MASK))
4758 t->flags |= SN_ERR_SRVTO;
4759 if (!(t->flags & SN_FINST_MASK))
4760 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004761 return 1;
4762 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004763
4764 /* recompute request time-outs */
4765 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004766 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4767 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4768 tv_eternity(&t->swexpire);
4769 }
4770 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004771 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004772 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4773 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004774 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004775 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004776 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4777 t->srexpire = t->swexpire;
4778 }
willy tarreau0f7af912005-12-17 12:21:26 +01004779 else
4780 tv_eternity(&t->swexpire);
4781 }
4782 }
4783
willy tarreaub1ff9db2005-12-17 13:51:03 +01004784 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004785 if (rep->l == BUFSIZE) { /* no room to read more data */
4786 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4787 FD_CLR(t->srv_fd, StaticReadEvent);
4788 tv_eternity(&t->srexpire);
4789 }
4790 }
4791 else {
4792 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4793 FD_SET(t->srv_fd, StaticReadEvent);
4794 if (t->proxy->srvtimeout)
4795 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4796 else
4797 tv_eternity(&t->srexpire);
4798 }
4799 }
4800
4801 return 0; /* other cases change nothing */
4802 }
4803 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004804 if (t->res_sw == RES_ERROR) {
4805 //FD_CLR(t->srv_fd, StaticWriteEvent);
4806 tv_eternity(&t->swexpire);
4807 fd_delete(t->srv_fd);
4808 //close(t->srv_fd);
4809 t->srv_state = SV_STCLOSE;
4810 if (!(t->flags & SN_ERR_MASK))
4811 t->flags |= SN_ERR_SRVCL;
4812 if (!(t->flags & SN_FINST_MASK))
4813 t->flags |= SN_FINST_D;
4814 return 1;
4815 }
4816 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004817 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004818 tv_eternity(&t->swexpire);
4819 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004820 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004821 t->srv_state = SV_STCLOSE;
4822 return 1;
4823 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004824 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4825 //FD_CLR(t->srv_fd, StaticWriteEvent);
4826 tv_eternity(&t->swexpire);
4827 fd_delete(t->srv_fd);
4828 //close(t->srv_fd);
4829 t->srv_state = SV_STCLOSE;
4830 if (!(t->flags & SN_ERR_MASK))
4831 t->flags |= SN_ERR_SRVTO;
4832 if (!(t->flags & SN_FINST_MASK))
4833 t->flags |= SN_FINST_D;
4834 return 1;
4835 }
willy tarreau0f7af912005-12-17 12:21:26 +01004836 else if (req->l == 0) {
4837 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4838 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4839 tv_eternity(&t->swexpire);
4840 }
4841 }
4842 else { /* buffer not empty */
4843 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4844 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004845 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004846 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004847 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4848 t->srexpire = t->swexpire;
4849 }
willy tarreau0f7af912005-12-17 12:21:26 +01004850 else
4851 tv_eternity(&t->swexpire);
4852 }
4853 }
4854 return 0;
4855 }
4856 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004857 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004858 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004859 tv_eternity(&t->srexpire);
4860 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004861 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004862 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004863 if (!(t->flags & SN_ERR_MASK))
4864 t->flags |= SN_ERR_SRVCL;
4865 if (!(t->flags & SN_FINST_MASK))
4866 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004867 return 1;
4868 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004869 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4870 //FD_CLR(t->srv_fd, StaticReadEvent);
4871 tv_eternity(&t->srexpire);
4872 fd_delete(t->srv_fd);
4873 //close(t->srv_fd);
4874 t->srv_state = SV_STCLOSE;
4875 return 1;
4876 }
4877 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4878 //FD_CLR(t->srv_fd, StaticReadEvent);
4879 tv_eternity(&t->srexpire);
4880 fd_delete(t->srv_fd);
4881 //close(t->srv_fd);
4882 t->srv_state = SV_STCLOSE;
4883 if (!(t->flags & SN_ERR_MASK))
4884 t->flags |= SN_ERR_SRVTO;
4885 if (!(t->flags & SN_FINST_MASK))
4886 t->flags |= SN_FINST_D;
4887 return 1;
4888 }
willy tarreau0f7af912005-12-17 12:21:26 +01004889 else if (rep->l == BUFSIZE) { /* no room to read more data */
4890 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4891 FD_CLR(t->srv_fd, StaticReadEvent);
4892 tv_eternity(&t->srexpire);
4893 }
4894 }
4895 else {
4896 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4897 FD_SET(t->srv_fd, StaticReadEvent);
4898 if (t->proxy->srvtimeout)
4899 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4900 else
4901 tv_eternity(&t->srexpire);
4902 }
4903 }
4904 return 0;
4905 }
4906 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004907 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004908 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004909 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 +01004910 write(1, trash, len);
4911 }
4912 return 0;
4913 }
4914 return 0;
4915}
4916
4917
willy tarreau5cbea6f2005-12-17 12:48:26 +01004918/* Processes the client and server jobs of a session task, then
4919 * puts it back to the wait queue in a clean state, or
4920 * cleans up its resources if it must be deleted. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004921 * the time the task accepts to wait, or TIME_ETERNITY for
4922 * infinity.
willy tarreau0f7af912005-12-17 12:21:26 +01004923 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004924int process_session(struct task *t) {
4925 struct session *s = t->context;
4926 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004927
willy tarreau5cbea6f2005-12-17 12:48:26 +01004928 do {
4929 fsm_resync = 0;
4930 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4931 fsm_resync |= process_cli(s);
4932 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4933 fsm_resync |= process_srv(s);
4934 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4935 } while (fsm_resync);
4936
4937 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004938 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004939 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004940
willy tarreau5cbea6f2005-12-17 12:48:26 +01004941 tv_min(&min1, &s->crexpire, &s->cwexpire);
4942 tv_min(&min2, &s->srexpire, &s->swexpire);
4943 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004944 tv_min(&t->expire, &min1, &min2);
4945
4946 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004947 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004948
willy tarreaub952e1d2005-12-18 01:31:20 +01004949 return tv_remain2(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004950 }
4951
willy tarreau5cbea6f2005-12-17 12:48:26 +01004952 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004953 actconn--;
4954
willy tarreau982249e2005-12-18 00:57:06 +01004955 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004956 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004957 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 +01004958 write(1, trash, len);
4959 }
4960
willy tarreau750a4722005-12-17 13:21:24 +01004961 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004962 if (s->rep != NULL)
4963 s->logs.bytes = s->rep->total;
4964
willy tarreau9fe663a2005-12-17 13:02:59 +01004965 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004966 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004967 sess_log(s);
4968
willy tarreau0f7af912005-12-17 12:21:26 +01004969 /* the task MUST not be in the run queue anymore */
4970 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004971 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004972 task_free(t);
willy tarreaub952e1d2005-12-18 01:31:20 +01004973 return TIME_ETERNITY; /* rest in peace for eternity */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004974}
4975
4976
4977
4978/*
4979 * manages a server health-check. Returns
willy tarreaub952e1d2005-12-18 01:31:20 +01004980 * the time the task accepts to wait, or TIME_ETERNITY for infinity.
willy tarreau5cbea6f2005-12-17 12:48:26 +01004981 */
4982int process_chk(struct task *t) {
4983 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004984 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004985 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004986
willy tarreauef900ab2005-12-17 12:52:52 +01004987 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004988
4989 if (fd < 0) { /* no check currently running */
4990 //fprintf(stderr, "process_chk: 2\n");
4991 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4992 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01004993 return tv_remain2(&now, &t->expire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004994 }
4995
4996 /* we'll initiate a new check */
4997 s->result = 0; /* no result yet */
4998 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004999 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01005000 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
5001 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
5002 //fprintf(stderr, "process_chk: 3\n");
5003
willy tarreaua41a8b42005-12-17 14:02:24 +01005004 /* we'll connect to the check port on the server */
5005 sa = s->addr;
5006 sa.sin_port = htons(s->check_port);
5007
willy tarreau0174f312005-12-18 01:02:42 +01005008 /* allow specific binding :
5009 * - server-specific at first
5010 * - proxy-specific next
5011 */
5012 if (s->state & SRV_BIND_SRC) {
5013 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5014 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
5015 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
5016 s->proxy->id, s->id);
5017 s->result = -1;
5018 }
willy tarreau036e1ce2005-12-17 13:46:33 +01005019 }
willy tarreau0174f312005-12-18 01:02:42 +01005020 else if (s->proxy->options & PR_O_BIND_SRC) {
5021 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
5022 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
5023 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
5024 s->proxy->id);
5025 s->result = -1;
5026 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005027 }
willy tarreau0174f312005-12-18 01:02:42 +01005028
5029 if (!s->result) {
5030 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
5031 /* OK, connection in progress or established */
5032
5033 //fprintf(stderr, "process_chk: 4\n");
5034
5035 s->curfd = fd; /* that's how we know a test is in progress ;-) */
5036 fdtab[fd].owner = t;
5037 fdtab[fd].read = &event_srv_chk_r;
5038 fdtab[fd].write = &event_srv_chk_w;
5039 fdtab[fd].state = FD_STCONN; /* connection in progress */
5040 FD_SET(fd, StaticWriteEvent); /* for connect status */
5041 fd_insert(fd);
5042 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5043 tv_delayfrom(&t->expire, &now, s->inter);
5044 task_queue(t); /* restore t to its place in the task list */
5045 return tv_remain(&now, &t->expire);
5046 }
5047 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
5048 s->result = -1; /* a real error */
5049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005050 }
5051 }
willy tarreau08dedbe2005-12-18 01:13:48 +01005052 close(fd); /* socket creation error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005053 }
5054
5055 if (!s->result) { /* nothing done */
5056 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005057 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005058 task_queue(t); /* restore t to its place in the task list */
5059 return tv_remain(&now, &t->expire);
5060 }
5061
5062 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01005063 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005064 s->health--; /* still good */
5065 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005066 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01005067 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005068 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005069 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01005070
willy tarreaudd07e972005-12-18 00:48:48 +01005071 if (find_server(s->proxy) == NULL) {
5072 Alert("Proxy %s has no server available !\n", s->proxy->id);
5073 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5074 }
5075 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005076 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005077 }
5078
5079 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01005080 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
5081 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005082 }
5083 else {
5084 //fprintf(stderr, "process_chk: 8\n");
5085 /* there was a test running */
5086 if (s->result > 0) { /* good server detected */
5087 //fprintf(stderr, "process_chk: 9\n");
5088 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01005089 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005090 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01005091 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005092 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005093 }
willy tarreauef900ab2005-12-17 12:52:52 +01005094
willy tarreaue47c8d72005-12-17 12:55:52 +01005095 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005096 s->state |= SRV_RUNNING;
5097 }
willy tarreauef900ab2005-12-17 12:52:52 +01005098 s->curfd = -1; /* no check running anymore */
5099 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005100 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005101 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005102 }
5103 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
5104 //fprintf(stderr, "process_chk: 10\n");
5105 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01005106 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01005107 s->health--; /* still good */
5108 else {
willy tarreaudd07e972005-12-18 00:48:48 +01005109 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01005110
willy tarreaudd07e972005-12-18 00:48:48 +01005111 if (s->health == s->rise) {
5112 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005113 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01005114
5115 if (find_server(s->proxy) == NULL) {
5116 Alert("Proxy %s has no server available !\n", s->proxy->id);
5117 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
5118 }
willy tarreau535ae7a2005-12-17 12:58:00 +01005119 }
willy tarreauef900ab2005-12-17 12:52:52 +01005120
willy tarreau5cbea6f2005-12-17 12:48:26 +01005121 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005122 }
5123 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01005124 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005125 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01005126 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005127 }
5128 /* if result is 0 and there's no timeout, we have to wait again */
5129 }
5130 //fprintf(stderr, "process_chk: 11\n");
5131 s->result = 0;
5132 task_queue(t); /* restore t to its place in the task list */
willy tarreaub952e1d2005-12-18 01:31:20 +01005133 return tv_remain2(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01005134}
5135
5136
willy tarreau5cbea6f2005-12-17 12:48:26 +01005137
willy tarreau0f7af912005-12-17 12:21:26 +01005138#if STATTIME > 0
5139int stats(void);
5140#endif
5141
5142/*
willy tarreau1c2ad212005-12-18 01:11:29 +01005143 * This does 4 things :
5144 * - wake up all expired tasks
5145 * - call all runnable tasks
5146 * - call maintain_proxies() to enable/disable the listeners
5147 * - return the delay till next event in ms, -1 = wait indefinitely
5148 * Note: this part should be rewritten with the O(ln(n)) scheduler.
5149 *
willy tarreau0f7af912005-12-17 12:21:26 +01005150 */
5151
willy tarreau1c2ad212005-12-18 01:11:29 +01005152int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01005153 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01005154 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005155 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01005156
willy tarreaub952e1d2005-12-18 01:31:20 +01005157 next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01005158
willy tarreau1c2ad212005-12-18 01:11:29 +01005159 /* look for expired tasks and add them to the run queue.
5160 */
5161 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5162 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5163 tnext = t->next;
5164 if (t->state & TASK_RUNNING)
5165 continue;
5166
willy tarreaub952e1d2005-12-18 01:31:20 +01005167 if (tv_iseternity(&t->expire))
5168 continue;
5169
willy tarreau1c2ad212005-12-18 01:11:29 +01005170 /* wakeup expired entries. It doesn't matter if they are
5171 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01005172 */
willy tarreaub952e1d2005-12-18 01:31:20 +01005173 if (tv_cmp_ms(&t->expire, &now) <= 0) {
willy tarreau1c2ad212005-12-18 01:11:29 +01005174 task_wakeup(&rq, t);
5175 }
5176 else {
5177 /* first non-runnable task. Use its expiration date as an upper bound */
5178 int temp_time = tv_remain(&now, &t->expire);
5179 if (temp_time)
5180 next_time = temp_time;
5181 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005182 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005183 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005184
willy tarreau1c2ad212005-12-18 01:11:29 +01005185 /* process each task in the run queue now. Each task may be deleted
5186 * since we only use tnext.
5187 */
5188 tnext = rq;
5189 while ((t = tnext) != NULL) {
5190 int temp_time;
5191
5192 tnext = t->rqnext;
5193 task_sleep(&rq, t);
5194 temp_time = t->process(t);
5195 next_time = MINTIME(temp_time, next_time);
5196 }
5197
5198 /* maintain all proxies in a consistent state. This should quickly become a task */
5199 time2 = maintain_proxies();
5200 return MINTIME(time2, next_time);
5201}
5202
5203
5204#if defined(ENABLE_EPOLL)
5205
5206/*
5207 * Main epoll() loop.
5208 */
5209
5210/* does 3 actions :
5211 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5212 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5213 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5214 *
5215 * returns 0 if initialization failed, !0 otherwise.
5216 */
5217
5218int epoll_loop(int action) {
5219 int next_time;
5220 int status;
5221 int fd;
5222
5223 int fds, count;
5224 int pr, pw, sr, sw;
5225 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
5226 struct epoll_event ev;
5227
5228 /* private data */
willy tarreau1c2ad212005-12-18 01:11:29 +01005229 static struct epoll_event *epoll_events = NULL;
5230 static int epoll_fd;
5231
5232 if (action == POLL_LOOP_ACTION_INIT) {
5233 epoll_fd = epoll_create(global.maxsock + 1);
5234 if (epoll_fd < 0)
5235 return 0;
5236 else {
5237 epoll_events = (struct epoll_event*)
5238 calloc(1, sizeof(struct epoll_event) * global.maxsock);
5239 PrevReadEvent = (fd_set *)
5240 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5241 PrevWriteEvent = (fd_set *)
5242 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005243 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005244 return 1;
5245 }
5246 else if (action == POLL_LOOP_ACTION_CLEAN) {
5247 if (PrevWriteEvent) free(PrevWriteEvent);
5248 if (PrevReadEvent) free(PrevReadEvent);
5249 if (epoll_events) free(epoll_events);
5250 close(epoll_fd);
willy tarreau1c2ad212005-12-18 01:11:29 +01005251 epoll_fd = 0;
5252 return 1;
5253 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005254
willy tarreau1c2ad212005-12-18 01:11:29 +01005255 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01005256
willy tarreau1c2ad212005-12-18 01:11:29 +01005257 tv_now(&now);
5258
5259 while (1) {
5260 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01005261
5262 /* stop when there's no connection left and we don't allow them anymore */
5263 if (!actconn && listeners == 0)
5264 break;
5265
willy tarreau0f7af912005-12-17 12:21:26 +01005266#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01005267 {
5268 int time2;
5269 time2 = stats();
5270 next_time = MINTIME(time2, next_time);
5271 }
willy tarreau0f7af912005-12-17 12:21:26 +01005272#endif
5273
willy tarreau1c2ad212005-12-18 01:11:29 +01005274 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5275
5276 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
5277 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
5278
5279 if ((ro^rn) | (wo^wn)) {
5280 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5281#define FDSETS_ARE_INT_ALIGNED
5282#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01005283
willy tarreauad90a0c2005-12-18 01:09:15 +01005284#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5285#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01005286 pr = (ro >> count) & 1;
5287 pw = (wo >> count) & 1;
5288 sr = (rn >> count) & 1;
5289 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01005290#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005291 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
5292 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
5293 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5294 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01005295#endif
5296#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005297 pr = FD_ISSET(fd, PrevReadEvent);
5298 pw = FD_ISSET(fd, PrevWriteEvent);
5299 sr = FD_ISSET(fd, StaticReadEvent);
5300 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01005301#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01005302 if (!((sr^pr) | (sw^pw)))
5303 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005304
willy tarreau1c2ad212005-12-18 01:11:29 +01005305 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
5306 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01005307
willy tarreaub952e1d2005-12-18 01:31:20 +01005308#ifdef EPOLL_CTL_MOD_WORKAROUND
5309 /* I encountered a rarely reproducible problem with
5310 * EPOLL_CTL_MOD where a modified FD (systematically
5311 * the one in epoll_events[0], fd#7) would sometimes
5312 * be set EPOLL_OUT while asked for a read ! This is
5313 * with the 2.4 epoll patch. The workaround is to
5314 * delete then recreate in case of modification.
5315 * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
5316 * nor RHEL kernels.
5317 */
5318
5319 if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
5320 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
5321
5322 if ((sr | sw))
5323 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
5324#else
willy tarreau1c2ad212005-12-18 01:11:29 +01005325 if ((pr | pw)) {
5326 /* the file-descriptor already exists... */
5327 if ((sr | sw)) {
5328 /* ...and it will still exist */
5329 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
5330 // perror("epoll_ctl(MOD)");
5331 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005332 }
5333 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01005334 /* ...and it will be removed */
5335 if (fdtab[fd].state != FD_STCLOSE &&
5336 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
5337 // perror("epoll_ctl(DEL)");
5338 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01005339 }
5340 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005341 } else {
5342 /* the file-descriptor did not exist, let's add it */
5343 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
5344 // perror("epoll_ctl(ADD)");
5345 // exit(1);
5346 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005347 }
willy tarreaub952e1d2005-12-18 01:31:20 +01005348#endif // EPOLL_CTL_MOD_WORKAROUND
willy tarreau1c2ad212005-12-18 01:11:29 +01005349 }
5350 ((int*)PrevReadEvent)[fds] = rn;
5351 ((int*)PrevWriteEvent)[fds] = wn;
5352 }
5353 }
5354
5355 /* now let's wait for events */
5356 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
5357 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005358
willy tarreau1c2ad212005-12-18 01:11:29 +01005359 for (count = 0; count < status; count++) {
5360 fd = epoll_events[count].data.fd;
5361
5362 if (fdtab[fd].state == FD_STCLOSE)
5363 continue;
5364
Willy TARREAUe78ae262006-01-08 01:24:12 +01005365 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP )) {
5366 if (FD_ISSET(fd, StaticReadEvent))
5367 fdtab[fd].read(fd);
5368 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005369
5370 if (fdtab[fd].state == FD_STCLOSE)
5371 continue;
5372
Willy TARREAUe78ae262006-01-08 01:24:12 +01005373 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP )) {
5374 if (FD_ISSET(fd, StaticWriteEvent))
5375 fdtab[fd].write(fd);
5376 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005377 }
5378 }
5379 return 1;
5380}
5381#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005382
willy tarreauad90a0c2005-12-18 01:09:15 +01005383
willy tarreau5cbea6f2005-12-17 12:48:26 +01005384
willy tarreau1c2ad212005-12-18 01:11:29 +01005385#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005386
willy tarreau1c2ad212005-12-18 01:11:29 +01005387/*
5388 * Main poll() loop.
5389 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005390
willy tarreau1c2ad212005-12-18 01:11:29 +01005391/* does 3 actions :
5392 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5393 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5394 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5395 *
5396 * returns 0 if initialization failed, !0 otherwise.
5397 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005398
willy tarreau1c2ad212005-12-18 01:11:29 +01005399int poll_loop(int action) {
5400 int next_time;
5401 int status;
5402 int fd, nbfd;
5403
5404 int fds, count;
5405 int sr, sw;
5406 unsigned rn, wn; /* read new, write new */
5407
5408 /* private data */
5409 static struct pollfd *poll_events = NULL;
5410
5411 if (action == POLL_LOOP_ACTION_INIT) {
5412 poll_events = (struct pollfd*)
5413 calloc(1, sizeof(struct pollfd) * global.maxsock);
5414 return 1;
5415 }
5416 else if (action == POLL_LOOP_ACTION_CLEAN) {
5417 if (poll_events)
5418 free(poll_events);
5419 return 1;
5420 }
5421
5422 /* OK, it's POLL_LOOP_ACTION_RUN */
5423
5424 tv_now(&now);
5425
5426 while (1) {
5427 next_time = process_runnable_tasks();
5428
5429 /* stop when there's no connection left and we don't allow them anymore */
5430 if (!actconn && listeners == 0)
5431 break;
5432
5433#if STATTIME > 0
5434 {
5435 int time2;
5436 time2 = stats();
5437 next_time = MINTIME(time2, next_time);
5438 }
5439#endif
5440
5441
5442 nbfd = 0;
5443 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5444
5445 rn = ((int*)StaticReadEvent)[fds];
5446 wn = ((int*)StaticWriteEvent)[fds];
5447
5448 if ((rn|wn)) {
5449 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5450#define FDSETS_ARE_INT_ALIGNED
5451#ifdef FDSETS_ARE_INT_ALIGNED
5452
5453#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5454#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5455 sr = (rn >> count) & 1;
5456 sw = (wn >> count) & 1;
5457#else
5458 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5459 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5460#endif
5461#else
5462 sr = FD_ISSET(fd, StaticReadEvent);
5463 sw = FD_ISSET(fd, StaticWriteEvent);
5464#endif
5465 if ((sr|sw)) {
5466 poll_events[nbfd].fd = fd;
5467 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5468 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005469 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005470 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005471 }
5472 }
5473
5474 /* now let's wait for events */
5475 status = poll(poll_events, nbfd, next_time);
5476 tv_now(&now);
5477
5478 for (count = 0; status > 0 && count < nbfd; count++) {
5479 fd = poll_events[count].fd;
5480
5481 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5482 continue;
5483
5484 /* ok, we found one active fd */
5485 status--;
5486
5487 if (fdtab[fd].state == FD_STCLOSE)
5488 continue;
5489
Willy TARREAUe78ae262006-01-08 01:24:12 +01005490 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP )) {
5491 if (FD_ISSET(fd, StaticReadEvent))
5492 fdtab[fd].read(fd);
5493 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005494
5495 if (fdtab[fd].state == FD_STCLOSE)
5496 continue;
5497
Willy TARREAUe78ae262006-01-08 01:24:12 +01005498 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP )) {
5499 if (FD_ISSET(fd, StaticWriteEvent))
5500 fdtab[fd].write(fd);
5501 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005502 }
5503 }
5504 return 1;
5505}
willy tarreauad90a0c2005-12-18 01:09:15 +01005506#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005507
willy tarreauad90a0c2005-12-18 01:09:15 +01005508
willy tarreauad90a0c2005-12-18 01:09:15 +01005509
willy tarreau1c2ad212005-12-18 01:11:29 +01005510/*
5511 * Main select() loop.
5512 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005513
willy tarreau1c2ad212005-12-18 01:11:29 +01005514/* does 3 actions :
5515 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5516 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5517 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5518 *
5519 * returns 0 if initialization failed, !0 otherwise.
5520 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005521
willy tarreauad90a0c2005-12-18 01:09:15 +01005522
willy tarreau1c2ad212005-12-18 01:11:29 +01005523int select_loop(int action) {
5524 int next_time;
5525 int status;
5526 int fd,i;
5527 struct timeval delta;
5528 int readnotnull, writenotnull;
5529 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005530
willy tarreau1c2ad212005-12-18 01:11:29 +01005531 if (action == POLL_LOOP_ACTION_INIT) {
5532 ReadEvent = (fd_set *)
5533 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5534 WriteEvent = (fd_set *)
5535 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5536 return 1;
5537 }
5538 else if (action == POLL_LOOP_ACTION_CLEAN) {
5539 if (WriteEvent) free(WriteEvent);
5540 if (ReadEvent) free(ReadEvent);
5541 return 1;
5542 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005543
willy tarreau1c2ad212005-12-18 01:11:29 +01005544 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005545
willy tarreau1c2ad212005-12-18 01:11:29 +01005546 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005547
willy tarreau1c2ad212005-12-18 01:11:29 +01005548 while (1) {
5549 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005550
willy tarreau1c2ad212005-12-18 01:11:29 +01005551 /* stop when there's no connection left and we don't allow them anymore */
5552 if (!actconn && listeners == 0)
5553 break;
5554
5555#if STATTIME > 0
5556 {
5557 int time2;
5558 time2 = stats();
5559 next_time = MINTIME(time2, next_time);
5560 }
5561#endif
5562
willy tarreau1c2ad212005-12-18 01:11:29 +01005563 if (next_time > 0) { /* FIXME */
5564 /* Convert to timeval */
5565 /* to avoid eventual select loops due to timer precision */
5566 next_time += SCHEDULER_RESOLUTION;
5567 delta.tv_sec = next_time / 1000;
5568 delta.tv_usec = (next_time % 1000) * 1000;
5569 }
5570 else if (next_time == 0) { /* allow select to return immediately when needed */
5571 delta.tv_sec = delta.tv_usec = 0;
5572 }
5573
5574
5575 /* let's restore fdset state */
5576
5577 readnotnull = 0; writenotnull = 0;
5578 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5579 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5580 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5581 }
5582
5583 // /* just a verification code, needs to be removed for performance */
5584 // for (i=0; i<maxfd; i++) {
5585 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5586 // abort();
5587 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5588 // abort();
5589 //
5590 // }
5591
5592 status = select(maxfd,
5593 readnotnull ? ReadEvent : NULL,
5594 writenotnull ? WriteEvent : NULL,
5595 NULL,
5596 (next_time >= 0) ? &delta : NULL);
5597
5598 /* this is an experiment on the separation of the select work */
5599 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5600 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5601
5602 tv_now(&now);
5603
5604 if (status > 0) { /* must proceed with events */
5605
5606 int fds;
5607 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005608
willy tarreau1c2ad212005-12-18 01:11:29 +01005609 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5610 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5611 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5612
5613 /* if we specify read first, the accepts and zero reads will be
5614 * seen first. Moreover, system buffers will be flushed faster.
5615 */
5616 if (fdtab[fd].state == FD_STCLOSE)
5617 continue;
willy tarreau64a3cc32005-12-18 01:13:11 +01005618
willy tarreau1c2ad212005-12-18 01:11:29 +01005619 if (FD_ISSET(fd, ReadEvent))
5620 fdtab[fd].read(fd);
willy tarreau64a3cc32005-12-18 01:13:11 +01005621
willy tarreau1c2ad212005-12-18 01:11:29 +01005622 if (FD_ISSET(fd, WriteEvent))
5623 fdtab[fd].write(fd);
5624 }
5625 }
5626 else {
5627 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005628 }
willy tarreau0f7af912005-12-17 12:21:26 +01005629 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005630 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005631}
5632
5633
5634#if STATTIME > 0
5635/*
5636 * Display proxy statistics regularly. It is designed to be called from the
5637 * select_loop().
5638 */
5639int stats(void) {
5640 static int lines;
5641 static struct timeval nextevt;
5642 static struct timeval lastevt;
5643 static struct timeval starttime = {0,0};
5644 unsigned long totaltime, deltatime;
5645 int ret;
5646
willy tarreau750a4722005-12-17 13:21:24 +01005647 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005648 deltatime = (tv_diff(&lastevt, &now)?:1);
5649 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005650
willy tarreau9fe663a2005-12-17 13:02:59 +01005651 if (global.mode & MODE_STATS) {
5652 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005653 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005654 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5655 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005656 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005657 actconn, totalconn,
5658 stats_tsk_new, stats_tsk_good,
5659 stats_tsk_left, stats_tsk_right,
5660 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5661 }
5662 }
5663
5664 tv_delayfrom(&nextevt, &now, STATTIME);
5665
5666 lastevt=now;
5667 }
5668 ret = tv_remain(&now, &nextevt);
5669 return ret;
5670}
5671#endif
5672
5673
5674/*
5675 * this function enables proxies when there are enough free sessions,
5676 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005677 * select_loop(). It returns the time left before next expiration event
willy tarreaub952e1d2005-12-18 01:31:20 +01005678 * during stop time, TIME_ETERNITY otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005679 */
5680static int maintain_proxies(void) {
5681 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005682 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005683 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005684
5685 p = proxy;
willy tarreaub952e1d2005-12-18 01:31:20 +01005686 tleft = TIME_ETERNITY; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005687
5688 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005689 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005690 while (p) {
5691 if (p->nbconn < p->maxconn) {
5692 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005693 for (l = p->listen; l != NULL; l = l->next) {
5694 FD_SET(l->fd, StaticReadEvent);
5695 }
willy tarreau0f7af912005-12-17 12:21:26 +01005696 p->state = PR_STRUN;
5697 }
5698 }
5699 else {
5700 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005701 for (l = p->listen; l != NULL; l = l->next) {
5702 FD_CLR(l->fd, StaticReadEvent);
5703 }
willy tarreau0f7af912005-12-17 12:21:26 +01005704 p->state = PR_STIDLE;
5705 }
5706 }
5707 p = p->next;
5708 }
5709 }
5710 else { /* block all proxies */
5711 while (p) {
5712 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005713 for (l = p->listen; l != NULL; l = l->next) {
5714 FD_CLR(l->fd, StaticReadEvent);
5715 }
willy tarreau0f7af912005-12-17 12:21:26 +01005716 p->state = PR_STIDLE;
5717 }
5718 p = p->next;
5719 }
5720 }
5721
willy tarreau5cbea6f2005-12-17 12:48:26 +01005722 if (stopping) {
5723 p = proxy;
5724 while (p) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01005725 if (p->state != PR_STSTOPPED) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005726 int t;
willy tarreaub952e1d2005-12-18 01:31:20 +01005727 t = tv_remain2(&now, &p->stop_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01005728 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005729 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005730 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005731
willy tarreaua41a8b42005-12-17 14:02:24 +01005732 for (l = p->listen; l != NULL; l = l->next) {
5733 fd_delete(l->fd);
5734 listeners--;
5735 }
willy tarreaudbd3bef2006-01-20 19:35:18 +01005736 p->state = PR_STSTOPPED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005737 }
5738 else {
5739 tleft = MINTIME(t, tleft);
5740 }
5741 }
5742 p = p->next;
5743 }
5744 }
5745 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005746}
5747
5748/*
5749 * this function disables health-check servers so that the process will quickly be ignored
willy tarreau808b4e62006-01-20 19:46:44 +01005750 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
5751 * time will not be used since it would already not listen anymore to the socket.
willy tarreau0f7af912005-12-17 12:21:26 +01005752 */
5753static void soft_stop(void) {
5754 struct proxy *p;
5755
5756 stopping = 1;
5757 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005758 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005759 while (p) {
willy tarreau808b4e62006-01-20 19:46:44 +01005760 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005761 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005762 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005763 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005764 }
willy tarreau0f7af912005-12-17 12:21:26 +01005765 p = p->next;
5766 }
5767}
5768
willy tarreaudbd3bef2006-01-20 19:35:18 +01005769static void pause_proxy(struct proxy *p) {
5770 struct listener *l;
5771 for (l = p->listen; l != NULL; l = l->next) {
5772 shutdown(l->fd, SHUT_RD);
5773 FD_CLR(l->fd, StaticReadEvent);
5774 p->state = PR_STPAUSED;
5775 }
5776}
5777
5778/*
5779 * This function temporarily disables listening so that another new instance
5780 * can start listening. It is designed to be called upon reception of a
willy tarreau808b4e62006-01-20 19:46:44 +01005781 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
willy tarreaudbd3bef2006-01-20 19:35:18 +01005782 * the proxy, or a SIGTTIN can be sent to listen again.
5783 */
5784static void pause_proxies(void) {
5785 struct proxy *p;
5786
5787 p = proxy;
5788 tv_now(&now); /* else, the old time before select will be used */
5789 while (p) {
5790 if (p->state != PR_STSTOPPED && p->state != PR_STPAUSED) {
5791 Warning("Pausing proxy %s.\n", p->id);
5792 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
5793 pause_proxy(p);
5794 }
5795 p = p->next;
5796 }
5797}
5798
5799
5800/*
5801 * This function reactivates listening. This can be used after a call to
5802 * sig_pause(), for example when a new instance has failed starting up.
5803 * It is designed to be called upon reception of a SIGTTIN.
5804 */
5805static void listen_proxies(void) {
5806 struct proxy *p;
5807 struct listener *l;
5808
5809 p = proxy;
5810 tv_now(&now); /* else, the old time before select will be used */
5811 while (p) {
5812 if (p->state == PR_STPAUSED) {
5813 Warning("Enabling proxy %s.\n", p->id);
5814 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
5815
5816 for (l = p->listen; l != NULL; l = l->next) {
5817 if (listen(l->fd, p->maxconn) == 0) {
5818 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
5819 FD_SET(l->fd, StaticReadEvent);
5820 p->state = PR_STRUN;
5821 }
5822 else
5823 p->state = PR_STIDLE;
5824 } else {
willy tarreaucb2e5622006-01-29 21:55:30 +01005825 int port;
5826
5827 if (l->addr.ss_family == AF_INET6)
5828 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
5829 else
5830 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
5831
willy tarreaudbd3bef2006-01-20 19:35:18 +01005832 Warning("Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005833 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005834 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
willy tarreaucb2e5622006-01-29 21:55:30 +01005835 port, p->id);
willy tarreaudbd3bef2006-01-20 19:35:18 +01005836 /* Another port might have been enabled. Let's stop everything. */
5837 pause_proxy(p);
5838 break;
5839 }
5840 }
5841 }
5842 p = p->next;
5843 }
5844}
5845
5846
willy tarreau0f7af912005-12-17 12:21:26 +01005847/*
5848 * upon SIGUSR1, let's have a soft stop.
5849 */
5850void sig_soft_stop(int sig) {
5851 soft_stop();
5852 signal(sig, SIG_IGN);
5853}
5854
willy tarreaudbd3bef2006-01-20 19:35:18 +01005855/*
5856 * upon SIGTTOU, we pause everything
5857 */
5858void sig_pause(int sig) {
5859 pause_proxies();
5860 signal(sig, sig_pause);
5861}
willy tarreau0f7af912005-12-17 12:21:26 +01005862
willy tarreau8337c6b2005-12-17 13:41:01 +01005863/*
willy tarreaudbd3bef2006-01-20 19:35:18 +01005864 * upon SIGTTIN, let's have a soft stop.
5865 */
5866void sig_listen(int sig) {
5867 listen_proxies();
5868 signal(sig, sig_listen);
5869}
5870
5871/*
willy tarreau8337c6b2005-12-17 13:41:01 +01005872 * this function dumps every server's state when the process receives SIGHUP.
5873 */
5874void sig_dump_state(int sig) {
5875 struct proxy *p = proxy;
5876
5877 Warning("SIGHUP received, dumping servers states.\n");
5878 while (p) {
5879 struct server *s = p->srv;
5880
5881 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5882 while (s) {
5883 if (s->state & SRV_RUNNING) {
5884 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5885 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5886 }
5887 else {
5888 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5889 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5890 }
5891 s = s->next;
5892 }
willy tarreaudd07e972005-12-18 00:48:48 +01005893
5894 if (find_server(p) == NULL) {
5895 Warning("SIGHUP: proxy %s has no server available !\n", p);
5896 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5897 }
5898
willy tarreau8337c6b2005-12-17 13:41:01 +01005899 p = p->next;
5900 }
5901 signal(sig, sig_dump_state);
5902}
5903
willy tarreau0f7af912005-12-17 12:21:26 +01005904void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005905 struct task *t, *tnext;
5906 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005907
willy tarreau5cbea6f2005-12-17 12:48:26 +01005908 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5909 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5910 tnext = t->next;
5911 s = t->context;
5912 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5913 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5914 "req=%d, rep=%d, clifd=%d\n",
5915 s, tv_remain(&now, &t->expire),
5916 s->cli_state,
5917 s->srv_state,
5918 FD_ISSET(s->cli_fd, StaticReadEvent),
5919 FD_ISSET(s->cli_fd, StaticWriteEvent),
5920 FD_ISSET(s->srv_fd, StaticReadEvent),
5921 FD_ISSET(s->srv_fd, StaticWriteEvent),
5922 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5923 );
willy tarreau0f7af912005-12-17 12:21:26 +01005924 }
willy tarreau12350152005-12-18 01:03:27 +01005925}
5926
willy tarreau64a3cc32005-12-18 01:13:11 +01005927#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01005928static void fast_stop(void)
5929{
5930 struct proxy *p;
5931 p = proxy;
5932 while (p) {
5933 p->grace = 0;
5934 p = p->next;
5935 }
5936 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005937}
5938
willy tarreau12350152005-12-18 01:03:27 +01005939void sig_int(int sig) {
5940 /* This would normally be a hard stop,
5941 but we want to be sure about deallocation,
5942 and so on, so we do a soft stop with
5943 0 GRACE time
5944 */
5945 fast_stop();
5946 /* If we are killed twice, we decide to die*/
5947 signal(sig, SIG_DFL);
5948}
5949
5950void sig_term(int sig) {
5951 /* This would normally be a hard stop,
5952 but we want to be sure about deallocation,
5953 and so on, so we do a soft stop with
5954 0 GRACE time
5955 */
5956 fast_stop();
5957 /* If we are killed twice, we decide to die*/
5958 signal(sig, SIG_DFL);
5959}
willy tarreau64a3cc32005-12-18 01:13:11 +01005960#endif
willy tarreau12350152005-12-18 01:03:27 +01005961
willy tarreauc1f47532005-12-18 01:08:26 +01005962/* returns the pointer to an error in the replacement string, or NULL if OK */
5963char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005964 struct hdr_exp *exp;
5965
willy tarreauc1f47532005-12-18 01:08:26 +01005966 if (replace != NULL) {
5967 char *err;
5968 err = check_replace_string(replace);
5969 if (err)
5970 return err;
5971 }
5972
willy tarreaue39cd132005-12-17 13:00:18 +01005973 while (*head != NULL)
5974 head = &(*head)->next;
5975
5976 exp = calloc(1, sizeof(struct hdr_exp));
5977
5978 exp->preg = preg;
5979 exp->replace = replace;
5980 exp->action = action;
5981 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005982
5983 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005984}
5985
willy tarreau9fe663a2005-12-17 13:02:59 +01005986
willy tarreau0f7af912005-12-17 12:21:26 +01005987/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005988 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005989 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005990int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005991
willy tarreau9fe663a2005-12-17 13:02:59 +01005992 if (!strcmp(args[0], "global")) { /* new section */
5993 /* no option, nothing special to do */
5994 return 0;
5995 }
5996 else if (!strcmp(args[0], "daemon")) {
5997 global.mode |= MODE_DAEMON;
5998 }
5999 else if (!strcmp(args[0], "debug")) {
6000 global.mode |= MODE_DEBUG;
6001 }
willy tarreau64a3cc32005-12-18 01:13:11 +01006002 else if (!strcmp(args[0], "noepoll")) {
6003 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
6004 }
6005 else if (!strcmp(args[0], "nopoll")) {
6006 cfg_polling_mechanism &= ~POLL_USE_POLL;
6007 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006008 else if (!strcmp(args[0], "quiet")) {
6009 global.mode |= MODE_QUIET;
6010 }
6011 else if (!strcmp(args[0], "stats")) {
6012 global.mode |= MODE_STATS;
6013 }
6014 else if (!strcmp(args[0], "uid")) {
6015 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006016 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006017 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006018 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006019 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006020 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006021 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006022 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006023 global.uid = atol(args[1]);
6024 }
6025 else if (!strcmp(args[0], "gid")) {
6026 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006027 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006028 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006029 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006030 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006031 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006032 return -1;
6033 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006034 global.gid = atol(args[1]);
6035 }
6036 else if (!strcmp(args[0], "nbproc")) {
6037 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006038 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006039 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006040 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006041 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006042 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006043 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006044 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006045 global.nbproc = atol(args[1]);
6046 }
6047 else if (!strcmp(args[0], "maxconn")) {
6048 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006049 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006050 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01006051 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006052 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006053 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006054 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006055 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006056 global.maxconn = atol(args[1]);
6057 }
willy tarreaub1285d52005-12-18 01:20:14 +01006058 else if (!strcmp(args[0], "ulimit-n")) {
6059 if (global.rlimit_nofile != 0) {
6060 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6061 return 0;
6062 }
6063 if (*(args[1]) == 0) {
6064 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
6065 return -1;
6066 }
6067 global.rlimit_nofile = atol(args[1]);
6068 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006069 else if (!strcmp(args[0], "chroot")) {
6070 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006071 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006072 return 0;
6073 }
6074 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006075 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006076 return -1;
6077 }
6078 global.chroot = strdup(args[1]);
6079 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01006080 else if (!strcmp(args[0], "pidfile")) {
6081 if (global.pidfile != NULL) {
6082 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
6083 return 0;
6084 }
6085 if (*(args[1]) == 0) {
6086 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
6087 return -1;
6088 }
6089 global.pidfile = strdup(args[1]);
6090 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006091 else if (!strcmp(args[0], "log")) { /* syslog server address */
6092 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01006093 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006094
6095 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006096 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006097 return -1;
6098 }
6099
6100 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6101 if (!strcmp(log_facilities[facility], args[2]))
6102 break;
6103
6104 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006105 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006106 exit(1);
6107 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006108
6109 level = 7; /* max syslog level = debug */
6110 if (*(args[3])) {
6111 while (level >= 0 && strcmp(log_levels[level], args[3]))
6112 level--;
6113 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006114 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006115 exit(1);
6116 }
6117 }
6118
willy tarreau9fe663a2005-12-17 13:02:59 +01006119 sa = str2sa(args[1]);
6120 if (!sa->sin_port)
6121 sa->sin_port = htons(SYSLOG_PORT);
6122
6123 if (global.logfac1 == -1) {
6124 global.logsrv1 = *sa;
6125 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006126 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006127 }
6128 else if (global.logfac2 == -1) {
6129 global.logsrv2 = *sa;
6130 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006131 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01006132 }
6133 else {
6134 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
6135 return -1;
6136 }
6137
6138 }
6139 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006140 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01006141 return -1;
6142 }
6143 return 0;
6144}
6145
6146
willy tarreaua41a8b42005-12-17 14:02:24 +01006147void init_default_instance() {
6148 memset(&defproxy, 0, sizeof(defproxy));
6149 defproxy.mode = PR_MODE_TCP;
6150 defproxy.state = PR_STNEW;
6151 defproxy.maxconn = cfg_maxpconn;
6152 defproxy.conn_retries = CONN_RETRIES;
6153 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
6154}
6155
willy tarreau9fe663a2005-12-17 13:02:59 +01006156/*
6157 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
6158 */
6159int cfg_parse_listen(char *file, int linenum, char **args) {
6160 static struct proxy *curproxy = NULL;
6161 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01006162 char *err;
willy tarreau12350152005-12-18 01:03:27 +01006163 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01006164
6165 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01006166 if (!*args[1]) {
6167 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
6168 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006169 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006170 return -1;
6171 }
6172
6173 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006174 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006175 return -1;
6176 }
6177 curproxy->next = proxy;
6178 proxy = curproxy;
6179 curproxy->id = strdup(args[1]);
willy tarreaud0fb4652005-12-18 01:32:04 +01006180
6181 /* parse the listener address if any */
6182 if (*args[2]) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006183 curproxy->listen = str2listener(args[2], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006184 if (!curproxy->listen)
6185 return -1;
6186 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006187
willy tarreau9fe663a2005-12-17 13:02:59 +01006188 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01006189 curproxy->state = defproxy.state;
6190 curproxy->maxconn = defproxy.maxconn;
6191 curproxy->conn_retries = defproxy.conn_retries;
6192 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006193
6194 if (defproxy.check_req)
6195 curproxy->check_req = strdup(defproxy.check_req);
6196 curproxy->check_len = defproxy.check_len;
6197
6198 if (defproxy.cookie_name)
6199 curproxy->cookie_name = strdup(defproxy.cookie_name);
6200 curproxy->cookie_len = defproxy.cookie_len;
6201
6202 if (defproxy.capture_name)
6203 curproxy->capture_name = strdup(defproxy.capture_name);
6204 curproxy->capture_namelen = defproxy.capture_namelen;
6205 curproxy->capture_len = defproxy.capture_len;
6206
6207 if (defproxy.errmsg.msg400)
6208 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
6209 curproxy->errmsg.len400 = defproxy.errmsg.len400;
6210
6211 if (defproxy.errmsg.msg403)
6212 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
6213 curproxy->errmsg.len403 = defproxy.errmsg.len403;
6214
6215 if (defproxy.errmsg.msg408)
6216 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
6217 curproxy->errmsg.len408 = defproxy.errmsg.len408;
6218
6219 if (defproxy.errmsg.msg500)
6220 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
6221 curproxy->errmsg.len500 = defproxy.errmsg.len500;
6222
6223 if (defproxy.errmsg.msg502)
6224 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
6225 curproxy->errmsg.len502 = defproxy.errmsg.len502;
6226
6227 if (defproxy.errmsg.msg503)
6228 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
6229 curproxy->errmsg.len503 = defproxy.errmsg.len503;
6230
6231 if (defproxy.errmsg.msg504)
6232 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
6233 curproxy->errmsg.len504 = defproxy.errmsg.len504;
6234
willy tarreaua41a8b42005-12-17 14:02:24 +01006235 curproxy->clitimeout = defproxy.clitimeout;
6236 curproxy->contimeout = defproxy.contimeout;
6237 curproxy->srvtimeout = defproxy.srvtimeout;
6238 curproxy->mode = defproxy.mode;
6239 curproxy->logfac1 = defproxy.logfac1;
6240 curproxy->logsrv1 = defproxy.logsrv1;
6241 curproxy->loglev1 = defproxy.loglev1;
6242 curproxy->logfac2 = defproxy.logfac2;
6243 curproxy->logsrv2 = defproxy.logsrv2;
6244 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01006245 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01006246 curproxy->grace = defproxy.grace;
6247 curproxy->source_addr = defproxy.source_addr;
willy tarreaub1285d52005-12-18 01:20:14 +01006248 curproxy->mon_net = defproxy.mon_net;
6249 curproxy->mon_mask = defproxy.mon_mask;
willy tarreaua41a8b42005-12-17 14:02:24 +01006250 return 0;
6251 }
6252 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006253 /* some variables may have already been initialized earlier */
6254 if (defproxy.check_req) free(defproxy.check_req);
6255 if (defproxy.cookie_name) free(defproxy.cookie_name);
6256 if (defproxy.capture_name) free(defproxy.capture_name);
6257 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
6258 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
6259 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
6260 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
6261 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
6262 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
6263 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
6264
6265 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01006266 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01006267 return 0;
6268 }
6269 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006270 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006271 return -1;
6272 }
6273
willy tarreaua41a8b42005-12-17 14:02:24 +01006274 if (!strcmp(args[0], "bind")) { /* new listen addresses */
6275 if (curproxy == &defproxy) {
6276 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6277 return -1;
6278 }
6279
6280 if (strchr(args[1], ':') == NULL) {
6281 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
6282 file, linenum, args[0]);
6283 return -1;
6284 }
6285 curproxy->listen = str2listener(args[1], curproxy->listen);
willy tarreaud0fb4652005-12-18 01:32:04 +01006286 if (!curproxy->listen)
6287 return -1;
willy tarreaua41a8b42005-12-17 14:02:24 +01006288 return 0;
6289 }
willy tarreaub1285d52005-12-18 01:20:14 +01006290 else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
6291 if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
6292 Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
6293 file, linenum, args[0]);
6294 return -1;
6295 }
6296 /* flush useless bits */
6297 curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
6298 return 0;
6299 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006300 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01006301 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
6302 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
6303 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
6304 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006305 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006306 return -1;
6307 }
6308 }
6309 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
willy tarreaudbd3bef2006-01-20 19:35:18 +01006310 curproxy->state = PR_STSTOPPED;
willy tarreau9fe663a2005-12-17 13:02:59 +01006311 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006312 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
6313 curproxy->state = PR_STNEW;
6314 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006315 else if (!strcmp(args[0], "cookie")) { /* cookie name */
6316 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006317// if (curproxy == &defproxy) {
6318// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6319// return -1;
6320// }
willy tarreaua41a8b42005-12-17 14:02:24 +01006321
willy tarreau9fe663a2005-12-17 13:02:59 +01006322 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006323// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6324// file, linenum);
6325// return 0;
6326 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006327 }
6328
6329 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006330 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
6331 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006332 return -1;
6333 }
6334 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006335 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01006336
6337 cur_arg = 2;
6338 while (*(args[cur_arg])) {
6339 if (!strcmp(args[cur_arg], "rewrite")) {
6340 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01006341 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006342 else if (!strcmp(args[cur_arg], "indirect")) {
6343 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01006344 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 else if (!strcmp(args[cur_arg], "insert")) {
6346 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01006347 }
willy tarreau240afa62005-12-17 13:14:35 +01006348 else if (!strcmp(args[cur_arg], "nocache")) {
6349 curproxy->options |= PR_O_COOK_NOC;
6350 }
willy tarreaucd878942005-12-17 13:27:43 +01006351 else if (!strcmp(args[cur_arg], "postonly")) {
6352 curproxy->options |= PR_O_COOK_POST;
6353 }
willy tarreau0174f312005-12-18 01:02:42 +01006354 else if (!strcmp(args[cur_arg], "prefix")) {
6355 curproxy->options |= PR_O_COOK_PFX;
6356 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006357 else {
willy tarreau0174f312005-12-18 01:02:42 +01006358 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006359 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006360 return -1;
6361 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006362 cur_arg++;
6363 }
willy tarreau0174f312005-12-18 01:02:42 +01006364 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
6365 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
6366 file, linenum);
6367 return -1;
6368 }
6369
6370 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
6371 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006372 file, linenum);
6373 return -1;
6374 }
willy tarreau12350152005-12-18 01:03:27 +01006375 }/* end else if (!strcmp(args[0], "cookie")) */
6376 else if (!strcmp(args[0], "appsession")) { /* cookie name */
6377// if (curproxy == &defproxy) {
6378// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6379// return -1;
6380// }
6381
6382 if (curproxy->appsession_name != NULL) {
6383// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
6384// file, linenum);
6385// return 0;
6386 free(curproxy->appsession_name);
6387 }
6388
6389 if (*(args[5]) == 0) {
6390 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
6391 file, linenum, args[0]);
6392 return -1;
6393 }
6394 have_appsession = 1;
6395 curproxy->appsession_name = strdup(args[1]);
6396 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
6397 curproxy->appsession_len = atoi(args[3]);
6398 curproxy->appsession_timeout = atoi(args[5]);
6399 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
6400 if (rc) {
6401 Alert("Error Init Appsession Hashtable.\n");
6402 return -1;
6403 }
6404 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01006405 else if (!strcmp(args[0], "capture")) {
6406 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
6407 // if (curproxy == &defproxy) {
6408 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6409 // return -1;
6410 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006411
willy tarreau4302f492005-12-18 01:00:37 +01006412 if (curproxy->capture_name != NULL) {
6413 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6414 // file, linenum, args[0]);
6415 // return 0;
6416 free(curproxy->capture_name);
6417 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006418
willy tarreau4302f492005-12-18 01:00:37 +01006419 if (*(args[4]) == 0) {
6420 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
6421 file, linenum, args[0]);
6422 return -1;
6423 }
6424 curproxy->capture_name = strdup(args[2]);
6425 curproxy->capture_namelen = strlen(curproxy->capture_name);
6426 curproxy->capture_len = atol(args[4]);
6427 if (curproxy->capture_len >= CAPTURE_LEN) {
6428 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
6429 file, linenum, CAPTURE_LEN - 1);
6430 curproxy->capture_len = CAPTURE_LEN - 1;
6431 }
6432 curproxy->to_log |= LW_COOKIE;
6433 }
6434 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
6435 struct cap_hdr *hdr;
6436
6437 if (curproxy == &defproxy) {
6438 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6439 return -1;
6440 }
6441
6442 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6443 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6444 file, linenum, args[0], args[1]);
6445 return -1;
6446 }
6447
6448 hdr = calloc(sizeof(struct cap_hdr), 1);
6449 hdr->next = curproxy->req_cap;
6450 hdr->name = strdup(args[3]);
6451 hdr->namelen = strlen(args[3]);
6452 hdr->len = atol(args[5]);
6453 hdr->index = curproxy->nb_req_cap++;
6454 curproxy->req_cap = hdr;
6455 curproxy->to_log |= LW_REQHDR;
6456 }
6457 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
6458 struct cap_hdr *hdr;
6459
6460 if (curproxy == &defproxy) {
6461 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
6462 return -1;
6463 }
6464
6465 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
6466 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
6467 file, linenum, args[0], args[1]);
6468 return -1;
6469 }
6470 hdr = calloc(sizeof(struct cap_hdr), 1);
6471 hdr->next = curproxy->rsp_cap;
6472 hdr->name = strdup(args[3]);
6473 hdr->namelen = strlen(args[3]);
6474 hdr->len = atol(args[5]);
6475 hdr->index = curproxy->nb_rsp_cap++;
6476 curproxy->rsp_cap = hdr;
6477 curproxy->to_log |= LW_RSPHDR;
6478 }
6479 else {
6480 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006481 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006482 return -1;
6483 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006484 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006485 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006486 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006487 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006488 return 0;
6489 }
6490 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006491 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6492 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006493 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006494 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006495 curproxy->contimeout = atol(args[1]);
6496 }
6497 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006498 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006499 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6500 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006501 return 0;
6502 }
6503 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006504 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6505 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006506 return -1;
6507 }
6508 curproxy->clitimeout = atol(args[1]);
6509 }
6510 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006511 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006512 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006513 return 0;
6514 }
6515 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006516 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6517 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006518 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006519 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006520 curproxy->srvtimeout = atol(args[1]);
6521 }
6522 else if (!strcmp(args[0], "retries")) { /* connection retries */
6523 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006524 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6525 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006526 return -1;
6527 }
6528 curproxy->conn_retries = atol(args[1]);
6529 }
6530 else if (!strcmp(args[0], "option")) {
6531 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006532 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006533 return -1;
6534 }
6535 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006536 /* enable reconnections to dispatch */
6537 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006538#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006539 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006540 /* enable transparent proxy connections */
6541 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006542#endif
6543 else if (!strcmp(args[1], "keepalive"))
6544 /* enable keep-alive */
6545 curproxy->options |= PR_O_KEEPALIVE;
6546 else if (!strcmp(args[1], "forwardfor"))
6547 /* insert x-forwarded-for field */
6548 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006549 else if (!strcmp(args[1], "logasap"))
6550 /* log as soon as possible, without waiting for the session to complete */
6551 curproxy->options |= PR_O_LOGASAP;
6552 else if (!strcmp(args[1], "httpclose"))
6553 /* force connection: close in both directions in HTTP mode */
6554 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006555 else if (!strcmp(args[1], "checkcache"))
6556 /* require examination of cacheability of the 'set-cookie' field */
6557 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006558 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006559 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006560 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006561 else if (!strcmp(args[1], "tcplog"))
6562 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006563 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006564 else if (!strcmp(args[1], "dontlognull")) {
6565 /* don't log empty requests */
6566 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006567 }
willy tarreaub952e1d2005-12-18 01:31:20 +01006568 else if (!strcmp(args[1], "tcpka")) {
6569 /* enable TCP keep-alives on client and server sessions */
6570 curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
6571 }
6572 else if (!strcmp(args[1], "clitcpka")) {
6573 /* enable TCP keep-alives on client sessions */
6574 curproxy->options |= PR_O_TCP_CLI_KA;
6575 }
6576 else if (!strcmp(args[1], "srvtcpka")) {
6577 /* enable TCP keep-alives on server sessions */
6578 curproxy->options |= PR_O_TCP_SRV_KA;
6579 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006580 else if (!strcmp(args[1], "httpchk")) {
6581 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006582 if (curproxy->check_req != NULL) {
6583 free(curproxy->check_req);
6584 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006585 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006586 if (!*args[2]) { /* no argument */
6587 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6588 curproxy->check_len = strlen(DEF_CHECK_REQ);
6589 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006590 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6591 curproxy->check_req = (char *)malloc(reqlen);
6592 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6593 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006594 } else { /* more arguments : METHOD URI [HTTP_VER] */
6595 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6596 if (*args[4])
6597 reqlen += strlen(args[4]);
6598 else
6599 reqlen += strlen("HTTP/1.0");
6600
6601 curproxy->check_req = (char *)malloc(reqlen);
6602 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6603 "%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 +01006604 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006605 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006606 else if (!strcmp(args[1], "persist")) {
6607 /* persist on using the server specified by the cookie, even when it's down */
6608 curproxy->options |= PR_O_PERSIST;
6609 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006610 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006611 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006612 return -1;
6613 }
6614 return 0;
6615 }
6616 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6617 /* enable reconnections to dispatch */
6618 curproxy->options |= PR_O_REDISP;
6619 }
willy tarreaua1598082005-12-17 13:08:06 +01006620#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006621 else if (!strcmp(args[0], "transparent")) {
6622 /* enable transparent proxy connections */
6623 curproxy->options |= PR_O_TRANSP;
6624 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006625#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006626 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6627 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006628 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006629 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006630 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 curproxy->maxconn = atol(args[1]);
6632 }
6633 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6634 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006635 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006636 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006637 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006638 curproxy->grace = atol(args[1]);
6639 }
6640 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006641 if (curproxy == &defproxy) {
6642 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6643 return -1;
6644 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006645 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006646 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006647 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006648 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006649 curproxy->dispatch_addr = *str2sa(args[1]);
6650 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006651 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006652 if (*(args[1])) {
6653 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006654 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006655 }
6656 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006657 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006658 return -1;
6659 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006660 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006661 else /* if no option is set, use round-robin by default */
6662 curproxy->options |= PR_O_BALANCE_RR;
6663 }
6664 else if (!strcmp(args[0], "server")) { /* server address */
6665 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006666 char *rport;
6667 char *raddr;
6668 short realport;
6669 int do_check;
6670
6671 if (curproxy == &defproxy) {
6672 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6673 return -1;
6674 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006675
willy tarreaua41a8b42005-12-17 14:02:24 +01006676 if (!*args[2]) {
6677 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006678 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006679 return -1;
6680 }
6681 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6682 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6683 return -1;
6684 }
willy tarreau0174f312005-12-18 01:02:42 +01006685
6686 if (curproxy->srv == NULL)
6687 curproxy->srv = newsrv;
6688 else
6689 curproxy->cursrv->next = newsrv;
6690 curproxy->cursrv = newsrv;
6691
6692 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006693 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006694
6695 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006696 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006697 newsrv->id = strdup(args[1]);
6698
6699 /* several ways to check the port component :
6700 * - IP => port=+0, relative
6701 * - IP: => port=+0, relative
6702 * - IP:N => port=N, absolute
6703 * - IP:+N => port=+N, relative
6704 * - IP:-N => port=-N, relative
6705 */
6706 raddr = strdup(args[2]);
6707 rport = strchr(raddr, ':');
6708 if (rport) {
6709 *rport++ = 0;
6710 realport = atol(rport);
6711 if (!isdigit((int)*rport))
6712 newsrv->state |= SRV_MAPPORTS;
6713 } else {
6714 realport = 0;
6715 newsrv->state |= SRV_MAPPORTS;
6716 }
6717
6718 newsrv->addr = *str2sa(raddr);
6719 newsrv->addr.sin_port = htons(realport);
6720 free(raddr);
6721
willy tarreau9fe663a2005-12-17 13:02:59 +01006722 newsrv->curfd = -1; /* no health-check in progress */
6723 newsrv->inter = DEF_CHKINTR;
6724 newsrv->rise = DEF_RISETIME;
6725 newsrv->fall = DEF_FALLTIME;
6726 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6727 cur_arg = 3;
6728 while (*args[cur_arg]) {
6729 if (!strcmp(args[cur_arg], "cookie")) {
6730 newsrv->cookie = strdup(args[cur_arg + 1]);
6731 newsrv->cklen = strlen(args[cur_arg + 1]);
6732 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006733 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006734 else if (!strcmp(args[cur_arg], "rise")) {
6735 newsrv->rise = atol(args[cur_arg + 1]);
6736 newsrv->health = newsrv->rise;
6737 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006738 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006739 else if (!strcmp(args[cur_arg], "fall")) {
6740 newsrv->fall = atol(args[cur_arg + 1]);
6741 cur_arg += 2;
6742 }
6743 else if (!strcmp(args[cur_arg], "inter")) {
6744 newsrv->inter = atol(args[cur_arg + 1]);
6745 cur_arg += 2;
6746 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006747 else if (!strcmp(args[cur_arg], "port")) {
6748 newsrv->check_port = atol(args[cur_arg + 1]);
6749 cur_arg += 2;
6750 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006751 else if (!strcmp(args[cur_arg], "backup")) {
6752 newsrv->state |= SRV_BACKUP;
6753 cur_arg ++;
6754 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006755 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006756 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006757 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006758 }
willy tarreau0174f312005-12-18 01:02:42 +01006759 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6760 if (!*args[cur_arg + 1]) {
6761 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6762 file, linenum, "source");
6763 return -1;
6764 }
6765 newsrv->state |= SRV_BIND_SRC;
6766 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6767 cur_arg += 2;
6768 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006769 else {
willy tarreau0174f312005-12-18 01:02:42 +01006770 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 +01006771 file, linenum, newsrv->id);
6772 return -1;
6773 }
6774 }
6775
6776 if (do_check) {
6777 struct task *t;
6778
6779 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6780 newsrv->check_port = realport; /* by default */
6781 if (!newsrv->check_port) {
6782 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 +01006783 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006784 return -1;
6785 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006786
6787 if ((t = pool_alloc(task)) == NULL) {
6788 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6789 return -1;
6790 }
6791
6792 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6793 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6794 t->state = TASK_IDLE;
6795 t->process = process_chk;
6796 t->context = newsrv;
6797
willy tarreaudbd3bef2006-01-20 19:35:18 +01006798 if (curproxy->state != PR_STSTOPPED) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006799 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6800 task_queue(t);
6801 task_wakeup(&rq, t);
6802 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006803 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006804
willy tarreau9fe663a2005-12-17 13:02:59 +01006805 curproxy->nbservers++;
6806 }
6807 else if (!strcmp(args[0], "log")) { /* syslog server address */
6808 struct sockaddr_in *sa;
6809 int facility;
6810
6811 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6812 curproxy->logfac1 = global.logfac1;
6813 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006814 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006815 curproxy->logfac2 = global.logfac2;
6816 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006817 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006818 }
6819 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006820 int level;
6821
willy tarreau0f7af912005-12-17 12:21:26 +01006822 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6823 if (!strcmp(log_facilities[facility], args[2]))
6824 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006825
willy tarreau0f7af912005-12-17 12:21:26 +01006826 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006827 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006828 exit(1);
6829 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006830
willy tarreau8337c6b2005-12-17 13:41:01 +01006831 level = 7; /* max syslog level = debug */
6832 if (*(args[3])) {
6833 while (level >= 0 && strcmp(log_levels[level], args[3]))
6834 level--;
6835 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006836 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006837 exit(1);
6838 }
6839 }
6840
willy tarreau0f7af912005-12-17 12:21:26 +01006841 sa = str2sa(args[1]);
6842 if (!sa->sin_port)
6843 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006844
willy tarreau0f7af912005-12-17 12:21:26 +01006845 if (curproxy->logfac1 == -1) {
6846 curproxy->logsrv1 = *sa;
6847 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006848 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006849 }
6850 else if (curproxy->logfac2 == -1) {
6851 curproxy->logsrv2 = *sa;
6852 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006853 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006854 }
6855 else {
6856 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006857 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006858 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006859 }
6860 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006861 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006862 file, linenum);
6863 return -1;
6864 }
6865 }
willy tarreaua1598082005-12-17 13:08:06 +01006866 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006867 if (!*args[1]) {
6868 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006869 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006870 return -1;
6871 }
6872
6873 curproxy->source_addr = *str2sa(args[1]);
6874 curproxy->options |= PR_O_BIND_SRC;
6875 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006876 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6877 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006878 if (curproxy == &defproxy) {
6879 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6880 return -1;
6881 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006882
6883 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006884 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6885 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006886 return -1;
6887 }
6888
6889 preg = calloc(1, sizeof(regex_t));
6890 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006891 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006892 return -1;
6893 }
6894
willy tarreauc1f47532005-12-18 01:08:26 +01006895 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6896 if (err) {
6897 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6898 file, linenum, *err);
6899 return -1;
6900 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006901 }
6902 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6903 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006904 if (curproxy == &defproxy) {
6905 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6906 return -1;
6907 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006908
6909 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006910 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006911 return -1;
6912 }
6913
6914 preg = calloc(1, sizeof(regex_t));
6915 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006916 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006917 return -1;
6918 }
6919
6920 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6921 }
6922 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6923 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006924 if (curproxy == &defproxy) {
6925 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6926 return -1;
6927 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006928
6929 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006930 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006931 return -1;
6932 }
6933
6934 preg = calloc(1, sizeof(regex_t));
6935 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006936 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006937 return -1;
6938 }
6939
6940 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6941 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006942 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6943 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006944 if (curproxy == &defproxy) {
6945 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6946 return -1;
6947 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006948
6949 if (*(args[1]) == 0) {
6950 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6951 return -1;
6952 }
6953
6954 preg = calloc(1, sizeof(regex_t));
6955 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6956 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6957 return -1;
6958 }
6959
6960 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6961 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006962 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6963 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006964 if (curproxy == &defproxy) {
6965 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6966 return -1;
6967 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006968
6969 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006970 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006971 return -1;
6972 }
6973
6974 preg = calloc(1, sizeof(regex_t));
6975 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006976 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006977 return -1;
6978 }
6979
6980 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6981 }
6982 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6983 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006984 if (curproxy == &defproxy) {
6985 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6986 return -1;
6987 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006988
6989 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006990 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6991 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006992 return -1;
6993 }
6994
6995 preg = calloc(1, sizeof(regex_t));
6996 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006997 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006998 return -1;
6999 }
7000
willy tarreauc1f47532005-12-18 01:08:26 +01007001 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
7002 if (err) {
7003 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7004 file, linenum, *err);
7005 return -1;
7006 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007007 }
7008 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
7009 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007010 if (curproxy == &defproxy) {
7011 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7012 return -1;
7013 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007014
7015 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007016 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007017 return -1;
7018 }
7019
7020 preg = calloc(1, sizeof(regex_t));
7021 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007022 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007023 return -1;
7024 }
7025
7026 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
7027 }
7028 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
7029 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007030 if (curproxy == &defproxy) {
7031 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7032 return -1;
7033 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007034
7035 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007036 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007037 return -1;
7038 }
7039
7040 preg = calloc(1, sizeof(regex_t));
7041 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007042 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007043 return -1;
7044 }
7045
7046 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
7047 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007048 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
7049 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007050 if (curproxy == &defproxy) {
7051 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7052 return -1;
7053 }
willy tarreau036e1ce2005-12-17 13:46:33 +01007054
7055 if (*(args[1]) == 0) {
7056 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
7057 return -1;
7058 }
7059
7060 preg = calloc(1, sizeof(regex_t));
7061 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7062 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7063 return -1;
7064 }
7065
7066 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
7067 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007068 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
7069 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007070 if (curproxy == &defproxy) {
7071 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7072 return -1;
7073 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007074
7075 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007076 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007077 return -1;
7078 }
7079
7080 preg = calloc(1, sizeof(regex_t));
7081 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007082 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007083 return -1;
7084 }
7085
7086 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
7087 }
7088 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007089 if (curproxy == &defproxy) {
7090 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7091 return -1;
7092 }
7093
willy tarreau9fe663a2005-12-17 13:02:59 +01007094 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007095 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007096 return 0;
7097 }
7098
7099 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007100 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007101 return -1;
7102 }
7103
willy tarreau4302f492005-12-18 01:00:37 +01007104 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
7105 }
7106 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
7107 regex_t *preg;
7108
7109 if (*(args[1]) == 0 || *(args[2]) == 0) {
7110 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7111 file, linenum, args[0]);
7112 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007113 }
willy tarreau4302f492005-12-18 01:00:37 +01007114
7115 preg = calloc(1, sizeof(regex_t));
7116 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7117 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7118 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007119 }
willy tarreau4302f492005-12-18 01:00:37 +01007120
willy tarreauc1f47532005-12-18 01:08:26 +01007121 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7122 if (err) {
7123 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7124 file, linenum, *err);
7125 return -1;
7126 }
willy tarreau4302f492005-12-18 01:00:37 +01007127 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007128 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
7129 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007130 if (curproxy == &defproxy) {
7131 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7132 return -1;
7133 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007134
7135 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007136 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007137 return -1;
7138 }
willy tarreaue39cd132005-12-17 13:00:18 +01007139
willy tarreau9fe663a2005-12-17 13:02:59 +01007140 preg = calloc(1, sizeof(regex_t));
7141 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007142 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007143 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007144 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007145
willy tarreauc1f47532005-12-18 01:08:26 +01007146 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7147 if (err) {
7148 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7149 file, linenum, *err);
7150 return -1;
7151 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007152 }
willy tarreau982249e2005-12-18 00:57:06 +01007153 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
7154 regex_t *preg;
7155 if (curproxy == &defproxy) {
7156 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7157 return -1;
7158 }
7159
7160 if (*(args[1]) == 0) {
7161 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7162 return -1;
7163 }
7164
7165 preg = calloc(1, sizeof(regex_t));
7166 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
7167 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7168 return -1;
7169 }
7170
willy tarreauc1f47532005-12-18 01:08:26 +01007171 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7172 if (err) {
7173 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7174 file, linenum, *err);
7175 return -1;
7176 }
willy tarreau982249e2005-12-18 00:57:06 +01007177 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007178 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01007179 regex_t *preg;
7180 if (curproxy == &defproxy) {
7181 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7182 return -1;
7183 }
willy tarreaue39cd132005-12-17 13:00:18 +01007184
willy tarreaua41a8b42005-12-17 14:02:24 +01007185 if (*(args[1]) == 0 || *(args[2]) == 0) {
7186 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
7187 file, linenum, args[0]);
7188 return -1;
7189 }
willy tarreaue39cd132005-12-17 13:00:18 +01007190
willy tarreaua41a8b42005-12-17 14:02:24 +01007191 preg = calloc(1, sizeof(regex_t));
7192 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7193 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7194 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01007195 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007196
willy tarreauc1f47532005-12-18 01:08:26 +01007197 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
7198 if (err) {
7199 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7200 file, linenum, *err);
7201 return -1;
7202 }
willy tarreaua41a8b42005-12-17 14:02:24 +01007203 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007204 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
7205 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01007206 if (curproxy == &defproxy) {
7207 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7208 return -1;
7209 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007210
7211 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007212 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007213 return -1;
7214 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007215
willy tarreau9fe663a2005-12-17 13:02:59 +01007216 preg = calloc(1, sizeof(regex_t));
7217 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007218 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007219 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007220 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007221
willy tarreauc1f47532005-12-18 01:08:26 +01007222 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
7223 if (err) {
7224 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7225 file, linenum, *err);
7226 return -1;
7227 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007228 }
willy tarreau982249e2005-12-18 00:57:06 +01007229 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
7230 regex_t *preg;
7231 if (curproxy == &defproxy) {
7232 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7233 return -1;
7234 }
7235
7236 if (*(args[1]) == 0) {
7237 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
7238 return -1;
7239 }
7240
7241 preg = calloc(1, sizeof(regex_t));
7242 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
7243 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
7244 return -1;
7245 }
7246
willy tarreauc1f47532005-12-18 01:08:26 +01007247 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
7248 if (err) {
7249 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
7250 file, linenum, *err);
7251 return -1;
7252 }
willy tarreau982249e2005-12-18 00:57:06 +01007253 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007254 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01007255 if (curproxy == &defproxy) {
7256 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7257 return -1;
7258 }
7259
willy tarreau9fe663a2005-12-17 13:02:59 +01007260 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007261 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007262 return 0;
7263 }
7264
7265 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01007266 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007267 return -1;
7268 }
7269
7270 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
7271 }
willy tarreauc1f47532005-12-18 01:08:26 +01007272 else if (!strcmp(args[0], "errorloc") ||
7273 !strcmp(args[0], "errorloc302") ||
7274 !strcmp(args[0], "errorloc303")) { /* error location */
7275 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007276 char *err;
7277
willy tarreaueedaa9f2005-12-17 14:08:03 +01007278 // if (curproxy == &defproxy) {
7279 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
7280 // return -1;
7281 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01007282
willy tarreau8337c6b2005-12-17 13:41:01 +01007283 if (*(args[2]) == 0) {
7284 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
7285 return -1;
7286 }
7287
7288 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01007289 if (!strcmp(args[0], "errorloc303")) {
7290 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
7291 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
7292 } else {
7293 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
7294 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
7295 }
willy tarreau8337c6b2005-12-17 13:41:01 +01007296
7297 if (errnum == 400) {
7298 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007299 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007300 free(curproxy->errmsg.msg400);
7301 }
7302 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007303 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007304 }
7305 else if (errnum == 403) {
7306 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007307 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007308 free(curproxy->errmsg.msg403);
7309 }
7310 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007311 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007312 }
7313 else if (errnum == 408) {
7314 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007315 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007316 free(curproxy->errmsg.msg408);
7317 }
7318 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007319 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007320 }
7321 else if (errnum == 500) {
7322 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007323 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007324 free(curproxy->errmsg.msg500);
7325 }
7326 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007327 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007328 }
7329 else if (errnum == 502) {
7330 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007331 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007332 free(curproxy->errmsg.msg502);
7333 }
7334 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007335 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007336 }
7337 else if (errnum == 503) {
7338 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007339 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007340 free(curproxy->errmsg.msg503);
7341 }
7342 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007343 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007344 }
7345 else if (errnum == 504) {
7346 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01007347 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01007348 free(curproxy->errmsg.msg504);
7349 }
7350 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01007351 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01007352 }
7353 else {
7354 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
7355 free(err);
7356 }
7357 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007358 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01007359 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01007360 return -1;
7361 }
7362 return 0;
7363}
willy tarreaue39cd132005-12-17 13:00:18 +01007364
willy tarreau5cbea6f2005-12-17 12:48:26 +01007365
willy tarreau9fe663a2005-12-17 13:02:59 +01007366/*
7367 * This function reads and parses the configuration file given in the argument.
7368 * returns 0 if OK, -1 if error.
7369 */
7370int readcfgfile(char *file) {
7371 char thisline[256];
7372 char *line;
7373 FILE *f;
7374 int linenum = 0;
7375 char *end;
7376 char *args[MAX_LINE_ARGS];
7377 int arg;
7378 int cfgerr = 0;
7379 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01007380
willy tarreau9fe663a2005-12-17 13:02:59 +01007381 struct proxy *curproxy = NULL;
7382 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01007383
willy tarreau9fe663a2005-12-17 13:02:59 +01007384 if ((f=fopen(file,"r")) == NULL)
7385 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01007386
willy tarreaueedaa9f2005-12-17 14:08:03 +01007387 init_default_instance();
7388
willy tarreau9fe663a2005-12-17 13:02:59 +01007389 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
7390 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007391
willy tarreau9fe663a2005-12-17 13:02:59 +01007392 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01007393
willy tarreau9fe663a2005-12-17 13:02:59 +01007394 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01007395 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01007396 line++;
7397
7398 arg = 0;
7399 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01007400
willy tarreau9fe663a2005-12-17 13:02:59 +01007401 while (*line && arg < MAX_LINE_ARGS) {
7402 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
7403 * C equivalent value. Other combinations left unchanged (eg: \1).
7404 */
7405 if (*line == '\\') {
7406 int skip = 0;
7407 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
7408 *line = line[1];
7409 skip = 1;
7410 }
7411 else if (line[1] == 'r') {
7412 *line = '\r';
7413 skip = 1;
7414 }
7415 else if (line[1] == 'n') {
7416 *line = '\n';
7417 skip = 1;
7418 }
7419 else if (line[1] == 't') {
7420 *line = '\t';
7421 skip = 1;
7422 }
willy tarreauc1f47532005-12-18 01:08:26 +01007423 else if (line[1] == 'x') {
7424 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
7425 unsigned char hex1, hex2;
7426 hex1 = toupper(line[2]) - '0';
7427 hex2 = toupper(line[3]) - '0';
7428 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
7429 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
7430 *line = (hex1<<4) + hex2;
7431 skip = 3;
7432 }
7433 else {
7434 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
7435 return -1;
7436 }
7437 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007438 if (skip) {
7439 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
7440 end -= skip;
7441 }
7442 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007443 }
willy tarreaua1598082005-12-17 13:08:06 +01007444 else if (*line == '#' || *line == '\n' || *line == '\r') {
7445 /* end of string, end of loop */
7446 *line = 0;
7447 break;
7448 }
willy tarreauc29948c2005-12-17 13:10:27 +01007449 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007450 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01007451 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01007452 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01007453 line++;
7454 args[++arg] = line;
7455 }
7456 else {
7457 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01007458 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007459 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007460
willy tarreau9fe663a2005-12-17 13:02:59 +01007461 /* empty line */
7462 if (!**args)
7463 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01007464
willy tarreau9fe663a2005-12-17 13:02:59 +01007465 /* zero out remaining args */
7466 while (++arg < MAX_LINE_ARGS) {
7467 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007468 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007469
willy tarreaua41a8b42005-12-17 14:02:24 +01007470 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01007471 confsect = CFG_LISTEN;
7472 else if (!strcmp(args[0], "global")) /* global config */
7473 confsect = CFG_GLOBAL;
7474 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007475
willy tarreau9fe663a2005-12-17 13:02:59 +01007476 switch (confsect) {
7477 case CFG_LISTEN:
7478 if (cfg_parse_listen(file, linenum, args) < 0)
7479 return -1;
7480 break;
7481 case CFG_GLOBAL:
7482 if (cfg_parse_global(file, linenum, args) < 0)
7483 return -1;
7484 break;
7485 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01007486 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01007487 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01007488 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007489
7490
willy tarreau0f7af912005-12-17 12:21:26 +01007491 }
7492 fclose(f);
7493
7494 /*
7495 * Now, check for the integrity of all that we have collected.
7496 */
7497
7498 if ((curproxy = proxy) == NULL) {
7499 Alert("parsing %s : no <listen> line. Nothing to do !\n",
7500 file);
7501 return -1;
7502 }
7503
7504 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01007505 curproxy->cursrv = NULL;
willy tarreaudbd3bef2006-01-20 19:35:18 +01007506 if (curproxy->state == PR_STSTOPPED) {
willy tarreauef900ab2005-12-17 12:52:52 +01007507 curproxy = curproxy->next;
7508 continue;
7509 }
willy tarreaud0fb4652005-12-18 01:32:04 +01007510
7511 if (curproxy->listen == NULL) {
7512 Alert("parsing %s : listener %s has no listen address. Please either specify a valid address on the <listen> line, or use the <bind> keyword.\n", file, curproxy->id);
7513 cfgerr++;
7514 }
7515 else if ((curproxy->mode != PR_MODE_HEALTH) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01007516 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007517 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007518 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7519 file, curproxy->id);
7520 cfgerr++;
7521 }
7522 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7523 if (curproxy->options & PR_O_TRANSP) {
7524 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7525 file, curproxy->id);
7526 cfgerr++;
7527 }
7528 else if (curproxy->srv == NULL) {
7529 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7530 file, curproxy->id);
7531 cfgerr++;
7532 }
willy tarreaua1598082005-12-17 13:08:06 +01007533 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007534 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7535 file, curproxy->id);
7536 }
7537 }
7538 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007539 if (curproxy->cookie_name != NULL) {
7540 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7541 file, curproxy->id);
7542 }
7543 if ((newsrv = curproxy->srv) != NULL) {
7544 Warning("parsing %s : servers will be ignored for listener %s.\n",
7545 file, curproxy->id);
7546 }
willy tarreaue39cd132005-12-17 13:00:18 +01007547 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007548 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7549 file, curproxy->id);
7550 }
willy tarreaue39cd132005-12-17 13:00:18 +01007551 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007552 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7553 file, curproxy->id);
7554 }
7555 }
7556 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7557 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7558 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7559 file, curproxy->id);
7560 cfgerr++;
7561 }
7562 else {
7563 while (newsrv != NULL) {
7564 /* nothing to check for now */
7565 newsrv = newsrv->next;
7566 }
7567 }
7568 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007569
7570 if (curproxy->options & PR_O_LOGASAP)
7571 curproxy->to_log &= ~LW_BYTES;
7572
willy tarreau8337c6b2005-12-17 13:41:01 +01007573 if (curproxy->errmsg.msg400 == NULL) {
7574 curproxy->errmsg.msg400 = (char *)HTTP_400;
7575 curproxy->errmsg.len400 = strlen(HTTP_400);
7576 }
7577 if (curproxy->errmsg.msg403 == NULL) {
7578 curproxy->errmsg.msg403 = (char *)HTTP_403;
7579 curproxy->errmsg.len403 = strlen(HTTP_403);
7580 }
7581 if (curproxy->errmsg.msg408 == NULL) {
7582 curproxy->errmsg.msg408 = (char *)HTTP_408;
7583 curproxy->errmsg.len408 = strlen(HTTP_408);
7584 }
7585 if (curproxy->errmsg.msg500 == NULL) {
7586 curproxy->errmsg.msg500 = (char *)HTTP_500;
7587 curproxy->errmsg.len500 = strlen(HTTP_500);
7588 }
7589 if (curproxy->errmsg.msg502 == NULL) {
7590 curproxy->errmsg.msg502 = (char *)HTTP_502;
7591 curproxy->errmsg.len502 = strlen(HTTP_502);
7592 }
7593 if (curproxy->errmsg.msg503 == NULL) {
7594 curproxy->errmsg.msg503 = (char *)HTTP_503;
7595 curproxy->errmsg.len503 = strlen(HTTP_503);
7596 }
7597 if (curproxy->errmsg.msg504 == NULL) {
7598 curproxy->errmsg.msg504 = (char *)HTTP_504;
7599 curproxy->errmsg.len504 = strlen(HTTP_504);
7600 }
willy tarreau0f7af912005-12-17 12:21:26 +01007601 curproxy = curproxy->next;
7602 }
7603 if (cfgerr > 0) {
7604 Alert("Errors found in configuration file, aborting.\n");
7605 return -1;
7606 }
7607 else
7608 return 0;
7609}
7610
7611
7612/*
7613 * This function initializes all the necessary variables. It only returns
7614 * if everything is OK. If something fails, it exits.
7615 */
7616void init(int argc, char **argv) {
7617 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007618 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007619 char *old_argv = *argv;
7620 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007621 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007622 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007623
7624 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007625 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007626 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007627 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007628 exit(1);
7629 }
7630
willy tarreau4302f492005-12-18 01:00:37 +01007631 /* initialize the log header encoding map : '{|}"#' should be encoded with
7632 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7633 * URL encoding only requires '"', '#' to be encoded as well as non-
7634 * printable characters above.
7635 */
7636 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7637 memset(url_encode_map, 0, sizeof(url_encode_map));
7638 for (i = 0; i < 32; i++) {
7639 FD_SET(i, hdr_encode_map);
7640 FD_SET(i, url_encode_map);
7641 }
7642 for (i = 127; i < 256; i++) {
7643 FD_SET(i, hdr_encode_map);
7644 FD_SET(i, url_encode_map);
7645 }
7646
7647 tmp = "\"#{|}";
7648 while (*tmp) {
7649 FD_SET(*tmp, hdr_encode_map);
7650 tmp++;
7651 }
7652
7653 tmp = "\"#";
7654 while (*tmp) {
7655 FD_SET(*tmp, url_encode_map);
7656 tmp++;
7657 }
7658
willy tarreau64a3cc32005-12-18 01:13:11 +01007659 cfg_polling_mechanism = POLL_USE_SELECT; /* select() is always available */
7660#if defined(ENABLE_POLL)
7661 cfg_polling_mechanism |= POLL_USE_POLL;
7662#endif
7663#if defined(ENABLE_EPOLL)
7664 cfg_polling_mechanism |= POLL_USE_EPOLL;
7665#endif
7666
willy tarreau0f7af912005-12-17 12:21:26 +01007667 pid = getpid();
7668 progname = *argv;
7669 while ((tmp = strchr(progname, '/')) != NULL)
7670 progname = tmp + 1;
7671
7672 argc--; argv++;
7673 while (argc > 0) {
7674 char *flag;
7675
7676 if (**argv == '-') {
7677 flag = *argv+1;
7678
7679 /* 1 arg */
7680 if (*flag == 'v') {
7681 display_version();
7682 exit(0);
7683 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007684#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007685 else if (*flag == 'd' && flag[1] == 'e')
7686 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007687#endif
7688#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01007689 else if (*flag == 'd' && flag[1] == 'p')
7690 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01007691#endif
willy tarreau982249e2005-12-18 00:57:06 +01007692 else if (*flag == 'V')
7693 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007694 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007695 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007696 else if (*flag == 'c')
7697 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007698 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007699 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007700 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007701 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007702#if STATTIME > 0
7703 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007704 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007705 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007706 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007707#endif
7708 else { /* >=2 args */
7709 argv++; argc--;
7710 if (argc == 0)
7711 usage(old_argv);
7712
7713 switch (*flag) {
7714 case 'n' : cfg_maxconn = atol(*argv); break;
7715 case 'N' : cfg_maxpconn = atol(*argv); break;
7716 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007717 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007718 default: usage(old_argv);
7719 }
7720 }
7721 }
7722 else
7723 usage(old_argv);
7724 argv++; argc--;
7725 }
7726
willy tarreaud0fb4652005-12-18 01:32:04 +01007727 global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
7728 (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007729
willy tarreau0f7af912005-12-17 12:21:26 +01007730 if (!cfg_cfgfile)
7731 usage(old_argv);
7732
7733 gethostname(hostname, MAX_HOSTNAME_LEN);
7734
willy tarreau12350152005-12-18 01:03:27 +01007735 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007736 if (readcfgfile(cfg_cfgfile) < 0) {
7737 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7738 exit(1);
7739 }
willy tarreau12350152005-12-18 01:03:27 +01007740 if (have_appsession)
7741 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007742
willy tarreau982249e2005-12-18 00:57:06 +01007743 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007744 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7745 exit(0);
7746 }
7747
willy tarreau9fe663a2005-12-17 13:02:59 +01007748 if (cfg_maxconn > 0)
7749 global.maxconn = cfg_maxconn;
7750
willy tarreaufe2c5c12005-12-17 14:14:34 +01007751 if (cfg_pidfile) {
7752 if (global.pidfile)
7753 free(global.pidfile);
7754 global.pidfile = strdup(cfg_pidfile);
7755 }
7756
willy tarreau9fe663a2005-12-17 13:02:59 +01007757 if (global.maxconn == 0)
7758 global.maxconn = DEFAULT_MAXCONN;
7759
7760 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7761
7762 if (arg_mode & MODE_DEBUG) {
7763 /* command line debug mode inhibits configuration mode */
7764 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7765 }
willy tarreau982249e2005-12-18 00:57:06 +01007766 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7767 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007768
7769 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7770 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7771 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7772 }
7773
7774 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7775 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7776 global.nbproc = 1;
7777 }
7778
7779 if (global.nbproc < 1)
7780 global.nbproc = 1;
7781
willy tarreau0f7af912005-12-17 12:21:26 +01007782 StaticReadEvent = (fd_set *)calloc(1,
7783 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007784 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007785 StaticWriteEvent = (fd_set *)calloc(1,
7786 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007787 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007788
7789 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007790 sizeof(struct fdtab) * (global.maxsock));
7791 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007792 fdtab[i].state = FD_STCLOSE;
7793 }
7794}
7795
7796/*
7797 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7798 */
7799int start_proxies() {
7800 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007801 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007802 int fd;
7803
7804 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreaudbd3bef2006-01-20 19:35:18 +01007805 if (curproxy->state == PR_STSTOPPED)
willy tarreau0f7af912005-12-17 12:21:26 +01007806 continue;
7807
willy tarreaua41a8b42005-12-17 14:02:24 +01007808 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7809 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007810 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007811 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7812 curproxy->id);
7813 return -1;
7814 }
willy tarreau0f7af912005-12-17 12:21:26 +01007815
willy tarreaua41a8b42005-12-17 14:02:24 +01007816 if (fd >= global.maxsock) {
7817 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7818 curproxy->id);
7819 close(fd);
7820 return -1;
7821 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007822
willy tarreaua41a8b42005-12-17 14:02:24 +01007823 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7824 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7825 (char *) &one, sizeof(one)) == -1)) {
7826 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7827 curproxy->id);
7828 close(fd);
7829 return -1;
7830 }
willy tarreau0f7af912005-12-17 12:21:26 +01007831
willy tarreaua41a8b42005-12-17 14:02:24 +01007832 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7833 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7834 curproxy->id);
7835 }
willy tarreau0f7af912005-12-17 12:21:26 +01007836
willy tarreaua41a8b42005-12-17 14:02:24 +01007837 if (bind(fd,
7838 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007839 listener->addr.ss_family == AF_INET6 ?
7840 sizeof(struct sockaddr_in6) :
7841 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007842 Alert("cannot bind socket for proxy %s. Aborting.\n",
7843 curproxy->id);
7844 close(fd);
7845 return -1;
7846 }
willy tarreau0f7af912005-12-17 12:21:26 +01007847
willy tarreaua41a8b42005-12-17 14:02:24 +01007848 if (listen(fd, curproxy->maxconn) == -1) {
7849 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7850 curproxy->id);
7851 close(fd);
7852 return -1;
7853 }
willy tarreau0f7af912005-12-17 12:21:26 +01007854
willy tarreaua41a8b42005-12-17 14:02:24 +01007855 /* the function for the accept() event */
7856 fdtab[fd].read = &event_accept;
7857 fdtab[fd].write = NULL; /* never called */
7858 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7859 curproxy->state = PR_STRUN;
7860 fdtab[fd].state = FD_STLISTEN;
7861 FD_SET(fd, StaticReadEvent);
7862 fd_insert(fd);
7863 listeners++;
7864 }
willy tarreaua1598082005-12-17 13:08:06 +01007865 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007866 }
7867 return 0;
7868}
7869
willy tarreaub952e1d2005-12-18 01:31:20 +01007870int match_str(const void *key1, const void *key2) {
willy tarreau12350152005-12-18 01:03:27 +01007871
7872 appsess *temp1,*temp2;
7873 temp1 = (appsess *)key1;
7874 temp2 = (appsess *)key2;
7875
7876 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7877 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7878
7879 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7880}/* end match_str */
7881
willy tarreaub952e1d2005-12-18 01:31:20 +01007882void destroy(void *data) {
willy tarreau12350152005-12-18 01:03:27 +01007883 appsess *temp1;
7884
7885 //printf("destroy called\n");
7886 temp1 = (appsess *)data;
7887
7888 if (temp1->sessid)
7889 pool_free_to(apools.sessid, temp1->sessid);
7890
7891 if (temp1->serverid)
7892 pool_free_to(apools.serverid, temp1->serverid);
7893
7894 pool_free(appsess, temp1);
7895} /* end destroy */
7896
7897void appsession_cleanup( void )
7898{
7899 struct proxy *p = proxy;
7900
7901 while(p) {
7902 chtbl_destroy(&(p->htbl_proxy));
7903 p = p->next;
7904 }
7905}/* end appsession_cleanup() */
7906
7907void pool_destroy(void **pool)
7908{
7909 void *temp, *next;
7910 next = pool;
7911 while (next) {
7912 temp = next;
7913 next = *(void **)temp;
7914 free(temp);
7915 }
7916}/* end pool_destroy() */
7917
willy tarreaub952e1d2005-12-18 01:31:20 +01007918void deinit(void) {
willy tarreau12350152005-12-18 01:03:27 +01007919 struct proxy *p = proxy;
7920 struct cap_hdr *h,*h_next;
7921 struct server *s,*s_next;
7922 struct listener *l,*l_next;
7923
7924 while (p) {
7925 if (p->id)
7926 free(p->id);
7927
7928 if (p->check_req)
7929 free(p->check_req);
7930
7931 if (p->cookie_name)
7932 free(p->cookie_name);
7933
7934 if (p->capture_name)
7935 free(p->capture_name);
7936
7937 /* only strup if the user have set in config.
7938 When should we free it?!
willy tarreaub952e1d2005-12-18 01:31:20 +01007939 if (p->errmsg.msg400) free(p->errmsg.msg400);
7940 if (p->errmsg.msg403) free(p->errmsg.msg403);
7941 if (p->errmsg.msg408) free(p->errmsg.msg408);
7942 if (p->errmsg.msg500) free(p->errmsg.msg500);
7943 if (p->errmsg.msg502) free(p->errmsg.msg502);
7944 if (p->errmsg.msg503) free(p->errmsg.msg503);
7945 if (p->errmsg.msg504) free(p->errmsg.msg504);
willy tarreau12350152005-12-18 01:03:27 +01007946 */
7947 if (p->appsession_name)
7948 free(p->appsession_name);
7949
7950 h = p->req_cap;
7951 while (h) {
7952 h_next = h->next;
7953 if (h->name)
7954 free(h->name);
7955 pool_destroy(h->pool);
7956 free(h);
7957 h = h_next;
7958 }/* end while(h) */
7959
7960 h = p->rsp_cap;
7961 while (h) {
7962 h_next = h->next;
7963 if (h->name)
7964 free(h->name);
7965
7966 pool_destroy(h->pool);
7967 free(h);
7968 h = h_next;
7969 }/* end while(h) */
7970
7971 s = p->srv;
7972 while (s) {
7973 s_next = s->next;
willy tarreaub952e1d2005-12-18 01:31:20 +01007974 if (s->id)
willy tarreau12350152005-12-18 01:03:27 +01007975 free(s->id);
7976
willy tarreaub952e1d2005-12-18 01:31:20 +01007977 if (s->cookie)
willy tarreau12350152005-12-18 01:03:27 +01007978 free(s->cookie);
7979
7980 free(s);
7981 s = s_next;
7982 }/* end while(s) */
7983
7984 l = p->listen;
7985 while (l) {
7986 l_next = l->next;
7987 free(l);
7988 l = l_next;
7989 }/* end while(l) */
7990
7991 pool_destroy((void **) p->req_cap_pool);
7992 pool_destroy((void **) p->rsp_cap_pool);
7993 p = p->next;
7994 }/* end while(p) */
7995
7996 if (global.chroot) free(global.chroot);
7997 if (global.pidfile) free(global.pidfile);
7998
willy tarreau12350152005-12-18 01:03:27 +01007999 if (StaticReadEvent) free(StaticReadEvent);
8000 if (StaticWriteEvent) free(StaticWriteEvent);
8001 if (fdtab) free(fdtab);
8002
8003 pool_destroy(pool_session);
8004 pool_destroy(pool_buffer);
8005 pool_destroy(pool_fdtab);
8006 pool_destroy(pool_requri);
8007 pool_destroy(pool_task);
8008 pool_destroy(pool_capture);
8009 pool_destroy(pool_appsess);
8010
8011 if (have_appsession) {
8012 pool_destroy(apools.serverid);
8013 pool_destroy(apools.sessid);
8014 }
8015} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01008016
8017int main(int argc, char **argv) {
willy tarreaub1285d52005-12-18 01:20:14 +01008018 struct rlimit limit;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008019 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01008020 init(argc, argv);
8021
willy tarreau0f7af912005-12-17 12:21:26 +01008022 signal(SIGQUIT, dump);
8023 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01008024 signal(SIGHUP, sig_dump_state);
willy tarreau64a3cc32005-12-18 01:13:11 +01008025#ifdef DEBUG_MEMORY
willy tarreau12350152005-12-18 01:03:27 +01008026 signal(SIGINT, sig_int);
8027 signal(SIGTERM, sig_term);
willy tarreau64a3cc32005-12-18 01:13:11 +01008028#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008029
8030 /* on very high loads, a sigpipe sometimes happen just between the
8031 * getsockopt() which tells "it's OK to write", and the following write :-(
8032 */
willy tarreau3242e862005-12-17 12:27:53 +01008033#ifndef MSG_NOSIGNAL
8034 signal(SIGPIPE, SIG_IGN);
8035#endif
willy tarreau0f7af912005-12-17 12:21:26 +01008036
willy tarreaud0fb4652005-12-18 01:32:04 +01008037 /* start_proxies() sends an alert when it fails. */
willy tarreau0f7af912005-12-17 12:21:26 +01008038 if (start_proxies() < 0)
8039 exit(1);
willy tarreaud0fb4652005-12-18 01:32:04 +01008040
8041 if (listeners == 0) {
8042 Alert("[%s.main()] No enabled listener found (check the <listen> keywords) ! Exiting.\n", argv[0]);
8043 exit(1);
8044 }
8045
willy tarreaudbd3bef2006-01-20 19:35:18 +01008046 /* prepare pause/play signals */
8047 signal(SIGTTOU, sig_pause);
8048 signal(SIGTTIN, sig_listen);
8049
willy tarreaud0fb4652005-12-18 01:32:04 +01008050 /* MODE_QUIET can inhibit alerts and warnings below this line */
8051
8052 global.mode &= ~MODE_STARTING;
8053 if (global.mode & MODE_QUIET) {
8054 /* detach from the tty */
8055 fclose(stdin); fclose(stdout); fclose(stderr);
8056 close(0); close(1); close(2);
8057 }
willy tarreau0f7af912005-12-17 12:21:26 +01008058
willy tarreaufe2c5c12005-12-17 14:14:34 +01008059 /* open log & pid files before the chroot */
8060 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
8061 int pidfd;
8062 unlink(global.pidfile);
8063 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
8064 if (pidfd < 0) {
8065 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
8066 exit(1);
8067 }
8068 pidfile = fdopen(pidfd, "w");
8069 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008070
8071 /* chroot if needed */
8072 if (global.chroot != NULL) {
8073 if (chroot(global.chroot) == -1) {
8074 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
8075 exit(1);
8076 }
8077 chdir("/");
8078 }
8079
willy tarreaub1285d52005-12-18 01:20:14 +01008080 /* ulimits */
8081 if (global.rlimit_nofile) {
8082 limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
8083 if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
8084 Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
8085 }
8086 }
8087
willy tarreau9fe663a2005-12-17 13:02:59 +01008088 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01008089 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008090 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
8091 exit(1);
8092 }
8093
willy tarreau036e1ce2005-12-17 13:46:33 +01008094 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01008095 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
8096 exit(1);
8097 }
8098
willy tarreaub1285d52005-12-18 01:20:14 +01008099 /* check ulimits */
8100 limit.rlim_cur = limit.rlim_max = 0;
8101 getrlimit(RLIMIT_NOFILE, &limit);
8102 if (limit.rlim_cur < global.maxsock) {
8103 Warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
8104 argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
8105 }
8106
willy tarreau9fe663a2005-12-17 13:02:59 +01008107 if (global.mode & MODE_DAEMON) {
8108 int ret = 0;
8109 int proc;
8110
8111 /* the father launches the required number of processes */
8112 for (proc = 0; proc < global.nbproc; proc++) {
8113 ret = fork();
8114 if (ret < 0) {
8115 Alert("[%s.main()] Cannot fork.\n", argv[0]);
8116 exit(1); /* there has been an error */
8117 }
8118 else if (ret == 0) /* child breaks here */
8119 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01008120 if (pidfile != NULL) {
8121 fprintf(pidfile, "%d\n", ret);
8122 fflush(pidfile);
8123 }
willy tarreau9fe663a2005-12-17 13:02:59 +01008124 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01008125 /* close the pidfile both in children and father */
8126 if (pidfile != NULL)
8127 fclose(pidfile);
8128 free(global.pidfile);
8129
willy tarreau9fe663a2005-12-17 13:02:59 +01008130 if (proc == global.nbproc)
8131 exit(0); /* parent must leave */
8132
willy tarreau750a4722005-12-17 13:21:24 +01008133 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
8134 * that we can detach from the TTY. We MUST NOT do it in other cases since
8135 * it would have already be done, and 0-2 would have been affected to listening
8136 * sockets
8137 */
8138 if (!(global.mode & MODE_QUIET)) {
8139 /* detach from the tty */
8140 fclose(stdin); fclose(stdout); fclose(stderr);
8141 close(0); close(1); close(2); /* close all fd's */
8142 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
8143 }
willy tarreaua1598082005-12-17 13:08:06 +01008144 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01008145 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01008146 }
8147
willy tarreau1c2ad212005-12-18 01:11:29 +01008148#if defined(ENABLE_EPOLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008149 if (cfg_polling_mechanism & POLL_USE_EPOLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008150 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
8151 epoll_loop(POLL_LOOP_ACTION_RUN);
8152 epoll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008153 cfg_polling_mechanism &= POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008154 }
8155 else {
willy tarreau64a3cc32005-12-18 01:13:11 +01008156 Warning("epoll() is not available. Using poll()/select() instead.\n");
8157 cfg_polling_mechanism &= ~POLL_USE_EPOLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008158 }
8159 }
8160#endif
8161
8162#if defined(ENABLE_POLL)
willy tarreau64a3cc32005-12-18 01:13:11 +01008163 if (cfg_polling_mechanism & POLL_USE_POLL) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008164 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
8165 poll_loop(POLL_LOOP_ACTION_RUN);
8166 poll_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008167 cfg_polling_mechanism &= POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008168 }
8169 else {
8170 Warning("poll() is not available. Using select() instead.\n");
willy tarreau64a3cc32005-12-18 01:13:11 +01008171 cfg_polling_mechanism &= ~POLL_USE_POLL;
willy tarreau1c2ad212005-12-18 01:11:29 +01008172 }
8173 }
8174#endif
willy tarreau64a3cc32005-12-18 01:13:11 +01008175 if (cfg_polling_mechanism & POLL_USE_SELECT) {
willy tarreau1c2ad212005-12-18 01:11:29 +01008176 if (select_loop(POLL_LOOP_ACTION_INIT)) {
8177 select_loop(POLL_LOOP_ACTION_RUN);
8178 select_loop(POLL_LOOP_ACTION_CLEAN);
willy tarreau64a3cc32005-12-18 01:13:11 +01008179 cfg_polling_mechanism &= POLL_USE_SELECT;
willy tarreau1c2ad212005-12-18 01:11:29 +01008180 }
8181 }
8182
willy tarreau0f7af912005-12-17 12:21:26 +01008183
willy tarreau12350152005-12-18 01:03:27 +01008184 /* Free all Hash Keys and all Hash elements */
8185 appsession_cleanup();
8186 /* Do some cleanup */
8187 deinit();
8188
willy tarreau0f7af912005-12-17 12:21:26 +01008189 exit(0);
8190}
willy tarreau12350152005-12-18 01:03:27 +01008191
8192#if defined(DEBUG_HASH)
8193static void print_table(const CHTbl *htbl) {
8194
8195 ListElmt *element;
8196 int i;
8197 appsess *asession;
8198
8199 /*****************************************************************************
8200 * *
8201 * Display the chained hash table. *
8202 * *
8203 *****************************************************************************/
8204
8205 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
8206
8207 for (i = 0; i < TBLSIZ; i++) {
8208 fprintf(stdout, "Bucket[%03d]\n", i);
8209
8210 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8211 //fprintf(stdout, "%c", *(char *)list_data(element));
8212 asession = (appsess *)list_data(element);
8213 fprintf(stdout, "ELEM :%s:", asession->sessid);
8214 fprintf(stdout, " Server :%s: \n", asession->serverid);
8215 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
8216 }
8217
8218 fprintf(stdout, "\n");
8219 }
8220 return;
8221} /* end print_table */
8222#endif
8223
8224static int appsession_init(void)
8225{
8226 static int initialized = 0;
8227 int idlen;
8228 struct server *s;
8229 struct proxy *p = proxy;
8230
8231 if (!initialized) {
8232 if (!appsession_task_init()) {
8233 apools.sessid = NULL;
8234 apools.serverid = NULL;
8235 apools.ser_waste = 0;
8236 apools.ser_use = 0;
8237 apools.ser_msize = sizeof(void *);
8238 apools.ses_waste = 0;
8239 apools.ses_use = 0;
8240 apools.ses_msize = sizeof(void *);
8241 while (p) {
8242 s = p->srv;
8243 if (apools.ses_msize < p->appsession_len)
8244 apools.ses_msize = p->appsession_len;
8245 while (s) {
8246 idlen = strlen(s->id);
8247 if (apools.ser_msize < idlen)
8248 apools.ser_msize = idlen;
8249 s = s->next;
8250 }
8251 p = p->next;
8252 }
8253 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
8254 apools.ses_msize ++;
8255 }
8256 else {
8257 fprintf(stderr, "appsession_task_init failed\n");
8258 return -1;
8259 }
8260 initialized ++;
8261 }
8262 return 0;
8263}
8264
8265static int appsession_task_init(void)
8266{
8267 static int initialized = 0;
8268 struct task *t;
8269 if (!initialized) {
8270 if ((t = pool_alloc(task)) == NULL)
8271 return -1;
8272 t->next = t->prev = t->rqnext = NULL;
8273 t->wq = LIST_HEAD(wait_queue);
8274 t->state = TASK_IDLE;
8275 t->context = NULL;
8276 tv_delayfrom(&t->expire, &now, TBLCHKINT);
8277 task_queue(t);
8278 t->process = appsession_refresh;
8279 initialized ++;
8280 }
8281 return 0;
8282}
8283
8284static int appsession_refresh(struct task *t) {
8285 struct proxy *p = proxy;
8286 CHTbl *htbl;
8287 ListElmt *element, *last;
8288 int i;
8289 appsess *asession;
8290 void *data;
8291
8292 while (p) {
8293 if (p->appsession_name != NULL) {
8294 htbl = &p->htbl_proxy;
8295 /* if we ever give up the use of TBLSIZ, we need to change this */
8296 for (i = 0; i < TBLSIZ; i++) {
8297 last = NULL;
8298 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
8299 asession = (appsess *)list_data(element);
8300 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
8301 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
8302 int len;
8303 /*
8304 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
8305 */
8306 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
8307 asession->sessid, asession->serverid?asession->serverid:"(null)");
8308 write(1, trash, len);
8309 }
8310 /* delete the expired element from within the hash table */
8311 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
8312 && (htbl->table[i].destroy != NULL)) {
8313 htbl->table[i].destroy(data);
8314 }
8315 if (last == NULL) {/* patient lost his head, get a new one */
8316 element = list_head(&htbl->table[i]);
8317 if (element == NULL) break; /* no heads left, go to next patient */
8318 }
8319 else
8320 element = last;
8321 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
8322 else
8323 last = element;
8324 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
8325 }
8326 }
8327 p = p->next;
8328 }
8329 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
8330 return TBLCHKINT;
8331} /* end appsession_refresh */
8332