blob: 63822e50370c398f59bf495f6b9a77e7220811e8 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
willy tarreau0174f312005-12-18 01:02:42 +01003 * 2000-2005 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreau906b2682005-12-17 13:49:52 +010010 * Please refer to RFC2068 or RFC2616 for informations about HTTP protocol, and
willy tarreau982249e2005-12-18 00:57:06 +010011 * RFC2965 for informations about cookies usage. More generally, the IETF HTTP
12 * Working Group's web site should be consulted for protocol related changes :
13 *
14 * http://ftp.ics.uci.edu/pub/ietf/http/
willy tarreau906b2682005-12-17 13:49:52 +010015 *
16 * Pending bugs (may be not fixed because never reproduced) :
willy tarreaua1598082005-12-17 13:08:06 +010017 * - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
18 * the proxy to terminate (no core) if the client breaks the connection during
willy tarreauc29948c2005-12-17 13:10:27 +010019 * the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
willy tarreau8337c6b2005-12-17 13:41:01 +010020 * the snprintf() bug since requests were simple (GET / HTTP/1.0), but may be
21 * related to missing setsid() (fixed in 1.1.15)
willy tarreauef900ab2005-12-17 12:52:52 +010022 * - a proxy with an invalid config will prevent the startup even if disabled.
23 *
willy tarreau036e1ce2005-12-17 13:46:33 +010024 * ChangeLog has moved to the CHANGELOG file.
willy tarreau0f7af912005-12-17 12:21:26 +010025 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010026 * TODO:
27 * - handle properly intermediate incomplete server headers. Done ?
willy tarreau5cbea6f2005-12-17 12:48:26 +010028 * - handle hot-reconfiguration
willy tarreau906b2682005-12-17 13:49:52 +010029 * - fix client/server state transition when server is in connect or headers state
30 * and client suddenly disconnects. The server *should* switch to SHUT_WR, but
31 * still handle HTTP headers.
willy tarreau4302f492005-12-18 01:00:37 +010032 * - remove MAX_NEWHDR
willy tarreauc1f47532005-12-18 01:08:26 +010033 * - cut this huge file into several ones
willy tarreau0f7af912005-12-17 12:21:26 +010034 *
35 */
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <netinet/tcp.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <fcntl.h>
50#include <errno.h>
51#include <signal.h>
52#include <stdarg.h>
53#include <sys/resource.h>
54#include <time.h>
55#include <regex.h>
56#include <syslog.h>
willy tarreaua1598082005-12-17 13:08:06 +010057#if defined(TPROXY) && defined(NETFILTER)
willy tarreau5cbea6f2005-12-17 12:48:26 +010058#include <linux/netfilter_ipv4.h>
59#endif
willy tarreau0f7af912005-12-17 12:21:26 +010060
willy tarreau12350152005-12-18 01:03:27 +010061#if defined(__dietlibc__)
62#include <strings.h>
63#endif
64
willy tarreau1c2ad212005-12-18 01:11:29 +010065#if defined(ENABLE_POLL)
66#include <sys/poll.h>
67#endif
68
69#if defined(ENABLE_EPOLL)
70#if !defined(USE_MY_EPOLL)
willy tarreauad90a0c2005-12-18 01:09:15 +010071#include <sys/epoll.h>
willy tarreau1c2ad212005-12-18 01:11:29 +010072#else
73#include "include/epoll.h"
74#endif
75#endif
willy tarreauad90a0c2005-12-18 01:09:15 +010076
willy tarreau598da412005-12-18 01:07:29 +010077#include "include/appsession.h"
willy tarreau12350152005-12-18 01:03:27 +010078
willy tarreauc1f47532005-12-18 01:08:26 +010079#define HAPROXY_VERSION "1.2.5"
80#define HAPROXY_DATE "2005/04/24"
willy tarreau0f7af912005-12-17 12:21:26 +010081
82/* this is for libc5 for example */
83#ifndef TCP_NODELAY
84#define TCP_NODELAY 1
85#endif
86
87#ifndef SHUT_RD
88#define SHUT_RD 0
89#endif
90
91#ifndef SHUT_WR
92#define SHUT_WR 1
93#endif
94
willy tarreau0174f312005-12-18 01:02:42 +010095/*
96 * BUFSIZE defines the size of a read and write buffer. It is the maximum
97 * amount of bytes which can be stored by the proxy for each session. However,
98 * when reading HTTP headers, the proxy needs some spare space to add or rewrite
99 * headers if needed. The size of this spare is defined with MAXREWRITE. So it
100 * is not possible to process headers longer than BUFSIZE-MAXREWRITE bytes. By
101 * default, BUFSIZE=16384 bytes and MAXREWRITE=BUFSIZE/2, so the maximum length
102 * of headers accepted is 8192 bytes, which is in line with Apache's limits.
103 */
104#ifndef BUFSIZE
105#define BUFSIZE 16384
106#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100107
108// reserved buffer space for header rewriting
willy tarreau0174f312005-12-18 01:02:42 +0100109#ifndef MAXREWRITE
110#define MAXREWRITE (BUFSIZE / 2)
111#endif
112
willy tarreau9fe663a2005-12-17 13:02:59 +0100113#define REQURI_LEN 1024
willy tarreau8337c6b2005-12-17 13:41:01 +0100114#define CAPTURE_LEN 64
willy tarreau0f7af912005-12-17 12:21:26 +0100115
willy tarreau5cbea6f2005-12-17 12:48:26 +0100116// max # args on a configuration line
willy tarreaue39cd132005-12-17 13:00:18 +0100117#define MAX_LINE_ARGS 40
willy tarreau5cbea6f2005-12-17 12:48:26 +0100118
willy tarreaue39cd132005-12-17 13:00:18 +0100119// max # of added headers per request
120#define MAX_NEWHDR 10
willy tarreau0f7af912005-12-17 12:21:26 +0100121
122// max # of matches per regexp
123#define MAX_MATCH 10
124
willy tarreau0174f312005-12-18 01:02:42 +0100125// cookie delimitor in "prefix" mode. This character is inserted between the
126// persistence cookie and the original value. The '~' is allowed by RFC2965,
127// and should not be too common in server names.
128#ifndef COOKIE_DELIM
129#define COOKIE_DELIM '~'
130#endif
131
willy tarreau0f7af912005-12-17 12:21:26 +0100132#define CONN_RETRIES 3
133
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100135#define DEF_CHKINTR 2000
136#define DEF_FALLTIME 3
137#define DEF_RISETIME 2
willy tarreau2f6ba652005-12-17 13:57:42 +0100138#define DEF_CHECK_REQ "OPTIONS / HTTP/1.0\r\n\r\n"
willy tarreau5cbea6f2005-12-17 12:48:26 +0100139
willy tarreau9fe663a2005-12-17 13:02:59 +0100140/* default connections limit */
141#define DEFAULT_MAXCONN 2000
142
willy tarreau0f7af912005-12-17 12:21:26 +0100143/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
144#define INTBITS 5
145
146/* show stats this every millisecond, 0 to disable */
147#ifndef STATTIME
148#define STATTIME 2000
149#endif
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151/* this reduces the number of calls to select() by choosing appropriate
152 * sheduler precision in milliseconds. It should be near the minimum
153 * time that is needed by select() to collect all events. All timeouts
154 * are rounded up by adding this value prior to pass it to select().
155 */
156#define SCHEDULER_RESOLUTION 9
157
willy tarreau0f7af912005-12-17 12:21:26 +0100158#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
159#define SETNOW(a) (*a=now)
160
willy tarreau9da061b2005-12-17 12:29:56 +0100161/****** string-specific macros and functions ******/
162/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
163#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
164
165/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
166#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
167
willy tarreau0174f312005-12-18 01:02:42 +0100168/* returns 1 only if only zero or one bit is set in X, which means that X is a
169 * power of 2, and 0 otherwise */
170#define POWEROF2(x) (((x) & ((x)-1)) == 0)
willy tarreau9da061b2005-12-17 12:29:56 +0100171/*
172 * copies at most <size-1> chars from <src> to <dst>. Last char is always
173 * set to 0, unless <size> is 0. The number of chars copied is returned
174 * (excluding the terminating zero).
175 * This code has been optimized for size and speed : on x86, it's 45 bytes
176 * long, uses only registers, and consumes only 4 cycles per char.
177 */
willy tarreau750a4722005-12-17 13:21:24 +0100178int strlcpy2(char *dst, const char *src, int size) {
willy tarreau9da061b2005-12-17 12:29:56 +0100179 char *orig = dst;
180 if (size) {
181 while (--size && (*dst = *src)) {
182 src++; dst++;
183 }
184 *dst = 0;
185 }
186 return dst - orig;
187}
willy tarreau9da061b2005-12-17 12:29:56 +0100188
willy tarreau4302f492005-12-18 01:00:37 +0100189/*
190 * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
191 * dynamically allocated. In the first case, <__pool> is updated to point to
192 * the next element in the list.
193 */
194#define pool_alloc_from(__pool, __len) ({ \
195 void *__p; \
196 if ((__p = (__pool)) == NULL) \
197 __p = malloc(((__len) >= sizeof (void *)) ? (__len) : sizeof(void *)); \
198 else { \
199 __pool = *(void **)(__pool); \
200 } \
201 __p; \
202})
203
204/*
205 * Puts a memory area back to the corresponding pool.
206 * Items are chained directly through a pointer that
207 * is written in the beginning of the memory area, so
208 * there's no need for any carrier cell. This implies
209 * that each memory area is at least as big as one
210 * pointer.
211 */
212#define pool_free_to(__pool, __ptr) ({ \
213 *(void **)(__ptr) = (void *)(__pool); \
214 __pool = (void *)(__ptr); \
215})
216
217
willy tarreau0f7af912005-12-17 12:21:26 +0100218#define MEM_OPTIM
219#ifdef MEM_OPTIM
220/*
221 * Returns a pointer to type <type> taken from the
222 * pool <pool_type> or dynamically allocated. In the
223 * first case, <pool_type> is updated to point to the
224 * next element in the list.
225 */
226#define pool_alloc(type) ({ \
willy tarreau4302f492005-12-18 01:00:37 +0100227 void *__p; \
228 if ((__p = pool_##type) == NULL) \
229 __p = malloc(sizeof_##type); \
willy tarreau0f7af912005-12-17 12:21:26 +0100230 else { \
231 pool_##type = *(void **)pool_##type; \
232 } \
willy tarreau4302f492005-12-18 01:00:37 +0100233 __p; \
willy tarreau0f7af912005-12-17 12:21:26 +0100234})
235
236/*
237 * Puts a memory area back to the corresponding pool.
238 * Items are chained directly through a pointer that
239 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100240 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100241 * that each memory area is at least as big as one
242 * pointer.
243 */
244#define pool_free(type, ptr) ({ \
245 *(void **)ptr = (void *)pool_##type; \
246 pool_##type = (void *)ptr; \
247})
248
249#else
250#define pool_alloc(type) (calloc(1,sizeof_##type));
251#define pool_free(type, ptr) (free(ptr));
252#endif /* MEM_OPTIM */
253
willy tarreau5cbea6f2005-12-17 12:48:26 +0100254#define sizeof_task sizeof(struct task)
255#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100256#define sizeof_buffer sizeof(struct buffer)
257#define sizeof_fdtab sizeof(struct fdtab)
willy tarreau12350152005-12-18 01:03:27 +0100258#define sizeof_curappsession CAPTURE_LEN /* current_session pool */
willy tarreau9fe663a2005-12-17 13:02:59 +0100259#define sizeof_requri REQURI_LEN
willy tarreau8337c6b2005-12-17 13:41:01 +0100260#define sizeof_capture CAPTURE_LEN
willy tarreau12350152005-12-18 01:03:27 +0100261#define sizeof_appsess sizeof(struct appsessions)
willy tarreau0f7af912005-12-17 12:21:26 +0100262
willy tarreau5cbea6f2005-12-17 12:48:26 +0100263/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100264#define FD_STCLOSE 0
265#define FD_STLISTEN 1
266#define FD_STCONN 2
267#define FD_STREADY 3
268#define FD_STERROR 4
269
willy tarreau5cbea6f2005-12-17 12:48:26 +0100270/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100271#define TASK_IDLE 0
272#define TASK_RUNNING 1
273
willy tarreau5cbea6f2005-12-17 12:48:26 +0100274/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100275#define PR_STNEW 0
276#define PR_STIDLE 1
277#define PR_STRUN 2
278#define PR_STDISABLED 3
279
willy tarreau5cbea6f2005-12-17 12:48:26 +0100280/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100281#define PR_MODE_TCP 0
282#define PR_MODE_HTTP 1
283#define PR_MODE_HEALTH 2
284
willy tarreau1c2ad212005-12-18 01:11:29 +0100285/* possible actions for the *poll() loops */
286#define POLL_LOOP_ACTION_INIT 0
287#define POLL_LOOP_ACTION_RUN 1
288#define POLL_LOOP_ACTION_CLEAN 2
289
willy tarreau5cbea6f2005-12-17 12:48:26 +0100290/* bits for proxy->options */
willy tarreau0174f312005-12-18 01:02:42 +0100291#define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */
292#define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */
293#define PR_O_COOK_RW 0x00000004 /* rewrite all direct cookies with the right serverid */
294#define PR_O_COOK_IND 0x00000008 /* keep only indirect cookies */
295#define PR_O_COOK_INS 0x00000010 /* insert cookies when not accessing a server directly */
296#define PR_O_COOK_PFX 0x00000020 /* rewrite all cookies by prefixing the right serverid */
297#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
298#define PR_O_BALANCE_RR 0x00000040 /* balance in round-robin mode */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100299#define PR_O_BALANCE (PR_O_BALANCE_RR)
willy tarreau0174f312005-12-18 01:02:42 +0100300#define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */
301#define PR_O_FWDFOR 0x00000100 /* insert x-forwarded-for with client address */
302#define PR_O_BIND_SRC 0x00000200 /* bind to a specific source address when connect()ing */
303#define PR_O_NULLNOLOG 0x00000400 /* a connect without request will not be logged */
304#define PR_O_COOK_NOC 0x00000800 /* add a 'Cache-control' header with the cookie */
305#define PR_O_COOK_POST 0x00001000 /* don't insert cookies for requests other than a POST */
306#define PR_O_HTTP_CHK 0x00002000 /* use HTTP 'OPTIONS' method to check server health */
307#define PR_O_PERSIST 0x00004000 /* server persistence stays effective even when server is down */
308#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
309#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
310#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100311
willy tarreaue39cd132005-12-17 13:00:18 +0100312/* various session flags */
willy tarreau036e1ce2005-12-17 13:46:33 +0100313#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
314#define SN_CLDENY 0x00000002 /* a client header matches a deny regex */
315#define SN_CLALLOW 0x00000004 /* a client header matches an allow regex */
316#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
317#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
318#define SN_POST 0x00000020 /* the request was an HTTP POST */
319
320#define SN_CK_NONE 0x00000000 /* this session had no cookie */
321#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
322#define SN_CK_DOWN 0x00000080 /* this session had cookie matching a down server */
323#define SN_CK_VALID 0x000000C0 /* this session had cookie matching a valid server */
324#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
325#define SN_CK_SHIFT 6 /* bit shift */
326
327#define SN_ERR_CLITO 0x00000100 /* client time-out */
328#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
329#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
330#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
331#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
332#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
333#define SN_ERR_SHIFT 8 /* bit shift */
334
335#define SN_FINST_R 0x00001000 /* session ended during client request */
336#define SN_FINST_C 0x00002000 /* session ended during server connect */
337#define SN_FINST_H 0x00003000 /* session ended during server headers */
338#define SN_FINST_D 0x00004000 /* session ended during data phase */
339#define SN_FINST_L 0x00005000 /* session ended while pushing last data to client */
340#define SN_FINST_MASK 0x00007000 /* mask to get only final session state flags */
341#define SN_FINST_SHIFT 12 /* bit shift */
342
343#define SN_SCK_NONE 0x00000000 /* no set-cookie seen for the server cookie */
344#define SN_SCK_DELETED 0x00010000 /* existing set-cookie deleted or changed */
345#define SN_SCK_INSERTED 0x00020000 /* new set-cookie inserted or changed existing one */
346#define SN_SCK_SEEN 0x00040000 /* set-cookie seen for the server cookie */
347#define SN_SCK_MASK 0x00070000 /* mask to get the set-cookie field */
willy tarreau97f58572005-12-18 00:53:44 +0100348#define SN_SCK_ANY 0x00080000 /* at least one set-cookie seen (not to be counted) */
willy tarreau036e1ce2005-12-17 13:46:33 +0100349#define SN_SCK_SHIFT 16 /* bit shift */
350
willy tarreau97f58572005-12-18 00:53:44 +0100351#define SN_CACHEABLE 0x00100000 /* at least part of the response is cacheable */
352#define SN_CACHE_COOK 0x00200000 /* a cookie in the response is cacheable */
353#define SN_CACHE_SHIFT 20 /* bit shift */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100354
355/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100356#define CL_STHEADERS 0
357#define CL_STDATA 1
358#define CL_STSHUTR 2
359#define CL_STSHUTW 3
360#define CL_STCLOSE 4
361
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100363#define SV_STIDLE 0
364#define SV_STCONN 1
365#define SV_STHEADERS 2
366#define SV_STDATA 3
367#define SV_STSHUTR 4
368#define SV_STSHUTW 5
369#define SV_STCLOSE 6
370
371/* result of an I/O event */
372#define RES_SILENT 0 /* didn't happen */
373#define RES_DATA 1 /* data were sent or received */
374#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
375#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
376
willy tarreau9fe663a2005-12-17 13:02:59 +0100377/* modes of operation (global.mode) */
willy tarreau0f7af912005-12-17 12:21:26 +0100378#define MODE_DEBUG 1
379#define MODE_STATS 2
380#define MODE_LOG 4
381#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100382#define MODE_QUIET 16
willy tarreaudd07e972005-12-18 00:48:48 +0100383#define MODE_CHECK 32
willy tarreau982249e2005-12-18 00:57:06 +0100384#define MODE_VERBOSE 64
willy tarreau5cbea6f2005-12-17 12:48:26 +0100385
386/* server flags */
willy tarreaua41a8b42005-12-17 14:02:24 +0100387#define SRV_RUNNING 1 /* the server is UP */
388#define SRV_BACKUP 2 /* this server is a backup server */
389#define SRV_MAPPORTS 4 /* this server uses mapped ports */
willy tarreau0174f312005-12-18 01:02:42 +0100390#define SRV_BIND_SRC 8 /* this server uses a specific source address */
willy tarreau0f7af912005-12-17 12:21:26 +0100391
willy tarreaue39cd132005-12-17 13:00:18 +0100392/* what to do when a header matches a regex */
393#define ACT_ALLOW 0 /* allow the request */
394#define ACT_REPLACE 1 /* replace the matching header */
395#define ACT_REMOVE 2 /* remove the matching header */
396#define ACT_DENY 3 /* deny the request */
willy tarreau036e1ce2005-12-17 13:46:33 +0100397#define ACT_PASS 4 /* pass this header without allowing or denying the request */
willy tarreaue39cd132005-12-17 13:00:18 +0100398
willy tarreau9fe663a2005-12-17 13:02:59 +0100399/* configuration sections */
400#define CFG_NONE 0
401#define CFG_GLOBAL 1
402#define CFG_LISTEN 2
403
willy tarreaua1598082005-12-17 13:08:06 +0100404/* fields that need to be logged. They appear as flags in session->logs.logwait */
willy tarreau9fe663a2005-12-17 13:02:59 +0100405#define LW_DATE 1 /* date */
406#define LW_CLIP 2 /* CLient IP */
407#define LW_SVIP 4 /* SerVer IP */
408#define LW_SVID 8 /* server ID */
409#define LW_REQ 16 /* http REQuest */
410#define LW_RESP 32 /* http RESPonse */
411#define LW_PXIP 64 /* proxy IP */
412#define LW_PXID 128 /* proxy ID */
willy tarreaua1598082005-12-17 13:08:06 +0100413#define LW_BYTES 256 /* bytes read from server */
willy tarreau4302f492005-12-18 01:00:37 +0100414#define LW_COOKIE 512 /* captured cookie */
415#define LW_REQHDR 1024 /* request header(s) */
416#define LW_RSPHDR 2048 /* response header(s) */
willy tarreau9fe663a2005-12-17 13:02:59 +0100417
willy tarreau0f7af912005-12-17 12:21:26 +0100418/*********************************************************************/
419
420#define LIST_HEAD(a) ((void *)(&(a)))
421
422/*********************************************************************/
423
willy tarreau4302f492005-12-18 01:00:37 +0100424struct cap_hdr {
425 struct cap_hdr *next;
426 char *name; /* header name, case insensitive */
427 int namelen; /* length of the header name, to speed-up lookups */
428 int len; /* capture length, not including terminal zero */
429 int index; /* index in the output array */
430 void *pool; /* pool of pre-allocated memory area of (len+1) bytes */
431};
432
willy tarreau0f7af912005-12-17 12:21:26 +0100433struct hdr_exp {
willy tarreaue39cd132005-12-17 13:00:18 +0100434 struct hdr_exp *next;
435 regex_t *preg; /* expression to look for */
436 int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
437 char *replace; /* expression to set instead */
willy tarreau0f7af912005-12-17 12:21:26 +0100438};
439
440struct buffer {
441 unsigned int l; /* data length */
442 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100443 char *rlim; /* read limit, used for header rewriting */
willy tarreaua1598082005-12-17 13:08:06 +0100444 unsigned long long total; /* total data read */
willy tarreau0f7af912005-12-17 12:21:26 +0100445 char data[BUFSIZE];
446};
447
448struct server {
449 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100450 int state; /* server state (SRV_*) */
451 int cklen; /* the len of the cookie, to speed up checks */
452 char *cookie; /* the id set in the cookie */
453 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100454 struct sockaddr_in addr; /* the address to connect to */
willy tarreau0174f312005-12-18 01:02:42 +0100455 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreaua41a8b42005-12-17 14:02:24 +0100456 short check_port; /* the port to use for the health checks */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100457 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100458 int rise, fall; /* time in iterations */
459 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100460 int result; /* 0 = connect OK, -1 = connect KO */
461 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau535ae7a2005-12-17 12:58:00 +0100462 struct proxy *proxy; /* the proxy this server belongs to */
willy tarreau0f7af912005-12-17 12:21:26 +0100463};
464
willy tarreau5cbea6f2005-12-17 12:48:26 +0100465/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100466struct task {
467 struct task *next, *prev; /* chaining ... */
468 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100469 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100470 int state; /* task state : IDLE or RUNNING */
471 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100472 int (*process)(struct task *t); /* the function which processes the task */
473 void *context; /* the task's context */
474};
475
476/* WARNING: if new fields are added, they must be initialized in event_accept() */
477struct session {
478 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100479 /* application specific below */
480 struct timeval crexpire; /* expiration date for a client read */
481 struct timeval cwexpire; /* expiration date for a client write */
482 struct timeval srexpire; /* expiration date for a server read */
483 struct timeval swexpire; /* expiration date for a server write */
484 struct timeval cnexpire; /* expiration date for a connect */
485 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
486 struct proxy *proxy; /* the proxy this socket belongs to */
487 int cli_fd; /* the client side fd */
488 int srv_fd; /* the server side fd */
489 int cli_state; /* state of the client side */
490 int srv_state; /* state of the server side */
491 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100492 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100493 struct buffer *req; /* request buffer */
494 struct buffer *rep; /* response buffer */
willy tarreau8a86dbf2005-12-18 00:45:59 +0100495 struct sockaddr_storage cli_addr; /* the client address */
willy tarreau0f7af912005-12-17 12:21:26 +0100496 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100497 struct server *srv; /* the server being used */
willy tarreau4302f492005-12-18 01:00:37 +0100498 char **req_cap; /* array of captured request headers (may be NULL) */
499 char **rsp_cap; /* array of captured response headers (may be NULL) */
willy tarreaua1598082005-12-17 13:08:06 +0100500 struct {
501 int logwait; /* log fields waiting to be collected : LW_* */
502 struct timeval tv_accept; /* date of the accept() (beginning of the session) */
503 long t_request; /* delay before the end of the request arrives, -1 if never occurs */
504 long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
505 long t_data; /* delay before the first data byte from the server ... */
506 unsigned long t_close; /* total session duration */
507 char *uri; /* first line if log needed, NULL otherwise */
willy tarreau8337c6b2005-12-17 13:41:01 +0100508 char *cli_cookie; /* cookie presented by the client, in capture mode */
509 char *srv_cookie; /* cookie presented by the server, in capture mode */
willy tarreaua1598082005-12-17 13:08:06 +0100510 int status; /* HTTP status from the server, negative if from proxy */
511 long long bytes; /* number of bytes transferred from the server */
512 } logs;
willy tarreau2f6ba652005-12-17 13:57:42 +0100513 unsigned int uniq_id; /* unique ID used for the traces */
willy tarreau0f7af912005-12-17 12:21:26 +0100514};
515
willy tarreaua41a8b42005-12-17 14:02:24 +0100516struct listener {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100517 int fd; /* the listen socket */
518 struct sockaddr_storage addr; /* the address we listen to */
519 struct listener *next; /* next address or NULL */
willy tarreaua41a8b42005-12-17 14:02:24 +0100520};
521
522
willy tarreau0f7af912005-12-17 12:21:26 +0100523struct proxy {
willy tarreaua41a8b42005-12-17 14:02:24 +0100524 struct listener *listen; /* the listen addresses and sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100525 int state; /* proxy state */
willy tarreau0f7af912005-12-17 12:21:26 +0100526 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100527 struct server *srv, *cursrv; /* known servers, current server */
528 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100529 char *cookie_name; /* name of the cookie to look for */
willy tarreau12350152005-12-18 01:03:27 +0100530 int cookie_len; /* strlen(cookie_name), computed only once */
531 char *appsession_name; /* name of the cookie to look for */
532 int appsession_name_len; /* strlen(appsession_name), computed only once */
533 int appsession_len; /* length of the appsession cookie value to be used */
534 int appsession_timeout;
535 CHTbl htbl_proxy; /* Per Proxy hashtable */
willy tarreau8337c6b2005-12-17 13:41:01 +0100536 char *capture_name; /* beginning of the name of the cookie to capture */
537 int capture_namelen; /* length of the cookie name to match */
538 int capture_len; /* length of the string to be captured */
willy tarreau0f7af912005-12-17 12:21:26 +0100539 int clitimeout; /* client I/O timeout (in milliseconds) */
540 int srvtimeout; /* server I/O timeout (in milliseconds) */
541 int contimeout; /* connect timeout (in milliseconds) */
542 char *id; /* proxy id */
543 int nbconn; /* # of active sessions */
544 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100545 int conn_retries; /* maximum number of connect retries */
546 int options; /* PR_O_REDISP, PR_O_TRANSP */
547 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreaua1598082005-12-17 13:08:06 +0100548 struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
willy tarreau0f7af912005-12-17 12:21:26 +0100549 struct proxy *next;
550 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
551 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
willy tarreau8337c6b2005-12-17 13:41:01 +0100552 int loglev1, loglev2; /* log level for each server, 7 by default */
willy tarreau9fe663a2005-12-17 13:02:59 +0100553 int to_log; /* things to be logged (LW_*) */
willy tarreau0f7af912005-12-17 12:21:26 +0100554 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreaue39cd132005-12-17 13:00:18 +0100555 int nb_reqadd, nb_rspadd;
556 struct hdr_exp *req_exp; /* regular expressions for request headers */
557 struct hdr_exp *rsp_exp; /* regular expressions for response headers */
willy tarreau4302f492005-12-18 01:00:37 +0100558 int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
559 struct cap_hdr *req_cap; /* chained list of request headers to be captured */
560 struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */
561 void *req_cap_pool, *rsp_cap_pool; /* pools of pre-allocated char ** used to build the sessions */
willy tarreaue39cd132005-12-17 13:00:18 +0100562 char *req_add[MAX_NEWHDR], *rsp_add[MAX_NEWHDR]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100563 int grace; /* grace time after stop request */
willy tarreau2f6ba652005-12-17 13:57:42 +0100564 char *check_req; /* HTTP request to use if PR_O_HTTP_CHK is set, else NULL */
565 int check_len; /* Length of the HTTP request */
willy tarreau8337c6b2005-12-17 13:41:01 +0100566 struct {
567 char *msg400; /* message for error 400 */
568 int len400; /* message length for error 400 */
569 char *msg403; /* message for error 403 */
570 int len403; /* message length for error 403 */
571 char *msg408; /* message for error 408 */
572 int len408; /* message length for error 408 */
573 char *msg500; /* message for error 500 */
574 int len500; /* message length for error 500 */
575 char *msg502; /* message for error 502 */
576 int len502; /* message length for error 502 */
577 char *msg503; /* message for error 503 */
578 int len503; /* message length for error 503 */
579 char *msg504; /* message for error 504 */
580 int len504; /* message length for error 504 */
581 } errmsg;
willy tarreau0f7af912005-12-17 12:21:26 +0100582};
583
584/* info about one given fd */
585struct fdtab {
586 int (*read)(int fd); /* read function */
587 int (*write)(int fd); /* write function */
588 struct task *owner; /* the session (or proxy) associated with this fd */
589 int state; /* the state of this fd */
590};
591
592/*********************************************************************/
593
willy tarreau0f7af912005-12-17 12:21:26 +0100594int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
willy tarreau0f7af912005-12-17 12:21:26 +0100595char *cfg_cfgfile = NULL; /* configuration file */
596char *progname = NULL; /* program name */
597int pid; /* current process id */
willy tarreau9fe663a2005-12-17 13:02:59 +0100598
599/* global options */
600static struct {
601 int uid;
602 int gid;
603 int nbproc;
604 int maxconn;
605 int maxsock; /* max # of sockets */
606 int mode;
607 char *chroot;
willy tarreaufe2c5c12005-12-17 14:14:34 +0100608 char *pidfile;
willy tarreau9fe663a2005-12-17 13:02:59 +0100609 int logfac1, logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +0100610 int loglev1, loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +0100611 struct sockaddr_in logsrv1, logsrv2;
612} global = {
613 logfac1 : -1,
614 logfac2 : -1,
willy tarreau8337c6b2005-12-17 13:41:01 +0100615 loglev1 : 7, /* max syslog level : debug */
616 loglev2 : 7,
willy tarreau9fe663a2005-12-17 13:02:59 +0100617 /* others NULL OK */
618};
619
willy tarreau0f7af912005-12-17 12:21:26 +0100620/*********************************************************************/
621
willy tarreau1c2ad212005-12-18 01:11:29 +0100622fd_set *StaticReadEvent,
willy tarreau0f7af912005-12-17 12:21:26 +0100623 *StaticWriteEvent;
624
willy tarreau1c2ad212005-12-18 01:11:29 +0100625int cfg_use_epoll = 0; /* use epoll() instead of select() ? */
626int cfg_use_poll = 0; /* use poll() instead of select() ? */
willy tarreauad90a0c2005-12-18 01:09:15 +0100627
willy tarreau0f7af912005-12-17 12:21:26 +0100628void **pool_session = NULL,
629 **pool_buffer = NULL,
630 **pool_fdtab = NULL,
willy tarreau9fe663a2005-12-17 13:02:59 +0100631 **pool_requri = NULL,
willy tarreau8337c6b2005-12-17 13:41:01 +0100632 **pool_task = NULL,
willy tarreau12350152005-12-18 01:03:27 +0100633 **pool_capture = NULL,
634 **pool_appsess = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100635
636struct proxy *proxy = NULL; /* list of all existing proxies */
637struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100638struct task *rq = NULL; /* global run queue */
639struct task wait_queue = { /* global wait queue */
640 prev:LIST_HEAD(wait_queue),
641 next:LIST_HEAD(wait_queue)
642};
willy tarreau0f7af912005-12-17 12:21:26 +0100643
willy tarreau0f7af912005-12-17 12:21:26 +0100644static int totalconn = 0; /* total # of terminated sessions */
645static int actconn = 0; /* # of active sessions */
646static int maxfd = 0; /* # of the highest fd + 1 */
647static int listeners = 0; /* # of listeners */
648static int stopping = 0; /* non zero means stopping in progress */
649static struct timeval now = {0,0}; /* the current date at any moment */
willy tarreaua41a8b42005-12-17 14:02:24 +0100650static struct proxy defproxy; /* fake proxy used to assign default values on all instances */
willy tarreau0f7af912005-12-17 12:21:26 +0100651
652static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
willy tarreau750a4722005-12-17 13:21:24 +0100653/* this is used to drain data, and as a temporary buffer for sprintf()... */
willy tarreau0f7af912005-12-17 12:21:26 +0100654static char trash[BUFSIZE];
655
willy tarreaudd07e972005-12-18 00:48:48 +0100656const int zero = 0;
657const int one = 1;
658
willy tarreau0f7af912005-12-17 12:21:26 +0100659/*
willy tarreau036e1ce2005-12-17 13:46:33 +0100660 * Syslog facilities and levels. Conforming to RFC3164.
willy tarreau0f7af912005-12-17 12:21:26 +0100661 */
662
663#define MAX_SYSLOG_LEN 1024
664#define NB_LOG_FACILITIES 24
665const char *log_facilities[NB_LOG_FACILITIES] = {
666 "kern", "user", "mail", "daemon",
667 "auth", "syslog", "lpr", "news",
668 "uucp", "cron", "auth2", "ftp",
669 "ntp", "audit", "alert", "cron2",
670 "local0", "local1", "local2", "local3",
671 "local4", "local5", "local6", "local7"
672};
673
674
675#define NB_LOG_LEVELS 8
676const char *log_levels[NB_LOG_LEVELS] = {
677 "emerg", "alert", "crit", "err",
678 "warning", "notice", "info", "debug"
679};
680
681#define SYSLOG_PORT 514
682
683const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
684 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
willy tarreau036e1ce2005-12-17 13:46:33 +0100685
686const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
687const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
688const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
689const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
690 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
691 unknown, Set-cookie Rewritten */
692
willy tarreau0f7af912005-12-17 12:21:26 +0100693#define MAX_HOSTNAME_LEN 32
694static char hostname[MAX_HOSTNAME_LEN] = "";
695
willy tarreau8337c6b2005-12-17 13:41:01 +0100696const char *HTTP_302 =
697 "HTTP/1.0 302 Found\r\n"
698 "Cache-Control: no-cache\r\n"
699 "Connection: close\r\n"
700 "Location: "; /* not terminated since it will be concatenated with the URL */
701
willy tarreauc1f47532005-12-18 01:08:26 +0100702/* same as 302 except that the browser MUST retry with the GET method */
703const char *HTTP_303 =
704 "HTTP/1.0 303 See Other\r\n"
705 "Cache-Control: no-cache\r\n"
706 "Connection: close\r\n"
707 "Location: "; /* not terminated since it will be concatenated with the URL */
708
willy tarreaua1598082005-12-17 13:08:06 +0100709const char *HTTP_400 =
710 "HTTP/1.0 400 Bad request\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100711 "Cache-Control: no-cache\r\n"
712 "Connection: close\r\n"
713 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100714 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100715
willy tarreaua1598082005-12-17 13:08:06 +0100716const char *HTTP_403 =
717 "HTTP/1.0 403 Forbidden\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100718 "Cache-Control: no-cache\r\n"
719 "Connection: close\r\n"
720 "\r\n"
willy tarreau750a4722005-12-17 13:21:24 +0100721 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
722
willy tarreau8337c6b2005-12-17 13:41:01 +0100723const char *HTTP_408 =
724 "HTTP/1.0 408 Request Time-out\r\n"
725 "Cache-Control: no-cache\r\n"
726 "Connection: close\r\n"
727 "\r\n"
728 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n";
729
willy tarreau750a4722005-12-17 13:21:24 +0100730const char *HTTP_500 =
731 "HTTP/1.0 500 Server Error\r\n"
732 "Cache-Control: no-cache\r\n"
733 "Connection: close\r\n"
734 "\r\n"
735 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
willy tarreaue39cd132005-12-17 13:00:18 +0100736
737const char *HTTP_502 =
willy tarreau8337c6b2005-12-17 13:41:01 +0100738 "HTTP/1.0 502 Bad Gateway\r\n"
willy tarreaue39cd132005-12-17 13:00:18 +0100739 "Cache-Control: no-cache\r\n"
740 "Connection: close\r\n"
741 "\r\n"
willy tarreau8337c6b2005-12-17 13:41:01 +0100742 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n";
743
744const char *HTTP_503 =
745 "HTTP/1.0 503 Service Unavailable\r\n"
746 "Cache-Control: no-cache\r\n"
747 "Connection: close\r\n"
748 "\r\n"
749 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n";
750
751const char *HTTP_504 =
752 "HTTP/1.0 504 Gateway Time-out\r\n"
753 "Cache-Control: no-cache\r\n"
754 "Connection: close\r\n"
755 "\r\n"
756 "<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 +0100757
willy tarreau0f7af912005-12-17 12:21:26 +0100758/*********************************************************************/
759/* statistics ******************************************************/
760/*********************************************************************/
761
willy tarreau750a4722005-12-17 13:21:24 +0100762#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +0100763static int stats_tsk_lsrch, stats_tsk_rsrch,
764 stats_tsk_good, stats_tsk_right, stats_tsk_left,
765 stats_tsk_new, stats_tsk_nsrch;
willy tarreau750a4722005-12-17 13:21:24 +0100766#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100767
768
769/*********************************************************************/
willy tarreau750a4722005-12-17 13:21:24 +0100770/* debugging *******************************************************/
771/*********************************************************************/
772#ifdef DEBUG_FULL
773static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
774static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
775#endif
776
777/*********************************************************************/
willy tarreau0f7af912005-12-17 12:21:26 +0100778/* function prototypes *********************************************/
779/*********************************************************************/
780
781int event_accept(int fd);
782int event_cli_read(int fd);
783int event_cli_write(int fd);
784int event_srv_read(int fd);
785int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100786int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100787
willy tarreau12350152005-12-18 01:03:27 +0100788static int appsession_task_init(void);
789static int appsession_init(void);
790static int appsession_refresh(struct task *t);
791
willy tarreau0f7af912005-12-17 12:21:26 +0100792/*********************************************************************/
793/* general purpose functions ***************************************/
794/*********************************************************************/
795
796void display_version() {
797 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau0174f312005-12-18 01:02:42 +0100798 printf("Copyright 2000-2005 Willy Tarreau <w@w.ods.org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100799}
800
801/*
802 * This function prints the command line usage and exits
803 */
804void usage(char *name) {
805 display_version();
806 fprintf(stderr,
willy tarreau982249e2005-12-18 00:57:06 +0100807 "Usage : %s -f <cfgfile> [ -vdV"
willy tarreau0f7af912005-12-17 12:21:26 +0100808#if STATTIME > 0
809 "sl"
810#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +0100811 "D ] [ -n <maxconn> ] [ -N <maxpconn> ] [ -p <pidfile> ]\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100812 " -v displays version\n"
813 " -d enters debug mode\n"
willy tarreau982249e2005-12-18 00:57:06 +0100814 " -V enters verbose mode (disables quiet mode)\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100815#if STATTIME > 0
816 " -s enables statistics output\n"
817 " -l enables long statistics format\n"
818#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100819 " -D goes daemon ; implies -q\n"
820 " -q quiet mode : don't display messages\n"
willy tarreaudd07e972005-12-18 00:48:48 +0100821 " -c check mode : only check config file and exit\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100822 " -n sets the maximum total # of connections (%d)\n"
willy tarreaufe2c5c12005-12-17 14:14:34 +0100823 " -N sets the default, per-proxy maximum # of connections (%d)\n"
willy tarreauad90a0c2005-12-18 01:09:15 +0100824 " -p writes pids of all children to this file\n"
willy tarreau1c2ad212005-12-18 01:11:29 +0100825#if defined(ENABLE_EPOLL)
826 " -E tries to use epoll() instead of select()\n"
827#endif
828#if defined(ENABLE_POLL)
829 " -P tries to use poll() instead of select()\n"
830#endif
willy tarreauad90a0c2005-12-18 01:09:15 +0100831 "\n",
willy tarreau9fe663a2005-12-17 13:02:59 +0100832 name, DEFAULT_MAXCONN, cfg_maxpconn);
willy tarreau0f7af912005-12-17 12:21:26 +0100833 exit(1);
834}
835
836
837/*
838 * Displays the message on stderr with the date and pid.
839 */
840void Alert(char *fmt, ...) {
841 va_list argp;
842 struct timeval tv;
843 struct tm *tm;
844
willy tarreau982249e2005-12-18 00:57:06 +0100845 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100846 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100847
willy tarreau5cbea6f2005-12-17 12:48:26 +0100848 gettimeofday(&tv, NULL);
849 tm=localtime(&tv.tv_sec);
850 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100851 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100852 vfprintf(stderr, fmt, argp);
853 fflush(stderr);
854 va_end(argp);
855 }
willy tarreau0f7af912005-12-17 12:21:26 +0100856}
857
858
859/*
860 * Displays the message on stderr with the date and pid.
861 */
862void Warning(char *fmt, ...) {
863 va_list argp;
864 struct timeval tv;
865 struct tm *tm;
866
willy tarreau982249e2005-12-18 00:57:06 +0100867 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100868 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100869
willy tarreau5cbea6f2005-12-17 12:48:26 +0100870 gettimeofday(&tv, NULL);
871 tm=localtime(&tv.tv_sec);
872 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
willy tarreaua1598082005-12-17 13:08:06 +0100873 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)getpid());
willy tarreau5cbea6f2005-12-17 12:48:26 +0100874 vfprintf(stderr, fmt, argp);
875 fflush(stderr);
876 va_end(argp);
877 }
878}
879
880/*
881 * Displays the message on <out> only if quiet mode is not set.
882 */
883void qfprintf(FILE *out, char *fmt, ...) {
884 va_list argp;
885
willy tarreau982249e2005-12-18 00:57:06 +0100886 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100887 va_start(argp, fmt);
888 vfprintf(out, fmt, argp);
889 fflush(out);
890 va_end(argp);
891 }
willy tarreau0f7af912005-12-17 12:21:26 +0100892}
893
894
895/*
896 * converts <str> to a struct sockaddr_in* which is locally allocated.
897 * The format is "addr:port", where "addr" can be empty or "*" to indicate
898 * INADDR_ANY.
899 */
900struct sockaddr_in *str2sa(char *str) {
901 static struct sockaddr_in sa;
902 char *c;
903 int port;
904
willy tarreaua1598082005-12-17 13:08:06 +0100905 memset(&sa, 0, sizeof(sa));
willy tarreau0f7af912005-12-17 12:21:26 +0100906 str=strdup(str);
907
908 if ((c=strrchr(str,':')) != NULL) {
909 *c++=0;
910 port=atol(c);
911 }
912 else
913 port=0;
914
915 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
916 sa.sin_addr.s_addr = INADDR_ANY;
917 }
willy tarreau8a86dbf2005-12-18 00:45:59 +0100918 else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
willy tarreau0f7af912005-12-17 12:21:26 +0100919 struct hostent *he;
920
921 if ((he = gethostbyname(str)) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +0100922 Alert("Invalid server name: '%s'\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100923 }
924 else
925 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
926 }
927 sa.sin_port=htons(port);
928 sa.sin_family=AF_INET;
929
930 free(str);
931 return &sa;
932}
933
willy tarreau9fe663a2005-12-17 13:02:59 +0100934
935/*
willy tarreaua41a8b42005-12-17 14:02:24 +0100936 * converts <str> to a list of listeners which are dynamically allocated.
937 * The format is "{addr|'*'}:port[-end][,{addr|'*'}:port[-end]]*", where :
938 * - <addr> can be empty or "*" to indicate INADDR_ANY ;
939 * - <port> is a numerical port from 1 to 65535 ;
940 * - <end> indicates to use the range from <port> to <end> instead (inclusive).
941 * This can be repeated as many times as necessary, separated by a coma.
942 * The <tail> argument is a pointer to a current list which should be appended
943 * to the tail of the new list. The pointer to the new list is returned.
944 */
945struct listener *str2listener(char *str, struct listener *tail) {
946 struct listener *l;
947 char *c, *next, *range, *dupstr;
948 int port, end;
949
950 next = dupstr = strdup(str);
willy tarreau4302f492005-12-18 01:00:37 +0100951
willy tarreaua41a8b42005-12-17 14:02:24 +0100952 while (next && *next) {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100953 struct sockaddr_storage ss;
954
willy tarreaua41a8b42005-12-17 14:02:24 +0100955 str = next;
956 /* 1) look for the end of the first address */
957 if ((next = strrchr(str, ',')) != NULL) {
958 *next++ = 0;
959 }
960
willy tarreau8a86dbf2005-12-18 00:45:59 +0100961 /* 2) look for the addr/port delimiter, it's the last colon. */
962 if ((range = strrchr(str, ':')) == NULL) {
963 Alert("Missing port number: '%s'\n", str);
964 }
965
966 *range++ = 0;
967
968 if (strrchr(str, ':') != NULL) {
969 /* IPv6 address contains ':' */
970 memset(&ss, 0, sizeof(ss));
971 ss.ss_family = AF_INET6;
972
973 if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
974 Alert("Invalid server address: '%s'\n", str);
975 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100976 }
977 else {
willy tarreau8a86dbf2005-12-18 00:45:59 +0100978 memset(&ss, 0, sizeof(ss));
979 ss.ss_family = AF_INET;
980
981 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
982 ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
983 }
984 else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
985 struct hostent *he;
986
987 if ((he = gethostbyname(str)) == NULL) {
988 Alert("Invalid server name: '%s'\n", str);
989 }
990 else
991 ((struct sockaddr_in *)&ss)->sin_addr =
992 *(struct in_addr *) *(he->h_addr_list);
993 }
994 }
willy tarreaua41a8b42005-12-17 14:02:24 +0100995
996 /* 3) look for the port-end delimiter */
997 if ((c = strchr(range, '-')) != NULL) {
998 *c++ = 0;
999 end = atol(c);
1000 }
1001 else {
1002 end = atol(range);
1003 }
1004
1005 for (port = atol(range); port <= end; port++) {
1006 l = (struct listener *)calloc(1, sizeof(struct listener));
1007 l->next = tail;
1008 tail = l;
1009
willy tarreau8a86dbf2005-12-18 00:45:59 +01001010 l->addr = ss;
1011 if (ss.ss_family == AF_INET6)
1012 ((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
1013 else
1014 ((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
1015
willy tarreaua41a8b42005-12-17 14:02:24 +01001016 } /* end for(port) */
1017 } /* end while(next) */
1018 free(dupstr);
1019 return tail;
1020}
1021
willy tarreau4302f492005-12-18 01:00:37 +01001022
1023#define FD_SETS_ARE_BITFIELDS
1024#ifdef FD_SETS_ARE_BITFIELDS
1025/*
1026 * This map is used with all the FD_* macros to check whether a particular bit
1027 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
1028 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
1029 * byte should be encoded. Be careful to always pass bytes from 0 to 255
1030 * exclusively to the macros.
1031 */
1032fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1033fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
1034
1035#else
1036#error "Check if your OS uses bitfields for fd_sets"
1037#endif
1038
1039/* will try to encode the string <string> replacing all characters tagged in
1040 * <map> with the hexadecimal representation of their ASCII-code (2 digits)
1041 * prefixed by <escape>, and will store the result between <start> (included
1042 *) and <stop> (excluded), and will always terminate the string with a '\0'
1043 * before <stop>. The position of the '\0' is returned if the conversion
1044 * completes. If bytes are missing between <start> and <stop>, then the
1045 * conversion will be incomplete and truncated. If <stop> <= <start>, the '\0'
1046 * cannot even be stored so we return <start> without writing the 0.
1047 * The input string must also be zero-terminated.
1048 */
1049char hextab[16] = "0123456789ABCDEF";
1050char *encode_string(char *start, char *stop,
1051 const char escape, const fd_set *map,
1052 const char *string)
1053{
1054 if (start < stop) {
1055 stop--; /* reserve one byte for the final '\0' */
1056 while (start < stop && *string != 0) {
1057 if (!FD_ISSET((unsigned char)(*string), map))
1058 *start++ = *string;
1059 else {
1060 if (start + 3 >= stop)
1061 break;
1062 *start++ = escape;
1063 *start++ = hextab[(*string >> 4) & 15];
1064 *start++ = hextab[*string & 15];
1065 }
1066 string++;
1067 }
1068 *start = '\0';
1069 }
1070 return start;
1071}
willy tarreaua41a8b42005-12-17 14:02:24 +01001072
1073/*
willy tarreau9fe663a2005-12-17 13:02:59 +01001074 * This function sends a syslog message to both log servers of a proxy,
1075 * or to global log servers if the proxy is NULL.
1076 * It also tries not to waste too much time computing the message header.
1077 * It doesn't care about errors nor does it report them.
willy tarreau9fe663a2005-12-17 13:02:59 +01001078 */
1079void send_log(struct proxy *p, int level, char *message, ...) {
1080 static int logfd = -1; /* syslog UDP socket */
1081 static long tvsec = -1; /* to force the string to be initialized */
1082 struct timeval tv;
1083 va_list argp;
1084 static char logmsg[MAX_SYSLOG_LEN];
1085 static char *dataptr = NULL;
1086 int fac_level;
1087 int hdr_len, data_len;
1088 struct sockaddr_in *sa[2];
willy tarreau8337c6b2005-12-17 13:41:01 +01001089 int facilities[2], loglevel[2];
willy tarreau9fe663a2005-12-17 13:02:59 +01001090 int nbloggers = 0;
1091 char *log_ptr;
1092
1093 if (logfd < 0) {
1094 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1095 return;
1096 }
1097
1098 if (level < 0 || progname == NULL || message == NULL)
1099 return;
1100
1101 gettimeofday(&tv, NULL);
willy tarreauc29948c2005-12-17 13:10:27 +01001102 if (tv.tv_sec != tvsec || dataptr == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01001103 /* this string is rebuild only once a second */
1104 struct tm *tm = localtime(&tv.tv_sec);
1105 tvsec = tv.tv_sec;
1106
willy tarreauc29948c2005-12-17 13:10:27 +01001107 hdr_len = snprintf(logmsg, sizeof(logmsg),
1108 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
1109 monthname[tm->tm_mon],
1110 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1111 progname, pid);
1112 /* WARNING: depending upon implementations, snprintf may return
1113 * either -1 or the number of bytes that would be needed to store
1114 * the total message. In both cases, we must adjust it.
willy tarreau9fe663a2005-12-17 13:02:59 +01001115 */
willy tarreauc29948c2005-12-17 13:10:27 +01001116 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
1117 hdr_len = sizeof(logmsg);
1118
1119 dataptr = logmsg + hdr_len;
willy tarreau9fe663a2005-12-17 13:02:59 +01001120 }
1121
1122 va_start(argp, message);
1123 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001124 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
1125 data_len = logmsg + sizeof(logmsg) - dataptr;
willy tarreau9fe663a2005-12-17 13:02:59 +01001126 va_end(argp);
willy tarreauc29948c2005-12-17 13:10:27 +01001127 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
willy tarreau9fe663a2005-12-17 13:02:59 +01001128
1129 if (p == NULL) {
1130 if (global.logfac1 >= 0) {
1131 sa[nbloggers] = &global.logsrv1;
1132 facilities[nbloggers] = global.logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001133 loglevel[nbloggers] = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001134 nbloggers++;
1135 }
1136 if (global.logfac2 >= 0) {
1137 sa[nbloggers] = &global.logsrv2;
1138 facilities[nbloggers] = global.logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001139 loglevel[nbloggers] = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001140 nbloggers++;
1141 }
1142 } else {
1143 if (p->logfac1 >= 0) {
1144 sa[nbloggers] = &p->logsrv1;
1145 facilities[nbloggers] = p->logfac1;
willy tarreau8337c6b2005-12-17 13:41:01 +01001146 loglevel[nbloggers] = p->loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01001147 nbloggers++;
1148 }
1149 if (p->logfac2 >= 0) {
1150 sa[nbloggers] = &p->logsrv2;
1151 facilities[nbloggers] = p->logfac2;
willy tarreau8337c6b2005-12-17 13:41:01 +01001152 loglevel[nbloggers] = p->loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01001153 nbloggers++;
1154 }
1155 }
1156
1157 while (nbloggers-- > 0) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001158 /* we can filter the level of the messages that are sent to each logger */
1159 if (level > loglevel[nbloggers])
1160 continue;
1161
willy tarreauc29948c2005-12-17 13:10:27 +01001162 /* For each target, we may have a different facility.
1163 * We can also have a different log level for each message.
1164 * This induces variations in the message header length.
1165 * Since we don't want to recompute it each time, nor copy it every
1166 * time, we only change the facility in the pre-computed header,
1167 * and we change the pointer to the header accordingly.
1168 */
willy tarreau9fe663a2005-12-17 13:02:59 +01001169 fac_level = (facilities[nbloggers] << 3) + level;
1170 log_ptr = logmsg + 3; /* last digit of the log level */
1171 do {
1172 *log_ptr = '0' + fac_level % 10;
1173 fac_level /= 10;
1174 log_ptr--;
1175 } while (fac_level && log_ptr > logmsg);
1176 *log_ptr = '<';
willy tarreau9fe663a2005-12-17 13:02:59 +01001177
willy tarreauc29948c2005-12-17 13:10:27 +01001178 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
willy tarreau9fe663a2005-12-17 13:02:59 +01001179
1180#ifndef MSG_NOSIGNAL
willy tarreauc29948c2005-12-17 13:10:27 +01001181 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT,
willy tarreau9fe663a2005-12-17 13:02:59 +01001182 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1183#else
willy tarreauc29948c2005-12-17 13:10:27 +01001184 sendto(logfd, log_ptr, dataptr + data_len - log_ptr, MSG_DONTWAIT | MSG_NOSIGNAL,
willy tarreau9fe663a2005-12-17 13:02:59 +01001185 (struct sockaddr *)sa[nbloggers], sizeof(**sa));
1186#endif
1187 }
willy tarreau0f7af912005-12-17 12:21:26 +01001188}
1189
1190
1191/* sets <tv> to the current time */
1192static inline struct timeval *tv_now(struct timeval *tv) {
1193 if (tv)
1194 gettimeofday(tv, NULL);
1195 return tv;
1196}
1197
1198/*
1199 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
1200 */
1201static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
1202 if (!tv || !from)
1203 return NULL;
1204 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
1205 tv->tv_sec = from->tv_sec + (ms/1000);
1206 while (tv->tv_usec >= 1000000) {
1207 tv->tv_usec -= 1000000;
1208 tv->tv_sec++;
1209 }
1210 return tv;
1211}
1212
1213/*
1214 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1215 */
1216static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
willy tarreau750a4722005-12-17 13:21:24 +01001217 if (tv1->tv_sec < tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001218 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001219 else if (tv1->tv_sec > tv2->tv_sec)
willy tarreau0f7af912005-12-17 12:21:26 +01001220 return 1;
1221 else if (tv1->tv_usec < tv2->tv_usec)
1222 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001223 else if (tv1->tv_usec > tv2->tv_usec)
1224 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001225 else
1226 return 0;
1227}
1228
1229/*
1230 * returns the absolute difference, in ms, between tv1 and tv2
1231 */
1232unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
1233 int cmp;
1234 unsigned long ret;
1235
1236
willy tarreauef900ab2005-12-17 12:52:52 +01001237 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +01001238 if (!cmp)
1239 return 0; /* same dates, null diff */
willy tarreau750a4722005-12-17 13:21:24 +01001240 else if (cmp < 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01001241 struct timeval *tmp = tv1;
1242 tv1 = tv2;
1243 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +01001244 }
willy tarreauef900ab2005-12-17 12:52:52 +01001245 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001246 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001247 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001248 else
willy tarreauef900ab2005-12-17 12:52:52 +01001249 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001250 return (unsigned long) ret;
1251}
1252
1253/*
willy tarreau750a4722005-12-17 13:21:24 +01001254 * returns the difference, in ms, between tv1 and tv2
1255 */
1256static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
1257 unsigned long ret;
1258
willy tarreau6e682ce2005-12-17 13:26:49 +01001259 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
1260 if (tv2->tv_usec > tv1->tv_usec)
1261 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001262 else
willy tarreau6e682ce2005-12-17 13:26:49 +01001263 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau750a4722005-12-17 13:21:24 +01001264 return (unsigned long) ret;
1265}
1266
1267/*
willy tarreau0f7af912005-12-17 12:21:26 +01001268 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
1269 */
1270static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +01001271 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreau750a4722005-12-17 13:21:24 +01001272 if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001273 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001274 else if (tv1->tv_usec > tv2->tv_usec + 1000)
1275 return 1;
willy tarreauefae1842005-12-17 12:51:03 +01001276 else
1277 return 0;
1278 }
willy tarreau0f7af912005-12-17 12:21:26 +01001279 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001280 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001281 return -1;
willy tarreau750a4722005-12-17 13:21:24 +01001282 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
1283 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
1284 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001285 else
1286 return 0;
1287}
1288
1289/*
1290 * returns the remaining time between tv1=now and event=tv2
1291 * if tv2 is passed, 0 is returned.
1292 */
1293static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
1294 unsigned long ret;
1295
willy tarreau0f7af912005-12-17 12:21:26 +01001296 if (tv_cmp_ms(tv1, tv2) >= 0)
1297 return 0; /* event elapsed */
1298
willy tarreauef900ab2005-12-17 12:52:52 +01001299 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001300 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +01001301 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001302 else
willy tarreauef900ab2005-12-17 12:52:52 +01001303 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +01001304 return (unsigned long) ret;
1305}
1306
1307
1308/*
1309 * zeroes a struct timeval
1310 */
1311
1312static inline struct timeval *tv_eternity(struct timeval *tv) {
1313 tv->tv_sec = tv->tv_usec = 0;
1314 return tv;
1315}
1316
1317/*
1318 * returns 1 if tv is null, else 0
1319 */
1320static inline int tv_iseternity(struct timeval *tv) {
1321 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1322 return 1;
1323 else
1324 return 0;
1325}
1326
1327/*
1328 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1329 * considering that 0 is the eternity.
1330 */
1331static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
1332 if (tv_iseternity(tv1))
1333 if (tv_iseternity(tv2))
1334 return 0; /* same */
1335 else
1336 return 1; /* tv1 later than tv2 */
1337 else if (tv_iseternity(tv2))
1338 return -1; /* tv2 later than tv1 */
1339
1340 if (tv1->tv_sec > tv2->tv_sec)
1341 return 1;
1342 else if (tv1->tv_sec < tv2->tv_sec)
1343 return -1;
1344 else if (tv1->tv_usec > tv2->tv_usec)
1345 return 1;
1346 else if (tv1->tv_usec < tv2->tv_usec)
1347 return -1;
1348 else
1349 return 0;
1350}
1351
1352/*
1353 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
1354 * considering that 0 is the eternity.
1355 */
1356static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
1357 if (tv_iseternity(tv1))
1358 if (tv_iseternity(tv2))
1359 return 0; /* same */
1360 else
1361 return 1; /* tv1 later than tv2 */
1362 else if (tv_iseternity(tv2))
1363 return -1; /* tv2 later than tv1 */
1364
willy tarreauefae1842005-12-17 12:51:03 +01001365 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +01001366 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001367 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +01001368 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +01001369 return -1;
1370 else
1371 return 0;
1372 }
1373 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001374 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001375 return 1;
1376 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +01001377 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +01001378 return -1;
1379 else
1380 return 0;
1381}
1382
1383/*
1384 * returns the first event between tv1 and tv2 into tvmin.
1385 * a zero tv is ignored. tvmin is returned.
1386 */
1387static inline struct timeval *tv_min(struct timeval *tvmin,
1388 struct timeval *tv1, struct timeval *tv2) {
1389
1390 if (tv_cmp2(tv1, tv2) <= 0)
1391 *tvmin = *tv1;
1392 else
1393 *tvmin = *tv2;
1394
1395 return tvmin;
1396}
1397
1398
1399
1400/***********************************************************/
1401/* fd management ***************************************/
1402/***********************************************************/
1403
1404
1405
willy tarreau5cbea6f2005-12-17 12:48:26 +01001406/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
1407 * The file descriptor is also closed.
1408 */
willy tarreau0f7af912005-12-17 12:21:26 +01001409static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +01001410 FD_CLR(fd, StaticReadEvent);
1411 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001412 close(fd);
1413 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01001414
1415 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
1416 maxfd--;
1417}
1418
1419/* recomputes the maxfd limit from the fd */
1420static inline void fd_insert(int fd) {
1421 if (fd+1 > maxfd)
1422 maxfd = fd+1;
1423}
1424
1425/*************************************************************/
1426/* task management ***************************************/
1427/*************************************************************/
1428
willy tarreau5cbea6f2005-12-17 12:48:26 +01001429/* puts the task <t> in run queue <q>, and returns <t> */
1430static inline struct task *task_wakeup(struct task **q, struct task *t) {
1431 if (t->state == TASK_RUNNING)
1432 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001433 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001434 t->rqnext = *q;
1435 t->state = TASK_RUNNING;
1436 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +01001437 }
1438}
1439
willy tarreau5cbea6f2005-12-17 12:48:26 +01001440/* removes the task <t> from the queue <q>
1441 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +01001442 * set the run queue to point to the next one, and return it
1443 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001444static inline struct task *task_sleep(struct task **q, struct task *t) {
1445 if (t->state == TASK_RUNNING) {
1446 *q = t->rqnext;
1447 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +01001448 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001449 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +01001450}
1451
1452/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001453 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +01001454 * from the run queue. A pointer to the task itself is returned.
1455 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001456static inline struct task *task_delete(struct task *t) {
1457 t->prev->next = t->next;
1458 t->next->prev = t->prev;
1459 return t;
willy tarreau0f7af912005-12-17 12:21:26 +01001460}
1461
1462/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001463 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +01001464 */
1465static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001467}
1468
willy tarreau5cbea6f2005-12-17 12:48:26 +01001469/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +01001470 * may be only moved or left where it was, depending on its timing requirements.
1471 * <task> is returned.
1472 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001473struct task *task_queue(struct task *task) {
1474 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +01001475 struct task *start_from;
1476
1477 /* first, test if the task was already in a list */
1478 if (task->prev == NULL) {
1479 // start_from = list;
1480 start_from = list->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001481#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001482 stats_tsk_new++;
willy tarreau750a4722005-12-17 13:21:24 +01001483#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001484 /* insert the unlinked <task> into the list, searching back from the last entry */
1485 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1486 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001487#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001488 stats_tsk_nsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001489#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001490 }
1491
1492 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1493 // start_from = start_from->next;
1494 // stats_tsk_nsrch++;
1495 // }
1496 }
1497 else if (task->prev == list ||
1498 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
1499 start_from = task->next;
1500 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
willy tarreau750a4722005-12-17 13:21:24 +01001501#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001502 stats_tsk_good++;
willy tarreau750a4722005-12-17 13:21:24 +01001503#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001504 return task; /* it's already in the right place */
1505 }
1506
willy tarreau750a4722005-12-17 13:21:24 +01001507#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001508 stats_tsk_right++;
willy tarreau750a4722005-12-17 13:21:24 +01001509#endif
1510
1511 /* if the task is not at the right place, there's little chance that
1512 * it has only shifted a bit, and it will nearly always be queued
1513 * at the end of the list because of constant timeouts
1514 * (observed in real case).
1515 */
1516#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
1517 start_from = list->prev; /* assume we'll queue to the end of the list */
1518 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1519 start_from = start_from->prev;
1520#if STATTIME > 0
1521 stats_tsk_lsrch++;
1522#endif
1523 }
1524#else /* WE_REALLY_... */
willy tarreau0f7af912005-12-17 12:21:26 +01001525 /* insert the unlinked <task> into the list, searching after position <start_from> */
1526 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1527 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001528#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001529 stats_tsk_rsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001530#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001531 }
willy tarreau750a4722005-12-17 13:21:24 +01001532#endif /* WE_REALLY_... */
1533
willy tarreau0f7af912005-12-17 12:21:26 +01001534 /* we need to unlink it now */
1535 task_delete(task);
1536 }
1537 else { /* walk left. */
willy tarreau750a4722005-12-17 13:21:24 +01001538#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001539 stats_tsk_left++;
willy tarreau750a4722005-12-17 13:21:24 +01001540#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001541#ifdef LEFT_TO_TOP /* not very good */
1542 start_from = list;
1543 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1544 start_from = start_from->next;
willy tarreau750a4722005-12-17 13:21:24 +01001545#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001546 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001547#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001548 }
1549#else
1550 start_from = task->prev->prev; /* valid because of the previous test above */
1551 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1552 start_from = start_from->prev;
willy tarreau750a4722005-12-17 13:21:24 +01001553#if STATTIME > 0
willy tarreau0f7af912005-12-17 12:21:26 +01001554 stats_tsk_lsrch++;
willy tarreau750a4722005-12-17 13:21:24 +01001555#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001556 }
1557#endif
1558 /* we need to unlink it now */
1559 task_delete(task);
1560 }
1561 task->prev = start_from;
1562 task->next = start_from->next;
1563 task->next->prev = task;
1564 start_from->next = task;
1565 return task;
1566}
1567
1568
1569/*********************************************************************/
1570/* more specific functions ***************************************/
1571/*********************************************************************/
1572
1573/* some prototypes */
1574static int maintain_proxies(void);
1575
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576/* this either returns the sockname or the original destination address. Code
1577 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1578 */
1579static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
willy tarreaua1598082005-12-17 13:08:06 +01001580#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1582#else
willy tarreaua1598082005-12-17 13:08:06 +01001583#if defined(TPROXY) && defined(USE_GETSOCKNAME)
willy tarreau5cbea6f2005-12-17 12:48:26 +01001584 return getsockname(fd, (struct sockaddr *)sa, salen);
1585#else
1586 return -1;
1587#endif
1588#endif
1589}
1590
1591/*
1592 * frees the context associated to a session. It must have been removed first.
1593 */
1594static inline void session_free(struct session *s) {
1595 if (s->req)
1596 pool_free(buffer, s->req);
1597 if (s->rep)
1598 pool_free(buffer, s->rep);
willy tarreau4302f492005-12-18 01:00:37 +01001599
1600 if (s->rsp_cap != NULL) {
1601 struct cap_hdr *h;
1602 for (h = s->proxy->rsp_cap; h; h = h->next) {
1603 if (s->rsp_cap[h->index] != NULL)
1604 pool_free_to(h->pool, s->rsp_cap[h->index]);
1605 }
1606 pool_free_to(s->proxy->rsp_cap_pool, s->rsp_cap);
1607 }
1608 if (s->req_cap != NULL) {
1609 struct cap_hdr *h;
1610 for (h = s->proxy->req_cap; h; h = h->next) {
1611 if (s->req_cap[h->index] != NULL)
1612 pool_free_to(h->pool, s->req_cap[h->index]);
1613 }
1614 pool_free_to(s->proxy->req_cap_pool, s->req_cap);
1615 }
1616
willy tarreaua1598082005-12-17 13:08:06 +01001617 if (s->logs.uri)
1618 pool_free(requri, s->logs.uri);
willy tarreau8337c6b2005-12-17 13:41:01 +01001619 if (s->logs.cli_cookie)
1620 pool_free(capture, s->logs.cli_cookie);
1621 if (s->logs.srv_cookie)
1622 pool_free(capture, s->logs.srv_cookie);
willy tarreau9fe663a2005-12-17 13:02:59 +01001623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624 pool_free(session, s);
1625}
1626
willy tarreau0f7af912005-12-17 12:21:26 +01001627
1628/*
willy tarreau8337c6b2005-12-17 13:41:01 +01001629 * This function tries to find a running server for the proxy <px>. A first
1630 * pass looks for active servers, and if none is found, a second pass also
1631 * looks for backup servers.
1632 * If no valid server is found, NULL is returned and px->cursrv is left undefined.
1633 */
1634static inline struct server *find_server(struct proxy *px) {
1635 struct server *srv = px->cursrv;
1636 int ignore_backup = 1;
1637
1638 do {
1639 do {
1640 if (srv == NULL)
1641 srv = px->srv;
1642 if (srv->state & SRV_RUNNING
1643 && !((srv->state & SRV_BACKUP) && ignore_backup))
1644 return srv;
1645 srv = srv->next;
1646 } while (srv != px->cursrv);
1647 } while (ignore_backup--);
1648 return NULL;
1649}
1650
1651/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001652 * This function initiates a connection to the current server (s->srv) if (s->direct)
1653 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001654 * it's OK, -1 if it's impossible.
1655 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001656int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001657 int fd;
1658
willy tarreau12350152005-12-18 01:03:27 +01001659#ifdef DEBUG_FULL
1660 fprintf(stderr,"connect_server : s=%p\n",s);
1661#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001662
willy tarreaue39cd132005-12-17 13:00:18 +01001663 if (s->flags & SN_DIRECT) { /* srv cannot be null */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001664 s->srv_addr = s->srv->addr;
1665 }
1666 else if (s->proxy->options & PR_O_BALANCE) {
1667 if (s->proxy->options & PR_O_BALANCE_RR) {
willy tarreau8337c6b2005-12-17 13:41:01 +01001668 struct server *srv;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001669
willy tarreau8337c6b2005-12-17 13:41:01 +01001670 srv = find_server(s->proxy);
1671
1672 if (srv == NULL) /* no server left */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001673 return -1;
1674
willy tarreau8337c6b2005-12-17 13:41:01 +01001675 s->srv_addr = srv->addr;
1676 s->srv = srv;
1677 s->proxy->cursrv = srv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001678 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001679 else /* unknown balancing algorithm */
1680 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001681 }
willy tarreaua1598082005-12-17 13:08:06 +01001682 else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001683 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001684 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001685 }
1686 else if (s->proxy->options & PR_O_TRANSP) {
1687 /* in transparent mode, use the original dest addr if no dispatch specified */
1688 int salen = sizeof(struct sockaddr_in);
1689 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1690 qfprintf(stderr, "Cannot get original server address.\n");
1691 return -1;
1692 }
1693 }
willy tarreau0f7af912005-12-17 12:21:26 +01001694
willy tarreaua41a8b42005-12-17 14:02:24 +01001695 /* if this server remaps proxied ports, we'll use
1696 * the port the client connected to with an offset. */
willy tarreaueedaa9f2005-12-17 14:08:03 +01001697 if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
willy tarreaua41a8b42005-12-17 14:02:24 +01001698 struct sockaddr_in sockname;
1699 int namelen;
1700
1701 namelen = sizeof(sockname);
1702 if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1703 getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
1704 s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
1705 }
1706
willy tarreau0f7af912005-12-17 12:21:26 +01001707 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001708 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001709 return -1;
1710 }
1711
willy tarreau9fe663a2005-12-17 13:02:59 +01001712 if (fd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001713 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1714 close(fd);
1715 return -1;
1716 }
1717
willy tarreau0f7af912005-12-17 12:21:26 +01001718 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1719 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001720 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001721 close(fd);
1722 return -1;
1723 }
1724
willy tarreau0174f312005-12-18 01:02:42 +01001725 /* allow specific binding :
1726 * - server-specific at first
1727 * - proxy-specific next
1728 */
1729 if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
1730 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1731 if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) {
1732 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
1733 s->proxy->id, s->srv->id);
1734 close(fd);
1735 return -1;
1736 }
1737 }
1738 else if (s->proxy->options & PR_O_BIND_SRC) {
1739 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
1740 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
1741 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
1742 close(fd);
1743 return -1;
1744 }
willy tarreaua1598082005-12-17 13:08:06 +01001745 }
1746
willy tarreau0f7af912005-12-17 12:21:26 +01001747 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1748 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001749 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001750 close(fd);
1751 return -1;
1752 }
1753 else if (errno != EALREADY && errno != EISCONN) {
1754 close(fd);
1755 return -1;
1756 }
1757 }
1758
willy tarreau5cbea6f2005-12-17 12:48:26 +01001759 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001760 fdtab[fd].read = &event_srv_read;
1761 fdtab[fd].write = &event_srv_write;
1762 fdtab[fd].state = FD_STCONN; /* connection in progress */
1763
1764 FD_SET(fd, StaticWriteEvent); /* for connect status */
1765
1766 fd_insert(fd);
1767
1768 if (s->proxy->contimeout)
1769 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1770 else
1771 tv_eternity(&s->cnexpire);
1772 return 0;
1773}
1774
1775/*
1776 * this function is called on a read event from a client socket.
1777 * It returns 0.
1778 */
1779int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001780 struct task *t = fdtab[fd].owner;
1781 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001782 struct buffer *b = s->req;
1783 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001784
willy tarreau12350152005-12-18 01:03:27 +01001785#ifdef DEBUG_FULL
1786 fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1787#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001788
willy tarreau0f7af912005-12-17 12:21:26 +01001789 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001790 while (1) {
1791 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1792 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001793 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001794 }
1795 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001796 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001797 }
1798 else {
1799 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001800 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1801 * since it means that the rewrite protection has been removed. This
1802 * implies that the if statement can be removed.
1803 */
1804 if (max > b->rlim - b->data)
1805 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 }
1807
1808 if (max == 0) { /* not anymore room to store data */
1809 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001810 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001811 }
1812
willy tarreau3242e862005-12-17 12:27:53 +01001813#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001814 {
1815 int skerr, lskerr;
1816
1817 lskerr = sizeof(skerr);
1818 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1819 if (skerr)
1820 ret = -1;
1821 else
1822 ret = recv(fd, b->r, max, 0);
1823 }
willy tarreau3242e862005-12-17 12:27:53 +01001824#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001826#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 if (ret > 0) {
1828 b->r += ret;
1829 b->l += ret;
1830 s->res_cr = RES_DATA;
1831
1832 if (b->r == b->data + BUFSIZE) {
1833 b->r = b->data; /* wrap around the buffer */
1834 }
willy tarreaua1598082005-12-17 13:08:06 +01001835
1836 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001837 /* we hope to read more data or to get a close on next round */
1838 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001839 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001840 else if (ret == 0) {
1841 s->res_cr = RES_NULL;
1842 break;
1843 }
1844 else if (errno == EAGAIN) {/* ignore EAGAIN */
1845 break;
1846 }
1847 else {
1848 s->res_cr = RES_ERROR;
1849 fdtab[fd].state = FD_STERROR;
1850 break;
1851 }
1852 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001853 }
1854 else {
1855 s->res_cr = RES_ERROR;
1856 fdtab[fd].state = FD_STERROR;
1857 }
1858
willy tarreau5cbea6f2005-12-17 12:48:26 +01001859 if (s->res_cr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001860 if (s->proxy->clitimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001861 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1862 else
1863 tv_eternity(&s->crexpire);
1864
1865 task_wakeup(&rq, t);
1866 }
willy tarreau0f7af912005-12-17 12:21:26 +01001867
willy tarreau0f7af912005-12-17 12:21:26 +01001868 return 0;
1869}
1870
1871
1872/*
1873 * this function is called on a read event from a server socket.
1874 * It returns 0.
1875 */
1876int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001877 struct task *t = fdtab[fd].owner;
1878 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001879 struct buffer *b = s->rep;
1880 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001881
willy tarreau12350152005-12-18 01:03:27 +01001882#ifdef DEBUG_FULL
1883 fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1884#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001885
willy tarreau0f7af912005-12-17 12:21:26 +01001886 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001887 while (1) {
1888 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1889 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001890 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001891 }
1892 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001893 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001894 }
1895 else {
1896 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001897 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1898 * since it means that the rewrite protection has been removed. This
1899 * implies that the if statement can be removed.
1900 */
1901 if (max > b->rlim - b->data)
1902 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001903 }
1904
1905 if (max == 0) { /* not anymore room to store data */
1906 FD_CLR(fd, StaticReadEvent);
1907 break;
1908 }
1909
willy tarreau3242e862005-12-17 12:27:53 +01001910#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001911 {
1912 int skerr, lskerr;
1913
1914 lskerr = sizeof(skerr);
1915 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1916 if (skerr)
1917 ret = -1;
1918 else
1919 ret = recv(fd, b->r, max, 0);
1920 }
willy tarreau3242e862005-12-17 12:27:53 +01001921#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001922 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001923#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001924 if (ret > 0) {
1925 b->r += ret;
1926 b->l += ret;
1927 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001928
willy tarreau5cbea6f2005-12-17 12:48:26 +01001929 if (b->r == b->data + BUFSIZE) {
1930 b->r = b->data; /* wrap around the buffer */
1931 }
willy tarreaua1598082005-12-17 13:08:06 +01001932
1933 b->total += ret;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001934 /* we hope to read more data or to get a close on next round */
1935 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001936 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001937 else if (ret == 0) {
1938 s->res_sr = RES_NULL;
1939 break;
1940 }
1941 else if (errno == EAGAIN) {/* ignore EAGAIN */
1942 break;
1943 }
1944 else {
1945 s->res_sr = RES_ERROR;
1946 fdtab[fd].state = FD_STERROR;
1947 break;
1948 }
1949 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001950 }
1951 else {
1952 s->res_sr = RES_ERROR;
1953 fdtab[fd].state = FD_STERROR;
1954 }
1955
willy tarreau5cbea6f2005-12-17 12:48:26 +01001956 if (s->res_sr != RES_SILENT) {
willy tarreaub1ff9db2005-12-17 13:51:03 +01001957 if (s->proxy->srvtimeout && FD_ISSET(fd, StaticReadEvent))
willy tarreau5cbea6f2005-12-17 12:48:26 +01001958 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1959 else
1960 tv_eternity(&s->srexpire);
1961
1962 task_wakeup(&rq, t);
1963 }
willy tarreau0f7af912005-12-17 12:21:26 +01001964
willy tarreau0f7af912005-12-17 12:21:26 +01001965 return 0;
1966}
1967
1968/*
1969 * this function is called on a write event from a client socket.
1970 * It returns 0.
1971 */
1972int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001973 struct task *t = fdtab[fd].owner;
1974 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001975 struct buffer *b = s->rep;
1976 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001977
willy tarreau12350152005-12-18 01:03:27 +01001978#ifdef DEBUG_FULL
1979 fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1980#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001981
1982 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001983 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001984 // max = BUFSIZE; BUG !!!!
1985 max = 0;
1986 }
1987 else if (b->r > b->w) {
1988 max = b->r - b->w;
1989 }
1990 else
1991 max = b->data + BUFSIZE - b->w;
1992
willy tarreau0f7af912005-12-17 12:21:26 +01001993 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001994#ifndef MSG_NOSIGNAL
1995 int skerr, lskerr;
1996#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001997
1998 if (max == 0) {
1999 s->res_cw = RES_NULL;
2000 task_wakeup(&rq, t);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002001 tv_eternity(&s->cwexpire);
2002 FD_CLR(fd, StaticWriteEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01002003 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002004 }
2005
willy tarreau3242e862005-12-17 12:27:53 +01002006#ifndef MSG_NOSIGNAL
2007 lskerr=sizeof(skerr);
2008 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2009 if (skerr)
2010 ret = -1;
2011 else
2012 ret = send(fd, b->w, max, MSG_DONTWAIT);
2013#else
willy tarreau0f7af912005-12-17 12:21:26 +01002014 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002015#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002016
2017 if (ret > 0) {
2018 b->l -= ret;
2019 b->w += ret;
2020
2021 s->res_cw = RES_DATA;
2022
2023 if (b->w == b->data + BUFSIZE) {
2024 b->w = b->data; /* wrap around the buffer */
2025 }
2026 }
2027 else if (ret == 0) {
2028 /* nothing written, just make as if we were never called */
2029// s->res_cw = RES_NULL;
2030 return 0;
2031 }
2032 else if (errno == EAGAIN) /* ignore EAGAIN */
2033 return 0;
2034 else {
2035 s->res_cw = RES_ERROR;
2036 fdtab[fd].state = FD_STERROR;
2037 }
2038 }
2039 else {
2040 s->res_cw = RES_ERROR;
2041 fdtab[fd].state = FD_STERROR;
2042 }
2043
willy tarreaub1ff9db2005-12-17 13:51:03 +01002044 if (s->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002045 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002046 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
2047 s->crexpire = s->cwexpire;
2048 }
willy tarreau0f7af912005-12-17 12:21:26 +01002049 else
2050 tv_eternity(&s->cwexpire);
2051
willy tarreau5cbea6f2005-12-17 12:48:26 +01002052 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002053 return 0;
2054}
2055
2056
2057/*
2058 * this function is called on a write event from a server socket.
2059 * It returns 0.
2060 */
2061int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002062 struct task *t = fdtab[fd].owner;
2063 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002064 struct buffer *b = s->req;
2065 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01002066
willy tarreau12350152005-12-18 01:03:27 +01002067#ifdef DEBUG_FULL
2068 fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
2069#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002070
2071 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01002072 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01002073 // max = BUFSIZE; BUG !!!!
2074 max = 0;
2075 }
2076 else if (b->r > b->w) {
2077 max = b->r - b->w;
2078 }
2079 else
2080 max = b->data + BUFSIZE - b->w;
2081
willy tarreau0f7af912005-12-17 12:21:26 +01002082 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01002083#ifndef MSG_NOSIGNAL
2084 int skerr, lskerr;
2085#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002086 if (max == 0) {
2087 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01002088 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002089 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002090 fdtab[fd].state = FD_STREADY;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002091 tv_eternity(&s->swexpire);
2092 FD_CLR(fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002093 return 0;
2094 }
2095
willy tarreauef900ab2005-12-17 12:52:52 +01002096
willy tarreau3242e862005-12-17 12:27:53 +01002097#ifndef MSG_NOSIGNAL
2098 lskerr=sizeof(skerr);
2099 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2100 if (skerr)
2101 ret = -1;
2102 else
2103 ret = send(fd, b->w, max, MSG_DONTWAIT);
2104#else
willy tarreau0f7af912005-12-17 12:21:26 +01002105 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01002106#endif
willy tarreauef900ab2005-12-17 12:52:52 +01002107 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002108 if (ret > 0) {
2109 b->l -= ret;
2110 b->w += ret;
2111
2112 s->res_sw = RES_DATA;
2113
2114 if (b->w == b->data + BUFSIZE) {
2115 b->w = b->data; /* wrap around the buffer */
2116 }
2117 }
2118 else if (ret == 0) {
2119 /* nothing written, just make as if we were never called */
2120 // s->res_sw = RES_NULL;
2121 return 0;
2122 }
2123 else if (errno == EAGAIN) /* ignore EAGAIN */
2124 return 0;
2125 else {
2126 s->res_sw = RES_ERROR;
2127 fdtab[fd].state = FD_STERROR;
2128 }
2129 }
2130 else {
2131 s->res_sw = RES_ERROR;
2132 fdtab[fd].state = FD_STERROR;
2133 }
2134
willy tarreaub1ff9db2005-12-17 13:51:03 +01002135 if (s->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01002136 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01002137 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
2138 s->srexpire = s->swexpire;
2139 }
willy tarreau0f7af912005-12-17 12:21:26 +01002140 else
2141 tv_eternity(&s->swexpire);
2142
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002144 return 0;
2145}
2146
2147
2148/*
willy tarreaue39cd132005-12-17 13:00:18 +01002149 * returns a message to the client ; the connection is shut down for read,
2150 * and the request is cleared so that no server connection can be initiated.
2151 * The client must be in a valid state for this (HEADER, DATA ...).
2152 * Nothing is performed on the server side.
willy tarreau8337c6b2005-12-17 13:41:01 +01002153 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002154 */
2155void client_retnclose(struct session *s, int len, const char *msg) {
2156 FD_CLR(s->cli_fd, StaticReadEvent);
2157 FD_SET(s->cli_fd, StaticWriteEvent);
2158 tv_eternity(&s->crexpire);
2159 shutdown(s->cli_fd, SHUT_RD);
2160 s->cli_state = CL_STSHUTR;
2161 strcpy(s->rep->data, msg);
2162 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002163 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002164 s->rep->r += len;
2165 s->req->l = 0;
2166}
2167
2168
2169/*
2170 * returns a message into the rep buffer, and flushes the req buffer.
willy tarreau8337c6b2005-12-17 13:41:01 +01002171 * The reply buffer doesn't need to be empty before this.
willy tarreaue39cd132005-12-17 13:00:18 +01002172 */
2173void client_return(struct session *s, int len, const char *msg) {
2174 strcpy(s->rep->data, msg);
2175 s->rep->l = len;
willy tarreau8337c6b2005-12-17 13:41:01 +01002176 s->rep->r = s->rep->h = s->rep->lr = s->rep->w = s->rep->data;
willy tarreaue39cd132005-12-17 13:00:18 +01002177 s->rep->r += len;
2178 s->req->l = 0;
2179}
2180
willy tarreau9fe663a2005-12-17 13:02:59 +01002181/*
2182 * send a log for the session when we have enough info about it
2183 */
2184void sess_log(struct session *s) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002185 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
willy tarreau9fe663a2005-12-17 13:02:59 +01002186 struct proxy *p = s->proxy;
2187 int log;
2188 char *uri;
2189 char *pxid;
2190 char *srv;
willy tarreauc1cae632005-12-17 14:12:23 +01002191 struct tm *tm;
willy tarreau9fe663a2005-12-17 13:02:59 +01002192
2193 /* This is a first attempt at a better logging system.
2194 * For now, we rely on send_log() to provide the date, although it obviously
2195 * is the date of the log and not of the request, and most fields are not
2196 * computed.
2197 */
2198
willy tarreaua1598082005-12-17 13:08:06 +01002199 log = p->to_log & ~s->logs.logwait;
willy tarreau9fe663a2005-12-17 13:02:59 +01002200
willy tarreau8a86dbf2005-12-18 00:45:59 +01002201 if (s->cli_addr.ss_family == AF_INET)
2202 inet_ntop(AF_INET,
2203 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2204 pn, sizeof(pn));
2205 else
2206 inet_ntop(AF_INET6,
2207 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2208 pn, sizeof(pn));
willy tarreau9fe663a2005-12-17 13:02:59 +01002209
willy tarreauc1cae632005-12-17 14:12:23 +01002210 uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
willy tarreau9fe663a2005-12-17 13:02:59 +01002211 pxid = p->id;
willy tarreauc1cae632005-12-17 14:12:23 +01002212 srv = (p->to_log & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
willy tarreaua1598082005-12-17 13:08:06 +01002213
willy tarreauc1cae632005-12-17 14:12:23 +01002214 tm = localtime(&s->logs.tv_accept.tv_sec);
2215 if (p->to_log & LW_REQ) {
willy tarreau4302f492005-12-18 01:00:37 +01002216 char tmpline[MAX_SYSLOG_LEN], *h;
2217 int hdr;
2218
2219 h = tmpline;
2220 if (p->to_log & LW_REQHDR && (h < tmpline + sizeof(tmpline) - 10)) {
2221 *(h++) = ' ';
2222 *(h++) = '{';
2223 for (hdr = 0; hdr < p->nb_req_cap; hdr++) {
2224 if (hdr)
2225 *(h++) = '|';
2226 if (s->req_cap[hdr] != NULL)
2227 h = encode_string(h, tmpline + sizeof(tmpline) - 7, '#', hdr_encode_map, s->req_cap[hdr]);
2228 }
2229 *(h++) = '}';
2230 }
2231
2232 if (p->to_log & LW_RSPHDR && (h < tmpline + sizeof(tmpline) - 7)) {
2233 *(h++) = ' ';
2234 *(h++) = '{';
2235 for (hdr = 0; hdr < p->nb_rsp_cap; hdr++) {
2236 if (hdr)
2237 *(h++) = '|';
2238 if (s->rsp_cap[hdr] != NULL)
2239 h = encode_string(h, tmpline + sizeof(tmpline) - 4, '#', hdr_encode_map, s->rsp_cap[hdr]);
2240 }
2241 *(h++) = '}';
2242 }
2243
2244 if (h < tmpline + sizeof(tmpline) - 4) {
2245 *(h++) = ' ';
2246 *(h++) = '"';
2247 h = encode_string(h, tmpline + sizeof(tmpline) - 1, '#', url_encode_map, uri);
2248 *(h++) = '"';
2249 }
2250 *h = '\0';
2251
2252 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%s%d %d %s%lld %s %s %c%c%c%c%s\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002253 pn,
2254 (s->cli_addr.ss_family == AF_INET) ?
2255 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2256 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreaua1598082005-12-17 13:08:06 +01002257 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2258 tm->tm_hour, tm->tm_min, tm->tm_sec,
2259 pxid, srv,
2260 s->logs.t_request,
2261 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_request : -1,
2262 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002263 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2264 s->logs.status,
2265 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau8337c6b2005-12-17 13:41:01 +01002266 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
2267 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
willy tarreau036e1ce2005-12-17 13:46:33 +01002268 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
2269 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
2270 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
2271 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
willy tarreau4302f492005-12-18 01:00:37 +01002272 tmpline);
willy tarreaua1598082005-12-17 13:08:06 +01002273 }
2274 else {
willy tarreau25c4ea52005-12-18 00:49:49 +01002275 send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%s%d %s%lld %c%c\n",
willy tarreau8a86dbf2005-12-18 00:45:59 +01002276 pn,
2277 (s->cli_addr.ss_family == AF_INET) ?
2278 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
2279 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
willy tarreauc1cae632005-12-17 14:12:23 +01002280 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
2281 tm->tm_hour, tm->tm_min, tm->tm_sec,
willy tarreaua1598082005-12-17 13:08:06 +01002282 pxid, srv,
willy tarreauc1cae632005-12-17 14:12:23 +01002283 (s->logs.t_connect >= 0) ? s->logs.t_connect : -1,
willy tarreau25c4ea52005-12-18 00:49:49 +01002284 (p->to_log & LW_BYTES) ? "" : "+", s->logs.t_close,
2285 (p->to_log & LW_BYTES) ? "" : "+", s->logs.bytes,
willy tarreau036e1ce2005-12-17 13:46:33 +01002286 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
willy tarreauc1cae632005-12-17 14:12:23 +01002287 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
willy tarreaua1598082005-12-17 13:08:06 +01002288 }
2289
2290 s->logs.logwait = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002291}
2292
willy tarreaue39cd132005-12-17 13:00:18 +01002293
2294/*
willy tarreau0f7af912005-12-17 12:21:26 +01002295 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01002296 * to an accept. It tries to accept as many connections as possible.
2297 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01002298 */
2299int event_accept(int fd) {
2300 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002301 struct session *s;
2302 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01002303 int cfd;
willy tarreau0f7af912005-12-17 12:21:26 +01002304
willy tarreau5cbea6f2005-12-17 12:48:26 +01002305 while (p->nbconn < p->maxconn) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002306 struct sockaddr_storage addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002307 int laddr = sizeof(addr);
2308 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
2309 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01002310
willy tarreau5cbea6f2005-12-17 12:48:26 +01002311 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
2312 Alert("out of memory in event_accept().\n");
2313 FD_CLR(fd, StaticReadEvent);
2314 p->state = PR_STIDLE;
2315 close(cfd);
2316 return 0;
2317 }
willy tarreau0f7af912005-12-17 12:21:26 +01002318
willy tarreau5cbea6f2005-12-17 12:48:26 +01002319 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
2320 Alert("out of memory in event_accept().\n");
2321 FD_CLR(fd, StaticReadEvent);
2322 p->state = PR_STIDLE;
2323 close(cfd);
2324 pool_free(session, s);
2325 return 0;
2326 }
willy tarreau0f7af912005-12-17 12:21:26 +01002327
willy tarreau5cbea6f2005-12-17 12:48:26 +01002328 s->cli_addr = addr;
willy tarreau9fe663a2005-12-17 13:02:59 +01002329 if (cfd >= global.maxsock) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002330 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
2331 close(cfd);
2332 pool_free(task, t);
2333 pool_free(session, s);
2334 return 0;
2335 }
willy tarreau0f7af912005-12-17 12:21:26 +01002336
willy tarreau5cbea6f2005-12-17 12:48:26 +01002337 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
2338 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
2339 (char *) &one, sizeof(one)) == -1)) {
2340 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
2341 close(cfd);
2342 pool_free(task, t);
2343 pool_free(session, s);
2344 return 0;
2345 }
willy tarreau0f7af912005-12-17 12:21:26 +01002346
willy tarreau9fe663a2005-12-17 13:02:59 +01002347 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
2348 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
2349 t->state = TASK_IDLE;
2350 t->process = process_session;
2351 t->context = s;
2352
2353 s->task = t;
2354 s->proxy = p;
2355 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
2356 s->srv_state = SV_STIDLE;
2357 s->req = s->rep = NULL; /* will be allocated later */
2358 s->flags = 0;
willy tarreau97f58572005-12-18 00:53:44 +01002359
willy tarreau9fe663a2005-12-17 13:02:59 +01002360 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
2361 s->cli_fd = cfd;
2362 s->srv_fd = -1;
willy tarreaua1598082005-12-17 13:08:06 +01002363 s->srv = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01002364 s->conn_retries = p->conn_retries;
willy tarreaua1598082005-12-17 13:08:06 +01002365
2366 s->logs.logwait = p->to_log;
2367 s->logs.tv_accept = now;
2368 s->logs.t_request = -1;
2369 s->logs.t_connect = -1;
2370 s->logs.t_data = -1;
2371 s->logs.t_close = 0;
2372 s->logs.uri = NULL;
willy tarreau8337c6b2005-12-17 13:41:01 +01002373 s->logs.cli_cookie = NULL;
2374 s->logs.srv_cookie = NULL;
willy tarreaua1598082005-12-17 13:08:06 +01002375 s->logs.status = -1;
2376 s->logs.bytes = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01002377
willy tarreau2f6ba652005-12-17 13:57:42 +01002378 s->uniq_id = totalconn;
2379
willy tarreau4302f492005-12-18 01:00:37 +01002380 if (p->nb_req_cap > 0) {
2381 if ((s->req_cap =
2382 pool_alloc_from(p->req_cap_pool, p->nb_req_cap*sizeof(char *)))
2383 == NULL) { /* no memory */
2384 close(cfd); /* nothing can be done for this fd without memory */
2385 pool_free(task, t);
2386 pool_free(session, s);
2387 return 0;
2388 }
2389 memset(s->req_cap, 0, p->nb_req_cap*sizeof(char *));
2390 }
2391 else
2392 s->req_cap = NULL;
2393
2394 if (p->nb_rsp_cap > 0) {
2395 if ((s->rsp_cap =
2396 pool_alloc_from(p->rsp_cap_pool, p->nb_rsp_cap*sizeof(char *)))
2397 == NULL) { /* no memory */
2398 if (s->req_cap != NULL)
2399 pool_free_to(p->req_cap_pool, s->req_cap);
2400 close(cfd); /* nothing can be done for this fd without memory */
2401 pool_free(task, t);
2402 pool_free(session, s);
2403 return 0;
2404 }
2405 memset(s->rsp_cap, 0, p->nb_rsp_cap*sizeof(char *));
2406 }
2407 else
2408 s->rsp_cap = NULL;
2409
willy tarreau5cbea6f2005-12-17 12:48:26 +01002410 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
2411 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002412 struct sockaddr_storage sockname;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002413 int namelen;
willy tarreau0f7af912005-12-17 12:21:26 +01002414
willy tarreau5cbea6f2005-12-17 12:48:26 +01002415 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002416 if (addr.ss_family != AF_INET ||
2417 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002418 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau0f7af912005-12-17 12:21:26 +01002419
willy tarreau9fe663a2005-12-17 13:02:59 +01002420 if (p->to_log) {
2421 /* we have the client ip */
willy tarreaua1598082005-12-17 13:08:06 +01002422 if (s->logs.logwait & LW_CLIP)
2423 if (!(s->logs.logwait &= ~LW_CLIP))
willy tarreau9fe663a2005-12-17 13:02:59 +01002424 sess_log(s);
2425 }
willy tarreau8a86dbf2005-12-18 00:45:59 +01002426 else if (s->cli_addr.ss_family == AF_INET) {
2427 char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
2428 if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
2429 sn, sizeof(sn)) &&
2430 inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2431 pn, sizeof(pn))) {
2432 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2433 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
2434 sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
2435 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2436 }
2437 }
2438 else {
2439 char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
2440 if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
2441 sn, sizeof(sn)) &&
2442 inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
2443 pn, sizeof(pn))) {
2444 send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
2445 pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
2446 sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
2447 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
2448 }
2449 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002450 }
willy tarreau0f7af912005-12-17 12:21:26 +01002451
willy tarreau982249e2005-12-18 00:57:06 +01002452 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau2f6ba652005-12-17 13:57:42 +01002453 struct sockaddr_in sockname;
willy tarreau2f6ba652005-12-17 13:57:42 +01002454 int namelen;
willy tarreauef900ab2005-12-17 12:52:52 +01002455 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01002456 namelen = sizeof(sockname);
willy tarreau8a86dbf2005-12-18 00:45:59 +01002457 if (addr.ss_family != AF_INET ||
2458 get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
willy tarreau2f6ba652005-12-17 13:57:42 +01002459 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
willy tarreau2f6ba652005-12-17 13:57:42 +01002460
willy tarreau8a86dbf2005-12-18 00:45:59 +01002461 if (s->cli_addr.ss_family == AF_INET) {
2462 char pn[INET_ADDRSTRLEN];
2463 inet_ntop(AF_INET,
2464 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
2465 pn, sizeof(pn));
2466
2467 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2468 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2469 pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
2470 }
2471 else {
2472 char pn[INET6_ADDRSTRLEN];
2473 inet_ntop(AF_INET6,
2474 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2475 pn, sizeof(pn));
2476
2477 len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
2478 s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
2479 pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
2480 }
2481
willy tarreauef900ab2005-12-17 12:52:52 +01002482 write(1, trash, len);
2483 }
willy tarreau0f7af912005-12-17 12:21:26 +01002484
willy tarreau5cbea6f2005-12-17 12:48:26 +01002485 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
willy tarreau4302f492005-12-18 01:00:37 +01002486 if (s->rsp_cap != NULL)
2487 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2488 if (s->req_cap != NULL)
2489 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002490 close(cfd); /* nothing can be done for this fd without memory */
2491 pool_free(task, t);
2492 pool_free(session, s);
2493 return 0;
2494 }
willy tarreau4302f492005-12-18 01:00:37 +01002495
willy tarreau5cbea6f2005-12-17 12:48:26 +01002496 s->req->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002497 s->req->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002498 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
2499 s->req->rlim = s->req->data + BUFSIZE;
willy tarreaub1ff9db2005-12-17 13:51:03 +01002500 if (s->cli_state == CL_STHEADERS) /* reserve some space for header rewriting */
willy tarreauef900ab2005-12-17 12:52:52 +01002501 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01002502
willy tarreau5cbea6f2005-12-17 12:48:26 +01002503 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
2504 pool_free(buffer, s->req);
willy tarreau4302f492005-12-18 01:00:37 +01002505 if (s->rsp_cap != NULL)
2506 pool_free_to(p->rsp_cap_pool, s->rsp_cap);
2507 if (s->req_cap != NULL)
2508 pool_free_to(p->req_cap_pool, s->req_cap);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002509 close(cfd); /* nothing can be done for this fd without memory */
2510 pool_free(task, t);
2511 pool_free(session, s);
2512 return 0;
2513 }
2514 s->rep->l = 0;
willy tarreaua1598082005-12-17 13:08:06 +01002515 s->rep->total = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01002516 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 +01002517
willy tarreau5cbea6f2005-12-17 12:48:26 +01002518 fdtab[cfd].read = &event_cli_read;
2519 fdtab[cfd].write = &event_cli_write;
2520 fdtab[cfd].owner = t;
2521 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01002522
willy tarreau5cbea6f2005-12-17 12:48:26 +01002523 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
willy tarreau197e8ec2005-12-17 14:10:59 +01002524 if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
2525 client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
2526 else
2527 client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002528 }
2529 else {
2530 FD_SET(cfd, StaticReadEvent);
2531 }
2532
2533 fd_insert(cfd);
2534
2535 tv_eternity(&s->cnexpire);
2536 tv_eternity(&s->srexpire);
2537 tv_eternity(&s->swexpire);
2538 tv_eternity(&s->cwexpire);
2539
2540 if (s->proxy->clitimeout)
2541 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
2542 else
2543 tv_eternity(&s->crexpire);
2544
2545 t->expire = s->crexpire;
2546
2547 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01002548
2549 if (p->mode != PR_MODE_HEALTH)
2550 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551
2552 p->nbconn++;
2553 actconn++;
2554 totalconn++;
2555
2556 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
2557 } /* end of while (p->nbconn < p->maxconn) */
2558 return 0;
2559}
willy tarreau0f7af912005-12-17 12:21:26 +01002560
willy tarreau0f7af912005-12-17 12:21:26 +01002561
willy tarreau5cbea6f2005-12-17 12:48:26 +01002562/*
2563 * This function is used only for server health-checks. It handles
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002564 * the connection acknowledgement. If the proxy requires HTTP health-checks,
2565 * it sends the request. In other cases, it returns 1 if the socket is OK,
willy tarreau5cbea6f2005-12-17 12:48:26 +01002566 * or -1 if an error occured.
2567 */
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002568int event_srv_chk_w(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002569 struct task *t = fdtab[fd].owner;
2570 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01002571
willy tarreau5cbea6f2005-12-17 12:48:26 +01002572 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01002573 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002574 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002575 /* in case of TCP only, this tells us if the connection succeeded */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002576 if (skerr)
2577 s->result = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002578 else {
2579 if (s->proxy->options & PR_O_HTTP_CHK) {
2580 int ret;
willy tarreau2f6ba652005-12-17 13:57:42 +01002581 /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002582 * so we'll send the request, and won't wake the checker up now.
2583 */
2584#ifndef MSG_NOSIGNAL
willy tarreau2f6ba652005-12-17 13:57:42 +01002585 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002586#else
willy tarreau2f6ba652005-12-17 13:57:42 +01002587 ret = send(fd, s->proxy->check_req, s->proxy->check_len, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002588#endif
willy tarreaufe2c5c12005-12-17 14:14:34 +01002589 if (ret == s->proxy->check_len) {
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002590 FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
2591 FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
2592 return 0;
2593 }
2594 else
2595 s->result = -1;
2596 }
2597 else {
2598 /* good TCP connection is enough */
2599 s->result = 1;
2600 }
2601 }
2602
2603 task_wakeup(&rq, t);
2604 return 0;
2605}
2606
willy tarreau0f7af912005-12-17 12:21:26 +01002607
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002608/*
2609 * This function is used only for server health-checks. It handles
2610 * the server's reply to an HTTP request. It returns 1 if the server replies
2611 * 2xx or 3xx (valid responses), or -1 in other cases.
2612 */
2613int event_srv_chk_r(int fd) {
2614 char reply[64];
2615 int len;
2616 struct task *t = fdtab[fd].owner;
2617 struct server *s = t->context;
2618
2619 int skerr, lskerr;
2620 lskerr = sizeof(skerr);
willy tarreau197e8ec2005-12-17 14:10:59 +01002621
2622 s->result = len = -1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002623#ifndef MSG_NOSIGNAL
willy tarreau197e8ec2005-12-17 14:10:59 +01002624 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
2625 if (!skerr)
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002626 len = recv(fd, reply, sizeof(reply), 0);
2627#else
willy tarreau197e8ec2005-12-17 14:10:59 +01002628 /* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
2629 * but the connection was closed on the remote end. Fortunately, recv still
2630 * works correctly and we don't need to do the getsockopt() on linux.
2631 */
2632 len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002633#endif
willy tarreau197e8ec2005-12-17 14:10:59 +01002634 if ((len >= sizeof("HTTP/1.0 000")) &&
2635 !memcmp(reply, "HTTP/1.", 7) &&
2636 (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
2637 s->result = 1;
willy tarreaubc4e1fb2005-12-17 13:32:07 +01002638
2639 FD_CLR(fd, StaticReadEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01002641 return 0;
2642}
2643
2644
2645/*
2646 * this function writes the string <str> at position <pos> which must be in buffer <b>,
2647 * and moves <end> just after the end of <str>.
2648 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
2649 * the shift value (positive or negative) is returned.
2650 * If there's no space left, the move is not done.
2651 *
2652 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002653int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01002654 int delta;
2655 int len;
2656
2657 len = strlen(str);
2658 delta = len - (end - pos);
2659
2660 if (delta + b->r >= b->data + BUFSIZE)
2661 return 0; /* no space left */
2662
2663 /* first, protect the end of the buffer */
2664 memmove(end + delta, end, b->data + b->l - end);
2665
2666 /* now, copy str over pos */
2667 memcpy(pos, str,len);
2668
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669 /* we only move data after the displaced zone */
2670 if (b->r > pos) b->r += delta;
2671 if (b->w > pos) b->w += delta;
2672 if (b->h > pos) b->h += delta;
2673 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002674 b->l += delta;
2675
2676 return delta;
2677}
2678
willy tarreau8337c6b2005-12-17 13:41:01 +01002679/* same except that the string length is given, which allows str to be NULL if
willy tarreau240afa62005-12-17 13:14:35 +01002680 * len is 0.
2681 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002682int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01002683 int delta;
2684
2685 delta = len - (end - pos);
2686
2687 if (delta + b->r >= b->data + BUFSIZE)
2688 return 0; /* no space left */
2689
2690 /* first, protect the end of the buffer */
2691 memmove(end + delta, end, b->data + b->l - end);
2692
2693 /* now, copy str over pos */
willy tarreau240afa62005-12-17 13:14:35 +01002694 if (len)
2695 memcpy(pos, str, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002696
willy tarreau5cbea6f2005-12-17 12:48:26 +01002697 /* we only move data after the displaced zone */
2698 if (b->r > pos) b->r += delta;
2699 if (b->w > pos) b->w += delta;
2700 if (b->h > pos) b->h += delta;
2701 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01002702 b->l += delta;
2703
2704 return delta;
2705}
2706
2707
2708int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
2709 char *old_dst = dst;
2710
2711 while (*str) {
2712 if (*str == '\\') {
2713 str++;
willy tarreauc29948c2005-12-17 13:10:27 +01002714 if (isdigit((int)*str)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002715 int len, num;
2716
2717 num = *str - '0';
2718 str++;
2719
willy tarreau8a86dbf2005-12-18 00:45:59 +01002720 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
willy tarreau0f7af912005-12-17 12:21:26 +01002721 len = matches[num].rm_eo - matches[num].rm_so;
2722 memcpy(dst, src + matches[num].rm_so, len);
2723 dst += len;
2724 }
2725
2726 }
2727 else if (*str == 'x') {
2728 unsigned char hex1, hex2;
2729 str++;
2730
willy tarreauc1f47532005-12-18 01:08:26 +01002731 hex1 = toupper(*str++) - '0';
2732 hex2 = toupper(*str++) - '0';
willy tarreau0f7af912005-12-17 12:21:26 +01002733
2734 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
2735 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
2736 *dst++ = (hex1<<4) + hex2;
2737 }
2738 else
2739 *dst++ = *str++;
2740 }
2741 else
2742 *dst++ = *str++;
2743 }
2744 *dst = 0;
2745 return dst - old_dst;
2746}
2747
willy tarreauc1f47532005-12-18 01:08:26 +01002748static int ishex(char s)
2749{
2750 return (s >= '0' && s <= '9') || (s >= 'A' && s <= 'F') || (s >= 'a' && s <= 'f');
2751}
2752
2753/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
2754char *check_replace_string(char *str)
2755{
2756 char *err = NULL;
2757 while (*str) {
2758 if (*str == '\\') {
2759 err = str; /* in case of a backslash, we return the pointer to it */
2760 str++;
2761 if (!*str)
2762 return err;
2763 else if (isdigit((int)*str))
2764 err = NULL;
2765 else if (*str == 'x') {
2766 str++;
2767 if (!ishex(*str))
2768 return err;
2769 str++;
2770 if (!ishex(*str))
2771 return err;
2772 err = NULL;
2773 }
2774 else {
2775 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
2776 err = NULL;
2777 }
2778 }
2779 str++;
2780 }
2781 return err;
2782}
2783
2784
willy tarreau9fe663a2005-12-17 13:02:59 +01002785
willy tarreau0f7af912005-12-17 12:21:26 +01002786/*
2787 * manages the client FSM and its socket. BTW, it also tries to handle the
2788 * cookie. It returns 1 if a state has changed (and a resync may be needed),
2789 * 0 else.
2790 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002791int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002792 int s = t->srv_state;
2793 int c = t->cli_state;
2794 struct buffer *req = t->req;
2795 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01002796 int method_checked = 0;
2797 appsess *asession_temp = NULL;
2798 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01002799
willy tarreau750a4722005-12-17 13:21:24 +01002800#ifdef DEBUG_FULL
2801 fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2802#endif
willy tarreau0f7af912005-12-17 12:21:26 +01002803 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2804 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2805 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2806 //);
2807 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 /* now parse the partial (or complete) headers */
2809 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
2810 char *ptr;
2811 int delete_header;
willy tarreau12350152005-12-18 01:03:27 +01002812 char *request_line = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01002813
willy tarreau5cbea6f2005-12-17 12:48:26 +01002814 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01002815
willy tarreau0f7af912005-12-17 12:21:26 +01002816 /* look for the end of the current header */
2817 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
2818 ptr++;
2819
willy tarreau5cbea6f2005-12-17 12:48:26 +01002820 if (ptr == req->h) { /* empty line, end of headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002821 int line, len;
2822 /* we can only get here after an end of headers */
2823 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01002824
willy tarreaue39cd132005-12-17 13:00:18 +01002825 if (t->flags & SN_CLDENY) {
2826 /* no need to go further */
willy tarreaua1598082005-12-17 13:08:06 +01002827 t->logs.status = 403;
willy tarreau8337c6b2005-12-17 13:41:01 +01002828 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
willy tarreau036e1ce2005-12-17 13:46:33 +01002829 if (!(t->flags & SN_ERR_MASK))
2830 t->flags |= SN_ERR_PRXCOND;
2831 if (!(t->flags & SN_FINST_MASK))
2832 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01002833 return 1;
2834 }
2835
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836 for (line = 0; line < t->proxy->nb_reqadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01002837 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
2838 buffer_replace2(req, req->h, req->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002839 }
willy tarreau0f7af912005-12-17 12:21:26 +01002840
willy tarreau9fe663a2005-12-17 13:02:59 +01002841 if (t->proxy->options & PR_O_FWDFOR) {
willy tarreau8a86dbf2005-12-18 00:45:59 +01002842 if (t->cli_addr.ss_family == AF_INET) {
2843 unsigned char *pn;
2844 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
2845 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
2846 pn[0], pn[1], pn[2], pn[3]);
2847 buffer_replace2(req, req->h, req->h, trash, len);
2848 }
2849 else if (t->cli_addr.ss_family == AF_INET6) {
2850 char pn[INET6_ADDRSTRLEN];
2851 inet_ntop(AF_INET6,
2852 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2853 pn, sizeof(pn));
2854 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
2855 buffer_replace2(req, req->h, req->h, trash, len);
2856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01002857 }
2858
willy tarreau25c4ea52005-12-18 00:49:49 +01002859 /* add a "connection: close" line if needed */
2860 if (t->proxy->options & PR_O_HTTP_CLOSE)
2861 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
2862
willy tarreau982249e2005-12-18 00:57:06 +01002863 if (!memcmp(req->data, "POST ", 5)) {
2864 /* this is a POST request, which is not cacheable by default */
2865 t->flags |= SN_POST;
2866 }
willy tarreaucd878942005-12-17 13:27:43 +01002867
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002869 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002870
willy tarreau750a4722005-12-17 13:21:24 +01002871 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 /* FIXME: we'll set the client in a wait state while we try to
2873 * connect to the server. Is this really needed ? wouldn't it be
2874 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01002875 //FD_CLR(t->cli_fd, StaticReadEvent);
2876 //tv_eternity(&t->crexpire);
willy tarreau197e8ec2005-12-17 14:10:59 +01002877
2878 /* FIXME: if we break here (as up to 1.1.23), having the client
2879 * shutdown its connection can lead to an abort further.
2880 * it's better to either return 1 or even jump directly to the
2881 * data state which will save one schedule.
2882 */
2883 //break;
willy tarreauc58fc692005-12-17 14:13:08 +01002884
2885 if (!t->proxy->clitimeout ||
2886 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
2887 /* If the client has no timeout, or if the server is not ready yet,
2888 * and we know for sure that it can expire, then it's cleaner to
2889 * disable the timeout on the client side so that too low values
2890 * cannot make the sessions abort too early.
2891 */
2892 tv_eternity(&t->crexpire);
2893
willy tarreau197e8ec2005-12-17 14:10:59 +01002894 goto process_data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002895 }
willy tarreau0f7af912005-12-17 12:21:26 +01002896
willy tarreau5cbea6f2005-12-17 12:48:26 +01002897 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2898 if (ptr > req->r - 2) {
2899 /* this is a partial header, let's wait for more to come */
2900 req->lr = ptr;
2901 break;
2902 }
willy tarreau0f7af912005-12-17 12:21:26 +01002903
willy tarreau5cbea6f2005-12-17 12:48:26 +01002904 /* now we know that *ptr is either \r or \n,
2905 * and that there are at least 1 char after it.
2906 */
2907 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2908 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2909 else
2910 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01002911
willy tarreau5cbea6f2005-12-17 12:48:26 +01002912 /*
2913 * now we know that we have a full header ; we can do whatever
2914 * we want with these pointers :
2915 * req->h = beginning of header
2916 * ptr = end of header (first \r or \n)
2917 * req->lr = beginning of next line (next rep->h)
2918 * req->r = end of data (not used at this stage)
2919 */
willy tarreau0f7af912005-12-17 12:21:26 +01002920
willy tarreau12350152005-12-18 01:03:27 +01002921 if (!method_checked && (t->proxy->appsession_name != NULL) &&
2922 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
2923 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
2924
2925 /* skip ; */
2926 request_line++;
2927
2928 /* look if we have a jsessionid */
2929
2930 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
2931
2932 /* skip jsessionid= */
2933 request_line += t->proxy->appsession_name_len + 1;
2934
2935 /* First try if we allready have an appsession */
2936 asession_temp = &local_asession;
2937
2938 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2939 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
2940 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
2941 return 0;
2942 }
2943
2944 /* Copy the sessionid */
2945 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
2946 asession_temp->sessid[t->proxy->appsession_len] = 0;
2947 asession_temp->serverid = NULL;
2948
2949 /* only do insert, if lookup fails */
2950 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
2951 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2952 Alert("Not enough memory process_cli():asession:calloc().\n");
2953 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
2954 return 0;
2955 }
2956 asession_temp->sessid = local_asession.sessid;
2957 asession_temp->serverid = local_asession.serverid;
2958 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
2959 } /* end if(chtbl_lookup()) */
2960 else{
2961 /*free wasted memory;*/
2962 pool_free_to(apools.sessid, local_asession.sessid);
2963 }
2964
2965 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
2966 asession_temp->request_count++;
2967
2968#if defined(DEBUG_HASH)
2969 print_table(&(t->proxy->htbl_proxy));
2970#endif
2971
2972 if (asession_temp->serverid == NULL) {
2973 Alert("Found Application Session without matching server.\n");
2974 } else {
2975 struct server *srv = t->proxy->srv;
2976 while (srv) {
2977 if (strcmp(srv->id, asession_temp->serverid) == 0) {
2978 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
2979 /* we found the server and it's usable */
2980 t->flags &= ~SN_CK_MASK;
2981 t->flags |= SN_CK_VALID | SN_DIRECT;
2982 t->srv = srv;
2983 break;
2984 }else {
2985 t->flags &= ~SN_CK_MASK;
2986 t->flags |= SN_CK_DOWN;
2987 }
2988 }/* end if(strcmp()) */
2989 srv = srv->next;
2990 }/* end while(srv) */
2991 }/* end else of if (asession_temp->serverid == NULL) */
willy tarreau12350152005-12-18 01:03:27 +01002992 }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
2993 else {
2994 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
2995 }
willy tarreau598da412005-12-18 01:07:29 +01002996 method_checked = 1;
willy tarreau12350152005-12-18 01:03:27 +01002997 }/* end if(!method_checked ...) */
2998 else{
2999 //printf("No Methode-Header with Session-String\n");
3000 }
3001
willy tarreau8337c6b2005-12-17 13:41:01 +01003002 if (t->logs.logwait & LW_REQ) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003003 /* we have a complete HTTP request that we must log */
3004 int urilen;
3005
willy tarreaua1598082005-12-17 13:08:06 +01003006 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
willy tarreau9fe663a2005-12-17 13:02:59 +01003007 Alert("HTTP logging : out of memory.\n");
willy tarreau750a4722005-12-17 13:21:24 +01003008 t->logs.status = 500;
willy tarreau8337c6b2005-12-17 13:41:01 +01003009 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
willy tarreau036e1ce2005-12-17 13:46:33 +01003010 if (!(t->flags & SN_ERR_MASK))
3011 t->flags |= SN_ERR_PRXCOND;
3012 if (!(t->flags & SN_FINST_MASK))
3013 t->flags |= SN_FINST_R;
willy tarreau9fe663a2005-12-17 13:02:59 +01003014 return 1;
3015 }
3016
3017 urilen = ptr - req->h;
3018 if (urilen >= REQURI_LEN)
3019 urilen = REQURI_LEN - 1;
willy tarreaua1598082005-12-17 13:08:06 +01003020 memcpy(t->logs.uri, req->h, urilen);
3021 t->logs.uri[urilen] = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01003022
willy tarreaua1598082005-12-17 13:08:06 +01003023 if (!(t->logs.logwait &= ~LW_REQ))
willy tarreau9fe663a2005-12-17 13:02:59 +01003024 sess_log(t);
3025 }
willy tarreau4302f492005-12-18 01:00:37 +01003026 else if (t->logs.logwait & LW_REQHDR) {
3027 struct cap_hdr *h;
3028 int len;
3029 for (h = t->proxy->req_cap; h; h = h->next) {
3030 if ((h->namelen + 2 <= ptr - req->h) &&
3031 (req->h[h->namelen] == ':') &&
3032 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
3033
3034 if (t->req_cap[h->index] == NULL)
3035 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3036
3037 len = ptr - (req->h + h->namelen + 2);
3038 if (len > h->len)
3039 len = h->len;
3040
3041 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
3042 t->req_cap[h->index][len]=0;
3043 }
3044 }
3045
3046 }
willy tarreau9fe663a2005-12-17 13:02:59 +01003047
willy tarreau5cbea6f2005-12-17 12:48:26 +01003048 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003049
willy tarreau982249e2005-12-18 00:57:06 +01003050 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003051 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003052 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 +01003053 max = ptr - req->h;
3054 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003055 len += strlcpy2(trash + len, req->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003056 trash[len++] = '\n';
3057 write(1, trash, len);
3058 }
willy tarreau0f7af912005-12-17 12:21:26 +01003059
willy tarreau25c4ea52005-12-18 00:49:49 +01003060
3061 /* remove "connection: " if needed */
3062 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
3063 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
3064 delete_header = 1;
3065 }
3066
willy tarreau5cbea6f2005-12-17 12:48:26 +01003067 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01003068 if (!delete_header && t->proxy->req_exp != NULL
3069 && !(t->flags & SN_CLDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003070 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003071 char term;
3072
3073 term = *ptr;
3074 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01003075 exp = t->proxy->req_exp;
3076 do {
3077 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
3078 switch (exp->action) {
3079 case ACT_ALLOW:
3080 if (!(t->flags & SN_CLDENY))
3081 t->flags |= SN_CLALLOW;
3082 break;
3083 case ACT_REPLACE:
3084 if (!(t->flags & SN_CLDENY)) {
3085 int len = exp_replace(trash, req->h, exp->replace, pmatch);
3086 ptr += buffer_replace2(req, req->h, ptr, trash, len);
3087 }
3088 break;
3089 case ACT_REMOVE:
3090 if (!(t->flags & SN_CLDENY))
3091 delete_header = 1;
3092 break;
3093 case ACT_DENY:
3094 if (!(t->flags & SN_CLALLOW))
3095 t->flags |= SN_CLDENY;
3096 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01003097 case ACT_PASS: /* we simply don't deny this one */
3098 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003099 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003100 break;
willy tarreau0f7af912005-12-17 12:21:26 +01003101 }
willy tarreaue39cd132005-12-17 13:00:18 +01003102 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003103 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01003104 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003105
willy tarreau240afa62005-12-17 13:14:35 +01003106 /* Now look for cookies. Conforming to RFC2109, we have to support
3107 * attributes whose name begin with a '$', and associate them with
3108 * the right cookie, if we want to delete this cookie.
3109 * So there are 3 cases for each cookie read :
3110 * 1) it's a special attribute, beginning with a '$' : ignore it.
3111 * 2) it's a server id cookie that we *MAY* want to delete : save
3112 * some pointers on it (last semi-colon, beginning of cookie...)
3113 * 3) it's an application cookie : we *MAY* have to delete a previous
3114 * "special" cookie.
3115 * At the end of loop, if a "special" cookie remains, we may have to
3116 * remove it. If no application cookie persists in the header, we
3117 * *MUST* delete it
3118 */
willy tarreau12350152005-12-18 01:03:27 +01003119 if (!delete_header &&
3120 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau240afa62005-12-17 13:14:35 +01003121 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
willy tarreau906b2682005-12-17 13:49:52 +01003122 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003123 char *p1, *p2, *p3, *p4;
willy tarreau240afa62005-12-17 13:14:35 +01003124 char *del_colon, *del_cookie, *colon;
3125 int app_cookies;
3126
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 p1 = req->h + 8; /* first char after 'Cookie: ' */
willy tarreau240afa62005-12-17 13:14:35 +01003128 colon = p1;
3129 /* del_cookie == NULL => nothing to be deleted */
3130 del_colon = del_cookie = NULL;
3131 app_cookies = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003132
3133 while (p1 < ptr) {
willy tarreau240afa62005-12-17 13:14:35 +01003134 /* skip spaces and colons, but keep an eye on these ones */
3135 while (p1 < ptr) {
3136 if (*p1 == ';' || *p1 == ',')
3137 colon = p1;
3138 else if (!isspace((int)*p1))
3139 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003140 p1++;
willy tarreau240afa62005-12-17 13:14:35 +01003141 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003142
3143 if (p1 == ptr)
3144 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003145
3146 /* p1 is at the beginning of the cookie name */
3147 p2 = p1;
willy tarreau240afa62005-12-17 13:14:35 +01003148 while (p2 < ptr && *p2 != '=')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003149 p2++;
3150
3151 if (p2 == ptr)
3152 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003153
3154 p3 = p2 + 1; /* skips the '=' sign */
3155 if (p3 == ptr)
3156 break;
3157
willy tarreau240afa62005-12-17 13:14:35 +01003158 p4 = p3;
3159 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 p4++;
3161
3162 /* here, we have the cookie name between p1 and p2,
3163 * and its value between p3 and p4.
willy tarreau0174f312005-12-18 01:02:42 +01003164 * we can process it :
3165 *
3166 * Cookie: NAME=VALUE;
3167 * | || || |
3168 * | || || +--> p4
3169 * | || |+-------> p3
3170 * | || +--------> p2
3171 * | |+------------> p1
3172 * | +-------------> colon
3173 * +--------------------> req->h
willy tarreau5cbea6f2005-12-17 12:48:26 +01003174 */
3175
willy tarreau240afa62005-12-17 13:14:35 +01003176 if (*p1 == '$') {
3177 /* skip this one */
3178 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003179 else {
3180 /* first, let's see if we want to capture it */
3181 if (t->proxy->capture_name != NULL &&
3182 t->logs.cli_cookie == NULL &&
3183 (p4 - p1 >= t->proxy->capture_namelen) &&
3184 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
3185 int log_len = p4 - p1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003186
willy tarreau8337c6b2005-12-17 13:41:01 +01003187 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3188 Alert("HTTP logging : out of memory.\n");
willy tarreau12350152005-12-18 01:03:27 +01003189 } else {
3190 if (log_len > t->proxy->capture_len)
3191 log_len = t->proxy->capture_len;
3192 memcpy(t->logs.cli_cookie, p1, log_len);
3193 t->logs.cli_cookie[log_len] = 0;
willy tarreau8337c6b2005-12-17 13:41:01 +01003194 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003195 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003196
3197 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
3198 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
3199 /* Cool... it's the right one */
3200 struct server *srv = t->proxy->srv;
willy tarreau0174f312005-12-18 01:02:42 +01003201 char *delim;
3202
3203 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3204 * have the server ID betweek p3 and delim, and the original cookie between
3205 * delim+1 and p4. Otherwise, delim==p4 :
3206 *
3207 * Cookie: NAME=SRV~VALUE;
3208 * | || || | |
3209 * | || || | +--> p4
3210 * | || || +--------> delim
3211 * | || |+-----------> p3
3212 * | || +------------> p2
3213 * | |+----------------> p1
3214 * | +-----------------> colon
3215 * +------------------------> req->h
3216 */
willy tarreau8337c6b2005-12-17 13:41:01 +01003217
willy tarreau0174f312005-12-18 01:02:42 +01003218 if (t->proxy->options & PR_O_COOK_PFX) {
3219 for (delim = p3; delim < p4; delim++)
3220 if (*delim == COOKIE_DELIM)
3221 break;
3222 }
3223 else
3224 delim = p4;
3225
3226
3227 /* Here, we'll look for the first running server which supports the cookie.
3228 * This allows to share a same cookie between several servers, for example
3229 * to dedicate backup servers to specific servers only.
3230 */
3231 while (srv) {
3232 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3233 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3234 /* we found the server and it's usable */
3235 t->flags &= ~SN_CK_MASK;
3236 t->flags |= SN_CK_VALID | SN_DIRECT;
3237 t->srv = srv;
3238 break;
willy tarreau12350152005-12-18 01:03:27 +01003239 } else {
willy tarreau0174f312005-12-18 01:02:42 +01003240 /* we found a server, but it's down */
3241 t->flags &= ~SN_CK_MASK;
3242 t->flags |= SN_CK_DOWN;
3243 }
3244 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003245 srv = srv->next;
3246 }
3247
willy tarreau0174f312005-12-18 01:02:42 +01003248 if (!srv && !(t->flags & SN_CK_DOWN)) {
3249 /* no server matched this cookie */
willy tarreau036e1ce2005-12-17 13:46:33 +01003250 t->flags &= ~SN_CK_MASK;
3251 t->flags |= SN_CK_INVALID;
3252 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003253
willy tarreau0174f312005-12-18 01:02:42 +01003254 /* depending on the cookie mode, we may have to either :
3255 * - delete the complete cookie if we're in insert+indirect mode, so that
3256 * the server never sees it ;
3257 * - remove the server id from the cookie value, and tag the cookie as an
3258 * application cookie so that it does not get accidentely removed later,
3259 * if we're in cookie prefix mode
willy tarreau8337c6b2005-12-17 13:41:01 +01003260 */
willy tarreau0174f312005-12-18 01:02:42 +01003261 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
3262 buffer_replace2(req, p3, delim + 1, NULL, 0);
3263 p4 -= (delim + 1 - p3);
3264 ptr -= (delim + 1 - p3);
3265 del_cookie = del_colon = NULL;
3266 app_cookies++; /* protect the header from deletion */
3267 }
3268 else if (del_cookie == NULL &&
willy tarreau8337c6b2005-12-17 13:41:01 +01003269 (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 +01003270 del_cookie = p1;
3271 del_colon = colon;
willy tarreau8337c6b2005-12-17 13:41:01 +01003272 }
willy tarreau12350152005-12-18 01:03:27 +01003273 } else {
willy tarreau8337c6b2005-12-17 13:41:01 +01003274 /* now we know that we must keep this cookie since it's
3275 * not ours. But if we wanted to delete our cookie
3276 * earlier, we cannot remove the complete header, but we
3277 * can remove the previous block itself.
3278 */
3279 app_cookies++;
3280
3281 if (del_cookie != NULL) {
3282 buffer_replace2(req, del_cookie, p1, NULL, 0);
3283 p4 -= (p1 - del_cookie);
3284 ptr -= (p1 - del_cookie);
3285 del_cookie = del_colon = NULL;
3286 }
willy tarreau240afa62005-12-17 13:14:35 +01003287 }
willy tarreau12350152005-12-18 01:03:27 +01003288
3289 if ((t->proxy->appsession_name != NULL) &&
3290 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
3291 /* first, let's see if the cookie is our appcookie*/
3292
3293 /* Cool... it's the right one */
3294
3295 asession_temp = &local_asession;
3296
3297 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3298 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3299 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3300 return 0;
3301 }
3302
3303 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
3304 asession_temp->sessid[t->proxy->appsession_len] = 0;
3305 asession_temp->serverid = NULL;
3306
3307 /* only do insert, if lookup fails */
3308 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
3309 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3310 Alert("Not enough memory process_cli():asession:calloc().\n");
3311 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3312 return 0;
3313 }
3314
3315 asession_temp->sessid = local_asession.sessid;
3316 asession_temp->serverid = local_asession.serverid;
3317 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
3318 }
3319 else{
3320 /* free wasted memory */
3321 pool_free_to(apools.sessid, local_asession.sessid);
3322 }
3323
3324 if (asession_temp->serverid == NULL) {
3325 Alert("Found Application Session without matching server.\n");
3326 } else {
3327 struct server *srv = t->proxy->srv;
3328 while (srv) {
3329 if(strcmp(srv->id, asession_temp->serverid) == 0) {
3330 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
3331 /* we found the server and it's usable */
3332 t->flags &= ~SN_CK_MASK;
3333 t->flags |= SN_CK_VALID | SN_DIRECT;
3334 t->srv = srv;
3335 break;
3336 } else {
3337 t->flags &= ~SN_CK_MASK;
3338 t->flags |= SN_CK_DOWN;
3339 }
3340 }
3341 srv = srv->next;
3342 }/* end while(srv) */
3343 }/* end else if server == NULL */
3344
3345 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
willy tarreau12350152005-12-18 01:03:27 +01003346 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347 }
willy tarreau240afa62005-12-17 13:14:35 +01003348
willy tarreau5cbea6f2005-12-17 12:48:26 +01003349 /* we'll have to look for another cookie ... */
3350 p1 = p4;
3351 } /* while (p1 < ptr) */
willy tarreau240afa62005-12-17 13:14:35 +01003352
3353 /* There's no more cookie on this line.
3354 * We may have marked the last one(s) for deletion.
3355 * We must do this now in two ways :
3356 * - if there is no app cookie, we simply delete the header ;
3357 * - if there are app cookies, we must delete the end of the
3358 * string properly, including the colon/semi-colon before
3359 * the cookie name.
3360 */
3361 if (del_cookie != NULL) {
3362 if (app_cookies) {
3363 buffer_replace2(req, del_colon, ptr, NULL, 0);
3364 /* WARNING! <ptr> becomes invalid for now. If some code
3365 * below needs to rely on it before the end of the global
3366 * header loop, we need to correct it with this code :
3367 * ptr = del_colon;
3368 */
3369 }
3370 else
3371 delete_header = 1;
3372 }
3373 } /* end of cookie processing on this header */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374
3375 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01003376 if (delete_header && !(t->flags & SN_CLDENY)) {
willy tarreau240afa62005-12-17 13:14:35 +01003377 buffer_replace2(req, req->h, req->lr, NULL, 0);
willy tarreau0f7af912005-12-17 12:21:26 +01003378 }
willy tarreau240afa62005-12-17 13:14:35 +01003379 /* WARNING: ptr is not valid anymore, since the header may have been deleted or truncated ! */
3380
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 req->h = req->lr;
3382 } /* while (req->lr < req->r) */
3383
3384 /* end of header processing (even if incomplete) */
3385
willy tarreauef900ab2005-12-17 12:52:52 +01003386 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3387 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
3388 * full. We cannot loop here since event_cli_read will disable it only if
3389 * req->l == rlim-data
3390 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003391 FD_SET(t->cli_fd, StaticReadEvent);
3392 if (t->proxy->clitimeout)
3393 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3394 else
3395 tv_eternity(&t->crexpire);
3396 }
3397
willy tarreaue39cd132005-12-17 13:00:18 +01003398 /* Since we are in header mode, if there's no space left for headers, we
willy tarreauef900ab2005-12-17 12:52:52 +01003399 * won't be able to free more later, so the session will never terminate.
3400 */
willy tarreaue39cd132005-12-17 13:00:18 +01003401 if (req->l >= req->rlim - req->data) {
willy tarreaua1598082005-12-17 13:08:06 +01003402 t->logs.status = 400;
willy tarreau8337c6b2005-12-17 13:41:01 +01003403 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
willy tarreau036e1ce2005-12-17 13:46:33 +01003404 if (!(t->flags & SN_ERR_MASK))
3405 t->flags |= SN_ERR_PRXCOND;
3406 if (!(t->flags & SN_FINST_MASK))
3407 t->flags |= SN_FINST_R;
willy tarreaue39cd132005-12-17 13:00:18 +01003408 return 1;
3409 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003410 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003411 /* read error, or last read : give up. */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003412 tv_eternity(&t->crexpire);
3413 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003414 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003415 if (!(t->flags & SN_ERR_MASK))
3416 t->flags |= SN_ERR_CLICL;
3417 if (!(t->flags & SN_FINST_MASK))
3418 t->flags |= SN_FINST_R;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003419 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003420 }
willy tarreau8337c6b2005-12-17 13:41:01 +01003421 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3422
3423 /* read timeout : give up with an error message.
3424 */
3425 t->logs.status = 408;
3426 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
willy tarreau036e1ce2005-12-17 13:46:33 +01003427 if (!(t->flags & SN_ERR_MASK))
3428 t->flags |= SN_ERR_CLITO;
3429 if (!(t->flags & SN_FINST_MASK))
3430 t->flags |= SN_FINST_R;
willy tarreau8337c6b2005-12-17 13:41:01 +01003431 return 1;
3432 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003433
3434 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01003435 }
3436 else if (c == CL_STDATA) {
willy tarreau197e8ec2005-12-17 14:10:59 +01003437 process_data:
willy tarreauc1cae632005-12-17 14:12:23 +01003438 /* FIXME: this error handling is partly buggy because we always report
3439 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
3440 * or HEADER phase. BTW, it's not logical to expire the client while
3441 * we're waiting for the server to connect.
3442 */
willy tarreau0f7af912005-12-17 12:21:26 +01003443 /* read or write error */
3444 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003445 tv_eternity(&t->crexpire);
3446 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003447 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003448 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003449 if (!(t->flags & SN_ERR_MASK))
3450 t->flags |= SN_ERR_CLICL;
3451 if (!(t->flags & SN_FINST_MASK))
3452 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003453 return 1;
3454 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003455 /* last read, or end of server write */
3456 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01003457 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003458 tv_eternity(&t->crexpire);
3459 shutdown(t->cli_fd, SHUT_RD);
3460 t->cli_state = CL_STSHUTR;
3461 return 1;
3462 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003463 /* last server read and buffer empty */
3464 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003465 FD_CLR(t->cli_fd, StaticWriteEvent);
3466 tv_eternity(&t->cwexpire);
3467 shutdown(t->cli_fd, SHUT_WR);
3468 t->cli_state = CL_STSHUTW;
3469 return 1;
3470 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003471 /* read timeout */
3472 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3473 FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau036e1ce2005-12-17 13:46:33 +01003474 tv_eternity(&t->crexpire);
3475 shutdown(t->cli_fd, SHUT_RD);
3476 t->cli_state = CL_STSHUTR;
3477 if (!(t->flags & SN_ERR_MASK))
3478 t->flags |= SN_ERR_CLITO;
3479 if (!(t->flags & SN_FINST_MASK))
3480 t->flags |= SN_FINST_D;
3481 return 1;
3482 }
3483 /* write timeout */
3484 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3485 FD_CLR(t->cli_fd, StaticWriteEvent);
3486 tv_eternity(&t->cwexpire);
3487 shutdown(t->cli_fd, SHUT_WR);
3488 t->cli_state = CL_STSHUTW;
3489 if (!(t->flags & SN_ERR_MASK))
willy tarreaub1ff9db2005-12-17 13:51:03 +01003490 t->flags |= SN_ERR_CLITO;
willy tarreau036e1ce2005-12-17 13:46:33 +01003491 if (!(t->flags & SN_FINST_MASK))
3492 t->flags |= SN_FINST_D;
3493 return 1;
3494 }
willy tarreau0f7af912005-12-17 12:21:26 +01003495
willy tarreauc58fc692005-12-17 14:13:08 +01003496 if (req->l >= req->rlim - req->data) {
3497 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003498 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003499 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003500 FD_CLR(t->cli_fd, StaticReadEvent);
3501 tv_eternity(&t->crexpire);
3502 }
3503 }
3504 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003505 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003506 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3507 FD_SET(t->cli_fd, StaticReadEvent);
willy tarreauc58fc692005-12-17 14:13:08 +01003508 if (!t->proxy->clitimeout ||
3509 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
3510 /* If the client has no timeout, or if the server not ready yet, and we
3511 * know for sure that it can expire, then it's cleaner to disable the
3512 * timeout on the client side so that too low values cannot make the
3513 * sessions abort too early.
3514 */
willy tarreau0f7af912005-12-17 12:21:26 +01003515 tv_eternity(&t->crexpire);
willy tarreauc58fc692005-12-17 14:13:08 +01003516 else
3517 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
willy tarreau0f7af912005-12-17 12:21:26 +01003518 }
3519 }
3520
3521 if ((rep->l == 0) ||
willy tarreauc1cae632005-12-17 14:12:23 +01003522 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003523 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3524 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3525 tv_eternity(&t->cwexpire);
3526 }
3527 }
3528 else { /* buffer not empty */
3529 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3530 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003531 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003532 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003533 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3534 t->crexpire = t->cwexpire;
3535 }
willy tarreau0f7af912005-12-17 12:21:26 +01003536 else
3537 tv_eternity(&t->cwexpire);
3538 }
3539 }
3540 return 0; /* other cases change nothing */
3541 }
3542 else if (c == CL_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003543 if (t->res_cw == RES_ERROR) {
3544 tv_eternity(&t->cwexpire);
3545 fd_delete(t->cli_fd);
3546 t->cli_state = CL_STCLOSE;
3547 if (!(t->flags & SN_ERR_MASK))
3548 t->flags |= SN_ERR_CLICL;
3549 if (!(t->flags & SN_FINST_MASK))
3550 t->flags |= SN_FINST_D;
3551 return 1;
3552 }
3553 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003554 tv_eternity(&t->cwexpire);
3555 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003556 t->cli_state = CL_STCLOSE;
3557 return 1;
3558 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003559 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
3560 tv_eternity(&t->cwexpire);
3561 fd_delete(t->cli_fd);
3562 t->cli_state = CL_STCLOSE;
3563 if (!(t->flags & SN_ERR_MASK))
3564 t->flags |= SN_ERR_CLITO;
3565 if (!(t->flags & SN_FINST_MASK))
3566 t->flags |= SN_FINST_D;
3567 return 1;
3568 }
willy tarreau0f7af912005-12-17 12:21:26 +01003569 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01003570 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01003571 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3572 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
3573 tv_eternity(&t->cwexpire);
3574 }
3575 }
3576 else { /* buffer not empty */
3577 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
3578 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01003579 if (t->proxy->clitimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01003580 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003581 /* FIXME: to avoid the client to read-time-out during writes, we refresh it */
3582 t->crexpire = t->cwexpire;
3583 }
willy tarreau0f7af912005-12-17 12:21:26 +01003584 else
3585 tv_eternity(&t->cwexpire);
3586 }
3587 }
3588 return 0;
3589 }
3590 else if (c == CL_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01003591 if (t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01003592 tv_eternity(&t->crexpire);
3593 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003594 t->cli_state = CL_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003595 if (!(t->flags & SN_ERR_MASK))
3596 t->flags |= SN_ERR_CLICL;
3597 if (!(t->flags & SN_FINST_MASK))
3598 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01003599 return 1;
3600 }
willy tarreau036e1ce2005-12-17 13:46:33 +01003601 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
3602 tv_eternity(&t->crexpire);
3603 fd_delete(t->cli_fd);
3604 t->cli_state = CL_STCLOSE;
3605 return 1;
3606 }
3607 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
3608 tv_eternity(&t->crexpire);
3609 fd_delete(t->cli_fd);
3610 t->cli_state = CL_STCLOSE;
3611 if (!(t->flags & SN_ERR_MASK))
3612 t->flags |= SN_ERR_CLITO;
3613 if (!(t->flags & SN_FINST_MASK))
3614 t->flags |= SN_FINST_D;
3615 return 1;
3616 }
willy tarreauef900ab2005-12-17 12:52:52 +01003617 else if (req->l >= req->rlim - req->data) {
3618 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01003619 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01003620 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01003621 FD_CLR(t->cli_fd, StaticReadEvent);
3622 tv_eternity(&t->crexpire);
3623 }
3624 }
3625 else {
willy tarreauef900ab2005-12-17 12:52:52 +01003626 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01003627 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
3628 FD_SET(t->cli_fd, StaticReadEvent);
3629 if (t->proxy->clitimeout)
3630 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
3631 else
3632 tv_eternity(&t->crexpire);
3633 }
3634 }
3635 return 0;
3636 }
3637 else { /* CL_STCLOSE: nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01003638 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01003639 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01003640 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 +01003641 write(1, trash, len);
3642 }
3643 return 0;
3644 }
3645 return 0;
3646}
3647
3648
3649/*
3650 * manages the server FSM and its socket. It returns 1 if a state has changed
3651 * (and a resync may be needed), 0 else.
3652 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003653int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01003654 int s = t->srv_state;
3655 int c = t->cli_state;
3656 struct buffer *req = t->req;
3657 struct buffer *rep = t->rep;
willy tarreau12350152005-12-18 01:03:27 +01003658 appsess *asession_temp = NULL;
3659 appsess local_asession;
willy tarreau0f7af912005-12-17 12:21:26 +01003660
willy tarreau750a4722005-12-17 13:21:24 +01003661#ifdef DEBUG_FULL
3662 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
3663#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01003664 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
3665 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
3666 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
3667 //);
willy tarreau0f7af912005-12-17 12:21:26 +01003668 if (s == SV_STIDLE) {
3669 if (c == CL_STHEADERS)
3670 return 0; /* stay in idle, waiting for data to reach the client side */
3671 else if (c == CL_STCLOSE ||
3672 c == CL_STSHUTW ||
3673 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
3674 tv_eternity(&t->cnexpire);
3675 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01003676 if (!(t->flags & SN_ERR_MASK))
3677 t->flags |= SN_ERR_CLICL;
3678 if (!(t->flags & SN_FINST_MASK))
3679 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003680 return 1;
3681 }
3682 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003683 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01003684 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
3685 t->srv_state = SV_STCONN;
3686 }
3687 else { /* try again */
3688 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003689 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003690 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003691 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003692 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3693 t->flags &= ~SN_CK_MASK;
3694 t->flags |= SN_CK_DOWN;
3695 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003696 }
3697
3698 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01003699 t->srv_state = SV_STCONN;
3700 break;
3701 }
3702 }
3703 if (t->conn_retries < 0) {
3704 /* if conn_retries < 0 or other error, let's abort */
3705 tv_eternity(&t->cnexpire);
3706 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003707 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003708 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003709 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003710 if (!(t->flags & SN_ERR_MASK))
3711 t->flags |= SN_ERR_SRVCL;
3712 if (!(t->flags & SN_FINST_MASK))
3713 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003714 }
3715 }
3716 return 1;
3717 }
3718 }
3719 else if (s == SV_STCONN) { /* connection in progress */
3720 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
3721 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
3722 return 0; /* nothing changed */
3723 }
3724 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
3725 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
3726 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003727 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01003728 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01003730 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731 if (t->conn_retries >= 0) {
3732 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
willy tarreaue39cd132005-12-17 13:00:18 +01003733 t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003734 t->srv = NULL; /* it's left to the dispatcher to choose a server */
willy tarreau036e1ce2005-12-17 13:46:33 +01003735 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
3736 t->flags &= ~SN_CK_MASK;
3737 t->flags |= SN_CK_DOWN;
3738 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003739 }
3740 if (connect_server(t) == 0)
3741 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01003742 }
3743 /* if conn_retries < 0 or other error, let's abort */
3744 tv_eternity(&t->cnexpire);
3745 t->srv_state = SV_STCLOSE;
willy tarreau8337c6b2005-12-17 13:41:01 +01003746 t->logs.status = 503;
willy tarreau750a4722005-12-17 13:21:24 +01003747 if (t->proxy->mode == PR_MODE_HTTP)
willy tarreau8337c6b2005-12-17 13:41:01 +01003748 client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
willy tarreau036e1ce2005-12-17 13:46:33 +01003749 if (!(t->flags & SN_ERR_MASK))
3750 t->flags |= SN_ERR_SRVCL;
3751 if (!(t->flags & SN_FINST_MASK))
3752 t->flags |= SN_FINST_C;
willy tarreau0f7af912005-12-17 12:21:26 +01003753 return 1;
3754 }
3755 else { /* no error or write 0 */
willy tarreau750a4722005-12-17 13:21:24 +01003756 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01003757
willy tarreau0f7af912005-12-17 12:21:26 +01003758 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003759 if (req->l == 0) /* nothing to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003760 FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003761 tv_eternity(&t->swexpire);
3762 } else /* need the right to write */ {
willy tarreau0f7af912005-12-17 12:21:26 +01003763 FD_SET(t->srv_fd, StaticWriteEvent);
willy tarreaub1ff9db2005-12-17 13:51:03 +01003764 if (t->proxy->srvtimeout) {
3765 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
3766 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
3767 t->srexpire = t->swexpire;
3768 }
3769 else
3770 tv_eternity(&t->swexpire);
3771 }
willy tarreau0f7af912005-12-17 12:21:26 +01003772
3773 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
3774 FD_SET(t->srv_fd, StaticReadEvent);
3775 if (t->proxy->srvtimeout)
3776 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
3777 else
3778 tv_eternity(&t->srexpire);
3779
3780 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003781 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau25c4ea52005-12-18 00:49:49 +01003782
3783 /* if the user wants to log as soon as possible, without counting
3784 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003785 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003786 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
3787 sess_log(t);
3788 }
willy tarreau0f7af912005-12-17 12:21:26 +01003789 }
willy tarreauef900ab2005-12-17 12:52:52 +01003790 else {
willy tarreau0f7af912005-12-17 12:21:26 +01003791 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01003792 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
3793 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003794 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01003795 return 1;
3796 }
3797 }
3798 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003799 /* now parse the partial (or complete) headers */
3800 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
3801 char *ptr;
3802 int delete_header;
3803
3804 ptr = rep->lr;
3805
3806 /* look for the end of the current header */
3807 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
3808 ptr++;
3809
3810 if (ptr == rep->h) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003811 int line, len;
3812
3813 /* we can only get here after an end of headers */
willy tarreau97f58572005-12-18 00:53:44 +01003814
3815 /* first, we'll block if security checks have caught nasty things */
3816 if (t->flags & SN_CACHEABLE) {
3817 if ((t->flags & SN_CACHE_COOK) &&
3818 (t->flags & SN_SCK_ANY) &&
3819 (t->proxy->options & PR_O_CHK_CACHE)) {
3820
3821 /* we're in presence of a cacheable response containing
3822 * a set-cookie header. We'll block it as requested by
3823 * the 'checkcache' option, and send an alert.
3824 */
3825 tv_eternity(&t->srexpire);
3826 tv_eternity(&t->swexpire);
3827 fd_delete(t->srv_fd);
3828 t->srv_state = SV_STCLOSE;
3829 t->logs.status = 502;
3830 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3831 if (!(t->flags & SN_ERR_MASK))
3832 t->flags |= SN_ERR_PRXCOND;
3833 if (!(t->flags & SN_FINST_MASK))
3834 t->flags |= SN_FINST_H;
3835
3836 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3837 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
3838
3839 return 1;
3840 }
3841 }
3842
willy tarreau982249e2005-12-18 00:57:06 +01003843 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
3844 if (t->flags & SN_SVDENY) {
3845 tv_eternity(&t->srexpire);
3846 tv_eternity(&t->swexpire);
3847 fd_delete(t->srv_fd);
3848 t->srv_state = SV_STCLOSE;
3849 t->logs.status = 502;
3850 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
3851 if (!(t->flags & SN_ERR_MASK))
3852 t->flags |= SN_ERR_PRXCOND;
3853 if (!(t->flags & SN_FINST_MASK))
3854 t->flags |= SN_FINST_H;
3855 return 1;
3856 }
3857
willy tarreau5cbea6f2005-12-17 12:48:26 +01003858 /* we'll have something else to do here : add new headers ... */
3859
willy tarreaucd878942005-12-17 13:27:43 +01003860 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
3861 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003862 /* the server is known, it's not the one the client requested, we have to
willy tarreaucd878942005-12-17 13:27:43 +01003863 * insert a set-cookie here, except if we want to insert only on POST
3864 * requests and this one isn't.
willy tarreau5cbea6f2005-12-17 12:48:26 +01003865 */
willy tarreau750a4722005-12-17 13:21:24 +01003866 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
willy tarreau8337c6b2005-12-17 13:41:01 +01003867 t->proxy->cookie_name,
3868 t->srv->cookie ? t->srv->cookie : "");
willy tarreau750a4722005-12-17 13:21:24 +01003869
willy tarreau036e1ce2005-12-17 13:46:33 +01003870 t->flags |= SN_SCK_INSERTED;
3871
willy tarreau750a4722005-12-17 13:21:24 +01003872 /* Here, we will tell an eventual cache on the client side that we don't
3873 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3874 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3875 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3876 */
willy tarreau240afa62005-12-17 13:14:35 +01003877 if (t->proxy->options & PR_O_COOK_NOC)
willy tarreau750a4722005-12-17 13:21:24 +01003878 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
3879 len += sprintf(trash + len, "Cache-control: private\r\n");
willy tarreaucd878942005-12-17 13:27:43 +01003880
willy tarreau750a4722005-12-17 13:21:24 +01003881 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003882 }
3883
3884 /* headers to be added */
3885 for (line = 0; line < t->proxy->nb_rspadd; line++) {
willy tarreau750a4722005-12-17 13:21:24 +01003886 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
3887 buffer_replace2(rep, rep->h, rep->h, trash, len);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003888 }
3889
willy tarreau25c4ea52005-12-18 00:49:49 +01003890 /* add a "connection: close" line if needed */
3891 if (t->proxy->options & PR_O_HTTP_CLOSE)
3892 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
3893
willy tarreau5cbea6f2005-12-17 12:48:26 +01003894 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01003895 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau750a4722005-12-17 13:21:24 +01003896 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
willy tarreau25c4ea52005-12-18 00:49:49 +01003897
3898 /* if the user wants to log as soon as possible, without counting
3899 bytes from the server, then this is the right moment. */
willy tarreau4302f492005-12-18 01:00:37 +01003900 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
willy tarreau25c4ea52005-12-18 00:49:49 +01003901 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3902 t->logs.bytes = rep->h - rep->data;
3903 sess_log(t);
3904 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003905 break;
3906 }
3907
3908 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
3909 if (ptr > rep->r - 2) {
3910 /* this is a partial header, let's wait for more to come */
3911 rep->lr = ptr;
3912 break;
3913 }
3914
3915 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
3916 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
3917
3918 /* now we know that *ptr is either \r or \n,
3919 * and that there are at least 1 char after it.
3920 */
3921 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
3922 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
3923 else
3924 rep->lr = ptr + 2; /* \r\n or \n\r */
3925
3926 /*
3927 * now we know that we have a full header ; we can do whatever
3928 * we want with these pointers :
3929 * rep->h = beginning of header
3930 * ptr = end of header (first \r or \n)
3931 * rep->lr = beginning of next line (next rep->h)
3932 * rep->r = end of data (not used at this stage)
3933 */
3934
willy tarreaua1598082005-12-17 13:08:06 +01003935
willy tarreau982249e2005-12-18 00:57:06 +01003936 if (t->logs.status == -1) {
willy tarreaua1598082005-12-17 13:08:06 +01003937 t->logs.logwait &= ~LW_RESP;
3938 t->logs.status = atoi(rep->h + 9);
willy tarreau982249e2005-12-18 00:57:06 +01003939 switch (t->logs.status) {
3940 case 200:
3941 case 203:
3942 case 206:
3943 case 300:
3944 case 301:
3945 case 410:
3946 /* RFC2616 @13.4:
3947 * "A response received with a status code of
3948 * 200, 203, 206, 300, 301 or 410 MAY be stored
3949 * by a cache (...) unless a cache-control
3950 * directive prohibits caching."
3951 *
3952 * RFC2616 @9.5: POST method :
3953 * "Responses to this method are not cacheable,
3954 * unless the response includes appropriate
3955 * Cache-Control or Expires header fields."
3956 */
3957 if ((!t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
3958 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
3959 break;
3960 default:
3961 break;
3962 }
willy tarreau4302f492005-12-18 01:00:37 +01003963 }
3964 else if (t->logs.logwait & LW_RSPHDR) {
3965 struct cap_hdr *h;
3966 int len;
3967 for (h = t->proxy->rsp_cap; h; h = h->next) {
3968 if ((h->namelen + 2 <= ptr - rep->h) &&
3969 (rep->h[h->namelen] == ':') &&
3970 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
3971
3972 if (t->rsp_cap[h->index] == NULL)
3973 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
3974
3975 len = ptr - (rep->h + h->namelen + 2);
3976 if (len > h->len)
3977 len = h->len;
3978
3979 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
3980 t->rsp_cap[h->index][len]=0;
3981 }
3982 }
3983
willy tarreaua1598082005-12-17 13:08:06 +01003984 }
3985
willy tarreau5cbea6f2005-12-17 12:48:26 +01003986 delete_header = 0;
3987
willy tarreau982249e2005-12-18 00:57:06 +01003988 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003989 int len, max;
willy tarreau2f6ba652005-12-17 13:57:42 +01003990 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 +01003991 max = ptr - rep->h;
3992 UBOUND(max, sizeof(trash) - len - 1);
willy tarreau750a4722005-12-17 13:21:24 +01003993 len += strlcpy2(trash + len, rep->h, max + 1);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003994 trash[len++] = '\n';
3995 write(1, trash, len);
3996 }
3997
willy tarreau25c4ea52005-12-18 00:49:49 +01003998 /* remove "connection: " if needed */
3999 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
4000 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
4001 delete_header = 1;
4002 }
4003
willy tarreau5cbea6f2005-12-17 12:48:26 +01004004 /* try headers regexps */
willy tarreau25c4ea52005-12-18 00:49:49 +01004005 if (!delete_header && t->proxy->rsp_exp != NULL
4006 && !(t->flags & SN_SVDENY)) {
willy tarreaue39cd132005-12-17 13:00:18 +01004007 struct hdr_exp *exp;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004008 char term;
4009
4010 term = *ptr;
4011 *ptr = '\0';
willy tarreaue39cd132005-12-17 13:00:18 +01004012 exp = t->proxy->rsp_exp;
4013 do {
4014 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
4015 switch (exp->action) {
4016 case ACT_ALLOW:
4017 if (!(t->flags & SN_SVDENY))
4018 t->flags |= SN_SVALLOW;
4019 break;
4020 case ACT_REPLACE:
4021 if (!(t->flags & SN_SVDENY)) {
4022 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
4023 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
4024 }
4025 break;
4026 case ACT_REMOVE:
4027 if (!(t->flags & SN_SVDENY))
4028 delete_header = 1;
4029 break;
4030 case ACT_DENY:
4031 if (!(t->flags & SN_SVALLOW))
4032 t->flags |= SN_SVDENY;
4033 break;
willy tarreau036e1ce2005-12-17 13:46:33 +01004034 case ACT_PASS: /* we simply don't deny this one */
4035 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004036 }
4037 break;
4038 }
willy tarreaue39cd132005-12-17 13:00:18 +01004039 } while ((exp = exp->next) != NULL);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004040 *ptr = term; /* restore the string terminator */
4041 }
4042
willy tarreau97f58572005-12-18 00:53:44 +01004043 /* check for cache-control: or pragma: headers */
4044 if (!delete_header && (t->flags & SN_CACHEABLE)) {
4045 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
4046 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4047 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
4048 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
willy tarreau982249e2005-12-18 00:57:06 +01004049 if (rep->h + 23 == ptr || rep->h[23] == ',')
willy tarreau97f58572005-12-18 00:53:44 +01004050 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4051 else {
4052 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
willy tarreau982249e2005-12-18 00:57:06 +01004053 && (rep->h[35] == '"' || rep->h[35] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004054 t->flags &= ~SN_CACHE_COOK;
4055 }
4056 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004057 (rep->h + 22 == ptr || rep->h[22] == ','))
willy tarreau97f58572005-12-18 00:53:44 +01004058 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004059 (rep->h + 23 == ptr || rep->h[23] == ','))) {
willy tarreau97f58572005-12-18 00:53:44 +01004060 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4061 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
willy tarreau982249e2005-12-18 00:57:06 +01004062 (rep->h + 24 == ptr || rep->h[24] == ',')) {
willy tarreau97f58572005-12-18 00:53:44 +01004063 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
willy tarreau982249e2005-12-18 00:57:06 +01004064 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
4065 (rep->h + 25 == ptr || rep->h[25] == ',')) {
4066 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
4067 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
4068 (rep->h + 21 == ptr || rep->h[21] == ',')) {
4069 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
willy tarreau97f58572005-12-18 00:53:44 +01004070 }
4071 }
4072 }
4073
willy tarreau5cbea6f2005-12-17 12:48:26 +01004074 /* check for server cookies */
willy tarreau8337c6b2005-12-17 13:41:01 +01004075 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
willy tarreau12350152005-12-18 01:03:27 +01004076 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
willy tarreau906b2682005-12-17 13:49:52 +01004077 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004078 char *p1, *p2, *p3, *p4;
4079
willy tarreau97f58572005-12-18 00:53:44 +01004080 t->flags |= SN_SCK_ANY;
4081
willy tarreau5cbea6f2005-12-17 12:48:26 +01004082 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
4083
4084 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
willy tarreauc29948c2005-12-17 13:10:27 +01004085 while (p1 < ptr && (isspace((int)*p1)))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004086 p1++;
4087
4088 if (p1 == ptr || *p1 == ';') /* end of cookie */
4089 break;
4090
4091 /* p1 is at the beginning of the cookie name */
4092 p2 = p1;
4093
4094 while (p2 < ptr && *p2 != '=' && *p2 != ';')
4095 p2++;
4096
4097 if (p2 == ptr || *p2 == ';') /* next cookie */
4098 break;
4099
4100 p3 = p2 + 1; /* skips the '=' sign */
4101 if (p3 == ptr)
4102 break;
4103
4104 p4 = p3;
willy tarreauc29948c2005-12-17 13:10:27 +01004105 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
willy tarreau5cbea6f2005-12-17 12:48:26 +01004106 p4++;
4107
4108 /* here, we have the cookie name between p1 and p2,
4109 * and its value between p3 and p4.
4110 * we can process it.
4111 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004112
4113 /* first, let's see if we want to capture it */
4114 if (t->proxy->capture_name != NULL &&
4115 t->logs.srv_cookie == NULL &&
4116 (p4 - p1 >= t->proxy->capture_namelen) &&
4117 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
4118 int log_len = p4 - p1;
4119
4120 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
4121 Alert("HTTP logging : out of memory.\n");
4122 }
4123
4124 if (log_len > t->proxy->capture_len)
4125 log_len = t->proxy->capture_len;
4126 memcpy(t->logs.srv_cookie, p1, log_len);
4127 t->logs.srv_cookie[log_len] = 0;
4128 }
4129
4130 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
4131 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004132 /* Cool... it's the right one */
willy tarreau036e1ce2005-12-17 13:46:33 +01004133 t->flags |= SN_SCK_SEEN;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004134
4135 /* If the cookie is in insert mode on a known server, we'll delete
4136 * this occurrence because we'll insert another one later.
4137 * We'll delete it too if the "indirect" option is set and we're in
4138 * a direct access. */
4139 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
willy tarreaue39cd132005-12-17 13:00:18 +01004140 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004141 /* this header must be deleted */
4142 delete_header = 1;
willy tarreau036e1ce2005-12-17 13:46:33 +01004143 t->flags |= SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004144 }
4145 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
4146 /* replace bytes p3->p4 with the cookie name associated
4147 * with this server since we know it.
4148 */
4149 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
willy tarreau036e1ce2005-12-17 13:46:33 +01004150 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004151 }
willy tarreau0174f312005-12-18 01:02:42 +01004152 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
4153 /* insert the cookie name associated with this server
4154 * before existing cookie, and insert a delimitor between them..
4155 */
4156 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4157 p3[t->srv->cklen] = COOKIE_DELIM;
4158 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
4159 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004160 break;
4161 }
willy tarreau12350152005-12-18 01:03:27 +01004162
4163 /* first, let's see if the cookie is our appcookie*/
4164 if ((t->proxy->appsession_name != NULL) &&
4165 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
4166
4167 /* Cool... it's the right one */
4168
4169 size_t server_id_len = strlen(t->srv->id)+1;
4170 asession_temp = &local_asession;
4171
4172 if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
4173 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4174 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4175 }
4176 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
4177 asession_temp->sessid[t->proxy->appsession_len] = 0;
4178 asession_temp->serverid = NULL;
4179
4180 /* only do insert, if lookup fails */
4181 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
4182 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4183 Alert("Not enought Memory process_srv():asession:calloc().\n");
4184 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
4185 return 0;
4186 }
4187 asession_temp->sessid = local_asession.sessid;
4188 asession_temp->serverid = local_asession.serverid;
4189 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
4190 }/* end if(chtbl_lookup()) */
4191 else
4192 {
4193 /* free wasted memory */
4194 pool_free_to(apools.sessid, local_asession.sessid);
4195 } /* end else from if(chtbl_lookup()) */
4196
4197 if(asession_temp->serverid == NULL){
4198 if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
4199 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
4200 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
4201 }
4202 asession_temp->serverid[0] = '\0';
4203 }
4204
4205 if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
4206
4207 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
4208
4209#if defined(DEBUG_HASH)
4210 print_table(&(t->proxy->htbl_proxy));
4211#endif
4212 break;
4213 }/* end if ((t->proxy->appsession_name != NULL) ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004214 else {
4215 // fprintf(stderr,"Ignoring unknown cookie : ");
4216 // write(2, p1, p2-p1);
4217 // fprintf(stderr," = ");
4218 // write(2, p3, p4-p3);
4219 // fprintf(stderr,"\n");
4220 }
4221 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4222 } /* we're now at the end of the cookie value */
4223 } /* end of cookie processing */
4224
willy tarreau97f58572005-12-18 00:53:44 +01004225 /* check for any set-cookie in case we check for cacheability */
4226 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
4227 (t->proxy->options & PR_O_CHK_CACHE) &&
4228 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
4229 t->flags |= SN_SCK_ANY;
4230 }
4231
willy tarreau5cbea6f2005-12-17 12:48:26 +01004232 /* let's look if we have to delete this header */
willy tarreaue39cd132005-12-17 13:00:18 +01004233 if (delete_header && !(t->flags & SN_SVDENY))
willy tarreau5cbea6f2005-12-17 12:48:26 +01004234 buffer_replace2(rep, rep->h, rep->lr, "", 0);
willy tarreaue39cd132005-12-17 13:00:18 +01004235
willy tarreau5cbea6f2005-12-17 12:48:26 +01004236 rep->h = rep->lr;
4237 } /* while (rep->lr < rep->r) */
4238
4239 /* end of header processing (even if incomplete) */
4240
willy tarreauef900ab2005-12-17 12:52:52 +01004241 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4242 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
4243 * full. We cannot loop here since event_srv_read will disable it only if
4244 * rep->l == rlim-data
4245 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004246 FD_SET(t->srv_fd, StaticReadEvent);
4247 if (t->proxy->srvtimeout)
4248 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4249 else
4250 tv_eternity(&t->srexpire);
4251 }
willy tarreau0f7af912005-12-17 12:21:26 +01004252
willy tarreau8337c6b2005-12-17 13:41:01 +01004253 /* read error, write error */
willy tarreau0f7af912005-12-17 12:21:26 +01004254 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004255 tv_eternity(&t->srexpire);
4256 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004257 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004258 t->srv_state = SV_STCLOSE;
willy tarreaucd878942005-12-17 13:27:43 +01004259 t->logs.status = 502;
willy tarreau8337c6b2005-12-17 13:41:01 +01004260 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
willy tarreau036e1ce2005-12-17 13:46:33 +01004261 if (!(t->flags & SN_ERR_MASK))
4262 t->flags |= SN_ERR_SRVCL;
4263 if (!(t->flags & SN_FINST_MASK))
4264 t->flags |= SN_FINST_H;
willy tarreau0f7af912005-12-17 12:21:26 +01004265 return 1;
4266 }
willy tarreau8337c6b2005-12-17 13:41:01 +01004267 /* end of client write or end of server read.
willy tarreauef900ab2005-12-17 12:52:52 +01004268 * since we are in header mode, if there's no space left for headers, we
4269 * won't be able to free more later, so the session will never terminate.
4270 */
willy tarreau8337c6b2005-12-17 13:41:01 +01004271 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 +01004272 FD_CLR(t->srv_fd, StaticReadEvent);
4273 tv_eternity(&t->srexpire);
4274 shutdown(t->srv_fd, SHUT_RD);
4275 t->srv_state = SV_STSHUTR;
4276 return 1;
willy tarreau8337c6b2005-12-17 13:41:01 +01004277 }
4278 /* read timeout : return a 504 to the client.
4279 */
4280 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4281 tv_eternity(&t->srexpire);
4282 tv_eternity(&t->swexpire);
4283 fd_delete(t->srv_fd);
4284 t->srv_state = SV_STCLOSE;
4285 t->logs.status = 504;
4286 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
willy tarreau036e1ce2005-12-17 13:46:33 +01004287 if (!(t->flags & SN_ERR_MASK))
4288 t->flags |= SN_ERR_SRVTO;
4289 if (!(t->flags & SN_FINST_MASK))
4290 t->flags |= SN_FINST_H;
willy tarreau8337c6b2005-12-17 13:41:01 +01004291 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004292
4293 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004294 /* last client read and buffer empty */
willy tarreau750a4722005-12-17 13:21:24 +01004295 /* FIXME!!! here, we don't want to switch to SHUTW if the
4296 * client shuts read too early, because we may still have
4297 * some work to do on the headers.
willy tarreau036e1ce2005-12-17 13:46:33 +01004298 * The side-effect is that if the client completely closes its
4299 * connection during SV_STHEADER, the connection to the server
4300 * is kept until a response comes back or the timeout is reached.
willy tarreau750a4722005-12-17 13:21:24 +01004301 */
willy tarreau036e1ce2005-12-17 13:46:33 +01004302 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01004303 FD_CLR(t->srv_fd, StaticWriteEvent);
4304 tv_eternity(&t->swexpire);
4305 shutdown(t->srv_fd, SHUT_WR);
4306 t->srv_state = SV_STSHUTW;
4307 return 1;
4308 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004309 /* write timeout */
4310 /* FIXME!!! here, we don't want to switch to SHUTW if the
4311 * client shuts read too early, because we may still have
4312 * some work to do on the headers.
4313 */
4314 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4315 FD_CLR(t->srv_fd, StaticWriteEvent);
4316 tv_eternity(&t->swexpire);
4317 shutdown(t->srv_fd, SHUT_WR);
4318 t->srv_state = SV_STSHUTW;
4319 if (!(t->flags & SN_ERR_MASK))
4320 t->flags |= SN_ERR_SRVTO;
4321 if (!(t->flags & SN_FINST_MASK))
4322 t->flags |= SN_FINST_H;
4323 return 1;
4324 }
willy tarreau0f7af912005-12-17 12:21:26 +01004325
4326 if (req->l == 0) {
4327 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4328 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4329 tv_eternity(&t->swexpire);
4330 }
4331 }
4332 else { /* client buffer not empty */
4333 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4334 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004335 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004336 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004337 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4338 t->srexpire = t->swexpire;
4339 }
willy tarreau0f7af912005-12-17 12:21:26 +01004340 else
4341 tv_eternity(&t->swexpire);
4342 }
4343 }
4344
willy tarreau5cbea6f2005-12-17 12:48:26 +01004345 /* be nice with the client side which would like to send a complete header
4346 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
4347 * would read all remaining data at once ! The client should not write past rep->lr
4348 * when the server is in header state.
4349 */
4350 //return header_processed;
4351 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01004352 }
4353 else if (s == SV_STDATA) {
4354 /* read or write error */
4355 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01004356 tv_eternity(&t->srexpire);
4357 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004358 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004359 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004360 if (!(t->flags & SN_ERR_MASK))
4361 t->flags |= SN_ERR_SRVCL;
4362 if (!(t->flags & SN_FINST_MASK))
4363 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004364 return 1;
4365 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004366 /* last read, or end of client write */
4367 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004368 FD_CLR(t->srv_fd, StaticReadEvent);
4369 tv_eternity(&t->srexpire);
4370 shutdown(t->srv_fd, SHUT_RD);
4371 t->srv_state = SV_STSHUTR;
4372 return 1;
willy tarreaua41a8b42005-12-17 14:02:24 +01004373 }
4374 /* end of client read and no more data to send */
4375 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
4376 FD_CLR(t->srv_fd, StaticWriteEvent);
4377 tv_eternity(&t->swexpire);
4378 shutdown(t->srv_fd, SHUT_WR);
4379 t->srv_state = SV_STSHUTW;
4380 return 1;
4381 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004382 /* read timeout */
4383 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4384 FD_CLR(t->srv_fd, StaticReadEvent);
4385 tv_eternity(&t->srexpire);
4386 shutdown(t->srv_fd, SHUT_RD);
4387 t->srv_state = SV_STSHUTR;
4388 if (!(t->flags & SN_ERR_MASK))
4389 t->flags |= SN_ERR_SRVTO;
4390 if (!(t->flags & SN_FINST_MASK))
4391 t->flags |= SN_FINST_D;
4392 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01004393 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004394 /* write timeout */
4395 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004396 FD_CLR(t->srv_fd, StaticWriteEvent);
4397 tv_eternity(&t->swexpire);
4398 shutdown(t->srv_fd, SHUT_WR);
4399 t->srv_state = SV_STSHUTW;
willy tarreau036e1ce2005-12-17 13:46:33 +01004400 if (!(t->flags & SN_ERR_MASK))
4401 t->flags |= SN_ERR_SRVTO;
4402 if (!(t->flags & SN_FINST_MASK))
4403 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004404 return 1;
4405 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004406
4407 /* recompute request time-outs */
4408 if (req->l == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01004409 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4410 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4411 tv_eternity(&t->swexpire);
4412 }
4413 }
willy tarreaub1ff9db2005-12-17 13:51:03 +01004414 else { /* buffer not empty, there are still data to be transferred */
willy tarreau0f7af912005-12-17 12:21:26 +01004415 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4416 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004417 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004418 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004419 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4420 t->srexpire = t->swexpire;
4421 }
willy tarreau0f7af912005-12-17 12:21:26 +01004422 else
4423 tv_eternity(&t->swexpire);
4424 }
4425 }
4426
willy tarreaub1ff9db2005-12-17 13:51:03 +01004427 /* recompute response time-outs */
willy tarreau0f7af912005-12-17 12:21:26 +01004428 if (rep->l == BUFSIZE) { /* no room to read more data */
4429 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4430 FD_CLR(t->srv_fd, StaticReadEvent);
4431 tv_eternity(&t->srexpire);
4432 }
4433 }
4434 else {
4435 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4436 FD_SET(t->srv_fd, StaticReadEvent);
4437 if (t->proxy->srvtimeout)
4438 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4439 else
4440 tv_eternity(&t->srexpire);
4441 }
4442 }
4443
4444 return 0; /* other cases change nothing */
4445 }
4446 else if (s == SV_STSHUTR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004447 if (t->res_sw == RES_ERROR) {
4448 //FD_CLR(t->srv_fd, StaticWriteEvent);
4449 tv_eternity(&t->swexpire);
4450 fd_delete(t->srv_fd);
4451 //close(t->srv_fd);
4452 t->srv_state = SV_STCLOSE;
4453 if (!(t->flags & SN_ERR_MASK))
4454 t->flags |= SN_ERR_SRVCL;
4455 if (!(t->flags & SN_FINST_MASK))
4456 t->flags |= SN_FINST_D;
4457 return 1;
4458 }
4459 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004460 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004461 tv_eternity(&t->swexpire);
4462 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004463 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004464 t->srv_state = SV_STCLOSE;
4465 return 1;
4466 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004467 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
4468 //FD_CLR(t->srv_fd, StaticWriteEvent);
4469 tv_eternity(&t->swexpire);
4470 fd_delete(t->srv_fd);
4471 //close(t->srv_fd);
4472 t->srv_state = SV_STCLOSE;
4473 if (!(t->flags & SN_ERR_MASK))
4474 t->flags |= SN_ERR_SRVTO;
4475 if (!(t->flags & SN_FINST_MASK))
4476 t->flags |= SN_FINST_D;
4477 return 1;
4478 }
willy tarreau0f7af912005-12-17 12:21:26 +01004479 else if (req->l == 0) {
4480 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4481 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
4482 tv_eternity(&t->swexpire);
4483 }
4484 }
4485 else { /* buffer not empty */
4486 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
4487 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
willy tarreaub1ff9db2005-12-17 13:51:03 +01004488 if (t->proxy->srvtimeout) {
willy tarreau0f7af912005-12-17 12:21:26 +01004489 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
willy tarreaub1ff9db2005-12-17 13:51:03 +01004490 /* FIXME: to avoid the server to read-time-out during writes, we refresh it */
4491 t->srexpire = t->swexpire;
4492 }
willy tarreau0f7af912005-12-17 12:21:26 +01004493 else
4494 tv_eternity(&t->swexpire);
4495 }
4496 }
4497 return 0;
4498 }
4499 else if (s == SV_STSHUTW) {
willy tarreau036e1ce2005-12-17 13:46:33 +01004500 if (t->res_sr == RES_ERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01004501 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01004502 tv_eternity(&t->srexpire);
4503 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004504 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01004505 t->srv_state = SV_STCLOSE;
willy tarreau036e1ce2005-12-17 13:46:33 +01004506 if (!(t->flags & SN_ERR_MASK))
4507 t->flags |= SN_ERR_SRVCL;
4508 if (!(t->flags & SN_FINST_MASK))
4509 t->flags |= SN_FINST_D;
willy tarreau0f7af912005-12-17 12:21:26 +01004510 return 1;
4511 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004512 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
4513 //FD_CLR(t->srv_fd, StaticReadEvent);
4514 tv_eternity(&t->srexpire);
4515 fd_delete(t->srv_fd);
4516 //close(t->srv_fd);
4517 t->srv_state = SV_STCLOSE;
4518 return 1;
4519 }
4520 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
4521 //FD_CLR(t->srv_fd, StaticReadEvent);
4522 tv_eternity(&t->srexpire);
4523 fd_delete(t->srv_fd);
4524 //close(t->srv_fd);
4525 t->srv_state = SV_STCLOSE;
4526 if (!(t->flags & SN_ERR_MASK))
4527 t->flags |= SN_ERR_SRVTO;
4528 if (!(t->flags & SN_FINST_MASK))
4529 t->flags |= SN_FINST_D;
4530 return 1;
4531 }
willy tarreau0f7af912005-12-17 12:21:26 +01004532 else if (rep->l == BUFSIZE) { /* no room to read more data */
4533 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
4534 FD_CLR(t->srv_fd, StaticReadEvent);
4535 tv_eternity(&t->srexpire);
4536 }
4537 }
4538 else {
4539 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
4540 FD_SET(t->srv_fd, StaticReadEvent);
4541 if (t->proxy->srvtimeout)
4542 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
4543 else
4544 tv_eternity(&t->srexpire);
4545 }
4546 }
4547 return 0;
4548 }
4549 else { /* SV_STCLOSE : nothing to do */
willy tarreau982249e2005-12-18 00:57:06 +01004550 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004551 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004552 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 +01004553 write(1, trash, len);
4554 }
4555 return 0;
4556 }
4557 return 0;
4558}
4559
4560
willy tarreau5cbea6f2005-12-17 12:48:26 +01004561/* Processes the client and server jobs of a session task, then
4562 * puts it back to the wait queue in a clean state, or
4563 * cleans up its resources if it must be deleted. Returns
4564 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01004565 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004566int process_session(struct task *t) {
4567 struct session *s = t->context;
4568 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01004569
willy tarreau5cbea6f2005-12-17 12:48:26 +01004570 do {
4571 fsm_resync = 0;
4572 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4573 fsm_resync |= process_cli(s);
4574 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4575 fsm_resync |= process_srv(s);
4576 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
4577 } while (fsm_resync);
4578
4579 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01004580 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004581 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01004582
willy tarreau5cbea6f2005-12-17 12:48:26 +01004583 tv_min(&min1, &s->crexpire, &s->cwexpire);
4584 tv_min(&min2, &s->srexpire, &s->swexpire);
4585 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01004586 tv_min(&t->expire, &min1, &min2);
4587
4588 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004589 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01004590
willy tarreau5cbea6f2005-12-17 12:48:26 +01004591 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01004592 }
4593
willy tarreau5cbea6f2005-12-17 12:48:26 +01004594 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01004595 actconn--;
4596
willy tarreau982249e2005-12-18 00:57:06 +01004597 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
willy tarreau0f7af912005-12-17 12:21:26 +01004598 int len;
willy tarreau2f6ba652005-12-17 13:57:42 +01004599 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 +01004600 write(1, trash, len);
4601 }
4602
willy tarreau750a4722005-12-17 13:21:24 +01004603 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
willy tarreaua1598082005-12-17 13:08:06 +01004604 if (s->rep != NULL)
4605 s->logs.bytes = s->rep->total;
4606
willy tarreau9fe663a2005-12-17 13:02:59 +01004607 /* let's do a final log if we need it */
willy tarreaua1598082005-12-17 13:08:06 +01004608 if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
willy tarreau9fe663a2005-12-17 13:02:59 +01004609 sess_log(s);
4610
willy tarreau0f7af912005-12-17 12:21:26 +01004611 /* the task MUST not be in the run queue anymore */
4612 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004613 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01004614 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004615 return -1; /* rest in peace for eternity */
4616}
4617
4618
4619
4620/*
4621 * manages a server health-check. Returns
4622 * the time the task accepts to wait, or -1 for infinity.
4623 */
4624int process_chk(struct task *t) {
4625 struct server *s = t->context;
willy tarreaua41a8b42005-12-17 14:02:24 +01004626 struct sockaddr_in sa;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004627 int fd = s->curfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004628
willy tarreauef900ab2005-12-17 12:52:52 +01004629 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004630
4631 if (fd < 0) { /* no check currently running */
4632 //fprintf(stderr, "process_chk: 2\n");
4633 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
4634 task_queue(t); /* restore t to its place in the task list */
4635 return tv_remain(&now, &t->expire);
4636 }
4637
4638 /* we'll initiate a new check */
4639 s->result = 0; /* no result yet */
4640 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01004641 if ((fd < global.maxsock) &&
willy tarreau5cbea6f2005-12-17 12:48:26 +01004642 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
4643 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
4644 //fprintf(stderr, "process_chk: 3\n");
4645
willy tarreaua41a8b42005-12-17 14:02:24 +01004646 /* we'll connect to the check port on the server */
4647 sa = s->addr;
4648 sa.sin_port = htons(s->check_port);
4649
willy tarreau0174f312005-12-18 01:02:42 +01004650 /* allow specific binding :
4651 * - server-specific at first
4652 * - proxy-specific next
4653 */
4654 if (s->state & SRV_BIND_SRC) {
4655 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4656 if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
4657 Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
4658 s->proxy->id, s->id);
4659 s->result = -1;
4660 }
willy tarreau036e1ce2005-12-17 13:46:33 +01004661 }
willy tarreau0174f312005-12-18 01:02:42 +01004662 else if (s->proxy->options & PR_O_BIND_SRC) {
4663 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
4664 if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
4665 Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n",
4666 s->proxy->id);
4667 s->result = -1;
4668 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004669 }
willy tarreau0174f312005-12-18 01:02:42 +01004670
4671 if (!s->result) {
4672 if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
4673 /* OK, connection in progress or established */
4674
4675 //fprintf(stderr, "process_chk: 4\n");
4676
4677 s->curfd = fd; /* that's how we know a test is in progress ;-) */
4678 fdtab[fd].owner = t;
4679 fdtab[fd].read = &event_srv_chk_r;
4680 fdtab[fd].write = &event_srv_chk_w;
4681 fdtab[fd].state = FD_STCONN; /* connection in progress */
4682 FD_SET(fd, StaticWriteEvent); /* for connect status */
4683 fd_insert(fd);
4684 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4685 tv_delayfrom(&t->expire, &now, s->inter);
4686 task_queue(t); /* restore t to its place in the task list */
4687 return tv_remain(&now, &t->expire);
4688 }
4689 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
4690 s->result = -1; /* a real error */
4691 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004692 }
4693 }
4694 //fprintf(stderr, "process_chk: 5\n");
4695 close(fd);
4696 }
4697
4698 if (!s->result) { /* nothing done */
4699 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004700 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004701 task_queue(t); /* restore t to its place in the task list */
4702 return tv_remain(&now, &t->expire);
4703 }
4704
4705 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01004706 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004707 s->health--; /* still good */
4708 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004709 s->state &= ~SRV_RUNNING;
willy tarreau535ae7a2005-12-17 12:58:00 +01004710 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004711 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004712 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreauef900ab2005-12-17 12:52:52 +01004713
willy tarreaudd07e972005-12-18 00:48:48 +01004714 if (find_server(s->proxy) == NULL) {
4715 Alert("Proxy %s has no server available !\n", s->proxy->id);
4716 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4717 }
4718 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004719 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004720 }
4721
4722 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01004723 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
4724 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004725 }
4726 else {
4727 //fprintf(stderr, "process_chk: 8\n");
4728 /* there was a test running */
4729 if (s->result > 0) { /* good server detected */
4730 //fprintf(stderr, "process_chk: 9\n");
4731 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01004732 if (s->health >= s->rise) {
willy tarreau535ae7a2005-12-17 12:58:00 +01004733 if (s->health == s->rise) {
willy tarreaudd07e972005-12-18 00:48:48 +01004734 Warning("server %s/%s UP.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004735 send_log(s->proxy, LOG_NOTICE, "Server %s/%s is UP.\n", s->proxy->id, s->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01004736 }
willy tarreauef900ab2005-12-17 12:52:52 +01004737
willy tarreaue47c8d72005-12-17 12:55:52 +01004738 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004739 s->state |= SRV_RUNNING;
4740 }
willy tarreauef900ab2005-12-17 12:52:52 +01004741 s->curfd = -1; /* no check running anymore */
4742 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004743 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004744 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004745 }
4746 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
4747 //fprintf(stderr, "process_chk: 10\n");
4748 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01004749 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01004750 s->health--; /* still good */
4751 else {
willy tarreaudd07e972005-12-18 00:48:48 +01004752 s->state &= ~SRV_RUNNING;
willy tarreau9fe663a2005-12-17 13:02:59 +01004753
willy tarreaudd07e972005-12-18 00:48:48 +01004754 if (s->health == s->rise) {
4755 Warning("Server %s/%s DOWN.\n", s->proxy->id, s->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01004756 send_log(s->proxy, LOG_ALERT, "Server %s/%s is DOWN.\n", s->proxy->id, s->id);
willy tarreaudd07e972005-12-18 00:48:48 +01004757
4758 if (find_server(s->proxy) == NULL) {
4759 Alert("Proxy %s has no server available !\n", s->proxy->id);
4760 send_log(s->proxy, LOG_EMERG, "Proxy %s has no server available !\n", s->proxy->id);
4761 }
willy tarreau535ae7a2005-12-17 12:58:00 +01004762 }
willy tarreauef900ab2005-12-17 12:52:52 +01004763
willy tarreau5cbea6f2005-12-17 12:48:26 +01004764 s->health = 0; /* failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004765 }
4766 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01004767 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004768 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01004769 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004770 }
4771 /* if result is 0 and there's no timeout, we have to wait again */
4772 }
4773 //fprintf(stderr, "process_chk: 11\n");
4774 s->result = 0;
4775 task_queue(t); /* restore t to its place in the task list */
4776 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01004777}
4778
4779
willy tarreau5cbea6f2005-12-17 12:48:26 +01004780
willy tarreau0f7af912005-12-17 12:21:26 +01004781#if STATTIME > 0
4782int stats(void);
4783#endif
4784
4785/*
willy tarreau1c2ad212005-12-18 01:11:29 +01004786 * This does 4 things :
4787 * - wake up all expired tasks
4788 * - call all runnable tasks
4789 * - call maintain_proxies() to enable/disable the listeners
4790 * - return the delay till next event in ms, -1 = wait indefinitely
4791 * Note: this part should be rewritten with the O(ln(n)) scheduler.
4792 *
willy tarreau0f7af912005-12-17 12:21:26 +01004793 */
4794
willy tarreau1c2ad212005-12-18 01:11:29 +01004795int process_runnable_tasks() {
willy tarreau0f7af912005-12-17 12:21:26 +01004796 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01004797 int time2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004798 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01004799
willy tarreau1c2ad212005-12-18 01:11:29 +01004800 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01004801
willy tarreau1c2ad212005-12-18 01:11:29 +01004802 /* look for expired tasks and add them to the run queue.
4803 */
4804 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
4805 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
4806 tnext = t->next;
4807 if (t->state & TASK_RUNNING)
4808 continue;
4809
4810 /* wakeup expired entries. It doesn't matter if they are
4811 * already running because of a previous event
willy tarreau5cbea6f2005-12-17 12:48:26 +01004812 */
willy tarreau1c2ad212005-12-18 01:11:29 +01004813 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
4814 task_wakeup(&rq, t);
4815 }
4816 else {
4817 /* first non-runnable task. Use its expiration date as an upper bound */
4818 int temp_time = tv_remain(&now, &t->expire);
4819 if (temp_time)
4820 next_time = temp_time;
4821 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004822 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004823 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004824
willy tarreau1c2ad212005-12-18 01:11:29 +01004825 /* process each task in the run queue now. Each task may be deleted
4826 * since we only use tnext.
4827 */
4828 tnext = rq;
4829 while ((t = tnext) != NULL) {
4830 int temp_time;
4831
4832 tnext = t->rqnext;
4833 task_sleep(&rq, t);
4834 temp_time = t->process(t);
4835 next_time = MINTIME(temp_time, next_time);
4836 }
4837
4838 /* maintain all proxies in a consistent state. This should quickly become a task */
4839 time2 = maintain_proxies();
4840 return MINTIME(time2, next_time);
4841}
4842
4843
4844#if defined(ENABLE_EPOLL)
4845
4846/*
4847 * Main epoll() loop.
4848 */
4849
4850/* does 3 actions :
4851 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
4852 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
4853 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
4854 *
4855 * returns 0 if initialization failed, !0 otherwise.
4856 */
4857
4858int epoll_loop(int action) {
4859 int next_time;
4860 int status;
4861 int fd;
4862
4863 int fds, count;
4864 int pr, pw, sr, sw;
4865 unsigned rn, ro, wn, wo; /* read new, read old, write new, write old */
4866 struct epoll_event ev;
4867
4868 /* private data */
4869 static int last_maxfd = 0;
4870 static fd_set *PrevReadEvent = NULL, *PrevWriteEvent = NULL;
4871 static struct epoll_event *epoll_events = NULL;
4872 static int epoll_fd;
4873
4874 if (action == POLL_LOOP_ACTION_INIT) {
4875 epoll_fd = epoll_create(global.maxsock + 1);
4876 if (epoll_fd < 0)
4877 return 0;
4878 else {
4879 epoll_events = (struct epoll_event*)
4880 calloc(1, sizeof(struct epoll_event) * global.maxsock);
4881 PrevReadEvent = (fd_set *)
4882 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
4883 PrevWriteEvent = (fd_set *)
4884 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau5cbea6f2005-12-17 12:48:26 +01004885 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004886 return 1;
4887 }
4888 else if (action == POLL_LOOP_ACTION_CLEAN) {
4889 if (PrevWriteEvent) free(PrevWriteEvent);
4890 if (PrevReadEvent) free(PrevReadEvent);
4891 if (epoll_events) free(epoll_events);
4892 close(epoll_fd);
4893 last_maxfd = 0;
4894 epoll_fd = 0;
4895 return 1;
4896 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01004897
willy tarreau1c2ad212005-12-18 01:11:29 +01004898 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01004899
willy tarreau1c2ad212005-12-18 01:11:29 +01004900 tv_now(&now);
4901
4902 while (1) {
4903 next_time = process_runnable_tasks();
willy tarreau5cbea6f2005-12-17 12:48:26 +01004904
4905 /* stop when there's no connection left and we don't allow them anymore */
4906 if (!actconn && listeners == 0)
4907 break;
4908
willy tarreau0f7af912005-12-17 12:21:26 +01004909#if STATTIME > 0
willy tarreau1c2ad212005-12-18 01:11:29 +01004910 {
4911 int time2;
4912 time2 = stats();
4913 next_time = MINTIME(time2, next_time);
4914 }
willy tarreau0f7af912005-12-17 12:21:26 +01004915#endif
4916
willy tarreau0f7af912005-12-17 12:21:26 +01004917
willy tarreau1c2ad212005-12-18 01:11:29 +01004918 /*
4919 * We'll first check if some fds have been closed recently, in which case
4920 * we'll have to remove them from the previous epoll set. It's
4921 * unnecessary to call epoll_ctl(DEL) because close() automatically
4922 * removes the fds from the epoll set.
4923 */
4924 for (fd = maxfd; fd < last_maxfd; fd++) {
4925 ev.data.fd = fd;
4926 FD_CLR(fd, PrevReadEvent);
4927 FD_CLR(fd, PrevWriteEvent);
4928 }
4929 last_maxfd = maxfd;
willy tarreau5cbea6f2005-12-17 12:48:26 +01004930
willy tarreau1c2ad212005-12-18 01:11:29 +01004931 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
4932
4933 rn = ((int*)StaticReadEvent)[fds]; ro = ((int*)PrevReadEvent)[fds];
4934 wn = ((int*)StaticWriteEvent)[fds]; wo = ((int*)PrevWriteEvent)[fds];
4935
4936 if ((ro^rn) | (wo^wn)) {
4937 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
4938#define FDSETS_ARE_INT_ALIGNED
4939#ifdef FDSETS_ARE_INT_ALIGNED
willy tarreau0f7af912005-12-17 12:21:26 +01004940
willy tarreauad90a0c2005-12-18 01:09:15 +01004941#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
4942#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
willy tarreau1c2ad212005-12-18 01:11:29 +01004943 pr = (ro >> count) & 1;
4944 pw = (wo >> count) & 1;
4945 sr = (rn >> count) & 1;
4946 sw = (wn >> count) & 1;
willy tarreauad90a0c2005-12-18 01:09:15 +01004947#else
willy tarreau1c2ad212005-12-18 01:11:29 +01004948 pr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&ro);
4949 pw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wo);
4950 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
4951 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
willy tarreauad90a0c2005-12-18 01:09:15 +01004952#endif
4953#else
willy tarreau1c2ad212005-12-18 01:11:29 +01004954 pr = FD_ISSET(fd, PrevReadEvent);
4955 pw = FD_ISSET(fd, PrevWriteEvent);
4956 sr = FD_ISSET(fd, StaticReadEvent);
4957 sw = FD_ISSET(fd, StaticWriteEvent);
willy tarreauad90a0c2005-12-18 01:09:15 +01004958#endif
willy tarreau1c2ad212005-12-18 01:11:29 +01004959 if (!((sr^pr) | (sw^pw)))
4960 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01004961
willy tarreau1c2ad212005-12-18 01:11:29 +01004962 ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
4963 ev.data.fd = fd;
willy tarreauad90a0c2005-12-18 01:09:15 +01004964
willy tarreau1c2ad212005-12-18 01:11:29 +01004965 if ((pr | pw)) {
4966 /* the file-descriptor already exists... */
4967 if ((sr | sw)) {
4968 /* ...and it will still exist */
4969 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) {
4970 // perror("epoll_ctl(MOD)");
4971 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01004972 }
4973 } else {
willy tarreau1c2ad212005-12-18 01:11:29 +01004974 /* ...and it will be removed */
4975 if (fdtab[fd].state != FD_STCLOSE &&
4976 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0) {
4977 // perror("epoll_ctl(DEL)");
4978 // exit(1);
willy tarreauad90a0c2005-12-18 01:09:15 +01004979 }
4980 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004981 } else {
4982 /* the file-descriptor did not exist, let's add it */
4983 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
4984 // perror("epoll_ctl(ADD)");
4985 // exit(1);
4986 }
willy tarreauad90a0c2005-12-18 01:09:15 +01004987 }
willy tarreau1c2ad212005-12-18 01:11:29 +01004988 }
4989 ((int*)PrevReadEvent)[fds] = rn;
4990 ((int*)PrevWriteEvent)[fds] = wn;
4991 }
4992 }
4993
4994 /* now let's wait for events */
4995 status = epoll_wait(epoll_fd, epoll_events, maxfd, next_time);
4996 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01004997
willy tarreau1c2ad212005-12-18 01:11:29 +01004998 for (count = 0; count < status; count++) {
4999 fd = epoll_events[count].data.fd;
5000
5001 if (fdtab[fd].state == FD_STCLOSE)
5002 continue;
5003
5004 if (epoll_events[count].events & ( EPOLLIN | EPOLLERR | EPOLLHUP ))
5005 fdtab[fd].read(fd);
5006
5007 if (fdtab[fd].state == FD_STCLOSE)
5008 continue;
5009
5010 if (epoll_events[count].events & ( EPOLLOUT | EPOLLERR | EPOLLHUP ))
5011 fdtab[fd].write(fd);
5012 }
5013 }
5014 return 1;
5015}
5016#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005017
willy tarreauad90a0c2005-12-18 01:09:15 +01005018
willy tarreau5cbea6f2005-12-17 12:48:26 +01005019
willy tarreau1c2ad212005-12-18 01:11:29 +01005020#if defined(ENABLE_POLL)
willy tarreauad90a0c2005-12-18 01:09:15 +01005021
willy tarreau1c2ad212005-12-18 01:11:29 +01005022/*
5023 * Main poll() loop.
5024 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005025
willy tarreau1c2ad212005-12-18 01:11:29 +01005026/* does 3 actions :
5027 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5028 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5029 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5030 *
5031 * returns 0 if initialization failed, !0 otherwise.
5032 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005033
willy tarreau1c2ad212005-12-18 01:11:29 +01005034int poll_loop(int action) {
5035 int next_time;
5036 int status;
5037 int fd, nbfd;
5038
5039 int fds, count;
5040 int sr, sw;
5041 unsigned rn, wn; /* read new, write new */
5042
5043 /* private data */
5044 static struct pollfd *poll_events = NULL;
5045
5046 if (action == POLL_LOOP_ACTION_INIT) {
5047 poll_events = (struct pollfd*)
5048 calloc(1, sizeof(struct pollfd) * global.maxsock);
5049 return 1;
5050 }
5051 else if (action == POLL_LOOP_ACTION_CLEAN) {
5052 if (poll_events)
5053 free(poll_events);
5054 return 1;
5055 }
5056
5057 /* OK, it's POLL_LOOP_ACTION_RUN */
5058
5059 tv_now(&now);
5060
5061 while (1) {
5062 next_time = process_runnable_tasks();
5063
5064 /* stop when there's no connection left and we don't allow them anymore */
5065 if (!actconn && listeners == 0)
5066 break;
5067
5068#if STATTIME > 0
5069 {
5070 int time2;
5071 time2 = stats();
5072 next_time = MINTIME(time2, next_time);
5073 }
5074#endif
5075
5076
5077 nbfd = 0;
5078 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
5079
5080 rn = ((int*)StaticReadEvent)[fds];
5081 wn = ((int*)StaticWriteEvent)[fds];
5082
5083 if ((rn|wn)) {
5084 for (count = 0, fd = fds << INTBITS; count < (1<<INTBITS) && fd < maxfd; count++, fd++) {
5085#define FDSETS_ARE_INT_ALIGNED
5086#ifdef FDSETS_ARE_INT_ALIGNED
5087
5088#define WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5089#ifdef WE_REALLY_NOW_THAT_FDSETS_ARE_INTS
5090 sr = (rn >> count) & 1;
5091 sw = (wn >> count) & 1;
5092#else
5093 sr = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&rn);
5094 sw = FD_ISSET(fd&((1<<INTBITS)-1), (typeof(fd_set*))&wn);
5095#endif
5096#else
5097 sr = FD_ISSET(fd, StaticReadEvent);
5098 sw = FD_ISSET(fd, StaticWriteEvent);
5099#endif
5100 if ((sr|sw)) {
5101 poll_events[nbfd].fd = fd;
5102 poll_events[nbfd].events = (sr ? POLLIN : 0) | (sw ? POLLOUT : 0);
5103 nbfd++;
willy tarreauad90a0c2005-12-18 01:09:15 +01005104 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005105 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005106 }
5107 }
5108
5109 /* now let's wait for events */
5110 status = poll(poll_events, nbfd, next_time);
5111 tv_now(&now);
5112
5113 for (count = 0; status > 0 && count < nbfd; count++) {
5114 fd = poll_events[count].fd;
5115
5116 if (!poll_events[count].revents & ( POLLOUT | POLLIN | POLLERR | POLLHUP ))
5117 continue;
5118
5119 /* ok, we found one active fd */
5120 status--;
5121
5122 if (fdtab[fd].state == FD_STCLOSE)
5123 continue;
5124
5125 if (poll_events[count].revents & ( POLLIN | POLLERR | POLLHUP ))
5126 fdtab[fd].read(fd);
5127
5128 if (fdtab[fd].state == FD_STCLOSE)
5129 continue;
5130
5131 if (poll_events[count].revents & ( POLLOUT | POLLERR | POLLHUP ))
5132 fdtab[fd].write(fd);
5133 }
5134 }
5135 return 1;
5136}
willy tarreauad90a0c2005-12-18 01:09:15 +01005137#endif
willy tarreauad90a0c2005-12-18 01:09:15 +01005138
willy tarreauad90a0c2005-12-18 01:09:15 +01005139
willy tarreauad90a0c2005-12-18 01:09:15 +01005140
willy tarreau1c2ad212005-12-18 01:11:29 +01005141/*
5142 * Main select() loop.
5143 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005144
willy tarreau1c2ad212005-12-18 01:11:29 +01005145/* does 3 actions :
5146 * 0 (POLL_LOOP_ACTION_INIT) : initializes necessary private structures
5147 * 1 (POLL_LOOP_ACTION_RUN) : runs the loop
5148 * 2 (POLL_LOOP_ACTION_CLEAN) : cleans up
5149 *
5150 * returns 0 if initialization failed, !0 otherwise.
5151 */
willy tarreauad90a0c2005-12-18 01:09:15 +01005152
willy tarreauad90a0c2005-12-18 01:09:15 +01005153
willy tarreau1c2ad212005-12-18 01:11:29 +01005154int select_loop(int action) {
5155 int next_time;
5156 int status;
5157 int fd,i;
5158 struct timeval delta;
5159 int readnotnull, writenotnull;
5160 static fd_set *ReadEvent = NULL, *WriteEvent = NULL;
willy tarreauad90a0c2005-12-18 01:09:15 +01005161
willy tarreau1c2ad212005-12-18 01:11:29 +01005162 if (action == POLL_LOOP_ACTION_INIT) {
5163 ReadEvent = (fd_set *)
5164 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5165 WriteEvent = (fd_set *)
5166 calloc(1, sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
5167 return 1;
5168 }
5169 else if (action == POLL_LOOP_ACTION_CLEAN) {
5170 if (WriteEvent) free(WriteEvent);
5171 if (ReadEvent) free(ReadEvent);
5172 return 1;
5173 }
willy tarreauad90a0c2005-12-18 01:09:15 +01005174
willy tarreau1c2ad212005-12-18 01:11:29 +01005175 /* OK, it's POLL_LOOP_ACTION_RUN */
willy tarreauad90a0c2005-12-18 01:09:15 +01005176
willy tarreau1c2ad212005-12-18 01:11:29 +01005177 tv_now(&now);
willy tarreauad90a0c2005-12-18 01:09:15 +01005178
willy tarreau1c2ad212005-12-18 01:11:29 +01005179 while (1) {
5180 next_time = process_runnable_tasks();
willy tarreauad90a0c2005-12-18 01:09:15 +01005181
willy tarreau1c2ad212005-12-18 01:11:29 +01005182 /* stop when there's no connection left and we don't allow them anymore */
5183 if (!actconn && listeners == 0)
5184 break;
5185
5186#if STATTIME > 0
5187 {
5188 int time2;
5189 time2 = stats();
5190 next_time = MINTIME(time2, next_time);
5191 }
5192#endif
5193
5194
5195 if (next_time > 0) { /* FIXME */
5196 /* Convert to timeval */
5197 /* to avoid eventual select loops due to timer precision */
5198 next_time += SCHEDULER_RESOLUTION;
5199 delta.tv_sec = next_time / 1000;
5200 delta.tv_usec = (next_time % 1000) * 1000;
5201 }
5202 else if (next_time == 0) { /* allow select to return immediately when needed */
5203 delta.tv_sec = delta.tv_usec = 0;
5204 }
5205
5206
5207 /* let's restore fdset state */
5208
5209 readnotnull = 0; writenotnull = 0;
5210 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
5211 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
5212 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
5213 }
5214
5215 // /* just a verification code, needs to be removed for performance */
5216 // for (i=0; i<maxfd; i++) {
5217 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
5218 // abort();
5219 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
5220 // abort();
5221 //
5222 // }
5223
5224 status = select(maxfd,
5225 readnotnull ? ReadEvent : NULL,
5226 writenotnull ? WriteEvent : NULL,
5227 NULL,
5228 (next_time >= 0) ? &delta : NULL);
5229
5230 /* this is an experiment on the separation of the select work */
5231 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5232 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
5233
5234 tv_now(&now);
5235
5236 if (status > 0) { /* must proceed with events */
5237
5238 int fds;
5239 char count;
willy tarreauad90a0c2005-12-18 01:09:15 +01005240
willy tarreau1c2ad212005-12-18 01:11:29 +01005241 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
5242 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
5243 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
5244
5245 /* if we specify read first, the accepts and zero reads will be
5246 * seen first. Moreover, system buffers will be flushed faster.
5247 */
5248 if (fdtab[fd].state == FD_STCLOSE)
5249 continue;
willy tarreauad90a0c2005-12-18 01:09:15 +01005250
willy tarreau1c2ad212005-12-18 01:11:29 +01005251 if (FD_ISSET(fd, ReadEvent))
5252 fdtab[fd].read(fd);
willy tarreauad90a0c2005-12-18 01:09:15 +01005253
willy tarreau1c2ad212005-12-18 01:11:29 +01005254 if (FD_ISSET(fd, WriteEvent))
5255 fdtab[fd].write(fd);
5256 }
5257 }
5258 else {
5259 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
willy tarreau0f7af912005-12-17 12:21:26 +01005260 }
willy tarreau0f7af912005-12-17 12:21:26 +01005261 }
willy tarreau1c2ad212005-12-18 01:11:29 +01005262 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01005263}
5264
5265
5266#if STATTIME > 0
5267/*
5268 * Display proxy statistics regularly. It is designed to be called from the
5269 * select_loop().
5270 */
5271int stats(void) {
5272 static int lines;
5273 static struct timeval nextevt;
5274 static struct timeval lastevt;
5275 static struct timeval starttime = {0,0};
5276 unsigned long totaltime, deltatime;
5277 int ret;
5278
willy tarreau750a4722005-12-17 13:21:24 +01005279 if (tv_cmp(&now, &nextevt) > 0) {
willy tarreau6e682ce2005-12-17 13:26:49 +01005280 deltatime = (tv_diff(&lastevt, &now)?:1);
5281 totaltime = (tv_diff(&starttime, &now)?:1);
willy tarreau0f7af912005-12-17 12:21:26 +01005282
willy tarreau9fe663a2005-12-17 13:02:59 +01005283 if (global.mode & MODE_STATS) {
5284 if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01005285 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01005286 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
5287 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005288 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01005289 actconn, totalconn,
5290 stats_tsk_new, stats_tsk_good,
5291 stats_tsk_left, stats_tsk_right,
5292 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
5293 }
5294 }
5295
5296 tv_delayfrom(&nextevt, &now, STATTIME);
5297
5298 lastevt=now;
5299 }
5300 ret = tv_remain(&now, &nextevt);
5301 return ret;
5302}
5303#endif
5304
5305
5306/*
5307 * this function enables proxies when there are enough free sessions,
5308 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01005309 * select_loop(). It returns the time left before next expiration event
5310 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01005311 */
5312static int maintain_proxies(void) {
5313 struct proxy *p;
willy tarreaua41a8b42005-12-17 14:02:24 +01005314 struct listener *l;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005315 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01005316
5317 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005318 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01005319
5320 /* if there are enough free sessions, we'll activate proxies */
willy tarreau9fe663a2005-12-17 13:02:59 +01005321 if (actconn < global.maxconn) {
willy tarreau0f7af912005-12-17 12:21:26 +01005322 while (p) {
5323 if (p->nbconn < p->maxconn) {
5324 if (p->state == PR_STIDLE) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005325 for (l = p->listen; l != NULL; l = l->next) {
5326 FD_SET(l->fd, StaticReadEvent);
5327 }
willy tarreau0f7af912005-12-17 12:21:26 +01005328 p->state = PR_STRUN;
5329 }
5330 }
5331 else {
5332 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005333 for (l = p->listen; l != NULL; l = l->next) {
5334 FD_CLR(l->fd, StaticReadEvent);
5335 }
willy tarreau0f7af912005-12-17 12:21:26 +01005336 p->state = PR_STIDLE;
5337 }
5338 }
5339 p = p->next;
5340 }
5341 }
5342 else { /* block all proxies */
5343 while (p) {
5344 if (p->state == PR_STRUN) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005345 for (l = p->listen; l != NULL; l = l->next) {
5346 FD_CLR(l->fd, StaticReadEvent);
5347 }
willy tarreau0f7af912005-12-17 12:21:26 +01005348 p->state = PR_STIDLE;
5349 }
5350 p = p->next;
5351 }
5352 }
5353
willy tarreau5cbea6f2005-12-17 12:48:26 +01005354 if (stopping) {
5355 p = proxy;
5356 while (p) {
5357 if (p->state != PR_STDISABLED) {
5358 int t;
5359 t = tv_remain(&now, &p->stop_time);
5360 if (t == 0) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005361 Warning("Proxy %s stopped.\n", p->id);
willy tarreau9fe663a2005-12-17 13:02:59 +01005362 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
willy tarreau535ae7a2005-12-17 12:58:00 +01005363
willy tarreaua41a8b42005-12-17 14:02:24 +01005364 for (l = p->listen; l != NULL; l = l->next) {
5365 fd_delete(l->fd);
5366 listeners--;
5367 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01005368 p->state = PR_STDISABLED;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005369 }
5370 else {
5371 tleft = MINTIME(t, tleft);
5372 }
5373 }
5374 p = p->next;
5375 }
5376 }
5377 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01005378}
5379
5380/*
5381 * this function disables health-check servers so that the process will quickly be ignored
5382 * by load balancers.
5383 */
5384static void soft_stop(void) {
5385 struct proxy *p;
5386
5387 stopping = 1;
5388 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005389 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01005390 while (p) {
willy tarreau535ae7a2005-12-17 12:58:00 +01005391 if (p->state != PR_STDISABLED) {
5392 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau9fe663a2005-12-17 13:02:59 +01005393 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
willy tarreau0f7af912005-12-17 12:21:26 +01005394 tv_delayfrom(&p->stop_time, &now, p->grace);
willy tarreau535ae7a2005-12-17 12:58:00 +01005395 }
willy tarreau0f7af912005-12-17 12:21:26 +01005396 p = p->next;
5397 }
5398}
5399
5400/*
5401 * upon SIGUSR1, let's have a soft stop.
5402 */
5403void sig_soft_stop(int sig) {
5404 soft_stop();
5405 signal(sig, SIG_IGN);
5406}
5407
5408
willy tarreau8337c6b2005-12-17 13:41:01 +01005409/*
5410 * this function dumps every server's state when the process receives SIGHUP.
5411 */
5412void sig_dump_state(int sig) {
5413 struct proxy *p = proxy;
5414
5415 Warning("SIGHUP received, dumping servers states.\n");
5416 while (p) {
5417 struct server *s = p->srv;
5418
5419 send_log(p, LOG_NOTICE, "SIGUP received, dumping servers states.\n");
5420 while (s) {
5421 if (s->state & SRV_RUNNING) {
5422 Warning("SIGHUP: server %s/%s is UP.\n", p->id, s->id);
5423 send_log(p, LOG_NOTICE, "SIGUP: server %s/%s is UP.\n", p->id, s->id);
5424 }
5425 else {
5426 Warning("SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5427 send_log(p, LOG_NOTICE, "SIGHUP: server %s/%s is DOWN.\n", p->id, s->id);
5428 }
5429 s = s->next;
5430 }
willy tarreaudd07e972005-12-18 00:48:48 +01005431
5432 if (find_server(p) == NULL) {
5433 Warning("SIGHUP: proxy %s has no server available !\n", p);
5434 send_log(p, LOG_NOTICE, "SIGHUP: proxy %s has no server available !\n", p);
5435 }
5436
willy tarreau8337c6b2005-12-17 13:41:01 +01005437 p = p->next;
5438 }
5439 signal(sig, sig_dump_state);
5440}
5441
willy tarreau0f7af912005-12-17 12:21:26 +01005442void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01005443 struct task *t, *tnext;
5444 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01005445
willy tarreau5cbea6f2005-12-17 12:48:26 +01005446 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
5447 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
5448 tnext = t->next;
5449 s = t->context;
5450 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
5451 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
5452 "req=%d, rep=%d, clifd=%d\n",
5453 s, tv_remain(&now, &t->expire),
5454 s->cli_state,
5455 s->srv_state,
5456 FD_ISSET(s->cli_fd, StaticReadEvent),
5457 FD_ISSET(s->cli_fd, StaticWriteEvent),
5458 FD_ISSET(s->srv_fd, StaticReadEvent),
5459 FD_ISSET(s->srv_fd, StaticWriteEvent),
5460 s->req->l, s->rep?s->rep->l:0, s->cli_fd
5461 );
willy tarreau0f7af912005-12-17 12:21:26 +01005462 }
willy tarreau12350152005-12-18 01:03:27 +01005463}
5464
5465static void fast_stop(void)
5466{
5467 struct proxy *p;
5468 p = proxy;
5469 while (p) {
5470 p->grace = 0;
5471 p = p->next;
5472 }
5473 soft_stop();
willy tarreau0f7af912005-12-17 12:21:26 +01005474}
5475
willy tarreau12350152005-12-18 01:03:27 +01005476void sig_int(int sig) {
5477 /* This would normally be a hard stop,
5478 but we want to be sure about deallocation,
5479 and so on, so we do a soft stop with
5480 0 GRACE time
5481 */
5482 fast_stop();
5483 /* If we are killed twice, we decide to die*/
5484 signal(sig, SIG_DFL);
5485}
5486
5487void sig_term(int sig) {
5488 /* This would normally be a hard stop,
5489 but we want to be sure about deallocation,
5490 and so on, so we do a soft stop with
5491 0 GRACE time
5492 */
5493 fast_stop();
5494 /* If we are killed twice, we decide to die*/
5495 signal(sig, SIG_DFL);
5496}
5497
willy tarreauc1f47532005-12-18 01:08:26 +01005498/* returns the pointer to an error in the replacement string, or NULL if OK */
5499char *chain_regex(struct hdr_exp **head, regex_t *preg, int action, char *replace) {
willy tarreaue39cd132005-12-17 13:00:18 +01005500 struct hdr_exp *exp;
5501
willy tarreauc1f47532005-12-18 01:08:26 +01005502 if (replace != NULL) {
5503 char *err;
5504 err = check_replace_string(replace);
5505 if (err)
5506 return err;
5507 }
5508
willy tarreaue39cd132005-12-17 13:00:18 +01005509 while (*head != NULL)
5510 head = &(*head)->next;
5511
5512 exp = calloc(1, sizeof(struct hdr_exp));
5513
5514 exp->preg = preg;
5515 exp->replace = replace;
5516 exp->action = action;
5517 *head = exp;
willy tarreauc1f47532005-12-18 01:08:26 +01005518
5519 return NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01005520}
5521
willy tarreau9fe663a2005-12-17 13:02:59 +01005522
willy tarreau0f7af912005-12-17 12:21:26 +01005523/*
willy tarreau9fe663a2005-12-17 13:02:59 +01005524 * parse a line in a <global> section. Returns 0 if OK, -1 if error.
willy tarreau0f7af912005-12-17 12:21:26 +01005525 */
willy tarreau9fe663a2005-12-17 13:02:59 +01005526int cfg_parse_global(char *file, int linenum, char **args) {
willy tarreau0f7af912005-12-17 12:21:26 +01005527
willy tarreau9fe663a2005-12-17 13:02:59 +01005528 if (!strcmp(args[0], "global")) { /* new section */
5529 /* no option, nothing special to do */
5530 return 0;
5531 }
5532 else if (!strcmp(args[0], "daemon")) {
5533 global.mode |= MODE_DAEMON;
5534 }
5535 else if (!strcmp(args[0], "debug")) {
5536 global.mode |= MODE_DEBUG;
5537 }
5538 else if (!strcmp(args[0], "quiet")) {
5539 global.mode |= MODE_QUIET;
5540 }
5541 else if (!strcmp(args[0], "stats")) {
5542 global.mode |= MODE_STATS;
5543 }
5544 else if (!strcmp(args[0], "uid")) {
5545 if (global.uid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005546 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005547 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005548 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005549 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005550 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005551 return -1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01005552 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005553 global.uid = atol(args[1]);
5554 }
5555 else if (!strcmp(args[0], "gid")) {
5556 if (global.gid != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005557 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005558 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005559 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005560 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005561 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005562 return -1;
5563 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005564 global.gid = atol(args[1]);
5565 }
5566 else if (!strcmp(args[0], "nbproc")) {
5567 if (global.nbproc != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005568 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005569 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005570 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005571 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005572 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005573 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005574 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005575 global.nbproc = atol(args[1]);
5576 }
5577 else if (!strcmp(args[0], "maxconn")) {
5578 if (global.maxconn != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005579 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005580 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01005581 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005582 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005583 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005584 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005585 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005586 global.maxconn = atol(args[1]);
5587 }
5588 else if (!strcmp(args[0], "chroot")) {
5589 if (global.chroot != NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005590 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005591 return 0;
5592 }
5593 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005594 Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005595 return -1;
5596 }
5597 global.chroot = strdup(args[1]);
5598 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01005599 else if (!strcmp(args[0], "pidfile")) {
5600 if (global.pidfile != NULL) {
5601 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
5602 return 0;
5603 }
5604 if (*(args[1]) == 0) {
5605 Alert("parsing [%s:%d] : '%s' expects a file name as an argument.\n", file, linenum, args[0]);
5606 return -1;
5607 }
5608 global.pidfile = strdup(args[1]);
5609 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005610 else if (!strcmp(args[0], "log")) { /* syslog server address */
5611 struct sockaddr_in *sa;
willy tarreau8337c6b2005-12-17 13:41:01 +01005612 int facility, level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005613
5614 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005615 Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005616 return -1;
5617 }
5618
5619 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
5620 if (!strcmp(log_facilities[facility], args[2]))
5621 break;
5622
5623 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005624 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005625 exit(1);
5626 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005627
5628 level = 7; /* max syslog level = debug */
5629 if (*(args[3])) {
5630 while (level >= 0 && strcmp(log_levels[level], args[3]))
5631 level--;
5632 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005633 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005634 exit(1);
5635 }
5636 }
5637
willy tarreau9fe663a2005-12-17 13:02:59 +01005638 sa = str2sa(args[1]);
5639 if (!sa->sin_port)
5640 sa->sin_port = htons(SYSLOG_PORT);
5641
5642 if (global.logfac1 == -1) {
5643 global.logsrv1 = *sa;
5644 global.logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005645 global.loglev1 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005646 }
5647 else if (global.logfac2 == -1) {
5648 global.logsrv2 = *sa;
5649 global.logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01005650 global.loglev2 = level;
willy tarreau9fe663a2005-12-17 13:02:59 +01005651 }
5652 else {
5653 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
5654 return -1;
5655 }
5656
5657 }
5658 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005659 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
willy tarreau9fe663a2005-12-17 13:02:59 +01005660 return -1;
5661 }
5662 return 0;
5663}
5664
5665
willy tarreaua41a8b42005-12-17 14:02:24 +01005666void init_default_instance() {
5667 memset(&defproxy, 0, sizeof(defproxy));
5668 defproxy.mode = PR_MODE_TCP;
5669 defproxy.state = PR_STNEW;
5670 defproxy.maxconn = cfg_maxpconn;
5671 defproxy.conn_retries = CONN_RETRIES;
5672 defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */
5673}
5674
willy tarreau9fe663a2005-12-17 13:02:59 +01005675/*
5676 * parse a line in a <listen> section. Returns 0 if OK, -1 if error.
5677 */
5678int cfg_parse_listen(char *file, int linenum, char **args) {
5679 static struct proxy *curproxy = NULL;
5680 struct server *newsrv = NULL;
willy tarreauc1f47532005-12-18 01:08:26 +01005681 char *err;
willy tarreau12350152005-12-18 01:03:27 +01005682 int rc;
willy tarreau9fe663a2005-12-17 13:02:59 +01005683
5684 if (!strcmp(args[0], "listen")) { /* new proxy */
willy tarreaua41a8b42005-12-17 14:02:24 +01005685 if (!*args[1]) {
5686 Alert("parsing [%s:%d] : '%s' expects an <id> argument and\n"
5687 " optionnally supports [addr1]:port1[-end1]{,[addr]:port[-end]}...\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005688 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005689 return -1;
5690 }
5691
5692 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005693 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005694 return -1;
5695 }
5696 curproxy->next = proxy;
5697 proxy = curproxy;
5698 curproxy->id = strdup(args[1]);
willy tarreaua41a8b42005-12-17 14:02:24 +01005699 if (strchr(args[2], ':') != NULL)
5700 curproxy->listen = str2listener(args[2], curproxy->listen);
5701
willy tarreau9fe663a2005-12-17 13:02:59 +01005702 /* set default values */
willy tarreaua41a8b42005-12-17 14:02:24 +01005703 curproxy->state = defproxy.state;
5704 curproxy->maxconn = defproxy.maxconn;
5705 curproxy->conn_retries = defproxy.conn_retries;
5706 curproxy->options = defproxy.options;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005707
5708 if (defproxy.check_req)
5709 curproxy->check_req = strdup(defproxy.check_req);
5710 curproxy->check_len = defproxy.check_len;
5711
5712 if (defproxy.cookie_name)
5713 curproxy->cookie_name = strdup(defproxy.cookie_name);
5714 curproxy->cookie_len = defproxy.cookie_len;
5715
5716 if (defproxy.capture_name)
5717 curproxy->capture_name = strdup(defproxy.capture_name);
5718 curproxy->capture_namelen = defproxy.capture_namelen;
5719 curproxy->capture_len = defproxy.capture_len;
5720
5721 if (defproxy.errmsg.msg400)
5722 curproxy->errmsg.msg400 = strdup(defproxy.errmsg.msg400);
5723 curproxy->errmsg.len400 = defproxy.errmsg.len400;
5724
5725 if (defproxy.errmsg.msg403)
5726 curproxy->errmsg.msg403 = strdup(defproxy.errmsg.msg403);
5727 curproxy->errmsg.len403 = defproxy.errmsg.len403;
5728
5729 if (defproxy.errmsg.msg408)
5730 curproxy->errmsg.msg408 = strdup(defproxy.errmsg.msg408);
5731 curproxy->errmsg.len408 = defproxy.errmsg.len408;
5732
5733 if (defproxy.errmsg.msg500)
5734 curproxy->errmsg.msg500 = strdup(defproxy.errmsg.msg500);
5735 curproxy->errmsg.len500 = defproxy.errmsg.len500;
5736
5737 if (defproxy.errmsg.msg502)
5738 curproxy->errmsg.msg502 = strdup(defproxy.errmsg.msg502);
5739 curproxy->errmsg.len502 = defproxy.errmsg.len502;
5740
5741 if (defproxy.errmsg.msg503)
5742 curproxy->errmsg.msg503 = strdup(defproxy.errmsg.msg503);
5743 curproxy->errmsg.len503 = defproxy.errmsg.len503;
5744
5745 if (defproxy.errmsg.msg504)
5746 curproxy->errmsg.msg504 = strdup(defproxy.errmsg.msg504);
5747 curproxy->errmsg.len504 = defproxy.errmsg.len504;
5748
willy tarreaua41a8b42005-12-17 14:02:24 +01005749 curproxy->clitimeout = defproxy.clitimeout;
5750 curproxy->contimeout = defproxy.contimeout;
5751 curproxy->srvtimeout = defproxy.srvtimeout;
5752 curproxy->mode = defproxy.mode;
5753 curproxy->logfac1 = defproxy.logfac1;
5754 curproxy->logsrv1 = defproxy.logsrv1;
5755 curproxy->loglev1 = defproxy.loglev1;
5756 curproxy->logfac2 = defproxy.logfac2;
5757 curproxy->logsrv2 = defproxy.logsrv2;
5758 curproxy->loglev2 = defproxy.loglev2;
willy tarreau4302f492005-12-18 01:00:37 +01005759 curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
willy tarreaua41a8b42005-12-17 14:02:24 +01005760 curproxy->grace = defproxy.grace;
5761 curproxy->source_addr = defproxy.source_addr;
5762 return 0;
5763 }
5764 else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
willy tarreaueedaa9f2005-12-17 14:08:03 +01005765 /* some variables may have already been initialized earlier */
5766 if (defproxy.check_req) free(defproxy.check_req);
5767 if (defproxy.cookie_name) free(defproxy.cookie_name);
5768 if (defproxy.capture_name) free(defproxy.capture_name);
5769 if (defproxy.errmsg.msg400) free(defproxy.errmsg.msg400);
5770 if (defproxy.errmsg.msg403) free(defproxy.errmsg.msg403);
5771 if (defproxy.errmsg.msg408) free(defproxy.errmsg.msg408);
5772 if (defproxy.errmsg.msg500) free(defproxy.errmsg.msg500);
5773 if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
5774 if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
5775 if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
5776
5777 init_default_instance();
willy tarreaua41a8b42005-12-17 14:02:24 +01005778 curproxy = &defproxy;
willy tarreau9fe663a2005-12-17 13:02:59 +01005779 return 0;
5780 }
5781 else if (curproxy == NULL) {
willy tarreaua41a8b42005-12-17 14:02:24 +01005782 Alert("parsing [%s:%d] : 'listen' or 'defaults' expected.\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01005783 return -1;
5784 }
5785
willy tarreaua41a8b42005-12-17 14:02:24 +01005786 if (!strcmp(args[0], "bind")) { /* new listen addresses */
5787 if (curproxy == &defproxy) {
5788 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5789 return -1;
5790 }
5791
5792 if (strchr(args[1], ':') == NULL) {
5793 Alert("parsing [%s:%d] : '%s' expects [addr1]:port1[-end1]{,[addr]:port[-end]}... as arguments.\n",
5794 file, linenum, args[0]);
5795 return -1;
5796 }
5797 curproxy->listen = str2listener(args[1], curproxy->listen);
5798 return 0;
5799 }
5800 else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
willy tarreau9fe663a2005-12-17 13:02:59 +01005801 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
5802 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
5803 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
5804 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01005805 Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005806 return -1;
5807 }
5808 }
5809 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
5810 curproxy->state = PR_STDISABLED;
5811 }
willy tarreaua41a8b42005-12-17 14:02:24 +01005812 else if (!strcmp(args[0], "enabled")) { /* enables this proxy (used to revert a disabled default) */
5813 curproxy->state = PR_STNEW;
5814 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005815 else if (!strcmp(args[0], "cookie")) { /* cookie name */
5816 int cur_arg;
willy tarreaueedaa9f2005-12-17 14:08:03 +01005817// if (curproxy == &defproxy) {
5818// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5819// return -1;
5820// }
willy tarreaua41a8b42005-12-17 14:02:24 +01005821
willy tarreau9fe663a2005-12-17 13:02:59 +01005822 if (curproxy->cookie_name != NULL) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01005823// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5824// file, linenum);
5825// return 0;
5826 free(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005827 }
5828
5829 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005830 Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
5831 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005832 return -1;
5833 }
5834 curproxy->cookie_name = strdup(args[1]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005835 curproxy->cookie_len = strlen(curproxy->cookie_name);
willy tarreau9fe663a2005-12-17 13:02:59 +01005836
5837 cur_arg = 2;
5838 while (*(args[cur_arg])) {
5839 if (!strcmp(args[cur_arg], "rewrite")) {
5840 curproxy->options |= PR_O_COOK_RW;
willy tarreau0f7af912005-12-17 12:21:26 +01005841 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005842 else if (!strcmp(args[cur_arg], "indirect")) {
5843 curproxy->options |= PR_O_COOK_IND;
willy tarreau0f7af912005-12-17 12:21:26 +01005844 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005845 else if (!strcmp(args[cur_arg], "insert")) {
5846 curproxy->options |= PR_O_COOK_INS;
willy tarreau0f7af912005-12-17 12:21:26 +01005847 }
willy tarreau240afa62005-12-17 13:14:35 +01005848 else if (!strcmp(args[cur_arg], "nocache")) {
5849 curproxy->options |= PR_O_COOK_NOC;
5850 }
willy tarreaucd878942005-12-17 13:27:43 +01005851 else if (!strcmp(args[cur_arg], "postonly")) {
5852 curproxy->options |= PR_O_COOK_POST;
5853 }
willy tarreau0174f312005-12-18 01:02:42 +01005854 else if (!strcmp(args[cur_arg], "prefix")) {
5855 curproxy->options |= PR_O_COOK_PFX;
5856 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005857 else {
willy tarreau0174f312005-12-18 01:02:42 +01005858 Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache' and 'postonly' options.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005859 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01005860 return -1;
5861 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005862 cur_arg++;
5863 }
willy tarreau0174f312005-12-18 01:02:42 +01005864 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND))) {
5865 Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' modes are incompatible.\n",
5866 file, linenum);
5867 return -1;
5868 }
5869
5870 if (!POWEROF2(curproxy->options & (PR_O_COOK_RW|PR_O_COOK_INS|PR_O_COOK_PFX))) {
5871 Alert("parsing [%s:%d] : cookie 'rewrite', 'insert' and 'prefix' modes are incompatible.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01005872 file, linenum);
5873 return -1;
5874 }
willy tarreau12350152005-12-18 01:03:27 +01005875 }/* end else if (!strcmp(args[0], "cookie")) */
5876 else if (!strcmp(args[0], "appsession")) { /* cookie name */
5877// if (curproxy == &defproxy) {
5878// Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5879// return -1;
5880// }
5881
5882 if (curproxy->appsession_name != NULL) {
5883// Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
5884// file, linenum);
5885// return 0;
5886 free(curproxy->appsession_name);
5887 }
5888
5889 if (*(args[5]) == 0) {
5890 Alert("parsing [%s:%d] : '%s' expects 'appsession' <cookie_name> 'len' <len> 'timeout' <timeout>.\n",
5891 file, linenum, args[0]);
5892 return -1;
5893 }
5894 have_appsession = 1;
5895 curproxy->appsession_name = strdup(args[1]);
5896 curproxy->appsession_name_len = strlen(curproxy->appsession_name);
5897 curproxy->appsession_len = atoi(args[3]);
5898 curproxy->appsession_timeout = atoi(args[5]);
5899 rc = chtbl_init(&(curproxy->htbl_proxy), TBLSIZ, hashpjw, match_str, destroy);
5900 if (rc) {
5901 Alert("Error Init Appsession Hashtable.\n");
5902 return -1;
5903 }
5904 } /* Url App Session */
willy tarreau4302f492005-12-18 01:00:37 +01005905 else if (!strcmp(args[0], "capture")) {
5906 if (!strcmp(args[1], "cookie")) { /* name of a cookie to capture */
5907 // if (curproxy == &defproxy) {
5908 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
5909 // return -1;
5910 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01005911
willy tarreau4302f492005-12-18 01:00:37 +01005912 if (curproxy->capture_name != NULL) {
5913 // Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
5914 // file, linenum, args[0]);
5915 // return 0;
5916 free(curproxy->capture_name);
5917 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005918
willy tarreau4302f492005-12-18 01:00:37 +01005919 if (*(args[4]) == 0) {
5920 Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
5921 file, linenum, args[0]);
5922 return -1;
5923 }
5924 curproxy->capture_name = strdup(args[2]);
5925 curproxy->capture_namelen = strlen(curproxy->capture_name);
5926 curproxy->capture_len = atol(args[4]);
5927 if (curproxy->capture_len >= CAPTURE_LEN) {
5928 Warning("parsing [%s:%d] : truncating capture length to %d bytes.\n",
5929 file, linenum, CAPTURE_LEN - 1);
5930 curproxy->capture_len = CAPTURE_LEN - 1;
5931 }
5932 curproxy->to_log |= LW_COOKIE;
5933 }
5934 else if (!strcmp(args[1], "request") && !strcmp(args[2], "header")) {
5935 struct cap_hdr *hdr;
5936
5937 if (curproxy == &defproxy) {
5938 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5939 return -1;
5940 }
5941
5942 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5943 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5944 file, linenum, args[0], args[1]);
5945 return -1;
5946 }
5947
5948 hdr = calloc(sizeof(struct cap_hdr), 1);
5949 hdr->next = curproxy->req_cap;
5950 hdr->name = strdup(args[3]);
5951 hdr->namelen = strlen(args[3]);
5952 hdr->len = atol(args[5]);
5953 hdr->index = curproxy->nb_req_cap++;
5954 curproxy->req_cap = hdr;
5955 curproxy->to_log |= LW_REQHDR;
5956 }
5957 else if (!strcmp(args[1], "response") && !strcmp(args[2], "header")) {
5958 struct cap_hdr *hdr;
5959
5960 if (curproxy == &defproxy) {
5961 Alert("parsing [%s:%d] : '%s %s' not allowed in 'defaults' section.\n", file, linenum, args[0], args[1]);
5962 return -1;
5963 }
5964
5965 if (*(args[3]) == 0 || strcmp(args[4], "len") != 0 || *(args[5]) == 0) {
5966 Alert("parsing [%s:%d] : '%s %s' expects 'header' <header_name> 'len' <len>.\n",
5967 file, linenum, args[0], args[1]);
5968 return -1;
5969 }
5970 hdr = calloc(sizeof(struct cap_hdr), 1);
5971 hdr->next = curproxy->rsp_cap;
5972 hdr->name = strdup(args[3]);
5973 hdr->namelen = strlen(args[3]);
5974 hdr->len = atol(args[5]);
5975 hdr->index = curproxy->nb_rsp_cap++;
5976 curproxy->rsp_cap = hdr;
5977 curproxy->to_log |= LW_RSPHDR;
5978 }
5979 else {
5980 Alert("parsing [%s:%d] : '%s' expects 'cookie' or 'request header' or 'response header'.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01005981 file, linenum, args[0]);
willy tarreau8337c6b2005-12-17 13:41:01 +01005982 return -1;
5983 }
willy tarreau8337c6b2005-12-17 13:41:01 +01005984 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005985 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005986 if (curproxy->contimeout != defproxy.contimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005987 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005988 return 0;
5989 }
5990 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005991 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
5992 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01005993 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01005994 }
willy tarreau9fe663a2005-12-17 13:02:59 +01005995 curproxy->contimeout = atol(args[1]);
5996 }
5997 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01005998 if (curproxy->clitimeout != defproxy.clitimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01005999 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
6000 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006001 return 0;
6002 }
6003 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006004 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6005 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006006 return -1;
6007 }
6008 curproxy->clitimeout = atol(args[1]);
6009 }
6010 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
willy tarreaua41a8b42005-12-17 14:02:24 +01006011 if (curproxy->srvtimeout != defproxy.srvtimeout) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006012 Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006013 return 0;
6014 }
6015 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006016 Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
6017 file, linenum, args[0]);
willy tarreau0f7af912005-12-17 12:21:26 +01006018 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006019 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006020 curproxy->srvtimeout = atol(args[1]);
6021 }
6022 else if (!strcmp(args[0], "retries")) { /* connection retries */
6023 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006024 Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
6025 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006026 return -1;
6027 }
6028 curproxy->conn_retries = atol(args[1]);
6029 }
6030 else if (!strcmp(args[0], "option")) {
6031 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006032 Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006033 return -1;
6034 }
6035 if (!strcmp(args[1], "redispatch"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006036 /* enable reconnections to dispatch */
6037 curproxy->options |= PR_O_REDISP;
willy tarreaua1598082005-12-17 13:08:06 +01006038#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006039 else if (!strcmp(args[1], "transparent"))
willy tarreau5cbea6f2005-12-17 12:48:26 +01006040 /* enable transparent proxy connections */
6041 curproxy->options |= PR_O_TRANSP;
willy tarreau9fe663a2005-12-17 13:02:59 +01006042#endif
6043 else if (!strcmp(args[1], "keepalive"))
6044 /* enable keep-alive */
6045 curproxy->options |= PR_O_KEEPALIVE;
6046 else if (!strcmp(args[1], "forwardfor"))
6047 /* insert x-forwarded-for field */
6048 curproxy->options |= PR_O_FWDFOR;
willy tarreau25c4ea52005-12-18 00:49:49 +01006049 else if (!strcmp(args[1], "logasap"))
6050 /* log as soon as possible, without waiting for the session to complete */
6051 curproxy->options |= PR_O_LOGASAP;
6052 else if (!strcmp(args[1], "httpclose"))
6053 /* force connection: close in both directions in HTTP mode */
6054 curproxy->options |= PR_O_HTTP_CLOSE;
willy tarreau97f58572005-12-18 00:53:44 +01006055 else if (!strcmp(args[1], "checkcache"))
6056 /* require examination of cacheability of the 'set-cookie' field */
6057 curproxy->options |= PR_O_CHK_CACHE;
willy tarreauc1cae632005-12-17 14:12:23 +01006058 else if (!strcmp(args[1], "httplog"))
willy tarreau9fe663a2005-12-17 13:02:59 +01006059 /* generate a complete HTTP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006060 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_REQ | LW_PXID | LW_RESP | LW_BYTES;
willy tarreauc1cae632005-12-17 14:12:23 +01006061 else if (!strcmp(args[1], "tcplog"))
6062 /* generate a detailed TCP log */
willy tarreau25c4ea52005-12-18 00:49:49 +01006063 curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
willy tarreaua1598082005-12-17 13:08:06 +01006064 else if (!strcmp(args[1], "dontlognull")) {
6065 /* don't log empty requests */
6066 curproxy->options |= PR_O_NULLNOLOG;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006067 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006068 else if (!strcmp(args[1], "httpchk")) {
6069 /* use HTTP request to check servers' health */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006070 if (curproxy->check_req != NULL) {
6071 free(curproxy->check_req);
6072 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006073 curproxy->options |= PR_O_HTTP_CHK;
willy tarreaueedaa9f2005-12-17 14:08:03 +01006074 if (!*args[2]) { /* no argument */
6075 curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */
6076 curproxy->check_len = strlen(DEF_CHECK_REQ);
6077 } else if (!*args[3]) { /* one argument : URI */
willy tarreau2f6ba652005-12-17 13:57:42 +01006078 int reqlen = strlen(args[2]) + strlen("OPTIONS / HTTP/1.0\r\n\r\n");
6079 curproxy->check_req = (char *)malloc(reqlen);
6080 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6081 "OPTIONS %s HTTP/1.0\r\n\r\n", args[2]); /* URI to use */
willy tarreaueedaa9f2005-12-17 14:08:03 +01006082 } else { /* more arguments : METHOD URI [HTTP_VER] */
6083 int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n\r\n");
6084 if (*args[4])
6085 reqlen += strlen(args[4]);
6086 else
6087 reqlen += strlen("HTTP/1.0");
6088
6089 curproxy->check_req = (char *)malloc(reqlen);
6090 curproxy->check_len = snprintf(curproxy->check_req, reqlen,
6091 "%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 +01006092 }
willy tarreaubc4e1fb2005-12-17 13:32:07 +01006093 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006094 else if (!strcmp(args[1], "persist")) {
6095 /* persist on using the server specified by the cookie, even when it's down */
6096 curproxy->options |= PR_O_PERSIST;
6097 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006098 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006099 Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006100 return -1;
6101 }
6102 return 0;
6103 }
6104 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
6105 /* enable reconnections to dispatch */
6106 curproxy->options |= PR_O_REDISP;
6107 }
willy tarreaua1598082005-12-17 13:08:06 +01006108#ifdef TPROXY
willy tarreau9fe663a2005-12-17 13:02:59 +01006109 else if (!strcmp(args[0], "transparent")) {
6110 /* enable transparent proxy connections */
6111 curproxy->options |= PR_O_TRANSP;
6112 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006113#endif
willy tarreau9fe663a2005-12-17 13:02:59 +01006114 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
6115 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006116 Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006117 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006118 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006119 curproxy->maxconn = atol(args[1]);
6120 }
6121 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
6122 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006123 Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006124 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006125 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006126 curproxy->grace = atol(args[1]);
6127 }
6128 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
willy tarreaua41a8b42005-12-17 14:02:24 +01006129 if (curproxy == &defproxy) {
6130 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6131 return -1;
6132 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006133 if (strchr(args[1], ':') == NULL) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006134 Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006135 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006136 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006137 curproxy->dispatch_addr = *str2sa(args[1]);
6138 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006139 else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */
willy tarreau9fe663a2005-12-17 13:02:59 +01006140 if (*(args[1])) {
6141 if (!strcmp(args[1], "roundrobin")) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01006142 curproxy->options |= PR_O_BALANCE_RR;
willy tarreau9fe663a2005-12-17 13:02:59 +01006143 }
6144 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006145 Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006146 return -1;
6147 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006148 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006149 else /* if no option is set, use round-robin by default */
6150 curproxy->options |= PR_O_BALANCE_RR;
6151 }
6152 else if (!strcmp(args[0], "server")) { /* server address */
6153 int cur_arg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006154 char *rport;
6155 char *raddr;
6156 short realport;
6157 int do_check;
6158
6159 if (curproxy == &defproxy) {
6160 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6161 return -1;
6162 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006163
willy tarreaua41a8b42005-12-17 14:02:24 +01006164 if (!*args[2]) {
6165 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006166 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006167 return -1;
6168 }
6169 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
6170 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6171 return -1;
6172 }
willy tarreau0174f312005-12-18 01:02:42 +01006173
6174 if (curproxy->srv == NULL)
6175 curproxy->srv = newsrv;
6176 else
6177 curproxy->cursrv->next = newsrv;
6178 curproxy->cursrv = newsrv;
6179
6180 newsrv->next = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01006181 newsrv->proxy = curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01006182
6183 do_check = 0;
willy tarreau9fe663a2005-12-17 13:02:59 +01006184 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreaua41a8b42005-12-17 14:02:24 +01006185 newsrv->id = strdup(args[1]);
6186
6187 /* several ways to check the port component :
6188 * - IP => port=+0, relative
6189 * - IP: => port=+0, relative
6190 * - IP:N => port=N, absolute
6191 * - IP:+N => port=+N, relative
6192 * - IP:-N => port=-N, relative
6193 */
6194 raddr = strdup(args[2]);
6195 rport = strchr(raddr, ':');
6196 if (rport) {
6197 *rport++ = 0;
6198 realport = atol(rport);
6199 if (!isdigit((int)*rport))
6200 newsrv->state |= SRV_MAPPORTS;
6201 } else {
6202 realport = 0;
6203 newsrv->state |= SRV_MAPPORTS;
6204 }
6205
6206 newsrv->addr = *str2sa(raddr);
6207 newsrv->addr.sin_port = htons(realport);
6208 free(raddr);
6209
willy tarreau9fe663a2005-12-17 13:02:59 +01006210 newsrv->curfd = -1; /* no health-check in progress */
6211 newsrv->inter = DEF_CHKINTR;
6212 newsrv->rise = DEF_RISETIME;
6213 newsrv->fall = DEF_FALLTIME;
6214 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
6215 cur_arg = 3;
6216 while (*args[cur_arg]) {
6217 if (!strcmp(args[cur_arg], "cookie")) {
6218 newsrv->cookie = strdup(args[cur_arg + 1]);
6219 newsrv->cklen = strlen(args[cur_arg + 1]);
6220 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006221 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006222 else if (!strcmp(args[cur_arg], "rise")) {
6223 newsrv->rise = atol(args[cur_arg + 1]);
6224 newsrv->health = newsrv->rise;
6225 cur_arg += 2;
willy tarreau0f7af912005-12-17 12:21:26 +01006226 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006227 else if (!strcmp(args[cur_arg], "fall")) {
6228 newsrv->fall = atol(args[cur_arg + 1]);
6229 cur_arg += 2;
6230 }
6231 else if (!strcmp(args[cur_arg], "inter")) {
6232 newsrv->inter = atol(args[cur_arg + 1]);
6233 cur_arg += 2;
6234 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006235 else if (!strcmp(args[cur_arg], "port")) {
6236 newsrv->check_port = atol(args[cur_arg + 1]);
6237 cur_arg += 2;
6238 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006239 else if (!strcmp(args[cur_arg], "backup")) {
6240 newsrv->state |= SRV_BACKUP;
6241 cur_arg ++;
6242 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006243 else if (!strcmp(args[cur_arg], "check")) {
willy tarreaua41a8b42005-12-17 14:02:24 +01006244 do_check = 1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006245 cur_arg += 1;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006246 }
willy tarreau0174f312005-12-18 01:02:42 +01006247 else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
6248 if (!*args[cur_arg + 1]) {
6249 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
6250 file, linenum, "source");
6251 return -1;
6252 }
6253 newsrv->state |= SRV_BIND_SRC;
6254 newsrv->source_addr = *str2sa(args[cur_arg + 1]);
6255 cur_arg += 2;
6256 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006257 else {
willy tarreau0174f312005-12-18 01:02:42 +01006258 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 +01006259 file, linenum, newsrv->id);
6260 return -1;
6261 }
6262 }
6263
6264 if (do_check) {
6265 struct task *t;
6266
6267 if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
6268 newsrv->check_port = realport; /* by default */
6269 if (!newsrv->check_port) {
6270 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 +01006271 file, linenum, newsrv->id);
willy tarreau0f7af912005-12-17 12:21:26 +01006272 return -1;
6273 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006274
6275 if ((t = pool_alloc(task)) == NULL) {
6276 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
6277 return -1;
6278 }
6279
6280 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
6281 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
6282 t->state = TASK_IDLE;
6283 t->process = process_chk;
6284 t->context = newsrv;
6285
6286 if (curproxy->state != PR_STDISABLED) {
6287 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
6288 task_queue(t);
6289 task_wakeup(&rq, t);
6290 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006291 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006292
willy tarreau9fe663a2005-12-17 13:02:59 +01006293 curproxy->nbservers++;
6294 }
6295 else if (!strcmp(args[0], "log")) { /* syslog server address */
6296 struct sockaddr_in *sa;
6297 int facility;
6298
6299 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
6300 curproxy->logfac1 = global.logfac1;
6301 curproxy->logsrv1 = global.logsrv1;
willy tarreau8337c6b2005-12-17 13:41:01 +01006302 curproxy->loglev1 = global.loglev1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006303 curproxy->logfac2 = global.logfac2;
6304 curproxy->logsrv2 = global.logsrv2;
willy tarreau8337c6b2005-12-17 13:41:01 +01006305 curproxy->loglev2 = global.loglev2;
willy tarreau9fe663a2005-12-17 13:02:59 +01006306 }
6307 else if (*(args[1]) && *(args[2])) {
willy tarreau8337c6b2005-12-17 13:41:01 +01006308 int level;
6309
willy tarreau0f7af912005-12-17 12:21:26 +01006310 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
6311 if (!strcmp(log_facilities[facility], args[2]))
6312 break;
willy tarreau9fe663a2005-12-17 13:02:59 +01006313
willy tarreau0f7af912005-12-17 12:21:26 +01006314 if (facility >= NB_LOG_FACILITIES) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006315 Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
willy tarreau0f7af912005-12-17 12:21:26 +01006316 exit(1);
6317 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006318
willy tarreau8337c6b2005-12-17 13:41:01 +01006319 level = 7; /* max syslog level = debug */
6320 if (*(args[3])) {
6321 while (level >= 0 && strcmp(log_levels[level], args[3]))
6322 level--;
6323 if (level < 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006324 Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
willy tarreau8337c6b2005-12-17 13:41:01 +01006325 exit(1);
6326 }
6327 }
6328
willy tarreau0f7af912005-12-17 12:21:26 +01006329 sa = str2sa(args[1]);
6330 if (!sa->sin_port)
6331 sa->sin_port = htons(SYSLOG_PORT);
willy tarreau9fe663a2005-12-17 13:02:59 +01006332
willy tarreau0f7af912005-12-17 12:21:26 +01006333 if (curproxy->logfac1 == -1) {
6334 curproxy->logsrv1 = *sa;
6335 curproxy->logfac1 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006336 curproxy->loglev1 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006337 }
6338 else if (curproxy->logfac2 == -1) {
6339 curproxy->logsrv2 = *sa;
6340 curproxy->logfac2 = facility;
willy tarreau8337c6b2005-12-17 13:41:01 +01006341 curproxy->loglev2 = level;
willy tarreau0f7af912005-12-17 12:21:26 +01006342 }
6343 else {
6344 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
willy tarreau9fe663a2005-12-17 13:02:59 +01006345 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006346 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006347 }
6348 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006349 Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
willy tarreau9fe663a2005-12-17 13:02:59 +01006350 file, linenum);
6351 return -1;
6352 }
6353 }
willy tarreaua1598082005-12-17 13:08:06 +01006354 else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */
willy tarreaua41a8b42005-12-17 14:02:24 +01006355 if (!*args[1]) {
6356 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>] as argument.\n",
willy tarreau036e1ce2005-12-17 13:46:33 +01006357 file, linenum, "source");
willy tarreaua1598082005-12-17 13:08:06 +01006358 return -1;
6359 }
6360
6361 curproxy->source_addr = *str2sa(args[1]);
6362 curproxy->options |= PR_O_BIND_SRC;
6363 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006364 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
6365 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006366 if (curproxy == &defproxy) {
6367 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6368 return -1;
6369 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006370
6371 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006372 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6373 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006374 return -1;
6375 }
6376
6377 preg = calloc(1, sizeof(regex_t));
6378 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006379 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006380 return -1;
6381 }
6382
willy tarreauc1f47532005-12-18 01:08:26 +01006383 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6384 if (err) {
6385 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6386 file, linenum, *err);
6387 return -1;
6388 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006389 }
6390 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
6391 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006392 if (curproxy == &defproxy) {
6393 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6394 return -1;
6395 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006396
6397 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006398 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006399 return -1;
6400 }
6401
6402 preg = calloc(1, sizeof(regex_t));
6403 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006404 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006405 return -1;
6406 }
6407
6408 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6409 }
6410 else if (!strcmp(args[0], "reqdeny")) { /* deny a request if a header matches this regex */
6411 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006412 if (curproxy == &defproxy) {
6413 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6414 return -1;
6415 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006416
6417 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006418 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006419 return -1;
6420 }
6421
6422 preg = calloc(1, sizeof(regex_t));
6423 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006424 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006425 return -1;
6426 }
6427
6428 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6429 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006430 else if (!strcmp(args[0], "reqpass")) { /* pass this header without allowing or denying the request */
6431 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006432 if (curproxy == &defproxy) {
6433 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6434 return -1;
6435 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006436
6437 if (*(args[1]) == 0) {
6438 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6439 return -1;
6440 }
6441
6442 preg = calloc(1, sizeof(regex_t));
6443 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6444 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6445 return -1;
6446 }
6447
6448 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6449 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006450 else if (!strcmp(args[0], "reqallow")) { /* allow a request if a header matches this regex */
6451 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006452 if (curproxy == &defproxy) {
6453 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6454 return -1;
6455 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006456
6457 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006458 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006459 return -1;
6460 }
6461
6462 preg = calloc(1, sizeof(regex_t));
6463 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006464 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006465 return -1;
6466 }
6467
6468 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6469 }
6470 else if (!strcmp(args[0], "reqirep")) { /* replace request header from a regex, ignoring case */
6471 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006472 if (curproxy == &defproxy) {
6473 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6474 return -1;
6475 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006476
6477 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006478 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6479 file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006480 return -1;
6481 }
6482
6483 preg = calloc(1, sizeof(regex_t));
6484 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006485 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006486 return -1;
6487 }
6488
willy tarreauc1f47532005-12-18 01:08:26 +01006489 err = chain_regex(&curproxy->req_exp, preg, ACT_REPLACE, strdup(args[2]));
6490 if (err) {
6491 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6492 file, linenum, *err);
6493 return -1;
6494 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006495 }
6496 else if (!strcmp(args[0], "reqidel")) { /* delete request header from a regex ignoring case */
6497 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006498 if (curproxy == &defproxy) {
6499 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6500 return -1;
6501 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006502
6503 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006504 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006505 return -1;
6506 }
6507
6508 preg = calloc(1, sizeof(regex_t));
6509 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006510 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006511 return -1;
6512 }
6513
6514 chain_regex(&curproxy->req_exp, preg, ACT_REMOVE, NULL);
6515 }
6516 else if (!strcmp(args[0], "reqideny")) { /* deny a request if a header matches this regex ignoring case */
6517 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006518 if (curproxy == &defproxy) {
6519 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6520 return -1;
6521 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006522
6523 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006524 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006525 return -1;
6526 }
6527
6528 preg = calloc(1, sizeof(regex_t));
6529 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006530 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006531 return -1;
6532 }
6533
6534 chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
6535 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006536 else if (!strcmp(args[0], "reqipass")) { /* pass this header without allowing or denying the request */
6537 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006538 if (curproxy == &defproxy) {
6539 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6540 return -1;
6541 }
willy tarreau036e1ce2005-12-17 13:46:33 +01006542
6543 if (*(args[1]) == 0) {
6544 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
6545 return -1;
6546 }
6547
6548 preg = calloc(1, sizeof(regex_t));
6549 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6550 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6551 return -1;
6552 }
6553
6554 chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
6555 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006556 else if (!strcmp(args[0], "reqiallow")) { /* allow a request if a header matches this regex ignoring case */
6557 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006558 if (curproxy == &defproxy) {
6559 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6560 return -1;
6561 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006562
6563 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006564 Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006565 return -1;
6566 }
6567
6568 preg = calloc(1, sizeof(regex_t));
6569 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006570 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006571 return -1;
6572 }
6573
6574 chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
6575 }
6576 else if (!strcmp(args[0], "reqadd")) { /* add request header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006577 if (curproxy == &defproxy) {
6578 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6579 return -1;
6580 }
6581
willy tarreau9fe663a2005-12-17 13:02:59 +01006582 if (curproxy->nb_reqadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006583 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006584 return 0;
6585 }
6586
6587 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006588 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006589 return -1;
6590 }
6591
willy tarreau4302f492005-12-18 01:00:37 +01006592 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
6593 }
6594 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
6595 regex_t *preg;
6596
6597 if (*(args[1]) == 0 || *(args[2]) == 0) {
6598 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6599 file, linenum, args[0]);
6600 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006601 }
willy tarreau4302f492005-12-18 01:00:37 +01006602
6603 preg = calloc(1, sizeof(regex_t));
6604 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6605 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6606 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006607 }
willy tarreau4302f492005-12-18 01:00:37 +01006608
willy tarreauc1f47532005-12-18 01:08:26 +01006609 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6610 if (err) {
6611 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6612 file, linenum, *err);
6613 return -1;
6614 }
willy tarreau4302f492005-12-18 01:00:37 +01006615 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006616 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
6617 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006618 if (curproxy == &defproxy) {
6619 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6620 return -1;
6621 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006622
6623 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006624 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006625 return -1;
6626 }
willy tarreaue39cd132005-12-17 13:00:18 +01006627
willy tarreau9fe663a2005-12-17 13:02:59 +01006628 preg = calloc(1, sizeof(regex_t));
6629 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006630 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006631 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006632 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006633
willy tarreauc1f47532005-12-18 01:08:26 +01006634 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6635 if (err) {
6636 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6637 file, linenum, *err);
6638 return -1;
6639 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006640 }
willy tarreau982249e2005-12-18 00:57:06 +01006641 else if (!strcmp(args[0], "rspdeny")) { /* block response header from a regex */
6642 regex_t *preg;
6643 if (curproxy == &defproxy) {
6644 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6645 return -1;
6646 }
6647
6648 if (*(args[1]) == 0) {
6649 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6650 return -1;
6651 }
6652
6653 preg = calloc(1, sizeof(regex_t));
6654 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
6655 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6656 return -1;
6657 }
6658
willy tarreauc1f47532005-12-18 01:08:26 +01006659 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6660 if (err) {
6661 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6662 file, linenum, *err);
6663 return -1;
6664 }
willy tarreau982249e2005-12-18 00:57:06 +01006665 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006666 else if (!strcmp(args[0], "rspirep")) { /* replace response header from a regex ignoring case */
willy tarreaua41a8b42005-12-17 14:02:24 +01006667 regex_t *preg;
6668 if (curproxy == &defproxy) {
6669 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6670 return -1;
6671 }
willy tarreaue39cd132005-12-17 13:00:18 +01006672
willy tarreaua41a8b42005-12-17 14:02:24 +01006673 if (*(args[1]) == 0 || *(args[2]) == 0) {
6674 Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
6675 file, linenum, args[0]);
6676 return -1;
6677 }
willy tarreaue39cd132005-12-17 13:00:18 +01006678
willy tarreaua41a8b42005-12-17 14:02:24 +01006679 preg = calloc(1, sizeof(regex_t));
6680 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6681 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6682 return -1;
willy tarreau9fe663a2005-12-17 13:02:59 +01006683 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006684
willy tarreauc1f47532005-12-18 01:08:26 +01006685 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REPLACE, strdup(args[2]));
6686 if (err) {
6687 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6688 file, linenum, *err);
6689 return -1;
6690 }
willy tarreaua41a8b42005-12-17 14:02:24 +01006691 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006692 else if (!strcmp(args[0], "rspidel")) { /* delete response header from a regex ignoring case */
6693 regex_t *preg;
willy tarreaua41a8b42005-12-17 14:02:24 +01006694 if (curproxy == &defproxy) {
6695 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6696 return -1;
6697 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006698
6699 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006700 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006701 return -1;
6702 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006703
willy tarreau9fe663a2005-12-17 13:02:59 +01006704 preg = calloc(1, sizeof(regex_t));
6705 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006706 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006707 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006708 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006709
willy tarreauc1f47532005-12-18 01:08:26 +01006710 err = chain_regex(&curproxy->rsp_exp, preg, ACT_REMOVE, strdup(args[2]));
6711 if (err) {
6712 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6713 file, linenum, *err);
6714 return -1;
6715 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006716 }
willy tarreau982249e2005-12-18 00:57:06 +01006717 else if (!strcmp(args[0], "rspideny")) { /* block response header from a regex ignoring case */
6718 regex_t *preg;
6719 if (curproxy == &defproxy) {
6720 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6721 return -1;
6722 }
6723
6724 if (*(args[1]) == 0) {
6725 Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
6726 return -1;
6727 }
6728
6729 preg = calloc(1, sizeof(regex_t));
6730 if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
6731 Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
6732 return -1;
6733 }
6734
willy tarreauc1f47532005-12-18 01:08:26 +01006735 err = chain_regex(&curproxy->rsp_exp, preg, ACT_DENY, strdup(args[2]));
6736 if (err) {
6737 Alert("parsing [%s:%d] : invalid character or unterminated sequence in replacement string near '%c'.\n",
6738 file, linenum, *err);
6739 return -1;
6740 }
willy tarreau982249e2005-12-18 00:57:06 +01006741 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006742 else if (!strcmp(args[0], "rspadd")) { /* add response header */
willy tarreaua41a8b42005-12-17 14:02:24 +01006743 if (curproxy == &defproxy) {
6744 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6745 return -1;
6746 }
6747
willy tarreau9fe663a2005-12-17 13:02:59 +01006748 if (curproxy->nb_rspadd >= MAX_NEWHDR) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006749 Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006750 return 0;
6751 }
6752
6753 if (*(args[1]) == 0) {
willy tarreau036e1ce2005-12-17 13:46:33 +01006754 Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006755 return -1;
6756 }
6757
6758 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
6759 }
willy tarreauc1f47532005-12-18 01:08:26 +01006760 else if (!strcmp(args[0], "errorloc") ||
6761 !strcmp(args[0], "errorloc302") ||
6762 !strcmp(args[0], "errorloc303")) { /* error location */
6763 int errnum, errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006764 char *err;
6765
willy tarreaueedaa9f2005-12-17 14:08:03 +01006766 // if (curproxy == &defproxy) {
6767 // Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
6768 // return -1;
6769 // }
willy tarreaua41a8b42005-12-17 14:02:24 +01006770
willy tarreau8337c6b2005-12-17 13:41:01 +01006771 if (*(args[2]) == 0) {
6772 Alert("parsing [%s:%d] : <errorloc> expects <error> and <url> as arguments.\n", file, linenum);
6773 return -1;
6774 }
6775
6776 errnum = atol(args[1]);
willy tarreauc1f47532005-12-18 01:08:26 +01006777 if (!strcmp(args[0], "errorloc303")) {
6778 err = malloc(strlen(HTTP_303) + strlen(args[2]) + 5);
6779 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_303, args[2]);
6780 } else {
6781 err = malloc(strlen(HTTP_302) + strlen(args[2]) + 5);
6782 errlen = sprintf(err, "%s%s\r\n\r\n", HTTP_302, args[2]);
6783 }
willy tarreau8337c6b2005-12-17 13:41:01 +01006784
6785 if (errnum == 400) {
6786 if (curproxy->errmsg.msg400) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006787 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006788 free(curproxy->errmsg.msg400);
6789 }
6790 curproxy->errmsg.msg400 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006791 curproxy->errmsg.len400 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006792 }
6793 else if (errnum == 403) {
6794 if (curproxy->errmsg.msg403) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006795 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006796 free(curproxy->errmsg.msg403);
6797 }
6798 curproxy->errmsg.msg403 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006799 curproxy->errmsg.len403 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006800 }
6801 else if (errnum == 408) {
6802 if (curproxy->errmsg.msg408) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006803 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006804 free(curproxy->errmsg.msg408);
6805 }
6806 curproxy->errmsg.msg408 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006807 curproxy->errmsg.len408 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006808 }
6809 else if (errnum == 500) {
6810 if (curproxy->errmsg.msg500) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006811 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006812 free(curproxy->errmsg.msg500);
6813 }
6814 curproxy->errmsg.msg500 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006815 curproxy->errmsg.len500 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006816 }
6817 else if (errnum == 502) {
6818 if (curproxy->errmsg.msg502) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006819 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006820 free(curproxy->errmsg.msg502);
6821 }
6822 curproxy->errmsg.msg502 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006823 curproxy->errmsg.len502 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006824 }
6825 else if (errnum == 503) {
6826 if (curproxy->errmsg.msg503) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006827 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006828 free(curproxy->errmsg.msg503);
6829 }
6830 curproxy->errmsg.msg503 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006831 curproxy->errmsg.len503 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006832 }
6833 else if (errnum == 504) {
6834 if (curproxy->errmsg.msg504) {
willy tarreaueedaa9f2005-12-17 14:08:03 +01006835 //Warning("parsing [%s:%d] : error %d already defined.\n", file, linenum, errnum);
willy tarreau8337c6b2005-12-17 13:41:01 +01006836 free(curproxy->errmsg.msg504);
6837 }
6838 curproxy->errmsg.msg504 = err;
willy tarreauc1f47532005-12-18 01:08:26 +01006839 curproxy->errmsg.len504 = errlen;
willy tarreau8337c6b2005-12-17 13:41:01 +01006840 }
6841 else {
6842 Warning("parsing [%s:%d] : error %d relocation will be ignored.\n", file, linenum, errnum);
6843 free(err);
6844 }
6845 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006846 else {
willy tarreau036e1ce2005-12-17 13:46:33 +01006847 Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
willy tarreau9fe663a2005-12-17 13:02:59 +01006848 return -1;
6849 }
6850 return 0;
6851}
willy tarreaue39cd132005-12-17 13:00:18 +01006852
willy tarreau5cbea6f2005-12-17 12:48:26 +01006853
willy tarreau9fe663a2005-12-17 13:02:59 +01006854/*
6855 * This function reads and parses the configuration file given in the argument.
6856 * returns 0 if OK, -1 if error.
6857 */
6858int readcfgfile(char *file) {
6859 char thisline[256];
6860 char *line;
6861 FILE *f;
6862 int linenum = 0;
6863 char *end;
6864 char *args[MAX_LINE_ARGS];
6865 int arg;
6866 int cfgerr = 0;
6867 int confsect = CFG_NONE;
willy tarreaue39cd132005-12-17 13:00:18 +01006868
willy tarreau9fe663a2005-12-17 13:02:59 +01006869 struct proxy *curproxy = NULL;
6870 struct server *newsrv = NULL;
willy tarreaue39cd132005-12-17 13:00:18 +01006871
willy tarreau9fe663a2005-12-17 13:02:59 +01006872 if ((f=fopen(file,"r")) == NULL)
6873 return -1;
willy tarreaue39cd132005-12-17 13:00:18 +01006874
willy tarreaueedaa9f2005-12-17 14:08:03 +01006875 init_default_instance();
6876
willy tarreau9fe663a2005-12-17 13:02:59 +01006877 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
6878 linenum++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006879
willy tarreau9fe663a2005-12-17 13:02:59 +01006880 end = line + strlen(line);
willy tarreau5cbea6f2005-12-17 12:48:26 +01006881
willy tarreau9fe663a2005-12-17 13:02:59 +01006882 /* skip leading spaces */
willy tarreauc29948c2005-12-17 13:10:27 +01006883 while (isspace((int)*line))
willy tarreau9fe663a2005-12-17 13:02:59 +01006884 line++;
6885
6886 arg = 0;
6887 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01006888
willy tarreau9fe663a2005-12-17 13:02:59 +01006889 while (*line && arg < MAX_LINE_ARGS) {
6890 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
6891 * C equivalent value. Other combinations left unchanged (eg: \1).
6892 */
6893 if (*line == '\\') {
6894 int skip = 0;
6895 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
6896 *line = line[1];
6897 skip = 1;
6898 }
6899 else if (line[1] == 'r') {
6900 *line = '\r';
6901 skip = 1;
6902 }
6903 else if (line[1] == 'n') {
6904 *line = '\n';
6905 skip = 1;
6906 }
6907 else if (line[1] == 't') {
6908 *line = '\t';
6909 skip = 1;
6910 }
willy tarreauc1f47532005-12-18 01:08:26 +01006911 else if (line[1] == 'x') {
6912 if ((line + 3 < end ) && ishex(line[2]) && ishex(line[3])) {
6913 unsigned char hex1, hex2;
6914 hex1 = toupper(line[2]) - '0';
6915 hex2 = toupper(line[3]) - '0';
6916 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
6917 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
6918 *line = (hex1<<4) + hex2;
6919 skip = 3;
6920 }
6921 else {
6922 Alert("parsing [%s:%d] : invalid or incomplete '\\x' sequence in '%s'.\n", file, linenum, args[0]);
6923 return -1;
6924 }
6925 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006926 if (skip) {
6927 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
6928 end -= skip;
6929 }
6930 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006931 }
willy tarreaua1598082005-12-17 13:08:06 +01006932 else if (*line == '#' || *line == '\n' || *line == '\r') {
6933 /* end of string, end of loop */
6934 *line = 0;
6935 break;
6936 }
willy tarreauc29948c2005-12-17 13:10:27 +01006937 else if (isspace((int)*line)) {
willy tarreau9fe663a2005-12-17 13:02:59 +01006938 /* a non-escaped space is an argument separator */
willy tarreaua1598082005-12-17 13:08:06 +01006939 *line++ = 0;
willy tarreauc29948c2005-12-17 13:10:27 +01006940 while (isspace((int)*line))
willy tarreaua1598082005-12-17 13:08:06 +01006941 line++;
6942 args[++arg] = line;
6943 }
6944 else {
6945 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01006946 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006947 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006948
willy tarreau9fe663a2005-12-17 13:02:59 +01006949 /* empty line */
6950 if (!**args)
6951 continue;
willy tarreaue39cd132005-12-17 13:00:18 +01006952
willy tarreau9fe663a2005-12-17 13:02:59 +01006953 /* zero out remaining args */
6954 while (++arg < MAX_LINE_ARGS) {
6955 args[arg] = line;
willy tarreau5cbea6f2005-12-17 12:48:26 +01006956 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006957
willy tarreaua41a8b42005-12-17 14:02:24 +01006958 if (!strcmp(args[0], "listen") || !strcmp(args[0], "defaults")) /* new proxy */
willy tarreau9fe663a2005-12-17 13:02:59 +01006959 confsect = CFG_LISTEN;
6960 else if (!strcmp(args[0], "global")) /* global config */
6961 confsect = CFG_GLOBAL;
6962 /* else it's a section keyword */
willy tarreau5cbea6f2005-12-17 12:48:26 +01006963
willy tarreau9fe663a2005-12-17 13:02:59 +01006964 switch (confsect) {
6965 case CFG_LISTEN:
6966 if (cfg_parse_listen(file, linenum, args) < 0)
6967 return -1;
6968 break;
6969 case CFG_GLOBAL:
6970 if (cfg_parse_global(file, linenum, args) < 0)
6971 return -1;
6972 break;
6973 default:
willy tarreau036e1ce2005-12-17 13:46:33 +01006974 Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
willy tarreau9fe663a2005-12-17 13:02:59 +01006975 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01006976 }
willy tarreau9fe663a2005-12-17 13:02:59 +01006977
6978
willy tarreau0f7af912005-12-17 12:21:26 +01006979 }
6980 fclose(f);
6981
6982 /*
6983 * Now, check for the integrity of all that we have collected.
6984 */
6985
6986 if ((curproxy = proxy) == NULL) {
6987 Alert("parsing %s : no <listen> line. Nothing to do !\n",
6988 file);
6989 return -1;
6990 }
6991
6992 while (curproxy != NULL) {
willy tarreau0174f312005-12-18 01:02:42 +01006993 curproxy->cursrv = NULL;
willy tarreauef900ab2005-12-17 12:52:52 +01006994 if (curproxy->state == PR_STDISABLED) {
6995 curproxy = curproxy->next;
6996 continue;
6997 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01006998 if ((curproxy->mode != PR_MODE_HEALTH) &&
6999 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
willy tarreaua1598082005-12-17 13:08:06 +01007000 (*(int *)&curproxy->dispatch_addr.sin_addr == 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007001 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
7002 file, curproxy->id);
7003 cfgerr++;
7004 }
7005 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
7006 if (curproxy->options & PR_O_TRANSP) {
7007 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
7008 file, curproxy->id);
7009 cfgerr++;
7010 }
7011 else if (curproxy->srv == NULL) {
7012 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
7013 file, curproxy->id);
7014 cfgerr++;
7015 }
willy tarreaua1598082005-12-17 13:08:06 +01007016 else if (*(int *)&curproxy->dispatch_addr.sin_addr != 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01007017 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
7018 file, curproxy->id);
7019 }
7020 }
7021 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01007022 if (curproxy->cookie_name != NULL) {
7023 Warning("parsing %s : cookie will be ignored for listener %s.\n",
7024 file, curproxy->id);
7025 }
7026 if ((newsrv = curproxy->srv) != NULL) {
7027 Warning("parsing %s : servers will be ignored for listener %s.\n",
7028 file, curproxy->id);
7029 }
willy tarreaue39cd132005-12-17 13:00:18 +01007030 if (curproxy->rsp_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007031 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
7032 file, curproxy->id);
7033 }
willy tarreaue39cd132005-12-17 13:00:18 +01007034 if (curproxy->req_exp != NULL) {
willy tarreau0f7af912005-12-17 12:21:26 +01007035 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
7036 file, curproxy->id);
7037 }
7038 }
7039 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
7040 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
7041 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
7042 file, curproxy->id);
7043 cfgerr++;
7044 }
7045 else {
7046 while (newsrv != NULL) {
7047 /* nothing to check for now */
7048 newsrv = newsrv->next;
7049 }
7050 }
7051 }
willy tarreau25c4ea52005-12-18 00:49:49 +01007052
7053 if (curproxy->options & PR_O_LOGASAP)
7054 curproxy->to_log &= ~LW_BYTES;
7055
willy tarreau8337c6b2005-12-17 13:41:01 +01007056 if (curproxy->errmsg.msg400 == NULL) {
7057 curproxy->errmsg.msg400 = (char *)HTTP_400;
7058 curproxy->errmsg.len400 = strlen(HTTP_400);
7059 }
7060 if (curproxy->errmsg.msg403 == NULL) {
7061 curproxy->errmsg.msg403 = (char *)HTTP_403;
7062 curproxy->errmsg.len403 = strlen(HTTP_403);
7063 }
7064 if (curproxy->errmsg.msg408 == NULL) {
7065 curproxy->errmsg.msg408 = (char *)HTTP_408;
7066 curproxy->errmsg.len408 = strlen(HTTP_408);
7067 }
7068 if (curproxy->errmsg.msg500 == NULL) {
7069 curproxy->errmsg.msg500 = (char *)HTTP_500;
7070 curproxy->errmsg.len500 = strlen(HTTP_500);
7071 }
7072 if (curproxy->errmsg.msg502 == NULL) {
7073 curproxy->errmsg.msg502 = (char *)HTTP_502;
7074 curproxy->errmsg.len502 = strlen(HTTP_502);
7075 }
7076 if (curproxy->errmsg.msg503 == NULL) {
7077 curproxy->errmsg.msg503 = (char *)HTTP_503;
7078 curproxy->errmsg.len503 = strlen(HTTP_503);
7079 }
7080 if (curproxy->errmsg.msg504 == NULL) {
7081 curproxy->errmsg.msg504 = (char *)HTTP_504;
7082 curproxy->errmsg.len504 = strlen(HTTP_504);
7083 }
willy tarreau0f7af912005-12-17 12:21:26 +01007084 curproxy = curproxy->next;
7085 }
7086 if (cfgerr > 0) {
7087 Alert("Errors found in configuration file, aborting.\n");
7088 return -1;
7089 }
7090 else
7091 return 0;
7092}
7093
7094
7095/*
7096 * This function initializes all the necessary variables. It only returns
7097 * if everything is OK. If something fails, it exits.
7098 */
7099void init(int argc, char **argv) {
7100 int i;
willy tarreau9fe663a2005-12-17 13:02:59 +01007101 int arg_mode = 0; /* MODE_DEBUG, ... */
willy tarreau0f7af912005-12-17 12:21:26 +01007102 char *old_argv = *argv;
7103 char *tmp;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007104 char *cfg_pidfile = NULL;
willy tarreau9fe663a2005-12-17 13:02:59 +01007105 int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
willy tarreau0f7af912005-12-17 12:21:26 +01007106
7107 if (1<<INTBITS != sizeof(int)*8) {
willy tarreaudd07e972005-12-18 00:48:48 +01007108 fprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01007109 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
willy tarreau982249e2005-12-18 00:57:06 +01007110 (int)(sizeof(int)*8));
willy tarreau0f7af912005-12-17 12:21:26 +01007111 exit(1);
7112 }
7113
willy tarreau4302f492005-12-18 01:00:37 +01007114 /* initialize the log header encoding map : '{|}"#' should be encoded with
7115 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
7116 * URL encoding only requires '"', '#' to be encoded as well as non-
7117 * printable characters above.
7118 */
7119 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
7120 memset(url_encode_map, 0, sizeof(url_encode_map));
7121 for (i = 0; i < 32; i++) {
7122 FD_SET(i, hdr_encode_map);
7123 FD_SET(i, url_encode_map);
7124 }
7125 for (i = 127; i < 256; i++) {
7126 FD_SET(i, hdr_encode_map);
7127 FD_SET(i, url_encode_map);
7128 }
7129
7130 tmp = "\"#{|}";
7131 while (*tmp) {
7132 FD_SET(*tmp, hdr_encode_map);
7133 tmp++;
7134 }
7135
7136 tmp = "\"#";
7137 while (*tmp) {
7138 FD_SET(*tmp, url_encode_map);
7139 tmp++;
7140 }
7141
willy tarreau0f7af912005-12-17 12:21:26 +01007142 pid = getpid();
7143 progname = *argv;
7144 while ((tmp = strchr(progname, '/')) != NULL)
7145 progname = tmp + 1;
7146
7147 argc--; argv++;
7148 while (argc > 0) {
7149 char *flag;
7150
7151 if (**argv == '-') {
7152 flag = *argv+1;
7153
7154 /* 1 arg */
7155 if (*flag == 'v') {
7156 display_version();
7157 exit(0);
7158 }
willy tarreau1c2ad212005-12-18 01:11:29 +01007159#if defined(ENABLE_EPOLL)
7160 else if (*flag == 'E')
willy tarreauad90a0c2005-12-18 01:09:15 +01007161 cfg_use_epoll = 1;
willy tarreau1c2ad212005-12-18 01:11:29 +01007162#endif
7163#if defined(ENABLE_POLL)
7164 else if (*flag == 'P')
7165 cfg_use_poll = 1;
7166#endif
willy tarreau982249e2005-12-18 00:57:06 +01007167 else if (*flag == 'V')
7168 arg_mode |= MODE_VERBOSE;
willy tarreau0f7af912005-12-17 12:21:26 +01007169 else if (*flag == 'd')
willy tarreau9fe663a2005-12-17 13:02:59 +01007170 arg_mode |= MODE_DEBUG;
willy tarreaudd07e972005-12-18 00:48:48 +01007171 else if (*flag == 'c')
7172 arg_mode |= MODE_CHECK;
willy tarreau0f7af912005-12-17 12:21:26 +01007173 else if (*flag == 'D')
willy tarreau9fe663a2005-12-17 13:02:59 +01007174 arg_mode |= MODE_DAEMON | MODE_QUIET;
willy tarreau5cbea6f2005-12-17 12:48:26 +01007175 else if (*flag == 'q')
willy tarreau9fe663a2005-12-17 13:02:59 +01007176 arg_mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01007177#if STATTIME > 0
7178 else if (*flag == 's')
willy tarreau9fe663a2005-12-17 13:02:59 +01007179 arg_mode |= MODE_STATS;
willy tarreau0f7af912005-12-17 12:21:26 +01007180 else if (*flag == 'l')
willy tarreau9fe663a2005-12-17 13:02:59 +01007181 arg_mode |= MODE_LOG;
willy tarreau0f7af912005-12-17 12:21:26 +01007182#endif
7183 else { /* >=2 args */
7184 argv++; argc--;
7185 if (argc == 0)
7186 usage(old_argv);
7187
7188 switch (*flag) {
7189 case 'n' : cfg_maxconn = atol(*argv); break;
7190 case 'N' : cfg_maxpconn = atol(*argv); break;
7191 case 'f' : cfg_cfgfile = *argv; break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007192 case 'p' : cfg_pidfile = *argv; break;
willy tarreau0f7af912005-12-17 12:21:26 +01007193 default: usage(old_argv);
7194 }
7195 }
7196 }
7197 else
7198 usage(old_argv);
7199 argv++; argc--;
7200 }
7201
willy tarreau982249e2005-12-18 00:57:06 +01007202 global.mode = (arg_mode & (MODE_DAEMON | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
willy tarreaudd07e972005-12-18 00:48:48 +01007203
willy tarreau0f7af912005-12-17 12:21:26 +01007204 if (!cfg_cfgfile)
7205 usage(old_argv);
7206
7207 gethostname(hostname, MAX_HOSTNAME_LEN);
7208
willy tarreau12350152005-12-18 01:03:27 +01007209 have_appsession = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01007210 if (readcfgfile(cfg_cfgfile) < 0) {
7211 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
7212 exit(1);
7213 }
willy tarreau12350152005-12-18 01:03:27 +01007214 if (have_appsession)
7215 appsession_init();
willy tarreau0f7af912005-12-17 12:21:26 +01007216
willy tarreau982249e2005-12-18 00:57:06 +01007217 if (global.mode & MODE_CHECK) {
willy tarreaudd07e972005-12-18 00:48:48 +01007218 qfprintf(stdout, "Configuration file is valid : %s\n", cfg_cfgfile);
7219 exit(0);
7220 }
7221
willy tarreau9fe663a2005-12-17 13:02:59 +01007222 if (cfg_maxconn > 0)
7223 global.maxconn = cfg_maxconn;
7224
willy tarreaufe2c5c12005-12-17 14:14:34 +01007225 if (cfg_pidfile) {
7226 if (global.pidfile)
7227 free(global.pidfile);
7228 global.pidfile = strdup(cfg_pidfile);
7229 }
7230
willy tarreau9fe663a2005-12-17 13:02:59 +01007231 if (global.maxconn == 0)
7232 global.maxconn = DEFAULT_MAXCONN;
7233
7234 global.maxsock = global.maxconn * 2; /* each connection needs two sockets */
7235
7236 if (arg_mode & MODE_DEBUG) {
7237 /* command line debug mode inhibits configuration mode */
7238 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7239 }
willy tarreau982249e2005-12-18 00:57:06 +01007240 global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_VERBOSE
7241 | MODE_DEBUG | MODE_STATS | MODE_LOG));
willy tarreau9fe663a2005-12-17 13:02:59 +01007242
7243 if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
7244 Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
7245 global.mode &= ~(MODE_DAEMON | MODE_QUIET);
7246 }
7247
7248 if ((global.nbproc > 1) && !(global.mode & MODE_DAEMON)) {
7249 Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
7250 global.nbproc = 1;
7251 }
7252
7253 if (global.nbproc < 1)
7254 global.nbproc = 1;
7255
willy tarreau0f7af912005-12-17 12:21:26 +01007256 StaticReadEvent = (fd_set *)calloc(1,
7257 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007258 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007259 StaticWriteEvent = (fd_set *)calloc(1,
7260 sizeof(fd_set) *
willy tarreau9fe663a2005-12-17 13:02:59 +01007261 (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01007262
7263 fdtab = (struct fdtab *)calloc(1,
willy tarreau9fe663a2005-12-17 13:02:59 +01007264 sizeof(struct fdtab) * (global.maxsock));
7265 for (i = 0; i < global.maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01007266 fdtab[i].state = FD_STCLOSE;
7267 }
7268}
7269
7270/*
7271 * this function starts all the proxies. It returns 0 if OK, -1 if not.
7272 */
7273int start_proxies() {
7274 struct proxy *curproxy;
willy tarreaua41a8b42005-12-17 14:02:24 +01007275 struct listener *listener;
willy tarreau0f7af912005-12-17 12:21:26 +01007276 int fd;
7277
7278 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
willy tarreau0f7af912005-12-17 12:21:26 +01007279 if (curproxy->state == PR_STDISABLED)
7280 continue;
7281
willy tarreaua41a8b42005-12-17 14:02:24 +01007282 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
7283 if ((fd = listener->fd =
willy tarreau8a86dbf2005-12-18 00:45:59 +01007284 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007285 Alert("cannot create listening socket for proxy %s. Aborting.\n",
7286 curproxy->id);
7287 return -1;
7288 }
willy tarreau0f7af912005-12-17 12:21:26 +01007289
willy tarreaua41a8b42005-12-17 14:02:24 +01007290 if (fd >= global.maxsock) {
7291 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
7292 curproxy->id);
7293 close(fd);
7294 return -1;
7295 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01007296
willy tarreaua41a8b42005-12-17 14:02:24 +01007297 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
7298 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
7299 (char *) &one, sizeof(one)) == -1)) {
7300 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
7301 curproxy->id);
7302 close(fd);
7303 return -1;
7304 }
willy tarreau0f7af912005-12-17 12:21:26 +01007305
willy tarreaua41a8b42005-12-17 14:02:24 +01007306 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
7307 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
7308 curproxy->id);
7309 }
willy tarreau0f7af912005-12-17 12:21:26 +01007310
willy tarreaua41a8b42005-12-17 14:02:24 +01007311 if (bind(fd,
7312 (struct sockaddr *)&listener->addr,
willy tarreau8a86dbf2005-12-18 00:45:59 +01007313 listener->addr.ss_family == AF_INET6 ?
7314 sizeof(struct sockaddr_in6) :
7315 sizeof(struct sockaddr_in)) == -1) {
willy tarreaua41a8b42005-12-17 14:02:24 +01007316 Alert("cannot bind socket for proxy %s. Aborting.\n",
7317 curproxy->id);
7318 close(fd);
7319 return -1;
7320 }
willy tarreau0f7af912005-12-17 12:21:26 +01007321
willy tarreaua41a8b42005-12-17 14:02:24 +01007322 if (listen(fd, curproxy->maxconn) == -1) {
7323 Alert("cannot listen to socket for proxy %s. Aborting.\n",
7324 curproxy->id);
7325 close(fd);
7326 return -1;
7327 }
willy tarreau0f7af912005-12-17 12:21:26 +01007328
willy tarreaua41a8b42005-12-17 14:02:24 +01007329 /* the function for the accept() event */
7330 fdtab[fd].read = &event_accept;
7331 fdtab[fd].write = NULL; /* never called */
7332 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
7333 curproxy->state = PR_STRUN;
7334 fdtab[fd].state = FD_STLISTEN;
7335 FD_SET(fd, StaticReadEvent);
7336 fd_insert(fd);
7337 listeners++;
7338 }
willy tarreaua1598082005-12-17 13:08:06 +01007339 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
willy tarreau0f7af912005-12-17 12:21:26 +01007340 }
7341 return 0;
7342}
7343
willy tarreau12350152005-12-18 01:03:27 +01007344int match_str(const void *key1, const void *key2){
7345
7346 appsess *temp1,*temp2;
7347 temp1 = (appsess *)key1;
7348 temp2 = (appsess *)key2;
7349
7350 //fprintf(stdout,">>>>>>>>>>>>>>temp1->sessid :%s:\n",temp1->sessid);
7351 //fprintf(stdout,">>>>>>>>>>>>>>temp2->sessid :%s:\n",temp2->sessid);
7352
7353 return (strcmp(temp1->sessid,temp2->sessid) == 0);
7354}/* end match_str */
7355
7356void destroy(void *data){
7357 appsess *temp1;
7358
7359 //printf("destroy called\n");
7360 temp1 = (appsess *)data;
7361
7362 if (temp1->sessid)
7363 pool_free_to(apools.sessid, temp1->sessid);
7364
7365 if (temp1->serverid)
7366 pool_free_to(apools.serverid, temp1->serverid);
7367
7368 pool_free(appsess, temp1);
7369} /* end destroy */
7370
7371void appsession_cleanup( void )
7372{
7373 struct proxy *p = proxy;
7374
7375 while(p) {
7376 chtbl_destroy(&(p->htbl_proxy));
7377 p = p->next;
7378 }
7379}/* end appsession_cleanup() */
7380
7381void pool_destroy(void **pool)
7382{
7383 void *temp, *next;
7384 next = pool;
7385 while (next) {
7386 temp = next;
7387 next = *(void **)temp;
7388 free(temp);
7389 }
7390}/* end pool_destroy() */
7391
7392void deinit(void){
7393 struct proxy *p = proxy;
7394 struct cap_hdr *h,*h_next;
7395 struct server *s,*s_next;
7396 struct listener *l,*l_next;
7397
7398 while (p) {
7399 if (p->id)
7400 free(p->id);
7401
7402 if (p->check_req)
7403 free(p->check_req);
7404
7405 if (p->cookie_name)
7406 free(p->cookie_name);
7407
7408 if (p->capture_name)
7409 free(p->capture_name);
7410
7411 /* only strup if the user have set in config.
7412 When should we free it?!
7413 if(p->errmsg.msg400) free(p->errmsg.msg400);
7414 if(p->errmsg.msg403) free(p->errmsg.msg403);
7415 if(p->errmsg.msg408) free(p->errmsg.msg408);
7416 if(p->errmsg.msg500) free(p->errmsg.msg500);
7417 if(p->errmsg.msg502) free(p->errmsg.msg502);
7418 if(p->errmsg.msg503) free(p->errmsg.msg503);
7419 if(p->errmsg.msg504) free(p->errmsg.msg504);
7420 */
7421 if (p->appsession_name)
7422 free(p->appsession_name);
7423
7424 h = p->req_cap;
7425 while (h) {
7426 h_next = h->next;
7427 if (h->name)
7428 free(h->name);
7429 pool_destroy(h->pool);
7430 free(h);
7431 h = h_next;
7432 }/* end while(h) */
7433
7434 h = p->rsp_cap;
7435 while (h) {
7436 h_next = h->next;
7437 if (h->name)
7438 free(h->name);
7439
7440 pool_destroy(h->pool);
7441 free(h);
7442 h = h_next;
7443 }/* end while(h) */
7444
7445 s = p->srv;
7446 while (s) {
7447 s_next = s->next;
7448 if(s->id)
7449 free(s->id);
7450
7451 if(s->cookie)
7452 free(s->cookie);
7453
7454 free(s);
7455 s = s_next;
7456 }/* end while(s) */
7457
7458 l = p->listen;
7459 while (l) {
7460 l_next = l->next;
7461 free(l);
7462 l = l_next;
7463 }/* end while(l) */
7464
7465 pool_destroy((void **) p->req_cap_pool);
7466 pool_destroy((void **) p->rsp_cap_pool);
7467 p = p->next;
7468 }/* end while(p) */
7469
7470 if (global.chroot) free(global.chroot);
7471 if (global.pidfile) free(global.pidfile);
7472
willy tarreau12350152005-12-18 01:03:27 +01007473 if (StaticReadEvent) free(StaticReadEvent);
7474 if (StaticWriteEvent) free(StaticWriteEvent);
7475 if (fdtab) free(fdtab);
7476
7477 pool_destroy(pool_session);
7478 pool_destroy(pool_buffer);
7479 pool_destroy(pool_fdtab);
7480 pool_destroy(pool_requri);
7481 pool_destroy(pool_task);
7482 pool_destroy(pool_capture);
7483 pool_destroy(pool_appsess);
7484
7485 if (have_appsession) {
7486 pool_destroy(apools.serverid);
7487 pool_destroy(apools.sessid);
7488 }
7489} /* end deinit() */
willy tarreau0f7af912005-12-17 12:21:26 +01007490
7491int main(int argc, char **argv) {
willy tarreaufe2c5c12005-12-17 14:14:34 +01007492 FILE *pidfile = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +01007493 init(argc, argv);
7494
willy tarreau9fe663a2005-12-17 13:02:59 +01007495 if (global.mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01007496 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01007497 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01007498 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01007499 }
7500
7501 signal(SIGQUIT, dump);
7502 signal(SIGUSR1, sig_soft_stop);
willy tarreau8337c6b2005-12-17 13:41:01 +01007503 signal(SIGHUP, sig_dump_state);
willy tarreau12350152005-12-18 01:03:27 +01007504 signal(SIGINT, sig_int);
7505 signal(SIGTERM, sig_term);
willy tarreau0f7af912005-12-17 12:21:26 +01007506
7507 /* on very high loads, a sigpipe sometimes happen just between the
7508 * getsockopt() which tells "it's OK to write", and the following write :-(
7509 */
willy tarreau3242e862005-12-17 12:27:53 +01007510#ifndef MSG_NOSIGNAL
7511 signal(SIGPIPE, SIG_IGN);
7512#endif
willy tarreau0f7af912005-12-17 12:21:26 +01007513
7514 if (start_proxies() < 0)
7515 exit(1);
7516
willy tarreaufe2c5c12005-12-17 14:14:34 +01007517 /* open log & pid files before the chroot */
7518 if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
7519 int pidfd;
7520 unlink(global.pidfile);
7521 pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
7522 if (pidfd < 0) {
7523 Alert("[%s.main()] Cannot create pidfile %s\n", argv[0], global.pidfile);
7524 exit(1);
7525 }
7526 pidfile = fdopen(pidfd, "w");
7527 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007528
7529 /* chroot if needed */
7530 if (global.chroot != NULL) {
7531 if (chroot(global.chroot) == -1) {
7532 Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
7533 exit(1);
7534 }
7535 chdir("/");
7536 }
7537
7538 /* setgid / setuid */
willy tarreau036e1ce2005-12-17 13:46:33 +01007539 if (global.gid && setgid(global.gid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007540 Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
7541 exit(1);
7542 }
7543
willy tarreau036e1ce2005-12-17 13:46:33 +01007544 if (global.uid && setuid(global.uid) == -1) {
willy tarreau9fe663a2005-12-17 13:02:59 +01007545 Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
7546 exit(1);
7547 }
7548
7549 if (global.mode & MODE_DAEMON) {
7550 int ret = 0;
7551 int proc;
7552
7553 /* the father launches the required number of processes */
7554 for (proc = 0; proc < global.nbproc; proc++) {
7555 ret = fork();
7556 if (ret < 0) {
7557 Alert("[%s.main()] Cannot fork.\n", argv[0]);
7558 exit(1); /* there has been an error */
7559 }
7560 else if (ret == 0) /* child breaks here */
7561 break;
willy tarreaufe2c5c12005-12-17 14:14:34 +01007562 if (pidfile != NULL) {
7563 fprintf(pidfile, "%d\n", ret);
7564 fflush(pidfile);
7565 }
willy tarreau9fe663a2005-12-17 13:02:59 +01007566 }
willy tarreaufe2c5c12005-12-17 14:14:34 +01007567 /* close the pidfile both in children and father */
7568 if (pidfile != NULL)
7569 fclose(pidfile);
7570 free(global.pidfile);
7571
willy tarreau9fe663a2005-12-17 13:02:59 +01007572 if (proc == global.nbproc)
7573 exit(0); /* parent must leave */
7574
willy tarreau750a4722005-12-17 13:21:24 +01007575 /* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
7576 * that we can detach from the TTY. We MUST NOT do it in other cases since
7577 * it would have already be done, and 0-2 would have been affected to listening
7578 * sockets
7579 */
7580 if (!(global.mode & MODE_QUIET)) {
7581 /* detach from the tty */
7582 fclose(stdin); fclose(stdout); fclose(stderr);
7583 close(0); close(1); close(2); /* close all fd's */
7584 global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
7585 }
willy tarreaua1598082005-12-17 13:08:06 +01007586 pid = getpid(); /* update child's pid */
willy tarreaue867b482005-12-17 13:28:43 +01007587 setsid();
willy tarreau9fe663a2005-12-17 13:02:59 +01007588 }
7589
willy tarreau1c2ad212005-12-18 01:11:29 +01007590#if defined(ENABLE_EPOLL)
7591 if (cfg_use_epoll) {
7592 if (epoll_loop(POLL_LOOP_ACTION_INIT)) {
7593 epoll_loop(POLL_LOOP_ACTION_RUN);
7594 epoll_loop(POLL_LOOP_ACTION_CLEAN);
7595 }
7596 else {
7597 Warning("epoll() is not available. Trying poll() or select() instead.\n");
7598 cfg_use_epoll = 0;
7599 }
7600 }
7601#endif
7602
7603#if defined(ENABLE_POLL)
7604 if (cfg_use_poll) {
7605 if (poll_loop(POLL_LOOP_ACTION_INIT)) {
7606 poll_loop(POLL_LOOP_ACTION_RUN);
7607 poll_loop(POLL_LOOP_ACTION_CLEAN);
7608 }
7609 else {
7610 Warning("poll() is not available. Using select() instead.\n");
7611 cfg_use_poll = 0;
7612 }
7613 }
7614#endif
7615 if (!cfg_use_epoll && !cfg_use_poll) {
7616 if (select_loop(POLL_LOOP_ACTION_INIT)) {
7617 select_loop(POLL_LOOP_ACTION_RUN);
7618 select_loop(POLL_LOOP_ACTION_CLEAN);
7619 }
7620 }
7621
willy tarreau0f7af912005-12-17 12:21:26 +01007622
willy tarreau12350152005-12-18 01:03:27 +01007623 /* Free all Hash Keys and all Hash elements */
7624 appsession_cleanup();
7625 /* Do some cleanup */
7626 deinit();
7627
willy tarreau0f7af912005-12-17 12:21:26 +01007628 exit(0);
7629}
willy tarreau12350152005-12-18 01:03:27 +01007630
7631#if defined(DEBUG_HASH)
7632static void print_table(const CHTbl *htbl) {
7633
7634 ListElmt *element;
7635 int i;
7636 appsess *asession;
7637
7638 /*****************************************************************************
7639 * *
7640 * Display the chained hash table. *
7641 * *
7642 *****************************************************************************/
7643
7644 fprintf(stdout, "Table size is %d\n", chtbl_size(htbl));
7645
7646 for (i = 0; i < TBLSIZ; i++) {
7647 fprintf(stdout, "Bucket[%03d]\n", i);
7648
7649 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7650 //fprintf(stdout, "%c", *(char *)list_data(element));
7651 asession = (appsess *)list_data(element);
7652 fprintf(stdout, "ELEM :%s:", asession->sessid);
7653 fprintf(stdout, " Server :%s: \n", asession->serverid);
7654 //fprintf(stdout, " Server request_count :%li:\n",asession->request_count);
7655 }
7656
7657 fprintf(stdout, "\n");
7658 }
7659 return;
7660} /* end print_table */
7661#endif
7662
7663static int appsession_init(void)
7664{
7665 static int initialized = 0;
7666 int idlen;
7667 struct server *s;
7668 struct proxy *p = proxy;
7669
7670 if (!initialized) {
7671 if (!appsession_task_init()) {
7672 apools.sessid = NULL;
7673 apools.serverid = NULL;
7674 apools.ser_waste = 0;
7675 apools.ser_use = 0;
7676 apools.ser_msize = sizeof(void *);
7677 apools.ses_waste = 0;
7678 apools.ses_use = 0;
7679 apools.ses_msize = sizeof(void *);
7680 while (p) {
7681 s = p->srv;
7682 if (apools.ses_msize < p->appsession_len)
7683 apools.ses_msize = p->appsession_len;
7684 while (s) {
7685 idlen = strlen(s->id);
7686 if (apools.ser_msize < idlen)
7687 apools.ser_msize = idlen;
7688 s = s->next;
7689 }
7690 p = p->next;
7691 }
7692 apools.ser_msize ++; /* we use strings, so reserve space for '\0' */
7693 apools.ses_msize ++;
7694 }
7695 else {
7696 fprintf(stderr, "appsession_task_init failed\n");
7697 return -1;
7698 }
7699 initialized ++;
7700 }
7701 return 0;
7702}
7703
7704static int appsession_task_init(void)
7705{
7706 static int initialized = 0;
7707 struct task *t;
7708 if (!initialized) {
7709 if ((t = pool_alloc(task)) == NULL)
7710 return -1;
7711 t->next = t->prev = t->rqnext = NULL;
7712 t->wq = LIST_HEAD(wait_queue);
7713 t->state = TASK_IDLE;
7714 t->context = NULL;
7715 tv_delayfrom(&t->expire, &now, TBLCHKINT);
7716 task_queue(t);
7717 t->process = appsession_refresh;
7718 initialized ++;
7719 }
7720 return 0;
7721}
7722
7723static int appsession_refresh(struct task *t) {
7724 struct proxy *p = proxy;
7725 CHTbl *htbl;
7726 ListElmt *element, *last;
7727 int i;
7728 appsess *asession;
7729 void *data;
7730
7731 while (p) {
7732 if (p->appsession_name != NULL) {
7733 htbl = &p->htbl_proxy;
7734 /* if we ever give up the use of TBLSIZ, we need to change this */
7735 for (i = 0; i < TBLSIZ; i++) {
7736 last = NULL;
7737 for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) {
7738 asession = (appsess *)list_data(element);
7739 if (tv_cmp2_ms(&asession->expire, &now) <= 0) {
7740 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
7741 int len;
7742 /*
7743 on Linux NULL pointers are catched by sprintf, on solaris -> segfault
7744 */
7745 len = sprintf(trash, "appsession_refresh: cleaning up expired Session '%s' on Server %s\n",
7746 asession->sessid, asession->serverid?asession->serverid:"(null)");
7747 write(1, trash, len);
7748 }
7749 /* delete the expired element from within the hash table */
7750 if ((list_rem_next(&htbl->table[i], last, (void **)&data) == 0)
7751 && (htbl->table[i].destroy != NULL)) {
7752 htbl->table[i].destroy(data);
7753 }
7754 if (last == NULL) {/* patient lost his head, get a new one */
7755 element = list_head(&htbl->table[i]);
7756 if (element == NULL) break; /* no heads left, go to next patient */
7757 }
7758 else
7759 element = last;
7760 }/* end if (tv_cmp2_ms(&asession->expire, &now) <= 0) */
7761 else
7762 last = element;
7763 }/* end for (element = list_head(&htbl->table[i]); element != NULL; element = list_next(element)) */
7764 }
7765 }
7766 p = p->next;
7767 }
7768 tv_delayfrom(&t->expire, &now, TBLCHKINT); /* check expiration every 5 seconds */
7769 return TBLCHKINT;
7770} /* end appsession_refresh */
7771