blob: bd5944cfe0ce60bd6891ad27db1570820b965f44 [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
3 * 2000-2002 - 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 tarreauef900ab2005-12-17 12:52:52 +010010 * Pending bugs :
11 * - cookie in insert+indirect mode sometimes segfaults !
12 * - a proxy with an invalid config will prevent the startup even if disabled.
13 *
willy tarreau0f7af912005-12-17 12:21:26 +010014 * ChangeLog :
15 *
willy tarreauef900ab2005-12-17 12:52:52 +010016 * 2002/03/21
17 * - released 1.1.2
18 * - fixed a bug in buffer management where we could have a loop
19 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
20 * => implemented an adjustable buffer limit.
21 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
22 * and running tasks are skipped.
23 * - added some debug lines for accept events.
24 * - send warnings for servers up/down.
willy tarreauefae1842005-12-17 12:51:03 +010025 * 2002/03/12
26 * - released 1.1.1
27 * - fixed a bug in total failure handling
28 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreau5cbea6f2005-12-17 12:48:26 +010029 * 2002/03/10
30 * - released 1.1.0
31 * - fixed a few timeout bugs
32 * - rearranged the task scheduler subsystem to improve performance,
33 * add new tasks, and make it easier to later port to librt ;
34 * - allow multiple accept() for one select() wake up ;
35 * - implemented internal load balancing with basic health-check ;
36 * - cookie insertion and header add/replace/delete, with better strings
37 * support.
38 * 2002/03/08
39 * - reworked buffer handling to fix a few rewrite bugs, and
40 * improve overall performance.
41 * - implement the "purge" option to delete server cookies in direct mode.
42 * 2002/03/07
43 * - fixed some error cases where the maxfd was not decreased.
44 * 2002/02/26
45 * - now supports transparent proxying, at least on linux 2.4.
46 * 2002/02/12
47 * - soft stop works again (fixed select timeout computation).
48 * - it seems that TCP proxies sometimes cannot timeout.
49 * - added a "quiet" mode.
50 * - enforce file descriptor limitation on socket() and accept().
51 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010052 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010053 * 2001/12/16 : release of version 1.0.0.
54 * 2001/12/16 : added syslog capability for each accepted connection.
55 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
56 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
57 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
58 * with or without cookies (use keyword http for this).
59 * 2001/09/01 : added client/server header replacing with regexps.
60 * eg:
61 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
62 * srvexp ^Server:\ .* Server:\ Apache
63 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
64 * 2000/11/28 : major rewrite
65 * 2000/11/26 : first write
66 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010067 * TODO:
68 * - handle properly intermediate incomplete server headers. Done ?
69 * - log proxies start/stop
70 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010071 *
72 */
73
74#include <stdio.h>
75#include <stdlib.h>
76#include <unistd.h>
77#include <string.h>
78#include <ctype.h>
79#include <sys/time.h>
80#include <sys/types.h>
81#include <sys/socket.h>
82#include <netinet/tcp.h>
83#include <netinet/in.h>
84#include <arpa/inet.h>
85#include <netdb.h>
86#include <fcntl.h>
87#include <errno.h>
88#include <signal.h>
89#include <stdarg.h>
90#include <sys/resource.h>
91#include <time.h>
92#include <regex.h>
93#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +010094#if defined(TRANSPARENT) && defined(NETFILTER)
95#include <linux/netfilter_ipv4.h>
96#endif
willy tarreau0f7af912005-12-17 12:21:26 +010097
willy tarreauef900ab2005-12-17 12:52:52 +010098#define HAPROXY_VERSION "1.1.2"
99#define HAPROXY_DATE "2002/03/22"
willy tarreau0f7af912005-12-17 12:21:26 +0100100
101/* this is for libc5 for example */
102#ifndef TCP_NODELAY
103#define TCP_NODELAY 1
104#endif
105
106#ifndef SHUT_RD
107#define SHUT_RD 0
108#endif
109
110#ifndef SHUT_WR
111#define SHUT_WR 1
112#endif
113
114#define BUFSIZE 4096
115
116// reserved buffer space for header rewriting
117#define MAXREWRITE 256
118
willy tarreau5cbea6f2005-12-17 12:48:26 +0100119// max # args on a configuration line
120#define MAX_LINE_ARGS 10
121
willy tarreau0f7af912005-12-17 12:21:26 +0100122// max # of regexps per proxy
123#define MAX_REGEXP 10
124
125// max # of matches per regexp
126#define MAX_MATCH 10
127
willy tarreau5cbea6f2005-12-17 12:48:26 +0100128/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100129#define COOKIENAME_LEN 16
130#define SERVERID_LEN 16
131#define CONN_RETRIES 3
132
willy tarreau5cbea6f2005-12-17 12:48:26 +0100133/* FIXME: this should be user-configurable */
134#define CHK_CONNTIME 2000
135#define CHK_INTERVAL 2000
136#define FALLTIME 3
137#define RISETIME 2
138
willy tarreau0f7af912005-12-17 12:21:26 +0100139/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
140#define INTBITS 5
141
142/* show stats this every millisecond, 0 to disable */
143#ifndef STATTIME
144#define STATTIME 2000
145#endif
146
willy tarreau5cbea6f2005-12-17 12:48:26 +0100147/* this reduces the number of calls to select() by choosing appropriate
148 * sheduler precision in milliseconds. It should be near the minimum
149 * time that is needed by select() to collect all events. All timeouts
150 * are rounded up by adding this value prior to pass it to select().
151 */
152#define SCHEDULER_RESOLUTION 9
153
willy tarreau0f7af912005-12-17 12:21:26 +0100154#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
155#define SETNOW(a) (*a=now)
156
willy tarreau9da061b2005-12-17 12:29:56 +0100157/****** string-specific macros and functions ******/
158/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
159#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
160
161/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
162#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
163
164
165#ifndef HAVE_STRLCPY
166/*
167 * copies at most <size-1> chars from <src> to <dst>. Last char is always
168 * set to 0, unless <size> is 0. The number of chars copied is returned
169 * (excluding the terminating zero).
170 * This code has been optimized for size and speed : on x86, it's 45 bytes
171 * long, uses only registers, and consumes only 4 cycles per char.
172 */
173int strlcpy(char *dst, const char *src, int size) {
174 char *orig = dst;
175 if (size) {
176 while (--size && (*dst = *src)) {
177 src++; dst++;
178 }
179 *dst = 0;
180 }
181 return dst - orig;
182}
183#endif
184
185
willy tarreau0f7af912005-12-17 12:21:26 +0100186#define MEM_OPTIM
187#ifdef MEM_OPTIM
188/*
189 * Returns a pointer to type <type> taken from the
190 * pool <pool_type> or dynamically allocated. In the
191 * first case, <pool_type> is updated to point to the
192 * next element in the list.
193 */
194#define pool_alloc(type) ({ \
195 void *p; \
196 if ((p = pool_##type) == NULL) \
197 p = malloc(sizeof_##type); \
198 else { \
199 pool_##type = *(void **)pool_##type; \
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
willy tarreau9da061b2005-12-17 12:29:56 +0100208 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100209 * that each memory area is at least as big as one
210 * pointer.
211 */
212#define pool_free(type, ptr) ({ \
213 *(void **)ptr = (void *)pool_##type; \
214 pool_##type = (void *)ptr; \
215})
216
217#else
218#define pool_alloc(type) (calloc(1,sizeof_##type));
219#define pool_free(type, ptr) (free(ptr));
220#endif /* MEM_OPTIM */
221
willy tarreau5cbea6f2005-12-17 12:48:26 +0100222#define sizeof_task sizeof(struct task)
223#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100224#define sizeof_buffer sizeof(struct buffer)
225#define sizeof_fdtab sizeof(struct fdtab)
226#define sizeof_str256 256
227
228
willy tarreau5cbea6f2005-12-17 12:48:26 +0100229/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100230#define FD_STCLOSE 0
231#define FD_STLISTEN 1
232#define FD_STCONN 2
233#define FD_STREADY 3
234#define FD_STERROR 4
235
willy tarreau5cbea6f2005-12-17 12:48:26 +0100236/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100237#define TASK_IDLE 0
238#define TASK_RUNNING 1
239
willy tarreau5cbea6f2005-12-17 12:48:26 +0100240/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100241#define PR_STNEW 0
242#define PR_STIDLE 1
243#define PR_STRUN 2
244#define PR_STDISABLED 3
245
willy tarreau5cbea6f2005-12-17 12:48:26 +0100246/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100247#define PR_MODE_TCP 0
248#define PR_MODE_HTTP 1
249#define PR_MODE_HEALTH 2
250
willy tarreau5cbea6f2005-12-17 12:48:26 +0100251/* bits for proxy->options */
252#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
253#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
254#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
255#define PR_O_COOK_IND 8 /* keep only indirect cookies */
256#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
257#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
258#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
259#define PR_O_BALANCE (PR_O_BALANCE_RR)
260
261/* various task flags */
262#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
263
264/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100265#define CL_STHEADERS 0
266#define CL_STDATA 1
267#define CL_STSHUTR 2
268#define CL_STSHUTW 3
269#define CL_STCLOSE 4
270
willy tarreau5cbea6f2005-12-17 12:48:26 +0100271/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100272#define SV_STIDLE 0
273#define SV_STCONN 1
274#define SV_STHEADERS 2
275#define SV_STDATA 3
276#define SV_STSHUTR 4
277#define SV_STSHUTW 5
278#define SV_STCLOSE 6
279
280/* result of an I/O event */
281#define RES_SILENT 0 /* didn't happen */
282#define RES_DATA 1 /* data were sent or received */
283#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
284#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
285
willy tarreau5cbea6f2005-12-17 12:48:26 +0100286/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100287#define MODE_DEBUG 1
288#define MODE_STATS 2
289#define MODE_LOG 4
290#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100291#define MODE_QUIET 16
292
293/* server flags */
294#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100295
296/*********************************************************************/
297
298#define LIST_HEAD(a) ((void *)(&(a)))
299
300/*********************************************************************/
301
302struct hdr_exp {
303 regex_t *preg; /* expression to look for */
304 char *replace; /* expression to set instead */
305};
306
307struct buffer {
308 unsigned int l; /* data length */
309 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100310 char *rlim; /* read limit, used for header rewriting */
willy tarreau0f7af912005-12-17 12:21:26 +0100311 char data[BUFSIZE];
312};
313
314struct server {
315 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100316 int state; /* server state (SRV_*) */
317 int cklen; /* the len of the cookie, to speed up checks */
318 char *cookie; /* the id set in the cookie */
319 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100320 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100321 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
322 int result; /* 0 = connect OK, -1 = connect KO */
323 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100324};
325
willy tarreau5cbea6f2005-12-17 12:48:26 +0100326/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100327struct task {
328 struct task *next, *prev; /* chaining ... */
329 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100331 int state; /* task state : IDLE or RUNNING */
332 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100333 int (*process)(struct task *t); /* the function which processes the task */
334 void *context; /* the task's context */
335};
336
337/* WARNING: if new fields are added, they must be initialized in event_accept() */
338struct session {
339 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100340 /* application specific below */
341 struct timeval crexpire; /* expiration date for a client read */
342 struct timeval cwexpire; /* expiration date for a client write */
343 struct timeval srexpire; /* expiration date for a server read */
344 struct timeval swexpire; /* expiration date for a server write */
345 struct timeval cnexpire; /* expiration date for a connect */
346 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
347 struct proxy *proxy; /* the proxy this socket belongs to */
348 int cli_fd; /* the client side fd */
349 int srv_fd; /* the server side fd */
350 int cli_state; /* state of the client side */
351 int srv_state; /* state of the server side */
352 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100353 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100354 struct buffer *req; /* request buffer */
355 struct buffer *rep; /* response buffer */
356 struct sockaddr_in cli_addr; /* the client address */
357 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100358 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100359};
360
361struct proxy {
362 int listen_fd; /* the listen socket */
363 int state; /* proxy state */
364 struct sockaddr_in listen_addr; /* the address we listen to */
365 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100366 struct server *srv, *cursrv; /* known servers, current server */
367 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100368 char *cookie_name; /* name of the cookie to look for */
369 int clitimeout; /* client I/O timeout (in milliseconds) */
370 int srvtimeout; /* server I/O timeout (in milliseconds) */
371 int contimeout; /* connect timeout (in milliseconds) */
372 char *id; /* proxy id */
373 int nbconn; /* # of active sessions */
374 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100375 int conn_retries; /* maximum number of connect retries */
376 int options; /* PR_O_REDISP, PR_O_TRANSP */
377 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100378 struct proxy *next;
379 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
380 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
381 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100382 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
383 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
384 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
385 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100386 int grace; /* grace time after stop request */
387};
388
389/* info about one given fd */
390struct fdtab {
391 int (*read)(int fd); /* read function */
392 int (*write)(int fd); /* write function */
393 struct task *owner; /* the session (or proxy) associated with this fd */
394 int state; /* the state of this fd */
395};
396
397/*********************************************************************/
398
399int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
400int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
401int cfg_maxsock = 0; /* max # of sockets */
402char *cfg_cfgfile = NULL; /* configuration file */
403char *progname = NULL; /* program name */
404int pid; /* current process id */
405/*********************************************************************/
406
407fd_set *ReadEvent,
408 *WriteEvent,
409 *StaticReadEvent,
410 *StaticWriteEvent;
411
412void **pool_session = NULL,
413 **pool_buffer = NULL,
414 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100415 **pool_str256 = NULL,
416 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100417
418struct proxy *proxy = NULL; /* list of all existing proxies */
419struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100420struct task *rq = NULL; /* global run queue */
421struct task wait_queue = { /* global wait queue */
422 prev:LIST_HEAD(wait_queue),
423 next:LIST_HEAD(wait_queue)
424};
willy tarreau0f7af912005-12-17 12:21:26 +0100425
426static int mode = 0; /* MODE_DEBUG, ... */
427static int totalconn = 0; /* total # of terminated sessions */
428static int actconn = 0; /* # of active sessions */
429static int maxfd = 0; /* # of the highest fd + 1 */
430static int listeners = 0; /* # of listeners */
431static int stopping = 0; /* non zero means stopping in progress */
432static struct timeval now = {0,0}; /* the current date at any moment */
433
434static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
435static char trash[BUFSIZE];
436
437/*
438 * Syslog facilities and levels
439 */
440
441#define MAX_SYSLOG_LEN 1024
442#define NB_LOG_FACILITIES 24
443const char *log_facilities[NB_LOG_FACILITIES] = {
444 "kern", "user", "mail", "daemon",
445 "auth", "syslog", "lpr", "news",
446 "uucp", "cron", "auth2", "ftp",
447 "ntp", "audit", "alert", "cron2",
448 "local0", "local1", "local2", "local3",
449 "local4", "local5", "local6", "local7"
450};
451
452
453#define NB_LOG_LEVELS 8
454const char *log_levels[NB_LOG_LEVELS] = {
455 "emerg", "alert", "crit", "err",
456 "warning", "notice", "info", "debug"
457};
458
459#define SYSLOG_PORT 514
460
461const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
462 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
463#define MAX_HOSTNAME_LEN 32
464static char hostname[MAX_HOSTNAME_LEN] = "";
465
466/*********************************************************************/
467/* statistics ******************************************************/
468/*********************************************************************/
469
470static int stats_tsk_lsrch, stats_tsk_rsrch,
471 stats_tsk_good, stats_tsk_right, stats_tsk_left,
472 stats_tsk_new, stats_tsk_nsrch;
473
474
475/*********************************************************************/
476/* function prototypes *********************************************/
477/*********************************************************************/
478
479int event_accept(int fd);
480int event_cli_read(int fd);
481int event_cli_write(int fd);
482int event_srv_read(int fd);
483int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100484int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100485
486/*********************************************************************/
487/* general purpose functions ***************************************/
488/*********************************************************************/
489
490void display_version() {
491 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100492 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100493}
494
495/*
496 * This function prints the command line usage and exits
497 */
498void usage(char *name) {
499 display_version();
500 fprintf(stderr,
501 "Usage : %s -f <cfgfile> [ -vd"
502#if STATTIME > 0
503 "sl"
504#endif
505 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
506 " -v displays version\n"
507 " -d enters debug mode\n"
508#if STATTIME > 0
509 " -s enables statistics output\n"
510 " -l enables long statistics format\n"
511#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100512 " -D goes daemon ; implies -q\n"
513 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100514 " -n sets the maximum total # of connections (%d)\n"
515 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
516 name, cfg_maxconn, cfg_maxpconn);
517 exit(1);
518}
519
520
521/*
522 * Displays the message on stderr with the date and pid.
523 */
524void Alert(char *fmt, ...) {
525 va_list argp;
526 struct timeval tv;
527 struct tm *tm;
528
willy tarreau5cbea6f2005-12-17 12:48:26 +0100529 if (!(mode & MODE_QUIET)) {
530 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100531
willy tarreau5cbea6f2005-12-17 12:48:26 +0100532 gettimeofday(&tv, NULL);
533 tm=localtime(&tv.tv_sec);
534 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
535 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
536 vfprintf(stderr, fmt, argp);
537 fflush(stderr);
538 va_end(argp);
539 }
willy tarreau0f7af912005-12-17 12:21:26 +0100540}
541
542
543/*
544 * Displays the message on stderr with the date and pid.
545 */
546void Warning(char *fmt, ...) {
547 va_list argp;
548 struct timeval tv;
549 struct tm *tm;
550
willy tarreau5cbea6f2005-12-17 12:48:26 +0100551 if (!(mode & MODE_QUIET)) {
552 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100553
willy tarreau5cbea6f2005-12-17 12:48:26 +0100554 gettimeofday(&tv, NULL);
555 tm=localtime(&tv.tv_sec);
556 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
557 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
558 vfprintf(stderr, fmt, argp);
559 fflush(stderr);
560 va_end(argp);
561 }
562}
563
564/*
565 * Displays the message on <out> only if quiet mode is not set.
566 */
567void qfprintf(FILE *out, char *fmt, ...) {
568 va_list argp;
569
570 if (!(mode & MODE_QUIET)) {
571 va_start(argp, fmt);
572 vfprintf(out, fmt, argp);
573 fflush(out);
574 va_end(argp);
575 }
willy tarreau0f7af912005-12-17 12:21:26 +0100576}
577
578
579/*
580 * converts <str> to a struct sockaddr_in* which is locally allocated.
581 * The format is "addr:port", where "addr" can be empty or "*" to indicate
582 * INADDR_ANY.
583 */
584struct sockaddr_in *str2sa(char *str) {
585 static struct sockaddr_in sa;
586 char *c;
587 int port;
588
589 bzero(&sa, sizeof(sa));
590 str=strdup(str);
591
592 if ((c=strrchr(str,':')) != NULL) {
593 *c++=0;
594 port=atol(c);
595 }
596 else
597 port=0;
598
599 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
600 sa.sin_addr.s_addr = INADDR_ANY;
601 }
602 else if (
603#ifndef SOLARIS
604 !inet_aton(str, &sa.sin_addr)
605#else
606 !inet_pton(AF_INET, str, &sa.sin_addr)
607#endif
608 ) {
609 struct hostent *he;
610
611 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100612 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100613 }
614 else
615 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
616 }
617 sa.sin_port=htons(port);
618 sa.sin_family=AF_INET;
619
620 free(str);
621 return &sa;
622}
623
624/*
625 * This function tries to send a syslog message to the syslog server at
626 * address <sa>. It doesn't care about errors nor does it report them.
627 * WARNING! no check is made on the prog+hostname+date length, so the
628 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
629 * the message will be truncated to fit the maximum length.
630 */
631void send_syslog(struct sockaddr_in *sa,
632 int facility, int level, char *message)
633{
634
635 static int logfd = -1; /* syslog UDP socket */
636 struct timeval tv;
637 struct tm *tm;
638 static char logmsg[MAX_SYSLOG_LEN];
639 char *p;
640
641 if (logfd < 0) {
642 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
643 return;
644 }
645
646 if (facility < 0 || level < 0
647 || sa == NULL || progname == NULL || message == NULL)
648 return;
649
650 gettimeofday(&tv, NULL);
651 tm = localtime(&tv.tv_sec);
652
653 p = logmsg;
654 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
655 // facility * 8 + level,
656 // monthname[tm->tm_mon],
657 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
658 // hostname, progname, pid);
659 /* 20011216/WT : other progs don't set the hostname, and syslogd
660 * systematically repeats it which is contrary to RFC3164.
661 */
662 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
663 facility * 8 + level,
664 monthname[tm->tm_mon],
665 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
666 progname, pid);
667
668 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
669 int len = strlen(message);
670 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
671 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
672 memcpy(p, message, len);
673 p += len;
674 }
willy tarreau3242e862005-12-17 12:27:53 +0100675#ifndef MSG_NOSIGNAL
676 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
677 (struct sockaddr *)sa, sizeof(*sa));
678#else
willy tarreau0f7af912005-12-17 12:21:26 +0100679 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
680 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100681#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100682}
683
684
685/* sets <tv> to the current time */
686static inline struct timeval *tv_now(struct timeval *tv) {
687 if (tv)
688 gettimeofday(tv, NULL);
689 return tv;
690}
691
692/*
693 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
694 */
695static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
696 if (!tv || !from)
697 return NULL;
698 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
699 tv->tv_sec = from->tv_sec + (ms/1000);
700 while (tv->tv_usec >= 1000000) {
701 tv->tv_usec -= 1000000;
702 tv->tv_sec++;
703 }
704 return tv;
705}
706
707/*
708 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
709 */
710static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
711 if (tv1->tv_sec > tv2->tv_sec)
712 return 1;
713 else if (tv1->tv_sec < tv2->tv_sec)
714 return -1;
715 else if (tv1->tv_usec > tv2->tv_usec)
716 return 1;
717 else if (tv1->tv_usec < tv2->tv_usec)
718 return -1;
719 else
720 return 0;
721}
722
723/*
724 * returns the absolute difference, in ms, between tv1 and tv2
725 */
726unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
727 int cmp;
728 unsigned long ret;
729
730
willy tarreauef900ab2005-12-17 12:52:52 +0100731 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100732 if (!cmp)
733 return 0; /* same dates, null diff */
734 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100735 struct timeval *tmp = tv1;
736 tv1 = tv2;
737 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100738 }
willy tarreauef900ab2005-12-17 12:52:52 +0100739 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100740 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100741 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100742 else
willy tarreauef900ab2005-12-17 12:52:52 +0100743 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100744 return (unsigned long) ret;
745}
746
747/*
748 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
749 */
750static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100751 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100752 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100753 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100754 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100755 return -1;
756 else
757 return 0;
758 }
759 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100760 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100761 return 1;
762 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100763 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100764 return -1;
765 else
766 return 0;
767}
768
769/*
770 * returns the remaining time between tv1=now and event=tv2
771 * if tv2 is passed, 0 is returned.
772 */
773static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
774 unsigned long ret;
775
willy tarreau0f7af912005-12-17 12:21:26 +0100776 if (tv_cmp_ms(tv1, tv2) >= 0)
777 return 0; /* event elapsed */
778
willy tarreauef900ab2005-12-17 12:52:52 +0100779 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100780 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100781 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100782 else
willy tarreauef900ab2005-12-17 12:52:52 +0100783 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100784 return (unsigned long) ret;
785}
786
787
788/*
789 * zeroes a struct timeval
790 */
791
792static inline struct timeval *tv_eternity(struct timeval *tv) {
793 tv->tv_sec = tv->tv_usec = 0;
794 return tv;
795}
796
797/*
798 * returns 1 if tv is null, else 0
799 */
800static inline int tv_iseternity(struct timeval *tv) {
801 if (tv->tv_sec == 0 && tv->tv_usec == 0)
802 return 1;
803 else
804 return 0;
805}
806
807/*
808 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
809 * considering that 0 is the eternity.
810 */
811static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
812 if (tv_iseternity(tv1))
813 if (tv_iseternity(tv2))
814 return 0; /* same */
815 else
816 return 1; /* tv1 later than tv2 */
817 else if (tv_iseternity(tv2))
818 return -1; /* tv2 later than tv1 */
819
820 if (tv1->tv_sec > tv2->tv_sec)
821 return 1;
822 else if (tv1->tv_sec < tv2->tv_sec)
823 return -1;
824 else if (tv1->tv_usec > tv2->tv_usec)
825 return 1;
826 else if (tv1->tv_usec < tv2->tv_usec)
827 return -1;
828 else
829 return 0;
830}
831
832/*
833 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
834 * considering that 0 is the eternity.
835 */
836static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
837 if (tv_iseternity(tv1))
838 if (tv_iseternity(tv2))
839 return 0; /* same */
840 else
841 return 1; /* tv1 later than tv2 */
842 else if (tv_iseternity(tv2))
843 return -1; /* tv2 later than tv1 */
844
willy tarreauefae1842005-12-17 12:51:03 +0100845 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100846 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100847 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100848 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100849 return -1;
850 else
851 return 0;
852 }
853 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100854 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100855 return 1;
856 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100857 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100858 return -1;
859 else
860 return 0;
861}
862
863/*
864 * returns the first event between tv1 and tv2 into tvmin.
865 * a zero tv is ignored. tvmin is returned.
866 */
867static inline struct timeval *tv_min(struct timeval *tvmin,
868 struct timeval *tv1, struct timeval *tv2) {
869
870 if (tv_cmp2(tv1, tv2) <= 0)
871 *tvmin = *tv1;
872 else
873 *tvmin = *tv2;
874
875 return tvmin;
876}
877
878
879
880/***********************************************************/
881/* fd management ***************************************/
882/***********************************************************/
883
884
885
willy tarreau5cbea6f2005-12-17 12:48:26 +0100886/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
887 * The file descriptor is also closed.
888 */
willy tarreau0f7af912005-12-17 12:21:26 +0100889static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100890 FD_CLR(fd, StaticReadEvent);
891 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100892 close(fd);
893 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100894
895 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
896 maxfd--;
897}
898
899/* recomputes the maxfd limit from the fd */
900static inline void fd_insert(int fd) {
901 if (fd+1 > maxfd)
902 maxfd = fd+1;
903}
904
905/*************************************************************/
906/* task management ***************************************/
907/*************************************************************/
908
willy tarreau5cbea6f2005-12-17 12:48:26 +0100909/* puts the task <t> in run queue <q>, and returns <t> */
910static inline struct task *task_wakeup(struct task **q, struct task *t) {
911 if (t->state == TASK_RUNNING)
912 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100913 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100914 t->rqnext = *q;
915 t->state = TASK_RUNNING;
916 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100917 }
918}
919
willy tarreau5cbea6f2005-12-17 12:48:26 +0100920/* removes the task <t> from the queue <q>
921 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100922 * set the run queue to point to the next one, and return it
923 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924static inline struct task *task_sleep(struct task **q, struct task *t) {
925 if (t->state == TASK_RUNNING) {
926 *q = t->rqnext;
927 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100928 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100930}
931
932/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100934 * from the run queue. A pointer to the task itself is returned.
935 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100936static inline struct task *task_delete(struct task *t) {
937 t->prev->next = t->next;
938 t->next->prev = t->prev;
939 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100940}
941
942/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100943 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100944 */
945static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100946 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100947}
948
willy tarreau5cbea6f2005-12-17 12:48:26 +0100949/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100950 * may be only moved or left where it was, depending on its timing requirements.
951 * <task> is returned.
952 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100953struct task *task_queue(struct task *task) {
954 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100955 struct task *start_from;
956
957 /* first, test if the task was already in a list */
958 if (task->prev == NULL) {
959 // start_from = list;
960 start_from = list->prev;
961 stats_tsk_new++;
962
963 /* insert the unlinked <task> into the list, searching back from the last entry */
964 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
965 start_from = start_from->prev;
966 stats_tsk_nsrch++;
967 }
968
969 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
970 // start_from = start_from->next;
971 // stats_tsk_nsrch++;
972 // }
973 }
974 else if (task->prev == list ||
975 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
976 start_from = task->next;
977 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
978 stats_tsk_good++;
979 return task; /* it's already in the right place */
980 }
981
982 stats_tsk_right++;
983 /* insert the unlinked <task> into the list, searching after position <start_from> */
984 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
985 start_from = start_from->next;
986 stats_tsk_rsrch++;
987 }
988 /* we need to unlink it now */
989 task_delete(task);
990 }
991 else { /* walk left. */
992 stats_tsk_left++;
993#ifdef LEFT_TO_TOP /* not very good */
994 start_from = list;
995 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
996 start_from = start_from->next;
997 stats_tsk_lsrch++;
998 }
999#else
1000 start_from = task->prev->prev; /* valid because of the previous test above */
1001 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1002 start_from = start_from->prev;
1003 stats_tsk_lsrch++;
1004 }
1005#endif
1006 /* we need to unlink it now */
1007 task_delete(task);
1008 }
1009 task->prev = start_from;
1010 task->next = start_from->next;
1011 task->next->prev = task;
1012 start_from->next = task;
1013 return task;
1014}
1015
1016
1017/*********************************************************************/
1018/* more specific functions ***************************************/
1019/*********************************************************************/
1020
1021/* some prototypes */
1022static int maintain_proxies(void);
1023
willy tarreau5cbea6f2005-12-17 12:48:26 +01001024/* this either returns the sockname or the original destination address. Code
1025 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1026 */
1027static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
1028#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
1029 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1030#else
1031#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
1032 return getsockname(fd, (struct sockaddr *)sa, salen);
1033#else
1034 return -1;
1035#endif
1036#endif
1037}
1038
1039/*
1040 * frees the context associated to a session. It must have been removed first.
1041 */
1042static inline void session_free(struct session *s) {
1043 if (s->req)
1044 pool_free(buffer, s->req);
1045 if (s->rep)
1046 pool_free(buffer, s->rep);
1047 pool_free(session, s);
1048}
1049
willy tarreau0f7af912005-12-17 12:21:26 +01001050
1051/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001052 * This function initiates a connection to the current server (s->srv) if (s->direct)
1053 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001054 * it's OK, -1 if it's impossible.
1055 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001056int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001057 int one = 1;
1058 int fd;
1059
1060 // fprintf(stderr,"connect_server : s=%p\n",s);
1061
willy tarreau5cbea6f2005-12-17 12:48:26 +01001062 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1063 s->srv_addr = s->srv->addr;
1064 }
1065 else if (s->proxy->options & PR_O_BALANCE) {
1066 if (s->proxy->options & PR_O_BALANCE_RR) {
1067 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001068 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001069 if (s->proxy->cursrv == NULL)
1070 s->proxy->cursrv = s->proxy->srv;
1071 if (s->proxy->cursrv->state & SRV_RUNNING)
1072 break;
1073 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001074 retry--;
1075 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001076
1077 if (retry == 0) /* no server left */
1078 return -1;
1079
1080 s->srv = s->proxy->cursrv;
1081 s->srv_addr = s->srv->addr;
1082 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001083 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001084 else /* unknown balancing algorithm */
1085 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001086 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001087 else if (*(int *)&s->proxy->dispatch_addr) {
1088 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001089 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001090 }
1091 else if (s->proxy->options & PR_O_TRANSP) {
1092 /* in transparent mode, use the original dest addr if no dispatch specified */
1093 int salen = sizeof(struct sockaddr_in);
1094 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1095 qfprintf(stderr, "Cannot get original server address.\n");
1096 return -1;
1097 }
1098 }
willy tarreau0f7af912005-12-17 12:21:26 +01001099
1100 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001101 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001102 return -1;
1103 }
1104
willy tarreau5cbea6f2005-12-17 12:48:26 +01001105 if (fd >= cfg_maxsock) {
1106 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1107 close(fd);
1108 return -1;
1109 }
1110
willy tarreau0f7af912005-12-17 12:21:26 +01001111 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1112 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001113 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001114 close(fd);
1115 return -1;
1116 }
1117
1118 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1119 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001120 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001121 close(fd);
1122 return -1;
1123 }
1124 else if (errno != EALREADY && errno != EISCONN) {
1125 close(fd);
1126 return -1;
1127 }
1128 }
1129
willy tarreau5cbea6f2005-12-17 12:48:26 +01001130 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001131 fdtab[fd].read = &event_srv_read;
1132 fdtab[fd].write = &event_srv_write;
1133 fdtab[fd].state = FD_STCONN; /* connection in progress */
1134
1135 FD_SET(fd, StaticWriteEvent); /* for connect status */
1136
1137 fd_insert(fd);
1138
1139 if (s->proxy->contimeout)
1140 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1141 else
1142 tv_eternity(&s->cnexpire);
1143 return 0;
1144}
1145
1146/*
1147 * this function is called on a read event from a client socket.
1148 * It returns 0.
1149 */
1150int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001151 struct task *t = fdtab[fd].owner;
1152 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001153 struct buffer *b = s->req;
1154 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001155
1156 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1157
willy tarreau0f7af912005-12-17 12:21:26 +01001158 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001159 while (1) {
1160 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1161 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001162 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001163 }
1164 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001165 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001166 }
1167 else {
1168 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001169 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1170 * since it means that the rewrite protection has been removed. This
1171 * implies that the if statement can be removed.
1172 */
1173 if (max > b->rlim - b->data)
1174 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001175 }
1176
1177 if (max == 0) { /* not anymore room to store data */
1178 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001179 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001180 }
1181
willy tarreau3242e862005-12-17 12:27:53 +01001182#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001183 {
1184 int skerr, lskerr;
1185
1186 lskerr = sizeof(skerr);
1187 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1188 if (skerr)
1189 ret = -1;
1190 else
1191 ret = recv(fd, b->r, max, 0);
1192 }
willy tarreau3242e862005-12-17 12:27:53 +01001193#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001194 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001195#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001196 if (ret > 0) {
1197 b->r += ret;
1198 b->l += ret;
1199 s->res_cr = RES_DATA;
1200
1201 if (b->r == b->data + BUFSIZE) {
1202 b->r = b->data; /* wrap around the buffer */
1203 }
1204 /* we hope to read more data or to get a close on next round */
1205 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001206 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001207 else if (ret == 0) {
1208 s->res_cr = RES_NULL;
1209 break;
1210 }
1211 else if (errno == EAGAIN) {/* ignore EAGAIN */
1212 break;
1213 }
1214 else {
1215 s->res_cr = RES_ERROR;
1216 fdtab[fd].state = FD_STERROR;
1217 break;
1218 }
1219 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001220 }
1221 else {
1222 s->res_cr = RES_ERROR;
1223 fdtab[fd].state = FD_STERROR;
1224 }
1225
willy tarreau5cbea6f2005-12-17 12:48:26 +01001226 if (s->res_cr != RES_SILENT) {
1227 if (s->proxy->clitimeout)
1228 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1229 else
1230 tv_eternity(&s->crexpire);
1231
1232 task_wakeup(&rq, t);
1233 }
willy tarreau0f7af912005-12-17 12:21:26 +01001234
willy tarreau0f7af912005-12-17 12:21:26 +01001235 return 0;
1236}
1237
1238
1239/*
1240 * this function is called on a read event from a server socket.
1241 * It returns 0.
1242 */
1243int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001244 struct task *t = fdtab[fd].owner;
1245 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001246 struct buffer *b = s->rep;
1247 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001248
1249 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1250
willy tarreau0f7af912005-12-17 12:21:26 +01001251 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001252 while (1) {
1253 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1254 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001255 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256 }
1257 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001258 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001259 }
1260 else {
1261 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001262 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1263 * since it means that the rewrite protection has been removed. This
1264 * implies that the if statement can be removed.
1265 */
1266 if (max > b->rlim - b->data)
1267 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268 }
1269
1270 if (max == 0) { /* not anymore room to store data */
1271 FD_CLR(fd, StaticReadEvent);
1272 break;
1273 }
1274
willy tarreau3242e862005-12-17 12:27:53 +01001275#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001276 {
1277 int skerr, lskerr;
1278
1279 lskerr = sizeof(skerr);
1280 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1281 if (skerr)
1282 ret = -1;
1283 else
1284 ret = recv(fd, b->r, max, 0);
1285 }
willy tarreau3242e862005-12-17 12:27:53 +01001286#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001287 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001288#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001289 if (ret > 0) {
1290 b->r += ret;
1291 b->l += ret;
1292 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001293
willy tarreau5cbea6f2005-12-17 12:48:26 +01001294 if (b->r == b->data + BUFSIZE) {
1295 b->r = b->data; /* wrap around the buffer */
1296 }
1297 /* we hope to read more data or to get a close on next round */
1298 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001299 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001300 else if (ret == 0) {
1301 s->res_sr = RES_NULL;
1302 break;
1303 }
1304 else if (errno == EAGAIN) {/* ignore EAGAIN */
1305 break;
1306 }
1307 else {
1308 s->res_sr = RES_ERROR;
1309 fdtab[fd].state = FD_STERROR;
1310 break;
1311 }
1312 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001313 }
1314 else {
1315 s->res_sr = RES_ERROR;
1316 fdtab[fd].state = FD_STERROR;
1317 }
1318
willy tarreau5cbea6f2005-12-17 12:48:26 +01001319 if (s->res_sr != RES_SILENT) {
1320 if (s->proxy->srvtimeout)
1321 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1322 else
1323 tv_eternity(&s->srexpire);
1324
1325 task_wakeup(&rq, t);
1326 }
willy tarreau0f7af912005-12-17 12:21:26 +01001327
willy tarreau0f7af912005-12-17 12:21:26 +01001328 return 0;
1329}
1330
1331/*
1332 * this function is called on a write event from a client socket.
1333 * It returns 0.
1334 */
1335int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001336 struct task *t = fdtab[fd].owner;
1337 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001338 struct buffer *b = s->rep;
1339 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001340
1341 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1342
1343 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001344 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001345 // max = BUFSIZE; BUG !!!!
1346 max = 0;
1347 }
1348 else if (b->r > b->w) {
1349 max = b->r - b->w;
1350 }
1351 else
1352 max = b->data + BUFSIZE - b->w;
1353
willy tarreau0f7af912005-12-17 12:21:26 +01001354 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001355#ifndef MSG_NOSIGNAL
1356 int skerr, lskerr;
1357#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001358
1359 if (max == 0) {
1360 s->res_cw = RES_NULL;
1361 task_wakeup(&rq, t);
1362 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001363 }
1364
willy tarreau3242e862005-12-17 12:27:53 +01001365#ifndef MSG_NOSIGNAL
1366 lskerr=sizeof(skerr);
1367 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1368 if (skerr)
1369 ret = -1;
1370 else
1371 ret = send(fd, b->w, max, MSG_DONTWAIT);
1372#else
willy tarreau0f7af912005-12-17 12:21:26 +01001373 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001374#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001375
1376 if (ret > 0) {
1377 b->l -= ret;
1378 b->w += ret;
1379
1380 s->res_cw = RES_DATA;
1381
1382 if (b->w == b->data + BUFSIZE) {
1383 b->w = b->data; /* wrap around the buffer */
1384 }
1385 }
1386 else if (ret == 0) {
1387 /* nothing written, just make as if we were never called */
1388// s->res_cw = RES_NULL;
1389 return 0;
1390 }
1391 else if (errno == EAGAIN) /* ignore EAGAIN */
1392 return 0;
1393 else {
1394 s->res_cw = RES_ERROR;
1395 fdtab[fd].state = FD_STERROR;
1396 }
1397 }
1398 else {
1399 s->res_cw = RES_ERROR;
1400 fdtab[fd].state = FD_STERROR;
1401 }
1402
1403 if (s->proxy->clitimeout)
1404 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1405 else
1406 tv_eternity(&s->cwexpire);
1407
willy tarreau5cbea6f2005-12-17 12:48:26 +01001408 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001409 return 0;
1410}
1411
1412
1413/*
1414 * this function is called on a write event from a server socket.
1415 * It returns 0.
1416 */
1417int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001418 struct task *t = fdtab[fd].owner;
1419 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001420 struct buffer *b = s->req;
1421 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001422
1423 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1424
1425 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001426 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001427 // max = BUFSIZE; BUG !!!!
1428 max = 0;
1429 }
1430 else if (b->r > b->w) {
1431 max = b->r - b->w;
1432 }
1433 else
1434 max = b->data + BUFSIZE - b->w;
1435
willy tarreau0f7af912005-12-17 12:21:26 +01001436 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001437#ifndef MSG_NOSIGNAL
1438 int skerr, lskerr;
1439#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001440 if (max == 0) {
1441 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001442 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001443 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001444 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001445 return 0;
1446 }
1447
willy tarreauef900ab2005-12-17 12:52:52 +01001448
willy tarreau3242e862005-12-17 12:27:53 +01001449#ifndef MSG_NOSIGNAL
1450 lskerr=sizeof(skerr);
1451 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1452 if (skerr)
1453 ret = -1;
1454 else
1455 ret = send(fd, b->w, max, MSG_DONTWAIT);
1456#else
willy tarreau0f7af912005-12-17 12:21:26 +01001457 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001458#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001459 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001460 if (ret > 0) {
1461 b->l -= ret;
1462 b->w += ret;
1463
1464 s->res_sw = RES_DATA;
1465
1466 if (b->w == b->data + BUFSIZE) {
1467 b->w = b->data; /* wrap around the buffer */
1468 }
1469 }
1470 else if (ret == 0) {
1471 /* nothing written, just make as if we were never called */
1472 // s->res_sw = RES_NULL;
1473 return 0;
1474 }
1475 else if (errno == EAGAIN) /* ignore EAGAIN */
1476 return 0;
1477 else {
1478 s->res_sw = RES_ERROR;
1479 fdtab[fd].state = FD_STERROR;
1480 }
1481 }
1482 else {
1483 s->res_sw = RES_ERROR;
1484 fdtab[fd].state = FD_STERROR;
1485 }
1486
1487 if (s->proxy->srvtimeout)
1488 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1489 else
1490 tv_eternity(&s->swexpire);
1491
willy tarreau5cbea6f2005-12-17 12:48:26 +01001492 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001493 return 0;
1494}
1495
1496
1497/*
1498 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 * to an accept. It tries to accept as many connections as possible.
1500 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001501 */
1502int event_accept(int fd) {
1503 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001504 struct session *s;
1505 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001506 int cfd;
1507 int one = 1;
1508
willy tarreau5cbea6f2005-12-17 12:48:26 +01001509 while (p->nbconn < p->maxconn) {
1510 struct sockaddr_in addr;
1511 int laddr = sizeof(addr);
1512 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1513 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001514
willy tarreau5cbea6f2005-12-17 12:48:26 +01001515 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1516 Alert("out of memory in event_accept().\n");
1517 FD_CLR(fd, StaticReadEvent);
1518 p->state = PR_STIDLE;
1519 close(cfd);
1520 return 0;
1521 }
willy tarreau0f7af912005-12-17 12:21:26 +01001522
willy tarreau5cbea6f2005-12-17 12:48:26 +01001523 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1524 Alert("out of memory in event_accept().\n");
1525 FD_CLR(fd, StaticReadEvent);
1526 p->state = PR_STIDLE;
1527 close(cfd);
1528 pool_free(session, s);
1529 return 0;
1530 }
willy tarreau0f7af912005-12-17 12:21:26 +01001531
willy tarreau5cbea6f2005-12-17 12:48:26 +01001532 s->cli_addr = addr;
1533 if (cfd >= cfg_maxsock) {
1534 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1535 close(cfd);
1536 pool_free(task, t);
1537 pool_free(session, s);
1538 return 0;
1539 }
willy tarreau0f7af912005-12-17 12:21:26 +01001540
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1542 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1543 (char *) &one, sizeof(one)) == -1)) {
1544 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1545 close(cfd);
1546 pool_free(task, t);
1547 pool_free(session, s);
1548 return 0;
1549 }
willy tarreau0f7af912005-12-17 12:21:26 +01001550
willy tarreau5cbea6f2005-12-17 12:48:26 +01001551 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1552 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1553 struct sockaddr_in peername, sockname;
1554 unsigned char *pn, *sn;
1555 int namelen;
1556 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001557
willy tarreau5cbea6f2005-12-17 12:48:26 +01001558 //namelen = sizeof(peername);
1559 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1560 //pn = (unsigned char *)&peername.sin_addr;
1561 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001562
willy tarreau5cbea6f2005-12-17 12:48:26 +01001563 namelen = sizeof(sockname);
1564 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1565 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1566 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001567
willy tarreau5cbea6f2005-12-17 12:48:26 +01001568 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1569 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1570 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1571 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001572
willy tarreau5cbea6f2005-12-17 12:48:26 +01001573 if (p->logfac1 >= 0)
1574 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1575 if (p->logfac2 >= 0)
1576 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1577 }
willy tarreau0f7af912005-12-17 12:21:26 +01001578
willy tarreauef900ab2005-12-17 12:52:52 +01001579 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1580 int len;
1581 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1582 write(1, trash, len);
1583 }
willy tarreau0f7af912005-12-17 12:21:26 +01001584
willy tarreau5cbea6f2005-12-17 12:48:26 +01001585 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1586 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1587 t->state = TASK_IDLE;
1588 t->process = process_session;
1589 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001590
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 s->task = t;
1592 s->proxy = p;
1593 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1594 s->srv_state = SV_STIDLE;
1595 s->req = s->rep = NULL; /* will be allocated later */
1596 s->flags = 0;
1597 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1598 s->cli_fd = cfd;
1599 s->srv_fd = -1;
1600 s->conn_retries = p->conn_retries;
1601
1602 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1603 close(cfd); /* nothing can be done for this fd without memory */
1604 pool_free(task, t);
1605 pool_free(session, s);
1606 return 0;
1607 }
1608 s->req->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001609 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1610 s->req->rlim = s->req->data + BUFSIZE;
1611 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1612 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001613
willy tarreau5cbea6f2005-12-17 12:48:26 +01001614 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1615 pool_free(buffer, s->req);
1616 close(cfd); /* nothing can be done for this fd without memory */
1617 pool_free(task, t);
1618 pool_free(session, s);
1619 return 0;
1620 }
1621 s->rep->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001622 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 +01001623
willy tarreau5cbea6f2005-12-17 12:48:26 +01001624 fdtab[cfd].read = &event_cli_read;
1625 fdtab[cfd].write = &event_cli_write;
1626 fdtab[cfd].owner = t;
1627 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001628
willy tarreau5cbea6f2005-12-17 12:48:26 +01001629 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1630 FD_CLR(cfd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001631 FD_SET(cfd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001632 tv_eternity(&s->crexpire);
1633 shutdown(s->cli_fd, SHUT_RD);
1634 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001635
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1637 s->rep->l = 3;
1638 s->rep->r += 3;
1639 }
1640 else {
1641 FD_SET(cfd, StaticReadEvent);
1642 }
1643
1644 fd_insert(cfd);
1645
1646 tv_eternity(&s->cnexpire);
1647 tv_eternity(&s->srexpire);
1648 tv_eternity(&s->swexpire);
1649 tv_eternity(&s->cwexpire);
1650
1651 if (s->proxy->clitimeout)
1652 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1653 else
1654 tv_eternity(&s->crexpire);
1655
1656 t->expire = s->crexpire;
1657
1658 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001659
1660 if (p->mode != PR_MODE_HEALTH)
1661 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001662
1663 p->nbconn++;
1664 actconn++;
1665 totalconn++;
1666
1667 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1668 } /* end of while (p->nbconn < p->maxconn) */
1669 return 0;
1670}
willy tarreau0f7af912005-12-17 12:21:26 +01001671
willy tarreau0f7af912005-12-17 12:21:26 +01001672
willy tarreau5cbea6f2005-12-17 12:48:26 +01001673/*
1674 * This function is used only for server health-checks. It handles
1675 * the connection acknowledgement and returns 1 if the socket is OK,
1676 * or -1 if an error occured.
1677 */
1678int event_srv_hck(int fd) {
1679 struct task *t = fdtab[fd].owner;
1680 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001681
willy tarreau5cbea6f2005-12-17 12:48:26 +01001682 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001683 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001684 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1685 if (skerr)
1686 s->result = -1;
1687 else
1688 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001689
willy tarreau5cbea6f2005-12-17 12:48:26 +01001690 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001691 return 0;
1692}
1693
1694
1695/*
1696 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1697 * and moves <end> just after the end of <str>.
1698 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1699 * the shift value (positive or negative) is returned.
1700 * If there's no space left, the move is not done.
1701 *
1702 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001703int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001704 int delta;
1705 int len;
1706
1707 len = strlen(str);
1708 delta = len - (end - pos);
1709
1710 if (delta + b->r >= b->data + BUFSIZE)
1711 return 0; /* no space left */
1712
1713 /* first, protect the end of the buffer */
1714 memmove(end + delta, end, b->data + b->l - end);
1715
1716 /* now, copy str over pos */
1717 memcpy(pos, str,len);
1718
willy tarreau5cbea6f2005-12-17 12:48:26 +01001719 /* we only move data after the displaced zone */
1720 if (b->r > pos) b->r += delta;
1721 if (b->w > pos) b->w += delta;
1722 if (b->h > pos) b->h += delta;
1723 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001724 b->l += delta;
1725
1726 return delta;
1727}
1728
1729/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001730int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001731 int delta;
1732
1733 delta = len - (end - pos);
1734
1735 if (delta + b->r >= b->data + BUFSIZE)
1736 return 0; /* no space left */
1737
1738 /* first, protect the end of the buffer */
1739 memmove(end + delta, end, b->data + b->l - end);
1740
1741 /* now, copy str over pos */
1742 memcpy(pos, str,len);
1743
willy tarreau5cbea6f2005-12-17 12:48:26 +01001744 /* we only move data after the displaced zone */
1745 if (b->r > pos) b->r += delta;
1746 if (b->w > pos) b->w += delta;
1747 if (b->h > pos) b->h += delta;
1748 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001749 b->l += delta;
1750
1751 return delta;
1752}
1753
1754
1755int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1756 char *old_dst = dst;
1757
1758 while (*str) {
1759 if (*str == '\\') {
1760 str++;
1761 if (isdigit(*str)) {
1762 int len, num;
1763
1764 num = *str - '0';
1765 str++;
1766
1767 if (matches[num].rm_so > -1) {
1768 len = matches[num].rm_eo - matches[num].rm_so;
1769 memcpy(dst, src + matches[num].rm_so, len);
1770 dst += len;
1771 }
1772
1773 }
1774 else if (*str == 'x') {
1775 unsigned char hex1, hex2;
1776 str++;
1777
1778 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1779
1780 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1781 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1782 *dst++ = (hex1<<4) + hex2;
1783 }
1784 else
1785 *dst++ = *str++;
1786 }
1787 else
1788 *dst++ = *str++;
1789 }
1790 *dst = 0;
1791 return dst - old_dst;
1792}
1793
1794/*
1795 * manages the client FSM and its socket. BTW, it also tries to handle the
1796 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1797 * 0 else.
1798 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001799int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001800 int s = t->srv_state;
1801 int c = t->cli_state;
1802 struct buffer *req = t->req;
1803 struct buffer *rep = t->rep;
1804
1805 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1806 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1807 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1808 //);
1809 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001810 /* now parse the partial (or complete) headers */
1811 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1812 char *ptr;
1813 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001814
willy tarreau5cbea6f2005-12-17 12:48:26 +01001815 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001816
willy tarreau0f7af912005-12-17 12:21:26 +01001817 /* look for the end of the current header */
1818 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1819 ptr++;
1820
willy tarreau5cbea6f2005-12-17 12:48:26 +01001821 if (ptr == req->h) { /* empty line, end of headers */
1822 char newhdr[MAXREWRITE + 1];
1823 int line, len;
1824 /* we can only get here after an end of headers */
1825 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001826
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1828 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1829 buffer_replace2(req, req->h, req->h, newhdr, len);
1830 }
willy tarreau0f7af912005-12-17 12:21:26 +01001831
willy tarreau5cbea6f2005-12-17 12:48:26 +01001832 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01001833 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01001834
willy tarreau5cbea6f2005-12-17 12:48:26 +01001835 /* FIXME: we'll set the client in a wait state while we try to
1836 * connect to the server. Is this really needed ? wouldn't it be
1837 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01001838 //FD_CLR(t->cli_fd, StaticReadEvent);
1839 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001840 break;
1841 }
willy tarreau0f7af912005-12-17 12:21:26 +01001842
willy tarreau5cbea6f2005-12-17 12:48:26 +01001843 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1844 if (ptr > req->r - 2) {
1845 /* this is a partial header, let's wait for more to come */
1846 req->lr = ptr;
1847 break;
1848 }
willy tarreau0f7af912005-12-17 12:21:26 +01001849
willy tarreau5cbea6f2005-12-17 12:48:26 +01001850 /* now we know that *ptr is either \r or \n,
1851 * and that there are at least 1 char after it.
1852 */
1853 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1854 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1855 else
1856 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001857
willy tarreau5cbea6f2005-12-17 12:48:26 +01001858 /*
1859 * now we know that we have a full header ; we can do whatever
1860 * we want with these pointers :
1861 * req->h = beginning of header
1862 * ptr = end of header (first \r or \n)
1863 * req->lr = beginning of next line (next rep->h)
1864 * req->r = end of data (not used at this stage)
1865 */
willy tarreau0f7af912005-12-17 12:21:26 +01001866
willy tarreau5cbea6f2005-12-17 12:48:26 +01001867 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001868
willy tarreau5cbea6f2005-12-17 12:48:26 +01001869 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1870 int len, max;
1871 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1872 max = ptr - req->h;
1873 UBOUND(max, sizeof(trash) - len - 1);
1874 len += strlcpy(trash + len, req->h, max + 1);
1875 trash[len++] = '\n';
1876 write(1, trash, len);
1877 }
willy tarreau0f7af912005-12-17 12:21:26 +01001878
willy tarreau5cbea6f2005-12-17 12:48:26 +01001879 /* try headers regexps */
1880 if (t->proxy->nb_reqexp) {
1881 struct proxy *p = t->proxy;
1882 int exp;
1883 char term;
1884
1885 term = *ptr;
1886 *ptr = '\0';
1887 for (exp=0; exp < p->nb_reqexp; exp++) {
1888 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1889 if (p->req_exp[exp].replace != NULL) {
1890 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1891 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001892 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001893 else {
1894 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001895 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001896 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001897 }
1898 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001899 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001900 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001901
1902 /* now look for cookies */
1903 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1904 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1905 char *p1, *p2, *p3, *p4;
1906
1907 p1 = req->h + 8; /* first char after 'Cookie: ' */
1908
1909 while (p1 < ptr) {
1910 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1911 p1++;
1912
1913 if (p1 == ptr)
1914 break;
1915 else if (*p1 == ';') { /* next cookie */
1916 ++p1;
1917 continue;
1918 }
1919
1920 /* p1 is at the beginning of the cookie name */
1921 p2 = p1;
1922
1923 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1924 p2++;
1925
1926 if (p2 == ptr)
1927 break;
1928 else if (*p2 == ';') { /* next cookie */
1929 p1=++p2;
1930 continue;
1931 }
1932
1933 p3 = p2 + 1; /* skips the '=' sign */
1934 if (p3 == ptr)
1935 break;
1936
1937 p4=p3;
1938 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1939 p4++;
1940
1941 /* here, we have the cookie name between p1 and p2,
1942 * and its value between p3 and p4.
1943 * we can process it.
1944 */
1945
1946 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1947 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1948 /* Cool... it's the right one */
1949 struct server *srv = t->proxy->srv;
1950
1951 while (srv &&
1952 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1953 srv = srv->next;
1954 }
1955
1956 if (srv) { /* we found the server */
1957 t->flags |= TF_DIRECT;
1958 t->srv = srv;
1959 }
1960
1961 break;
1962 }
1963 else {
1964 // fprintf(stderr,"Ignoring unknown cookie : ");
1965 // write(2, p1, p2-p1);
1966 // fprintf(stderr," = ");
1967 // write(2, p3, p4-p3);
1968 // fprintf(stderr,"\n");
1969 }
1970 /* we'll have to look for another cookie ... */
1971 p1 = p4;
1972 } /* while (p1 < ptr) */
1973 } /* end of cookie processing */
1974
1975 /* let's look if we have to delete this header */
1976 if (delete_header) {
1977 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001978 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001979 req->h = req->lr;
1980 } /* while (req->lr < req->r) */
1981
1982 /* end of header processing (even if incomplete) */
1983
willy tarreauef900ab2005-12-17 12:52:52 +01001984
1985 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1986 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1987 * full. We cannot loop here since event_cli_read will disable it only if
1988 * req->l == rlim-data
1989 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001990 FD_SET(t->cli_fd, StaticReadEvent);
1991 if (t->proxy->clitimeout)
1992 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1993 else
1994 tv_eternity(&t->crexpire);
1995 }
1996
willy tarreauef900ab2005-12-17 12:52:52 +01001997 /* read timeout, read error, or last read : give up.
1998 * since we are in header mode, if there's no space left for headers, we
1999 * won't be able to free more later, so the session will never terminate.
2000 */
2001 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2002 || req->l >= req->rlim - req->data || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002003 tv_eternity(&t->crexpire);
2004 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002005 t->cli_state = CL_STCLOSE;
2006 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002007 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002008
2009 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002010 }
2011 else if (c == CL_STDATA) {
2012 /* read or write error */
2013 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002014 tv_eternity(&t->crexpire);
2015 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002016 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002017 t->cli_state = CL_STCLOSE;
2018 return 1;
2019 }
2020 /* read timeout, last read, or end of server write */
2021 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2022 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002023 FD_CLR(t->cli_fd, StaticReadEvent);
2024 // if (req->l == 0) /* nothing to write on the server side */
2025 // FD_CLR(t->srv_fd, StaticWriteEvent);
2026 tv_eternity(&t->crexpire);
2027 shutdown(t->cli_fd, SHUT_RD);
2028 t->cli_state = CL_STSHUTR;
2029 return 1;
2030 }
2031 /* write timeout, or last server read and buffer empty */
2032 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2033 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002034 FD_CLR(t->cli_fd, StaticWriteEvent);
2035 tv_eternity(&t->cwexpire);
2036 shutdown(t->cli_fd, SHUT_WR);
2037 t->cli_state = CL_STSHUTW;
2038 return 1;
2039 }
2040
willy tarreauef900ab2005-12-17 12:52:52 +01002041 if (req->l >= req->rlim - req->data) {
2042 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002043 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002044 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002045 FD_CLR(t->cli_fd, StaticReadEvent);
2046 tv_eternity(&t->crexpire);
2047 }
2048 }
2049 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002050 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002051 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2052 FD_SET(t->cli_fd, StaticReadEvent);
2053 if (t->proxy->clitimeout)
2054 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2055 else
2056 tv_eternity(&t->crexpire);
2057 }
2058 }
2059
2060 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002061 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002062 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2063 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2064 tv_eternity(&t->cwexpire);
2065 }
2066 }
2067 else { /* buffer not empty */
2068 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2069 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2070 if (t->proxy->clitimeout)
2071 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2072 else
2073 tv_eternity(&t->cwexpire);
2074 }
2075 }
2076 return 0; /* other cases change nothing */
2077 }
2078 else if (c == CL_STSHUTR) {
2079 if ((t->res_cw == RES_ERROR) ||
2080 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2081 || (tv_cmp2_ms(&t->crexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002082 tv_eternity(&t->cwexpire);
2083 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002084 t->cli_state = CL_STCLOSE;
2085 return 1;
2086 }
2087 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002088 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002089 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2090 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2091 tv_eternity(&t->cwexpire);
2092 }
2093 }
2094 else { /* buffer not empty */
2095 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2096 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2097 if (t->proxy->clitimeout)
2098 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2099 else
2100 tv_eternity(&t->cwexpire);
2101 }
2102 }
2103 return 0;
2104 }
2105 else if (c == CL_STSHUTW) {
2106 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
2107 s == SV_STCLOSE || tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002108 tv_eternity(&t->crexpire);
2109 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002110 t->cli_state = CL_STCLOSE;
2111 return 1;
2112 }
willy tarreauef900ab2005-12-17 12:52:52 +01002113 else if (req->l >= req->rlim - req->data) {
2114 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002115 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002116 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002117 FD_CLR(t->cli_fd, StaticReadEvent);
2118 tv_eternity(&t->crexpire);
2119 }
2120 }
2121 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002122 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002123 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2124 FD_SET(t->cli_fd, StaticReadEvent);
2125 if (t->proxy->clitimeout)
2126 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2127 else
2128 tv_eternity(&t->crexpire);
2129 }
2130 }
2131 return 0;
2132 }
2133 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002134 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002135 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002136 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002137 write(1, trash, len);
2138 }
2139 return 0;
2140 }
2141 return 0;
2142}
2143
2144
2145/*
2146 * manages the server FSM and its socket. It returns 1 if a state has changed
2147 * (and a resync may be needed), 0 else.
2148 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002149int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002150 int s = t->srv_state;
2151 int c = t->cli_state;
2152 struct buffer *req = t->req;
2153 struct buffer *rep = t->rep;
2154
willy tarreau5cbea6f2005-12-17 12:48:26 +01002155 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2156 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2157 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2158 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2159 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002160 if (s == SV_STIDLE) {
2161 if (c == CL_STHEADERS)
2162 return 0; /* stay in idle, waiting for data to reach the client side */
2163 else if (c == CL_STCLOSE ||
2164 c == CL_STSHUTW ||
2165 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2166 tv_eternity(&t->cnexpire);
2167 t->srv_state = SV_STCLOSE;
2168 return 1;
2169 }
2170 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002171 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002172 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2173 t->srv_state = SV_STCONN;
2174 }
2175 else { /* try again */
2176 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002177 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2178 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2179 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2180 }
2181
2182 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002183 t->srv_state = SV_STCONN;
2184 break;
2185 }
2186 }
2187 if (t->conn_retries < 0) {
2188 /* if conn_retries < 0 or other error, let's abort */
2189 tv_eternity(&t->cnexpire);
2190 t->srv_state = SV_STCLOSE;
2191 }
2192 }
2193 return 1;
2194 }
2195 }
2196 else if (s == SV_STCONN) { /* connection in progress */
2197 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2198 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2199 return 0; /* nothing changed */
2200 }
2201 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2202 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2203 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002204 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002205 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002206 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002207 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208 if (t->conn_retries >= 0) {
2209 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2210 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2211 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2212 }
2213 if (connect_server(t) == 0)
2214 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002215 }
2216 /* if conn_retries < 0 or other error, let's abort */
2217 tv_eternity(&t->cnexpire);
2218 t->srv_state = SV_STCLOSE;
2219 return 1;
2220 }
2221 else { /* no error or write 0 */
2222 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2223 if (req->l == 0) /* nothing to write */
2224 FD_CLR(t->srv_fd, StaticWriteEvent);
2225 else /* need the right to write */
2226 FD_SET(t->srv_fd, StaticWriteEvent);
2227
2228 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2229 FD_SET(t->srv_fd, StaticReadEvent);
2230 if (t->proxy->srvtimeout)
2231 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2232 else
2233 tv_eternity(&t->srexpire);
2234
2235 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002236 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002237 }
willy tarreauef900ab2005-12-17 12:52:52 +01002238 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002239 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002240 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2241 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002242 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002243 return 1;
2244 }
2245 }
2246 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002247
2248 /* now parse the partial (or complete) headers */
2249 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2250 char *ptr;
2251 int delete_header;
2252
2253 ptr = rep->lr;
2254
2255 /* look for the end of the current header */
2256 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2257 ptr++;
2258
2259 if (ptr == rep->h) {
2260 char newhdr[MAXREWRITE + 1];
2261 int line, len;
2262
2263 /* we can only get here after an end of headers */
2264 /* we'll have something else to do here : add new headers ... */
2265
2266 if ((t->srv) && !(t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
2267 /* the server is known, it's not the one the client requested, we have to
2268 * insert a set-cookie here.
2269 */
2270 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2271 t->proxy->cookie_name, t->srv->cookie);
2272 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2273 }
2274
2275 /* headers to be added */
2276 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2277 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2278 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2279 }
2280
2281 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002282 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002283 break;
2284 }
2285
2286 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2287 if (ptr > rep->r - 2) {
2288 /* this is a partial header, let's wait for more to come */
2289 rep->lr = ptr;
2290 break;
2291 }
2292
2293 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2294 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2295
2296 /* now we know that *ptr is either \r or \n,
2297 * and that there are at least 1 char after it.
2298 */
2299 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2300 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2301 else
2302 rep->lr = ptr + 2; /* \r\n or \n\r */
2303
2304 /*
2305 * now we know that we have a full header ; we can do whatever
2306 * we want with these pointers :
2307 * rep->h = beginning of header
2308 * ptr = end of header (first \r or \n)
2309 * rep->lr = beginning of next line (next rep->h)
2310 * rep->r = end of data (not used at this stage)
2311 */
2312
2313 delete_header = 0;
2314
2315 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
2316 int len, max;
2317 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2318 max = ptr - rep->h;
2319 UBOUND(max, sizeof(trash) - len - 1);
2320 len += strlcpy(trash + len, rep->h, max + 1);
2321 trash[len++] = '\n';
2322 write(1, trash, len);
2323 }
2324
2325 /* try headers regexps */
2326 if (t->proxy->nb_rspexp) {
2327 struct proxy *p = t->proxy;
2328 int exp;
2329 char term;
2330
2331 term = *ptr;
2332 *ptr = '\0';
2333 for (exp=0; exp < p->nb_rspexp; exp++) {
2334 if (regexec(p->rsp_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2335 if (p->rsp_exp[exp].replace != NULL) {
2336 int len = exp_replace(trash, rep->h, p->rsp_exp[exp].replace, pmatch);
2337 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2338 }
2339 else {
2340 delete_header = 1;
2341 }
2342 break;
2343 }
2344 }
2345 *ptr = term; /* restore the string terminator */
2346 }
2347
2348 /* check for server cookies */
2349 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2350 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2351 char *p1, *p2, *p3, *p4;
2352
2353 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2354
2355 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2356 while (p1 < ptr && (isspace(*p1)))
2357 p1++;
2358
2359 if (p1 == ptr || *p1 == ';') /* end of cookie */
2360 break;
2361
2362 /* p1 is at the beginning of the cookie name */
2363 p2 = p1;
2364
2365 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2366 p2++;
2367
2368 if (p2 == ptr || *p2 == ';') /* next cookie */
2369 break;
2370
2371 p3 = p2 + 1; /* skips the '=' sign */
2372 if (p3 == ptr)
2373 break;
2374
2375 p4 = p3;
2376 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
2377 p4++;
2378
2379 /* here, we have the cookie name between p1 and p2,
2380 * and its value between p3 and p4.
2381 * we can process it.
2382 */
2383
2384 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2385 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2386 /* Cool... it's the right one */
2387
2388 /* If the cookie is in insert mode on a known server, we'll delete
2389 * this occurrence because we'll insert another one later.
2390 * We'll delete it too if the "indirect" option is set and we're in
2391 * a direct access. */
2392 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
2393 ((t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
2394 /* this header must be deleted */
2395 delete_header = 1;
2396 }
2397 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2398 /* replace bytes p3->p4 with the cookie name associated
2399 * with this server since we know it.
2400 */
2401 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2402 }
2403 break;
2404 }
2405 else {
2406 // fprintf(stderr,"Ignoring unknown cookie : ");
2407 // write(2, p1, p2-p1);
2408 // fprintf(stderr," = ");
2409 // write(2, p3, p4-p3);
2410 // fprintf(stderr,"\n");
2411 }
2412 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2413 } /* we're now at the end of the cookie value */
2414 } /* end of cookie processing */
2415
2416 /* let's look if we have to delete this header */
2417 if (delete_header) {
2418 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2419 }
2420 rep->h = rep->lr;
2421 } /* while (rep->lr < rep->r) */
2422
2423 /* end of header processing (even if incomplete) */
2424
willy tarreauef900ab2005-12-17 12:52:52 +01002425 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2426 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2427 * full. We cannot loop here since event_srv_read will disable it only if
2428 * rep->l == rlim-data
2429 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002430 FD_SET(t->srv_fd, StaticReadEvent);
2431 if (t->proxy->srvtimeout)
2432 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2433 else
2434 tv_eternity(&t->srexpire);
2435 }
willy tarreau0f7af912005-12-17 12:21:26 +01002436
2437 /* read or write error */
2438 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002439 tv_eternity(&t->srexpire);
2440 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002441 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002442 t->srv_state = SV_STCLOSE;
2443 return 1;
2444 }
willy tarreauef900ab2005-12-17 12:52:52 +01002445 /* read timeout, last read, or end of client write
2446 * since we are in header mode, if there's no space left for headers, we
2447 * won't be able to free more later, so the session will never terminate.
2448 */
2449 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2450 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002451 FD_CLR(t->srv_fd, StaticReadEvent);
2452 tv_eternity(&t->srexpire);
2453 shutdown(t->srv_fd, SHUT_RD);
2454 t->srv_state = SV_STSHUTR;
2455 return 1;
2456
2457 }
2458 /* write timeout, or last client read and buffer empty */
2459 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2460 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2461 FD_CLR(t->srv_fd, StaticWriteEvent);
2462 tv_eternity(&t->swexpire);
2463 shutdown(t->srv_fd, SHUT_WR);
2464 t->srv_state = SV_STSHUTW;
2465 return 1;
2466 }
2467
2468 if (req->l == 0) {
2469 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2470 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2471 tv_eternity(&t->swexpire);
2472 }
2473 }
2474 else { /* client buffer not empty */
2475 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2476 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2477 if (t->proxy->srvtimeout)
2478 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2479 else
2480 tv_eternity(&t->swexpire);
2481 }
2482 }
2483
willy tarreau5cbea6f2005-12-17 12:48:26 +01002484 /* be nice with the client side which would like to send a complete header
2485 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2486 * would read all remaining data at once ! The client should not write past rep->lr
2487 * when the server is in header state.
2488 */
2489 //return header_processed;
2490 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002491 }
2492 else if (s == SV_STDATA) {
2493 /* read or write error */
2494 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002495 tv_eternity(&t->srexpire);
2496 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002497 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002498 t->srv_state = SV_STCLOSE;
2499 return 1;
2500 }
2501 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002502 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2503 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002504 FD_CLR(t->srv_fd, StaticReadEvent);
2505 tv_eternity(&t->srexpire);
2506 shutdown(t->srv_fd, SHUT_RD);
2507 t->srv_state = SV_STSHUTR;
2508 return 1;
2509
2510 }
2511 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002512 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2513 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002514 FD_CLR(t->srv_fd, StaticWriteEvent);
2515 tv_eternity(&t->swexpire);
2516 shutdown(t->srv_fd, SHUT_WR);
2517 t->srv_state = SV_STSHUTW;
2518 return 1;
2519 }
2520 else if (req->l == 0) {
2521 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2522 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2523 tv_eternity(&t->swexpire);
2524 }
2525 }
2526 else { /* buffer not empty */
2527 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2528 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2529 if (t->proxy->srvtimeout)
2530 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2531 else
2532 tv_eternity(&t->swexpire);
2533 }
2534 }
2535
2536 if (rep->l == BUFSIZE) { /* no room to read more data */
2537 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2538 FD_CLR(t->srv_fd, StaticReadEvent);
2539 tv_eternity(&t->srexpire);
2540 }
2541 }
2542 else {
2543 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2544 FD_SET(t->srv_fd, StaticReadEvent);
2545 if (t->proxy->srvtimeout)
2546 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2547 else
2548 tv_eternity(&t->srexpire);
2549 }
2550 }
2551
2552 return 0; /* other cases change nothing */
2553 }
2554 else if (s == SV_STSHUTR) {
2555 if ((t->res_sw == RES_ERROR) ||
2556 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2557 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002558 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002559 tv_eternity(&t->swexpire);
2560 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002561 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002562 t->srv_state = SV_STCLOSE;
2563 return 1;
2564 }
2565 else if (req->l == 0) {
2566 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2567 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2568 tv_eternity(&t->swexpire);
2569 }
2570 }
2571 else { /* buffer not empty */
2572 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2573 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2574 if (t->proxy->srvtimeout)
2575 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2576 else
2577 tv_eternity(&t->swexpire);
2578 }
2579 }
2580 return 0;
2581 }
2582 else if (s == SV_STSHUTW) {
2583 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2584 c == CL_STSHUTW || c == CL_STCLOSE ||
2585 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002586 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002587 tv_eternity(&t->srexpire);
2588 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002589 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002590 t->srv_state = SV_STCLOSE;
2591 return 1;
2592 }
2593 else if (rep->l == BUFSIZE) { /* no room to read more data */
2594 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2595 FD_CLR(t->srv_fd, StaticReadEvent);
2596 tv_eternity(&t->srexpire);
2597 }
2598 }
2599 else {
2600 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2601 FD_SET(t->srv_fd, StaticReadEvent);
2602 if (t->proxy->srvtimeout)
2603 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2604 else
2605 tv_eternity(&t->srexpire);
2606 }
2607 }
2608 return 0;
2609 }
2610 else { /* SV_STCLOSE : nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002611 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002612 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002613 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002614 write(1, trash, len);
2615 }
2616 return 0;
2617 }
2618 return 0;
2619}
2620
2621
willy tarreau5cbea6f2005-12-17 12:48:26 +01002622/* Processes the client and server jobs of a session task, then
2623 * puts it back to the wait queue in a clean state, or
2624 * cleans up its resources if it must be deleted. Returns
2625 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01002626 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002627int process_session(struct task *t) {
2628 struct session *s = t->context;
2629 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002630
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631 do {
2632 fsm_resync = 0;
2633 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2634 fsm_resync |= process_cli(s);
2635 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2636 fsm_resync |= process_srv(s);
2637 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2638 } while (fsm_resync);
2639
2640 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002641 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002642 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01002643
willy tarreau5cbea6f2005-12-17 12:48:26 +01002644 tv_min(&min1, &s->crexpire, &s->cwexpire);
2645 tv_min(&min2, &s->srexpire, &s->swexpire);
2646 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002647 tv_min(&t->expire, &min1, &min2);
2648
2649 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002650 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01002651
willy tarreau5cbea6f2005-12-17 12:48:26 +01002652 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01002653 }
2654
willy tarreau5cbea6f2005-12-17 12:48:26 +01002655 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01002656 actconn--;
2657
willy tarreau5cbea6f2005-12-17 12:48:26 +01002658 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002659 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002660 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002661 write(1, trash, len);
2662 }
2663
2664 /* the task MUST not be in the run queue anymore */
2665 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002666 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01002667 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002668 return -1; /* rest in peace for eternity */
2669}
2670
2671
2672
2673/*
2674 * manages a server health-check. Returns
2675 * the time the task accepts to wait, or -1 for infinity.
2676 */
2677int process_chk(struct task *t) {
2678 struct server *s = t->context;
2679 int fd = s->curfd;
2680 int one = 1;
2681
willy tarreauef900ab2005-12-17 12:52:52 +01002682 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002683
2684 if (fd < 0) { /* no check currently running */
2685 //fprintf(stderr, "process_chk: 2\n");
2686 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
2687 task_queue(t); /* restore t to its place in the task list */
2688 return tv_remain(&now, &t->expire);
2689 }
2690
2691 /* we'll initiate a new check */
2692 s->result = 0; /* no result yet */
2693 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
2694 if ((fd < cfg_maxsock) &&
2695 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
2696 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
2697 //fprintf(stderr, "process_chk: 3\n");
2698
2699 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
2700 /* OK, connection in progress or established */
2701
2702 //fprintf(stderr, "process_chk: 4\n");
2703
2704 s->curfd = fd; /* that's how we know a test is in progress ;-) */
2705 fdtab[fd].owner = t;
2706 fdtab[fd].read = NULL;
2707 fdtab[fd].write = &event_srv_hck;
2708 fdtab[fd].state = FD_STCONN; /* connection in progress */
2709 FD_SET(fd, StaticWriteEvent); /* for connect status */
2710 fd_insert(fd);
2711 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2712 task_queue(t); /* restore t to its place in the task list */
2713 return tv_remain(&now, &t->expire);
2714 }
2715 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
2716 s->result = -1; /* a real error */
2717 }
2718 }
2719 //fprintf(stderr, "process_chk: 5\n");
2720 close(fd);
2721 }
2722
2723 if (!s->result) { /* nothing done */
2724 //fprintf(stderr, "process_chk: 6\n");
2725 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2726 task_queue(t); /* restore t to its place in the task list */
2727 return tv_remain(&now, &t->expire);
2728 }
2729
2730 /* here, we have seen a failure */
2731 if (s->health > FALLTIME)
2732 s->health--; /* still good */
2733 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002734 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2735 Warning("server %s DOWN.\n", s->id);
2736
willy tarreau5cbea6f2005-12-17 12:48:26 +01002737 s->health = 0; /* failure */
2738 s->state &= ~SRV_RUNNING;
2739 }
2740
2741 //fprintf(stderr, "process_chk: 7\n");
2742 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2743 }
2744 else {
2745 //fprintf(stderr, "process_chk: 8\n");
2746 /* there was a test running */
2747 if (s->result > 0) { /* good server detected */
2748 //fprintf(stderr, "process_chk: 9\n");
2749 s->health++; /* was bad, stays for a while */
2750 if (s->health >= FALLTIME) {
willy tarreauef900ab2005-12-17 12:52:52 +01002751 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2752 Warning("server %s UP.\n", s->id);
2753
willy tarreau5cbea6f2005-12-17 12:48:26 +01002754 s->health = FALLTIME + RISETIME -1; /* OK now */
2755 s->state |= SRV_RUNNING;
2756 }
willy tarreauef900ab2005-12-17 12:52:52 +01002757 s->curfd = -1; /* no check running anymore */
2758 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002759 fd_delete(fd);
2760 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2761 }
2762 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
2763 //fprintf(stderr, "process_chk: 10\n");
2764 /* failure or timeout detected */
2765 if (s->health > FALLTIME)
2766 s->health--; /* still good */
2767 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002768 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2769 Warning("server %s DOWN.\n", s->id);
2770
willy tarreau5cbea6f2005-12-17 12:48:26 +01002771 s->health = 0; /* failure */
2772 s->state &= ~SRV_RUNNING;
2773 }
2774 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01002775 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002776 fd_delete(fd);
2777 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2778 }
2779 /* if result is 0 and there's no timeout, we have to wait again */
2780 }
2781 //fprintf(stderr, "process_chk: 11\n");
2782 s->result = 0;
2783 task_queue(t); /* restore t to its place in the task list */
2784 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01002785}
2786
2787
willy tarreau5cbea6f2005-12-17 12:48:26 +01002788
willy tarreau0f7af912005-12-17 12:21:26 +01002789#if STATTIME > 0
2790int stats(void);
2791#endif
2792
2793/*
2794 * Main select() loop.
2795 */
2796
2797void select_loop() {
2798 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01002799 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01002800 int status;
2801 int fd,i;
2802 struct timeval delta;
2803 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002804 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01002805
willy tarreau5cbea6f2005-12-17 12:48:26 +01002806 tv_now(&now);
2807
2808 while (1) {
2809 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01002810
willy tarreau5cbea6f2005-12-17 12:48:26 +01002811 /* look for expired tasks and add them to the run queue.
2812 */
2813 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
2814 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
2815 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01002816 if (t->state & TASK_RUNNING)
2817 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002818
2819 /* wakeup expired entries. It doesn't matter if they are
2820 * already running because of a previous event
2821 */
2822 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01002823 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002824 task_wakeup(&rq, t);
2825 }
2826 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002827 /* first non-runnable task. Use its expiration date as an upper bound */
2828 int temp_time = tv_remain(&now, &t->expire);
2829 if (temp_time)
2830 next_time = temp_time;
2831 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002832 break;
2833 }
2834 }
2835
2836 /* process each task in the run queue now. Each task may be deleted
2837 * since we only use tnext.
2838 */
2839 tnext = rq;
2840 while ((t = tnext) != NULL) {
2841 int temp_time;
2842
2843 tnext = t->rqnext;
2844 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002845 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002846 temp_time = t->process(t);
2847 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01002848 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002849 }
2850
willy tarreauef900ab2005-12-17 12:52:52 +01002851 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002852
2853 /* maintain all proxies in a consistent state. This should quickly become a task */
2854 time2 = maintain_proxies();
2855 next_time = MINTIME(time2, next_time);
2856
2857 /* stop when there's no connection left and we don't allow them anymore */
2858 if (!actconn && listeners == 0)
2859 break;
2860
willy tarreau0f7af912005-12-17 12:21:26 +01002861
2862#if STATTIME > 0
2863 time2 = stats();
2864 // fprintf(stderr," stats = %d\n", time2);
2865 next_time = MINTIME(time2, next_time);
2866#endif
2867
willy tarreau5cbea6f2005-12-17 12:48:26 +01002868 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01002869 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002870 /* to avoid eventual select loops due to timer precision */
2871 next_time += SCHEDULER_RESOLUTION;
2872 delta.tv_sec = next_time / 1000;
2873 delta.tv_usec = (next_time % 1000) * 1000;
2874 }
2875 else if (next_time == 0) { /* allow select to return immediately when needed */
2876 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002877 }
2878
2879
2880 /* let's restore fdset state */
2881
2882 readnotnull = 0; writenotnull = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002883 for (i = 0; i < (cfg_maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01002884 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2885 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2886 }
2887
2888// /* just a verification code, needs to be removed for performance */
2889// for (i=0; i<maxfd; i++) {
2890// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2891// abort();
2892// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2893// abort();
2894//
2895// }
2896
2897 status=select(maxfd,
2898 readnotnull ? ReadEvent : NULL,
2899 writenotnull ? WriteEvent : NULL,
2900 NULL,
2901 (next_time >= 0) ? &delta : NULL);
2902
willy tarreau5cbea6f2005-12-17 12:48:26 +01002903 /* this is an experiment on the separation of the select work */
2904 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2905 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2906
willy tarreau0f7af912005-12-17 12:21:26 +01002907 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002908
willy tarreau0f7af912005-12-17 12:21:26 +01002909 if (status > 0) { /* must proceed with events */
2910
2911 int fds;
2912 char count;
2913
2914 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2915 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2916 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2917
willy tarreau5cbea6f2005-12-17 12:48:26 +01002918 /* if we specify read first, the accepts and zero reads will be
2919 * seen first. Moreover, system buffers will be flushed faster.
2920 */
willy tarreau0f7af912005-12-17 12:21:26 +01002921 if (fdtab[fd].state == FD_STCLOSE)
2922 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002923
2924 if (FD_ISSET(fd, ReadEvent))
2925 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002926
willy tarreau5cbea6f2005-12-17 12:48:26 +01002927 if (FD_ISSET(fd, WriteEvent))
2928 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002929 }
2930 }
2931 else {
2932 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2933 }
willy tarreau0f7af912005-12-17 12:21:26 +01002934 }
2935}
2936
2937
2938#if STATTIME > 0
2939/*
2940 * Display proxy statistics regularly. It is designed to be called from the
2941 * select_loop().
2942 */
2943int stats(void) {
2944 static int lines;
2945 static struct timeval nextevt;
2946 static struct timeval lastevt;
2947 static struct timeval starttime = {0,0};
2948 unsigned long totaltime, deltatime;
2949 int ret;
2950
2951 if (tv_remain(&now, &nextevt) == 0) {
2952 deltatime = (tv_delta(&now, &lastevt)?:1);
2953 totaltime = (tv_delta(&now, &starttime)?:1);
2954
2955 if (mode & MODE_STATS) {
2956 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002957 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01002958 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2959 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002960 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01002961 actconn, totalconn,
2962 stats_tsk_new, stats_tsk_good,
2963 stats_tsk_left, stats_tsk_right,
2964 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2965 }
2966 }
2967
2968 tv_delayfrom(&nextevt, &now, STATTIME);
2969
2970 lastevt=now;
2971 }
2972 ret = tv_remain(&now, &nextevt);
2973 return ret;
2974}
2975#endif
2976
2977
2978/*
2979 * this function enables proxies when there are enough free sessions,
2980 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01002981 * select_loop(). It returns the time left before next expiration event
2982 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01002983 */
2984static int maintain_proxies(void) {
2985 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002986 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01002987
2988 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002989 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01002990
2991 /* if there are enough free sessions, we'll activate proxies */
2992 if (actconn < cfg_maxconn) {
2993 while (p) {
2994 if (p->nbconn < p->maxconn) {
2995 if (p->state == PR_STIDLE) {
2996 FD_SET(p->listen_fd, StaticReadEvent);
2997 p->state = PR_STRUN;
2998 }
2999 }
3000 else {
3001 if (p->state == PR_STRUN) {
3002 FD_CLR(p->listen_fd, StaticReadEvent);
3003 p->state = PR_STIDLE;
3004 }
3005 }
3006 p = p->next;
3007 }
3008 }
3009 else { /* block all proxies */
3010 while (p) {
3011 if (p->state == PR_STRUN) {
3012 FD_CLR(p->listen_fd, StaticReadEvent);
3013 p->state = PR_STIDLE;
3014 }
3015 p = p->next;
3016 }
3017 }
3018
willy tarreau5cbea6f2005-12-17 12:48:26 +01003019 if (stopping) {
3020 p = proxy;
3021 while (p) {
3022 if (p->state != PR_STDISABLED) {
3023 int t;
3024 t = tv_remain(&now, &p->stop_time);
3025 if (t == 0) {
3026 //FD_CLR(p->listen_fd, StaticReadEvent);
3027 //close(p->listen_fd);
3028 fd_delete(p->listen_fd);
3029 p->state = PR_STDISABLED;
3030 listeners--;
3031 }
3032 else {
3033 tleft = MINTIME(t, tleft);
3034 }
3035 }
3036 p = p->next;
3037 }
3038 }
3039 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003040}
3041
3042/*
3043 * this function disables health-check servers so that the process will quickly be ignored
3044 * by load balancers.
3045 */
3046static void soft_stop(void) {
3047 struct proxy *p;
3048
3049 stopping = 1;
3050 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003051 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003052 while (p) {
3053 if (p->state != PR_STDISABLED)
3054 tv_delayfrom(&p->stop_time, &now, p->grace);
3055 p = p->next;
3056 }
3057}
3058
3059/*
3060 * upon SIGUSR1, let's have a soft stop.
3061 */
3062void sig_soft_stop(int sig) {
3063 soft_stop();
3064 signal(sig, SIG_IGN);
3065}
3066
3067
3068void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003069 struct task *t, *tnext;
3070 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003071
willy tarreau5cbea6f2005-12-17 12:48:26 +01003072 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3073 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3074 tnext = t->next;
3075 s = t->context;
3076 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3077 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3078 "req=%d, rep=%d, clifd=%d\n",
3079 s, tv_remain(&now, &t->expire),
3080 s->cli_state,
3081 s->srv_state,
3082 FD_ISSET(s->cli_fd, StaticReadEvent),
3083 FD_ISSET(s->cli_fd, StaticWriteEvent),
3084 FD_ISSET(s->srv_fd, StaticReadEvent),
3085 FD_ISSET(s->srv_fd, StaticWriteEvent),
3086 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3087 );
willy tarreau0f7af912005-12-17 12:21:26 +01003088 }
3089}
3090
3091/*
3092 * This function reads and parses the configuration file given in the argument.
3093 * returns 0 if OK, -1 if error.
3094 */
3095int readcfgfile(char *file) {
3096 char thisline[256];
3097 char *line;
3098 FILE *f;
3099 int linenum = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003100 char *end;
3101 char *args[MAX_LINE_ARGS];
willy tarreau0f7af912005-12-17 12:21:26 +01003102 int arg;
3103 int cfgerr = 0;
3104
3105 struct proxy *curproxy = NULL;
3106 struct server *newsrv = NULL;
3107
3108 if ((f=fopen(file,"r")) == NULL)
3109 return -1;
3110
3111 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
3112 linenum++;
willy tarreau0f7af912005-12-17 12:21:26 +01003113
willy tarreau5cbea6f2005-12-17 12:48:26 +01003114 end = line + strlen(line);
willy tarreau0f7af912005-12-17 12:21:26 +01003115
willy tarreau5cbea6f2005-12-17 12:48:26 +01003116 /* skip leading spaces */
3117 while (isspace(*line))
3118 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01003119
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120 arg = 0;
3121 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01003122
willy tarreau5cbea6f2005-12-17 12:48:26 +01003123 while (*line && arg < MAX_LINE_ARGS) {
3124 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
3125 * C equivalent value. Other combinations left unchanged (eg: \1).
3126 */
3127 if (*line == '\\') {
3128 int skip = 0;
3129 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
3130 *line = line[1];
3131 skip = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003132 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003133 else if (line[1] == 'r') {
3134 *line = '\r';
3135 skip = 1;
3136 }
3137 else if (line[1] == 'n') {
3138 *line = '\n';
3139 skip = 1;
3140 }
3141 else if (line[1] == 't') {
3142 *line = '\t';
3143 skip = 1;
3144 }
3145 else if (line[1] == 'x' && (line + 3 < end )) {
3146 unsigned char hex1, hex2;
3147 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
3148 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3149 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3150 *line = (hex1<<4) + hex2;
3151 skip = 3;
3152 }
3153 if (skip) {
3154 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
3155 end -= skip;
3156 }
willy tarreau0f7af912005-12-17 12:21:26 +01003157 line++;
3158 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003159 else {
3160 if (*line == '#' || *line == '\n' || *line == '\r')
3161 *line = 0; /* end of string, end of loop */
3162 else
willy tarreau0f7af912005-12-17 12:21:26 +01003163 line++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003164
3165 /* a non-escaped space is an argument separator */
3166 if (isspace(*line)) {
3167 *line++ = 0;
3168 while (isspace(*line))
3169 line++;
3170 args[++arg] = line;
3171 }
willy tarreau0f7af912005-12-17 12:21:26 +01003172 }
3173 }
3174
willy tarreau5cbea6f2005-12-17 12:48:26 +01003175 /* empty line */
3176 if (!**args)
3177 continue;
3178
3179 /* zero out remaining args */
3180 while (++arg < MAX_LINE_ARGS) {
3181 args[arg] = line;
3182 }
3183
willy tarreau0f7af912005-12-17 12:21:26 +01003184 if (!strcmp(args[0], "listen")) { /* new proxy */
3185 if (strchr(args[2], ':') == NULL) {
3186 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3187 file, linenum);
3188 return -1;
3189 }
3190
3191 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
3192 == NULL) {
3193 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3194 exit(1);
3195 }
3196 curproxy->next = proxy;
3197 proxy = curproxy;
3198 curproxy->id = strdup(args[1]);
3199 curproxy->listen_addr = *str2sa(args[2]);
3200 curproxy->state = PR_STNEW;
willy tarreau0f7af912005-12-17 12:21:26 +01003201 /* set default values */
3202 curproxy->maxconn = cfg_maxpconn;
3203 curproxy->conn_retries = CONN_RETRIES;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003204 curproxy->options = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003205 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3206 curproxy->mode = PR_MODE_TCP;
3207 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3208 continue;
3209 }
3210 else if (curproxy == NULL) {
3211 Alert("parsing [%s:%d] : <listen> expected.\n",
3212 file, linenum);
3213 return -1;
3214 }
3215
3216 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3217 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3218 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3219 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3220 else {
3221 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3222 return -1;
3223 }
3224 }
3225 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3226 curproxy->state = PR_STDISABLED;
3227 }
3228 else if (!strcmp(args[0], "cookie")) { /* cookie name */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003229 int cur_arg;
willy tarreau0f7af912005-12-17 12:21:26 +01003230 if (curproxy->cookie_name != NULL) {
3231 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3232 file, linenum);
3233 continue;
3234 }
3235
3236 if (*(args[1]) == 0) {
3237 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3238 file, linenum);
3239 return -1;
3240 }
3241 curproxy->cookie_name = strdup(args[1]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003242
3243 cur_arg = 2;
3244 while (*(args[cur_arg])) {
3245 if (!strcmp(args[cur_arg], "rewrite")) {
3246 curproxy->options |= PR_O_COOK_RW;
3247 }
3248 else if (!strcmp(args[cur_arg], "indirect")) {
3249 curproxy->options |= PR_O_COOK_IND;
3250 }
3251 else if (!strcmp(args[cur_arg], "insert")) {
3252 curproxy->options |= PR_O_COOK_INS;
3253 }
3254 else {
3255 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
3256 file, linenum);
3257 return -1;
3258 }
3259 cur_arg++;
3260 }
3261 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3262 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3263 file, linenum);
3264 return -1;
3265 }
willy tarreau0f7af912005-12-17 12:21:26 +01003266 }
3267 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3268 if (curproxy->contimeout != 0) {
3269 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
3270 file, linenum);
3271 continue;
3272 }
3273 if (*(args[1]) == 0) {
3274 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3275 file, linenum);
3276 return -1;
3277 }
3278 curproxy->contimeout = atol(args[1]);
3279 }
3280 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3281 if (curproxy->clitimeout != 0) {
3282 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3283 file, linenum);
3284 continue;
3285 }
3286 if (*(args[1]) == 0) {
3287 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3288 file, linenum);
3289 return -1;
3290 }
3291 curproxy->clitimeout = atol(args[1]);
3292 }
3293 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3294 if (curproxy->srvtimeout != 0) {
3295 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
3296 file, linenum);
3297 continue;
3298 }
3299 if (*(args[1]) == 0) {
3300 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
3301 file, linenum);
3302 return -1;
3303 }
3304 curproxy->srvtimeout = atol(args[1]);
3305 }
3306 else if (!strcmp(args[0], "retries")) { /* connection retries */
3307 if (*(args[1]) == 0) {
3308 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3309 file, linenum);
3310 return -1;
3311 }
3312 curproxy->conn_retries = atol(args[1]);
3313 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003314 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3315 /* enable reconnections to dispatch */
3316 curproxy->options |= PR_O_REDISP;
willy tarreau0f7af912005-12-17 12:21:26 +01003317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318#ifdef TRANSPARENT
3319 else if (!strcmp(args[0], "transparent")) {
3320 /* enable transparent proxy connections */
3321 curproxy->options |= PR_O_TRANSP;
3322 }
3323#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003324 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3325 if (*(args[1]) == 0) {
3326 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
3327 file, linenum);
3328 return -1;
3329 }
3330 curproxy->maxconn = atol(args[1]);
3331 }
3332 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3333 if (*(args[1]) == 0) {
3334 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
3335 file, linenum);
3336 return -1;
3337 }
3338 curproxy->grace = atol(args[1]);
3339 }
3340 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3341 if (strchr(args[1], ':') == NULL) {
3342 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
3343 file, linenum);
3344 return -1;
3345 }
3346 curproxy->dispatch_addr = *str2sa(args[1]);
3347 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003348 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3349 if (*(args[1])) {
3350 if (!strcmp(args[1], "roundrobin")) {
3351 curproxy->options |= PR_O_BALANCE_RR;
3352 }
3353 else {
3354 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n",
3355 file, linenum);
3356 return -1;
3357 }
3358 }
3359 else /* if no option is set, use round-robin by default */
3360 curproxy->options |= PR_O_BALANCE_RR;
3361 }
willy tarreau0f7af912005-12-17 12:21:26 +01003362 else if (!strcmp(args[0], "server")) { /* server address */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003363 int cur_arg;
3364
willy tarreau0f7af912005-12-17 12:21:26 +01003365 if (strchr(args[2], ':') == NULL) {
3366 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3367 file, linenum);
3368 return -1;
3369 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003370 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3371 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003372 exit(1);
3373 }
3374 newsrv->next = curproxy->srv;
3375 curproxy->srv = newsrv;
3376 newsrv->id = strdup(args[1]);
3377 newsrv->addr = *str2sa(args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003378 newsrv->state = SRV_RUNNING; /* early server setup */
3379 newsrv->health = FALLTIME; /* up, but will fall down at first failure */
3380 newsrv->curfd = -1; /* no health-check in progress */
3381 cur_arg = 3;
3382 while (*args[cur_arg]) {
3383 if (!strcmp(args[cur_arg], "cookie")) {
3384 newsrv->cookie = strdup(args[cur_arg + 1]);
3385 newsrv->cklen = strlen(args[cur_arg + 1]);
3386 cur_arg += 2;
3387 }
3388 else if (!strcmp(args[cur_arg], "check")) {
3389 struct task *t;
3390
3391 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3392 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3393 return -1;
3394 }
3395
3396 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3397 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3398 t->state = TASK_IDLE;
3399 t->process = process_chk;
3400 t->context = newsrv;
3401
3402 tv_delayfrom(&t->expire, &now, CHK_INTERVAL); /* check this every ms */
3403 task_queue(t);
3404 task_wakeup(&rq, t);
3405
3406 cur_arg += 1;
3407 }
3408 else {
3409 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3410 file, linenum, newsrv->id);
3411 return -1;
3412 }
3413 }
3414 curproxy->nbservers++;
willy tarreau0f7af912005-12-17 12:21:26 +01003415 }
3416 else if (!strcmp(args[0], "log")) { /* syslog server address */
3417 struct sockaddr_in *sa;
3418 int facility;
3419
3420 if (*(args[1]) == 0 || *(args[2]) == 0) {
3421 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
3422 file, linenum);
3423 return -1;
3424 }
3425
3426 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3427 if (!strcmp(log_facilities[facility], args[2]))
3428 break;
3429
3430 if (facility >= NB_LOG_FACILITIES) {
3431 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3432 exit(1);
3433 }
3434
3435 sa = str2sa(args[1]);
3436 if (!sa->sin_port)
3437 sa->sin_port = htons(SYSLOG_PORT);
3438
3439 if (curproxy->logfac1 == -1) {
3440 curproxy->logsrv1 = *sa;
3441 curproxy->logfac1 = facility;
3442 }
3443 else if (curproxy->logfac2 == -1) {
3444 curproxy->logsrv2 = *sa;
3445 curproxy->logfac2 = facility;
3446 }
3447 else {
3448 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3449 exit(1);
3450 }
3451
3452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003454 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003455 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3456 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003457 file, linenum);
3458 continue;
3459 }
3460
3461 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003462 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003463 file, linenum);
3464 return -1;
3465 }
3466
3467 preg = calloc(1, sizeof(regex_t));
3468 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3469 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3470 return -1;
3471 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003472 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3473 curproxy->req_exp[curproxy->nb_reqexp].replace = strdup(args[2]);
3474 curproxy->nb_reqexp++;
willy tarreau0f7af912005-12-17 12:21:26 +01003475 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003476 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003477 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003478 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3479 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
3480 file, linenum);
3481 continue;
3482 }
3483
3484 if (*(args[1]) == 0) {
3485 Alert("parsing [%s:%d] : <reqdel> expects <search> as an argument.\n",
3486 file, linenum);
3487 return -1;
3488 }
3489
3490 preg = calloc(1, sizeof(regex_t));
3491 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3492 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3493 return -1;
3494 }
3495 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3496 curproxy->req_exp[curproxy->nb_reqexp].replace = NULL; /* means it must be deleted */
3497 curproxy->nb_reqexp++;
3498 }
3499 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3500 if (curproxy->nb_reqadd >= MAX_REGEXP) {
3501 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
3502 file, linenum);
3503 continue;
3504 }
3505
3506 if (*(args[1]) == 0) {
3507 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n",
3508 file, linenum);
3509 return -1;
3510 }
3511
3512 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
3513 }
3514 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3515 regex_t *preg;
3516 if (curproxy->nb_rspexp >= MAX_REGEXP) {
willy tarreau0f7af912005-12-17 12:21:26 +01003517 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3518 file, linenum);
3519 continue;
3520 }
3521
3522 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003523 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003524 file, linenum);
3525 return -1;
3526 }
3527
3528 preg = calloc(1, sizeof(regex_t));
3529 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3530 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3531 return -1;
3532 }
3533 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003534 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3535 curproxy->rsp_exp[curproxy->nb_rspexp].replace = strdup(args[2]);
3536 curproxy->nb_rspexp++;
3537 }
3538 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3539 regex_t *preg;
3540 if (curproxy->nb_rspexp >= MAX_REGEXP) {
3541 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3542 file, linenum);
3543 continue;
3544 }
3545
3546 if (*(args[1]) == 0) {
3547 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n",
3548 file, linenum);
3549 return -1;
3550 }
3551
3552 preg = calloc(1, sizeof(regex_t));
3553 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3554 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3555 return -1;
3556 }
3557 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
3558 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3559 curproxy->rsp_exp[curproxy->nb_rspexp].replace = NULL; /* means it must be deleted */
3560 curproxy->nb_rspexp++;
3561 }
3562 else if (!strcmp(args[0], "rspadd")) { /* add response header */
3563 if (curproxy->nb_rspadd >= MAX_REGEXP) {
3564 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3565 file, linenum);
3566 continue;
3567 }
3568
3569 if (*(args[1]) == 0) {
3570 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n",
3571 file, linenum);
3572 return -1;
3573 }
3574
3575 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01003576 }
3577 else {
3578 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
3579 exit(1);
3580 }
3581 }
3582 fclose(f);
3583
3584 /*
3585 * Now, check for the integrity of all that we have collected.
3586 */
3587
3588 if ((curproxy = proxy) == NULL) {
3589 Alert("parsing %s : no <listen> line. Nothing to do !\n",
3590 file);
3591 return -1;
3592 }
3593
3594 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01003595 if (curproxy->state == PR_STDISABLED) {
3596 curproxy = curproxy->next;
3597 continue;
3598 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003599 if ((curproxy->mode != PR_MODE_HEALTH) &&
3600 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
3601 (*(int *)&curproxy->dispatch_addr == 0)) {
3602 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
3603 file, curproxy->id);
3604 cfgerr++;
3605 }
3606 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
3607 if (curproxy->options & PR_O_TRANSP) {
3608 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
3609 file, curproxy->id);
3610 cfgerr++;
3611 }
3612 else if (curproxy->srv == NULL) {
3613 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
3614 file, curproxy->id);
3615 cfgerr++;
3616 }
3617 else if (*(int *)&curproxy->dispatch_addr != 0) {
3618 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
3619 file, curproxy->id);
3620 }
3621 }
3622 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01003623 if (curproxy->cookie_name != NULL) {
3624 Warning("parsing %s : cookie will be ignored for listener %s.\n",
3625 file, curproxy->id);
3626 }
3627 if ((newsrv = curproxy->srv) != NULL) {
3628 Warning("parsing %s : servers will be ignored for listener %s.\n",
3629 file, curproxy->id);
3630 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003631 if (curproxy->nb_rspexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003632 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
3633 file, curproxy->id);
3634 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635 if (curproxy->nb_reqexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003636 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
3637 file, curproxy->id);
3638 }
3639 }
3640 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
3641 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
3642 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
3643 file, curproxy->id);
3644 cfgerr++;
3645 }
3646 else {
3647 while (newsrv != NULL) {
3648 /* nothing to check for now */
3649 newsrv = newsrv->next;
3650 }
3651 }
3652 }
3653 curproxy = curproxy->next;
3654 }
3655 if (cfgerr > 0) {
3656 Alert("Errors found in configuration file, aborting.\n");
3657 return -1;
3658 }
3659 else
3660 return 0;
3661}
3662
3663
3664/*
3665 * This function initializes all the necessary variables. It only returns
3666 * if everything is OK. If something fails, it exits.
3667 */
3668void init(int argc, char **argv) {
3669 int i;
3670 char *old_argv = *argv;
3671 char *tmp;
3672
3673 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003674 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003675 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
3676 sizeof(int)*8);
3677 exit(1);
3678 }
3679
3680 pid = getpid();
3681 progname = *argv;
3682 while ((tmp = strchr(progname, '/')) != NULL)
3683 progname = tmp + 1;
3684
3685 argc--; argv++;
3686 while (argc > 0) {
3687 char *flag;
3688
3689 if (**argv == '-') {
3690 flag = *argv+1;
3691
3692 /* 1 arg */
3693 if (*flag == 'v') {
3694 display_version();
3695 exit(0);
3696 }
3697 else if (*flag == 'd')
3698 mode |= MODE_DEBUG;
3699 else if (*flag == 'D')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003700 mode |= MODE_DAEMON | MODE_QUIET;
3701 else if (*flag == 'q')
3702 mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01003703#if STATTIME > 0
3704 else if (*flag == 's')
3705 mode |= MODE_STATS;
3706 else if (*flag == 'l')
3707 mode |= MODE_LOG;
3708#endif
3709 else { /* >=2 args */
3710 argv++; argc--;
3711 if (argc == 0)
3712 usage(old_argv);
3713
3714 switch (*flag) {
3715 case 'n' : cfg_maxconn = atol(*argv); break;
3716 case 'N' : cfg_maxpconn = atol(*argv); break;
3717 case 'f' : cfg_cfgfile = *argv; break;
3718 default: usage(old_argv);
3719 }
3720 }
3721 }
3722 else
3723 usage(old_argv);
3724 argv++; argc--;
3725 }
3726
3727 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
3728
3729 if (!cfg_cfgfile)
3730 usage(old_argv);
3731
3732 gethostname(hostname, MAX_HOSTNAME_LEN);
3733
3734 if (readcfgfile(cfg_cfgfile) < 0) {
3735 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
3736 exit(1);
3737 }
3738
3739 ReadEvent = (fd_set *)calloc(1,
3740 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003741 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003742 WriteEvent = (fd_set *)calloc(1,
3743 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003744 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003745 StaticReadEvent = (fd_set *)calloc(1,
3746 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003747 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003748 StaticWriteEvent = (fd_set *)calloc(1,
3749 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003750 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003751
3752 fdtab = (struct fdtab *)calloc(1,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003753 sizeof(struct fdtab) * (cfg_maxsock));
3754 for (i = 0; i < cfg_maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003755 fdtab[i].state = FD_STCLOSE;
3756 }
3757}
3758
3759/*
3760 * this function starts all the proxies. It returns 0 if OK, -1 if not.
3761 */
3762int start_proxies() {
3763 struct proxy *curproxy;
3764 int one = 1;
3765 int fd;
3766
3767 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
3768
3769 if (curproxy->state == PR_STDISABLED)
3770 continue;
3771
3772 if ((fd = curproxy->listen_fd =
3773 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
3774 Alert("cannot create listening socket for proxy %s. Aborting.\n",
3775 curproxy->id);
3776 return -1;
3777 }
3778
willy tarreau5cbea6f2005-12-17 12:48:26 +01003779 if (fd >= cfg_maxsock) {
3780 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
3781 curproxy->id);
3782 close(fd);
3783 return -1;
3784 }
3785
willy tarreau0f7af912005-12-17 12:21:26 +01003786 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
3787 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
3788 (char *) &one, sizeof(one)) == -1)) {
3789 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
3790 curproxy->id);
3791 close(fd);
3792 return -1;
3793 }
3794
3795 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
3796 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
3797 curproxy->id);
3798 }
3799
3800 if (bind(fd,
3801 (struct sockaddr *)&curproxy->listen_addr,
3802 sizeof(curproxy->listen_addr)) == -1) {
3803 Alert("cannot bind socket for proxy %s. Aborting.\n",
3804 curproxy->id);
3805 close(fd);
3806 return -1;
3807 }
3808
3809 if (listen(fd, curproxy->maxconn) == -1) {
3810 Alert("cannot listen to socket for proxy %s. Aborting.\n",
3811 curproxy->id);
3812 close(fd);
3813 return -1;
3814 }
3815
3816 /* the function for the accept() event */
3817 fdtab[fd].read = &event_accept;
3818 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003819 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01003820 curproxy->state = PR_STRUN;
3821 fdtab[fd].state = FD_STLISTEN;
3822 FD_SET(fd, StaticReadEvent);
3823 fd_insert(fd);
3824 listeners++;
3825// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3826 }
3827 return 0;
3828}
3829
3830
3831int main(int argc, char **argv) {
3832 init(argc, argv);
3833
3834 if (mode & MODE_DAEMON) {
3835 int ret;
3836
3837 ret = fork();
3838
3839 if (ret > 0)
3840 exit(0); /* parent must leave */
3841 else if (ret < 0) {
3842 Alert("[%s.main()] Cannot fork\n", argv[0]);
3843 exit(1); /* there has been an error */
3844 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003845 setpgid(1, 0);
3846 }
willy tarreau0f7af912005-12-17 12:21:26 +01003847
willy tarreau5cbea6f2005-12-17 12:48:26 +01003848 if (mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01003849 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003850 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01003851 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01003852 }
3853
3854 signal(SIGQUIT, dump);
3855 signal(SIGUSR1, sig_soft_stop);
3856
3857 /* on very high loads, a sigpipe sometimes happen just between the
3858 * getsockopt() which tells "it's OK to write", and the following write :-(
3859 */
willy tarreau3242e862005-12-17 12:27:53 +01003860#ifndef MSG_NOSIGNAL
3861 signal(SIGPIPE, SIG_IGN);
3862#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003863
3864 if (start_proxies() < 0)
3865 exit(1);
3866
3867 select_loop();
3868
3869 exit(0);
3870}