blob: f0c36cdc9a925a157051c7b8c197864a92efc582 [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 *
10 * ChangeLog :
11 *
willy tarreauefae1842005-12-17 12:51:03 +010012 * 2002/03/12
13 * - released 1.1.1
14 * - fixed a bug in total failure handling
15 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreau5cbea6f2005-12-17 12:48:26 +010016 * 2002/03/10
17 * - released 1.1.0
18 * - fixed a few timeout bugs
19 * - rearranged the task scheduler subsystem to improve performance,
20 * add new tasks, and make it easier to later port to librt ;
21 * - allow multiple accept() for one select() wake up ;
22 * - implemented internal load balancing with basic health-check ;
23 * - cookie insertion and header add/replace/delete, with better strings
24 * support.
25 * 2002/03/08
26 * - reworked buffer handling to fix a few rewrite bugs, and
27 * improve overall performance.
28 * - implement the "purge" option to delete server cookies in direct mode.
29 * 2002/03/07
30 * - fixed some error cases where the maxfd was not decreased.
31 * 2002/02/26
32 * - now supports transparent proxying, at least on linux 2.4.
33 * 2002/02/12
34 * - soft stop works again (fixed select timeout computation).
35 * - it seems that TCP proxies sometimes cannot timeout.
36 * - added a "quiet" mode.
37 * - enforce file descriptor limitation on socket() and accept().
38 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010039 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010040 * 2001/12/16 : release of version 1.0.0.
41 * 2001/12/16 : added syslog capability for each accepted connection.
42 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
43 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
44 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
45 * with or without cookies (use keyword http for this).
46 * 2001/09/01 : added client/server header replacing with regexps.
47 * eg:
48 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
49 * srvexp ^Server:\ .* Server:\ Apache
50 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
51 * 2000/11/28 : major rewrite
52 * 2000/11/26 : first write
53 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010054 * TODO:
55 * - handle properly intermediate incomplete server headers. Done ?
56 * - log proxies start/stop
57 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010058 *
59 */
60
61#include <stdio.h>
62#include <stdlib.h>
63#include <unistd.h>
64#include <string.h>
65#include <ctype.h>
66#include <sys/time.h>
67#include <sys/types.h>
68#include <sys/socket.h>
69#include <netinet/tcp.h>
70#include <netinet/in.h>
71#include <arpa/inet.h>
72#include <netdb.h>
73#include <fcntl.h>
74#include <errno.h>
75#include <signal.h>
76#include <stdarg.h>
77#include <sys/resource.h>
78#include <time.h>
79#include <regex.h>
80#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +010081#if defined(TRANSPARENT) && defined(NETFILTER)
82#include <linux/netfilter_ipv4.h>
83#endif
willy tarreau0f7af912005-12-17 12:21:26 +010084
willy tarreauefae1842005-12-17 12:51:03 +010085#define HAPROXY_VERSION "1.1.1"
86#define HAPROXY_DATE "2002/03/13"
willy tarreau0f7af912005-12-17 12:21:26 +010087
88/* this is for libc5 for example */
89#ifndef TCP_NODELAY
90#define TCP_NODELAY 1
91#endif
92
93#ifndef SHUT_RD
94#define SHUT_RD 0
95#endif
96
97#ifndef SHUT_WR
98#define SHUT_WR 1
99#endif
100
101#define BUFSIZE 4096
102
103// reserved buffer space for header rewriting
104#define MAXREWRITE 256
105
willy tarreau5cbea6f2005-12-17 12:48:26 +0100106// max # args on a configuration line
107#define MAX_LINE_ARGS 10
108
willy tarreau0f7af912005-12-17 12:21:26 +0100109// max # of regexps per proxy
110#define MAX_REGEXP 10
111
112// max # of matches per regexp
113#define MAX_MATCH 10
114
willy tarreau5cbea6f2005-12-17 12:48:26 +0100115/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100116#define COOKIENAME_LEN 16
117#define SERVERID_LEN 16
118#define CONN_RETRIES 3
119
willy tarreau5cbea6f2005-12-17 12:48:26 +0100120/* FIXME: this should be user-configurable */
121#define CHK_CONNTIME 2000
122#define CHK_INTERVAL 2000
123#define FALLTIME 3
124#define RISETIME 2
125
willy tarreau0f7af912005-12-17 12:21:26 +0100126/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
127#define INTBITS 5
128
129/* show stats this every millisecond, 0 to disable */
130#ifndef STATTIME
131#define STATTIME 2000
132#endif
133
willy tarreau5cbea6f2005-12-17 12:48:26 +0100134/* this reduces the number of calls to select() by choosing appropriate
135 * sheduler precision in milliseconds. It should be near the minimum
136 * time that is needed by select() to collect all events. All timeouts
137 * are rounded up by adding this value prior to pass it to select().
138 */
139#define SCHEDULER_RESOLUTION 9
140
willy tarreau0f7af912005-12-17 12:21:26 +0100141#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
142#define SETNOW(a) (*a=now)
143
willy tarreau9da061b2005-12-17 12:29:56 +0100144/****** string-specific macros and functions ******/
145/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
146#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
147
148/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
149#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
150
151
152#ifndef HAVE_STRLCPY
153/*
154 * copies at most <size-1> chars from <src> to <dst>. Last char is always
155 * set to 0, unless <size> is 0. The number of chars copied is returned
156 * (excluding the terminating zero).
157 * This code has been optimized for size and speed : on x86, it's 45 bytes
158 * long, uses only registers, and consumes only 4 cycles per char.
159 */
160int strlcpy(char *dst, const char *src, int size) {
161 char *orig = dst;
162 if (size) {
163 while (--size && (*dst = *src)) {
164 src++; dst++;
165 }
166 *dst = 0;
167 }
168 return dst - orig;
169}
170#endif
171
172
willy tarreau0f7af912005-12-17 12:21:26 +0100173#define MEM_OPTIM
174#ifdef MEM_OPTIM
175/*
176 * Returns a pointer to type <type> taken from the
177 * pool <pool_type> or dynamically allocated. In the
178 * first case, <pool_type> is updated to point to the
179 * next element in the list.
180 */
181#define pool_alloc(type) ({ \
182 void *p; \
183 if ((p = pool_##type) == NULL) \
184 p = malloc(sizeof_##type); \
185 else { \
186 pool_##type = *(void **)pool_##type; \
187 } \
188 p; \
189})
190
191/*
192 * Puts a memory area back to the corresponding pool.
193 * Items are chained directly through a pointer that
194 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100195 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100196 * that each memory area is at least as big as one
197 * pointer.
198 */
199#define pool_free(type, ptr) ({ \
200 *(void **)ptr = (void *)pool_##type; \
201 pool_##type = (void *)ptr; \
202})
203
204#else
205#define pool_alloc(type) (calloc(1,sizeof_##type));
206#define pool_free(type, ptr) (free(ptr));
207#endif /* MEM_OPTIM */
208
willy tarreau5cbea6f2005-12-17 12:48:26 +0100209#define sizeof_task sizeof(struct task)
210#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100211#define sizeof_buffer sizeof(struct buffer)
212#define sizeof_fdtab sizeof(struct fdtab)
213#define sizeof_str256 256
214
215
willy tarreau5cbea6f2005-12-17 12:48:26 +0100216/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100217#define FD_STCLOSE 0
218#define FD_STLISTEN 1
219#define FD_STCONN 2
220#define FD_STREADY 3
221#define FD_STERROR 4
222
willy tarreau5cbea6f2005-12-17 12:48:26 +0100223/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100224#define TASK_IDLE 0
225#define TASK_RUNNING 1
226
willy tarreau5cbea6f2005-12-17 12:48:26 +0100227/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100228#define PR_STNEW 0
229#define PR_STIDLE 1
230#define PR_STRUN 2
231#define PR_STDISABLED 3
232
willy tarreau5cbea6f2005-12-17 12:48:26 +0100233/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100234#define PR_MODE_TCP 0
235#define PR_MODE_HTTP 1
236#define PR_MODE_HEALTH 2
237
willy tarreau5cbea6f2005-12-17 12:48:26 +0100238/* bits for proxy->options */
239#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
240#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
241#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
242#define PR_O_COOK_IND 8 /* keep only indirect cookies */
243#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
244#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
245#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
246#define PR_O_BALANCE (PR_O_BALANCE_RR)
247
248/* various task flags */
249#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
250
251/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100252#define CL_STHEADERS 0
253#define CL_STDATA 1
254#define CL_STSHUTR 2
255#define CL_STSHUTW 3
256#define CL_STCLOSE 4
257
willy tarreau5cbea6f2005-12-17 12:48:26 +0100258/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100259#define SV_STIDLE 0
260#define SV_STCONN 1
261#define SV_STHEADERS 2
262#define SV_STDATA 3
263#define SV_STSHUTR 4
264#define SV_STSHUTW 5
265#define SV_STCLOSE 6
266
267/* result of an I/O event */
268#define RES_SILENT 0 /* didn't happen */
269#define RES_DATA 1 /* data were sent or received */
270#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
271#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
272
willy tarreau5cbea6f2005-12-17 12:48:26 +0100273/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100274#define MODE_DEBUG 1
275#define MODE_STATS 2
276#define MODE_LOG 4
277#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100278#define MODE_QUIET 16
279
280/* server flags */
281#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100282
283/*********************************************************************/
284
285#define LIST_HEAD(a) ((void *)(&(a)))
286
287/*********************************************************************/
288
289struct hdr_exp {
290 regex_t *preg; /* expression to look for */
291 char *replace; /* expression to set instead */
292};
293
294struct buffer {
295 unsigned int l; /* data length */
296 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
297 char data[BUFSIZE];
298};
299
300struct server {
301 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100302 int state; /* server state (SRV_*) */
303 int cklen; /* the len of the cookie, to speed up checks */
304 char *cookie; /* the id set in the cookie */
305 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100306 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100307 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
308 int result; /* 0 = connect OK, -1 = connect KO */
309 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100310};
311
willy tarreau5cbea6f2005-12-17 12:48:26 +0100312/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100313struct task {
314 struct task *next, *prev; /* chaining ... */
315 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100316 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100317 int state; /* task state : IDLE or RUNNING */
318 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100319 int (*process)(struct task *t); /* the function which processes the task */
320 void *context; /* the task's context */
321};
322
323/* WARNING: if new fields are added, they must be initialized in event_accept() */
324struct session {
325 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100326 /* application specific below */
327 struct timeval crexpire; /* expiration date for a client read */
328 struct timeval cwexpire; /* expiration date for a client write */
329 struct timeval srexpire; /* expiration date for a server read */
330 struct timeval swexpire; /* expiration date for a server write */
331 struct timeval cnexpire; /* expiration date for a connect */
332 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
333 struct proxy *proxy; /* the proxy this socket belongs to */
334 int cli_fd; /* the client side fd */
335 int srv_fd; /* the server side fd */
336 int cli_state; /* state of the client side */
337 int srv_state; /* state of the server side */
338 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100339 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100340 struct buffer *req; /* request buffer */
341 struct buffer *rep; /* response buffer */
342 struct sockaddr_in cli_addr; /* the client address */
343 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100344 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100345};
346
347struct proxy {
348 int listen_fd; /* the listen socket */
349 int state; /* proxy state */
350 struct sockaddr_in listen_addr; /* the address we listen to */
351 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100352 struct server *srv, *cursrv; /* known servers, current server */
353 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100354 char *cookie_name; /* name of the cookie to look for */
355 int clitimeout; /* client I/O timeout (in milliseconds) */
356 int srvtimeout; /* server I/O timeout (in milliseconds) */
357 int contimeout; /* connect timeout (in milliseconds) */
358 char *id; /* proxy id */
359 int nbconn; /* # of active sessions */
360 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100361 int conn_retries; /* maximum number of connect retries */
362 int options; /* PR_O_REDISP, PR_O_TRANSP */
363 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100364 struct proxy *next;
365 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
366 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
367 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100368 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
369 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
370 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
371 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100372 int grace; /* grace time after stop request */
373};
374
375/* info about one given fd */
376struct fdtab {
377 int (*read)(int fd); /* read function */
378 int (*write)(int fd); /* write function */
379 struct task *owner; /* the session (or proxy) associated with this fd */
380 int state; /* the state of this fd */
381};
382
383/*********************************************************************/
384
385int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
386int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
387int cfg_maxsock = 0; /* max # of sockets */
388char *cfg_cfgfile = NULL; /* configuration file */
389char *progname = NULL; /* program name */
390int pid; /* current process id */
391/*********************************************************************/
392
393fd_set *ReadEvent,
394 *WriteEvent,
395 *StaticReadEvent,
396 *StaticWriteEvent;
397
398void **pool_session = NULL,
399 **pool_buffer = NULL,
400 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100401 **pool_str256 = NULL,
402 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100403
404struct proxy *proxy = NULL; /* list of all existing proxies */
405struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100406struct task *rq = NULL; /* global run queue */
407struct task wait_queue = { /* global wait queue */
408 prev:LIST_HEAD(wait_queue),
409 next:LIST_HEAD(wait_queue)
410};
willy tarreau0f7af912005-12-17 12:21:26 +0100411
412static int mode = 0; /* MODE_DEBUG, ... */
413static int totalconn = 0; /* total # of terminated sessions */
414static int actconn = 0; /* # of active sessions */
415static int maxfd = 0; /* # of the highest fd + 1 */
416static int listeners = 0; /* # of listeners */
417static int stopping = 0; /* non zero means stopping in progress */
418static struct timeval now = {0,0}; /* the current date at any moment */
419
420static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
421static char trash[BUFSIZE];
422
423/*
424 * Syslog facilities and levels
425 */
426
427#define MAX_SYSLOG_LEN 1024
428#define NB_LOG_FACILITIES 24
429const char *log_facilities[NB_LOG_FACILITIES] = {
430 "kern", "user", "mail", "daemon",
431 "auth", "syslog", "lpr", "news",
432 "uucp", "cron", "auth2", "ftp",
433 "ntp", "audit", "alert", "cron2",
434 "local0", "local1", "local2", "local3",
435 "local4", "local5", "local6", "local7"
436};
437
438
439#define NB_LOG_LEVELS 8
440const char *log_levels[NB_LOG_LEVELS] = {
441 "emerg", "alert", "crit", "err",
442 "warning", "notice", "info", "debug"
443};
444
445#define SYSLOG_PORT 514
446
447const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
448 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
449#define MAX_HOSTNAME_LEN 32
450static char hostname[MAX_HOSTNAME_LEN] = "";
451
452/*********************************************************************/
453/* statistics ******************************************************/
454/*********************************************************************/
455
456static int stats_tsk_lsrch, stats_tsk_rsrch,
457 stats_tsk_good, stats_tsk_right, stats_tsk_left,
458 stats_tsk_new, stats_tsk_nsrch;
459
460
461/*********************************************************************/
462/* function prototypes *********************************************/
463/*********************************************************************/
464
465int event_accept(int fd);
466int event_cli_read(int fd);
467int event_cli_write(int fd);
468int event_srv_read(int fd);
469int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100470int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100471
472/*********************************************************************/
473/* general purpose functions ***************************************/
474/*********************************************************************/
475
476void display_version() {
477 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100478 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100479}
480
481/*
482 * This function prints the command line usage and exits
483 */
484void usage(char *name) {
485 display_version();
486 fprintf(stderr,
487 "Usage : %s -f <cfgfile> [ -vd"
488#if STATTIME > 0
489 "sl"
490#endif
491 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
492 " -v displays version\n"
493 " -d enters debug mode\n"
494#if STATTIME > 0
495 " -s enables statistics output\n"
496 " -l enables long statistics format\n"
497#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100498 " -D goes daemon ; implies -q\n"
499 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100500 " -n sets the maximum total # of connections (%d)\n"
501 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
502 name, cfg_maxconn, cfg_maxpconn);
503 exit(1);
504}
505
506
507/*
508 * Displays the message on stderr with the date and pid.
509 */
510void Alert(char *fmt, ...) {
511 va_list argp;
512 struct timeval tv;
513 struct tm *tm;
514
willy tarreau5cbea6f2005-12-17 12:48:26 +0100515 if (!(mode & MODE_QUIET)) {
516 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100517
willy tarreau5cbea6f2005-12-17 12:48:26 +0100518 gettimeofday(&tv, NULL);
519 tm=localtime(&tv.tv_sec);
520 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
521 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
522 vfprintf(stderr, fmt, argp);
523 fflush(stderr);
524 va_end(argp);
525 }
willy tarreau0f7af912005-12-17 12:21:26 +0100526}
527
528
529/*
530 * Displays the message on stderr with the date and pid.
531 */
532void Warning(char *fmt, ...) {
533 va_list argp;
534 struct timeval tv;
535 struct tm *tm;
536
willy tarreau5cbea6f2005-12-17 12:48:26 +0100537 if (!(mode & MODE_QUIET)) {
538 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100539
willy tarreau5cbea6f2005-12-17 12:48:26 +0100540 gettimeofday(&tv, NULL);
541 tm=localtime(&tv.tv_sec);
542 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
543 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
544 vfprintf(stderr, fmt, argp);
545 fflush(stderr);
546 va_end(argp);
547 }
548}
549
550/*
551 * Displays the message on <out> only if quiet mode is not set.
552 */
553void qfprintf(FILE *out, char *fmt, ...) {
554 va_list argp;
555
556 if (!(mode & MODE_QUIET)) {
557 va_start(argp, fmt);
558 vfprintf(out, fmt, argp);
559 fflush(out);
560 va_end(argp);
561 }
willy tarreau0f7af912005-12-17 12:21:26 +0100562}
563
564
565/*
566 * converts <str> to a struct sockaddr_in* which is locally allocated.
567 * The format is "addr:port", where "addr" can be empty or "*" to indicate
568 * INADDR_ANY.
569 */
570struct sockaddr_in *str2sa(char *str) {
571 static struct sockaddr_in sa;
572 char *c;
573 int port;
574
575 bzero(&sa, sizeof(sa));
576 str=strdup(str);
577
578 if ((c=strrchr(str,':')) != NULL) {
579 *c++=0;
580 port=atol(c);
581 }
582 else
583 port=0;
584
585 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
586 sa.sin_addr.s_addr = INADDR_ANY;
587 }
588 else if (
589#ifndef SOLARIS
590 !inet_aton(str, &sa.sin_addr)
591#else
592 !inet_pton(AF_INET, str, &sa.sin_addr)
593#endif
594 ) {
595 struct hostent *he;
596
597 if ((he = gethostbyname(str)) == NULL) {
598 Alert("Invalid server name: <%s>\n",str);
599 }
600 else
601 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
602 }
603 sa.sin_port=htons(port);
604 sa.sin_family=AF_INET;
605
606 free(str);
607 return &sa;
608}
609
610/*
611 * This function tries to send a syslog message to the syslog server at
612 * address <sa>. It doesn't care about errors nor does it report them.
613 * WARNING! no check is made on the prog+hostname+date length, so the
614 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
615 * the message will be truncated to fit the maximum length.
616 */
617void send_syslog(struct sockaddr_in *sa,
618 int facility, int level, char *message)
619{
620
621 static int logfd = -1; /* syslog UDP socket */
622 struct timeval tv;
623 struct tm *tm;
624 static char logmsg[MAX_SYSLOG_LEN];
625 char *p;
626
627 if (logfd < 0) {
628 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
629 return;
630 }
631
632 if (facility < 0 || level < 0
633 || sa == NULL || progname == NULL || message == NULL)
634 return;
635
636 gettimeofday(&tv, NULL);
637 tm = localtime(&tv.tv_sec);
638
639 p = logmsg;
640 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
641 // facility * 8 + level,
642 // monthname[tm->tm_mon],
643 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
644 // hostname, progname, pid);
645 /* 20011216/WT : other progs don't set the hostname, and syslogd
646 * systematically repeats it which is contrary to RFC3164.
647 */
648 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
649 facility * 8 + level,
650 monthname[tm->tm_mon],
651 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
652 progname, pid);
653
654 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
655 int len = strlen(message);
656 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
657 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
658 memcpy(p, message, len);
659 p += len;
660 }
willy tarreau3242e862005-12-17 12:27:53 +0100661#ifndef MSG_NOSIGNAL
662 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
663 (struct sockaddr *)sa, sizeof(*sa));
664#else
willy tarreau0f7af912005-12-17 12:21:26 +0100665 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
666 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100667#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100668}
669
670
671/* sets <tv> to the current time */
672static inline struct timeval *tv_now(struct timeval *tv) {
673 if (tv)
674 gettimeofday(tv, NULL);
675 return tv;
676}
677
678/*
679 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
680 */
681static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
682 if (!tv || !from)
683 return NULL;
684 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
685 tv->tv_sec = from->tv_sec + (ms/1000);
686 while (tv->tv_usec >= 1000000) {
687 tv->tv_usec -= 1000000;
688 tv->tv_sec++;
689 }
690 return tv;
691}
692
693/*
694 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
695 */
696static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
697 if (tv1->tv_sec > tv2->tv_sec)
698 return 1;
699 else if (tv1->tv_sec < tv2->tv_sec)
700 return -1;
701 else if (tv1->tv_usec > tv2->tv_usec)
702 return 1;
703 else if (tv1->tv_usec < tv2->tv_usec)
704 return -1;
705 else
706 return 0;
707}
708
709/*
710 * returns the absolute difference, in ms, between tv1 and tv2
711 */
712unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
713 int cmp;
714 unsigned long ret;
715
716
717 cmp=tv_cmp(tv1, tv2);
718 if (!cmp)
719 return 0; /* same dates, null diff */
720 else if (cmp<0) {
721 struct timeval *tmp=tv1;
722 tv1=tv2;
723 tv2=tmp;
724 }
725 ret=(tv1->tv_sec - tv2->tv_sec)*1000;
726 if (tv1->tv_usec > tv2->tv_usec)
727 ret+=(tv1->tv_usec - tv2->tv_usec)/1000;
728 else
729 ret-=(tv2->tv_usec - tv1->tv_usec)/1000;
730 return (unsigned long) ret;
731}
732
733/*
734 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
735 */
736static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100737 if (tv1->tv_sec == tv2->tv_sec) {
738 if (tv1->tv_usec >= tv2->tv_usec + 1000)
739 return 1;
740 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
741 return -1;
742 else
743 return 0;
744 }
745 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreau0f7af912005-12-17 12:21:26 +0100746 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
747 return 1;
748 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
749 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
750 return -1;
751 else
752 return 0;
753}
754
755/*
756 * returns the remaining time between tv1=now and event=tv2
757 * if tv2 is passed, 0 is returned.
758 */
759static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
760 unsigned long ret;
761
762
763 if (tv_cmp_ms(tv1, tv2) >= 0)
764 return 0; /* event elapsed */
765
766 ret=(tv2->tv_sec - tv1->tv_sec)*1000;
767 if (tv2->tv_usec > tv1->tv_usec)
768 ret+=(tv2->tv_usec - tv1->tv_usec)/1000;
769 else
770 ret-=(tv1->tv_usec - tv2->tv_usec)/1000;
771 return (unsigned long) ret;
772}
773
774
775/*
776 * zeroes a struct timeval
777 */
778
779static inline struct timeval *tv_eternity(struct timeval *tv) {
780 tv->tv_sec = tv->tv_usec = 0;
781 return tv;
782}
783
784/*
785 * returns 1 if tv is null, else 0
786 */
787static inline int tv_iseternity(struct timeval *tv) {
788 if (tv->tv_sec == 0 && tv->tv_usec == 0)
789 return 1;
790 else
791 return 0;
792}
793
794/*
795 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
796 * considering that 0 is the eternity.
797 */
798static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
799 if (tv_iseternity(tv1))
800 if (tv_iseternity(tv2))
801 return 0; /* same */
802 else
803 return 1; /* tv1 later than tv2 */
804 else if (tv_iseternity(tv2))
805 return -1; /* tv2 later than tv1 */
806
807 if (tv1->tv_sec > tv2->tv_sec)
808 return 1;
809 else if (tv1->tv_sec < tv2->tv_sec)
810 return -1;
811 else if (tv1->tv_usec > tv2->tv_usec)
812 return 1;
813 else if (tv1->tv_usec < tv2->tv_usec)
814 return -1;
815 else
816 return 0;
817}
818
819/*
820 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
821 * considering that 0 is the eternity.
822 */
823static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
824 if (tv_iseternity(tv1))
825 if (tv_iseternity(tv2))
826 return 0; /* same */
827 else
828 return 1; /* tv1 later than tv2 */
829 else if (tv_iseternity(tv2))
830 return -1; /* tv2 later than tv1 */
831
willy tarreauefae1842005-12-17 12:51:03 +0100832 if (tv1->tv_sec == tv2->tv_sec) {
833 if (tv1->tv_usec >= tv2->tv_usec + 1000)
834 return 1;
835 else if (tv2->tv_usec >= tv1->tv_usec + 1000)
836 return -1;
837 else
838 return 0;
839 }
840 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreau0f7af912005-12-17 12:21:26 +0100841 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
842 return 1;
843 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
844 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
845 return -1;
846 else
847 return 0;
848}
849
850/*
851 * returns the first event between tv1 and tv2 into tvmin.
852 * a zero tv is ignored. tvmin is returned.
853 */
854static inline struct timeval *tv_min(struct timeval *tvmin,
855 struct timeval *tv1, struct timeval *tv2) {
856
857 if (tv_cmp2(tv1, tv2) <= 0)
858 *tvmin = *tv1;
859 else
860 *tvmin = *tv2;
861
862 return tvmin;
863}
864
865
866
867/***********************************************************/
868/* fd management ***************************************/
869/***********************************************************/
870
871
872
willy tarreau5cbea6f2005-12-17 12:48:26 +0100873/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
874 * The file descriptor is also closed.
875 */
willy tarreau0f7af912005-12-17 12:21:26 +0100876static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100877 FD_CLR(fd, StaticReadEvent);
878 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100879 close(fd);
880 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100881
882 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
883 maxfd--;
884}
885
886/* recomputes the maxfd limit from the fd */
887static inline void fd_insert(int fd) {
888 if (fd+1 > maxfd)
889 maxfd = fd+1;
890}
891
892/*************************************************************/
893/* task management ***************************************/
894/*************************************************************/
895
willy tarreau5cbea6f2005-12-17 12:48:26 +0100896/* puts the task <t> in run queue <q>, and returns <t> */
897static inline struct task *task_wakeup(struct task **q, struct task *t) {
898 if (t->state == TASK_RUNNING)
899 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100900 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100901 t->rqnext = *q;
902 t->state = TASK_RUNNING;
903 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100904 }
905}
906
willy tarreau5cbea6f2005-12-17 12:48:26 +0100907/* removes the task <t> from the queue <q>
908 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100909 * set the run queue to point to the next one, and return it
910 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100911static inline struct task *task_sleep(struct task **q, struct task *t) {
912 if (t->state == TASK_RUNNING) {
913 *q = t->rqnext;
914 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100915 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100916 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100917}
918
919/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100920 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100921 * from the run queue. A pointer to the task itself is returned.
922 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100923static inline struct task *task_delete(struct task *t) {
924 t->prev->next = t->next;
925 t->next->prev = t->prev;
926 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100927}
928
929/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100930 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100931 */
932static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100934}
935
willy tarreau5cbea6f2005-12-17 12:48:26 +0100936/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100937 * may be only moved or left where it was, depending on its timing requirements.
938 * <task> is returned.
939 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100940struct task *task_queue(struct task *task) {
941 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100942 struct task *start_from;
943
944 /* first, test if the task was already in a list */
945 if (task->prev == NULL) {
946 // start_from = list;
947 start_from = list->prev;
948 stats_tsk_new++;
949
950 /* insert the unlinked <task> into the list, searching back from the last entry */
951 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
952 start_from = start_from->prev;
953 stats_tsk_nsrch++;
954 }
955
956 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
957 // start_from = start_from->next;
958 // stats_tsk_nsrch++;
959 // }
960 }
961 else if (task->prev == list ||
962 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
963 start_from = task->next;
964 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
965 stats_tsk_good++;
966 return task; /* it's already in the right place */
967 }
968
969 stats_tsk_right++;
970 /* insert the unlinked <task> into the list, searching after position <start_from> */
971 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
972 start_from = start_from->next;
973 stats_tsk_rsrch++;
974 }
975 /* we need to unlink it now */
976 task_delete(task);
977 }
978 else { /* walk left. */
979 stats_tsk_left++;
980#ifdef LEFT_TO_TOP /* not very good */
981 start_from = list;
982 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
983 start_from = start_from->next;
984 stats_tsk_lsrch++;
985 }
986#else
987 start_from = task->prev->prev; /* valid because of the previous test above */
988 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
989 start_from = start_from->prev;
990 stats_tsk_lsrch++;
991 }
992#endif
993 /* we need to unlink it now */
994 task_delete(task);
995 }
996 task->prev = start_from;
997 task->next = start_from->next;
998 task->next->prev = task;
999 start_from->next = task;
1000 return task;
1001}
1002
1003
1004/*********************************************************************/
1005/* more specific functions ***************************************/
1006/*********************************************************************/
1007
1008/* some prototypes */
1009static int maintain_proxies(void);
1010
willy tarreau5cbea6f2005-12-17 12:48:26 +01001011/* this either returns the sockname or the original destination address. Code
1012 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1013 */
1014static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
1015#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
1016 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1017#else
1018#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
1019 return getsockname(fd, (struct sockaddr *)sa, salen);
1020#else
1021 return -1;
1022#endif
1023#endif
1024}
1025
1026/*
1027 * frees the context associated to a session. It must have been removed first.
1028 */
1029static inline void session_free(struct session *s) {
1030 if (s->req)
1031 pool_free(buffer, s->req);
1032 if (s->rep)
1033 pool_free(buffer, s->rep);
1034 pool_free(session, s);
1035}
1036
willy tarreau0f7af912005-12-17 12:21:26 +01001037
1038/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001039 * This function initiates a connection to the current server (s->srv) if (s->direct)
1040 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001041 * it's OK, -1 if it's impossible.
1042 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001043int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001044 int one = 1;
1045 int fd;
1046
1047 // fprintf(stderr,"connect_server : s=%p\n",s);
1048
willy tarreau5cbea6f2005-12-17 12:48:26 +01001049 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1050 s->srv_addr = s->srv->addr;
1051 }
1052 else if (s->proxy->options & PR_O_BALANCE) {
1053 if (s->proxy->options & PR_O_BALANCE_RR) {
1054 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001055 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001056 if (s->proxy->cursrv == NULL)
1057 s->proxy->cursrv = s->proxy->srv;
1058 if (s->proxy->cursrv->state & SRV_RUNNING)
1059 break;
1060 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001061 retry--;
1062 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001063
1064 if (retry == 0) /* no server left */
1065 return -1;
1066
1067 s->srv = s->proxy->cursrv;
1068 s->srv_addr = s->srv->addr;
1069 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001070 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001071 else /* unknown balancing algorithm */
1072 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001073 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001074 else if (*(int *)&s->proxy->dispatch_addr) {
1075 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001076 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001077 }
1078 else if (s->proxy->options & PR_O_TRANSP) {
1079 /* in transparent mode, use the original dest addr if no dispatch specified */
1080 int salen = sizeof(struct sockaddr_in);
1081 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1082 qfprintf(stderr, "Cannot get original server address.\n");
1083 return -1;
1084 }
1085 }
willy tarreau0f7af912005-12-17 12:21:26 +01001086
1087 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001088 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001089 return -1;
1090 }
1091
willy tarreau5cbea6f2005-12-17 12:48:26 +01001092 if (fd >= cfg_maxsock) {
1093 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1094 close(fd);
1095 return -1;
1096 }
1097
willy tarreau0f7af912005-12-17 12:21:26 +01001098 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1099 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001100 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001101 close(fd);
1102 return -1;
1103 }
1104
1105 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1106 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001107 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001108 close(fd);
1109 return -1;
1110 }
1111 else if (errno != EALREADY && errno != EISCONN) {
1112 close(fd);
1113 return -1;
1114 }
1115 }
1116
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001118 fdtab[fd].read = &event_srv_read;
1119 fdtab[fd].write = &event_srv_write;
1120 fdtab[fd].state = FD_STCONN; /* connection in progress */
1121
1122 FD_SET(fd, StaticWriteEvent); /* for connect status */
1123
1124 fd_insert(fd);
1125
1126 if (s->proxy->contimeout)
1127 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1128 else
1129 tv_eternity(&s->cnexpire);
1130 return 0;
1131}
1132
1133/*
1134 * this function is called on a read event from a client socket.
1135 * It returns 0.
1136 */
1137int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001138 struct task *t = fdtab[fd].owner;
1139 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001140 struct buffer *b = s->req;
1141 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001142
1143 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1144
willy tarreau0f7af912005-12-17 12:21:26 +01001145 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001146 while (1) {
1147 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1148 b->r = b->w = b->h = b->lr = b->data;
1149 max = BUFSIZE - MAXREWRITE;
1150 }
1151 else if (b->r > b->w) {
1152 max = b->data + BUFSIZE - MAXREWRITE - b->r;
1153 }
1154 else {
1155 max = b->w - b->r;
1156 if (max > BUFSIZE - MAXREWRITE)
1157 max = BUFSIZE - MAXREWRITE;
1158 }
1159
1160 if (max == 0) { /* not anymore room to store data */
1161 FD_CLR(fd, StaticReadEvent);
1162 break;;
1163 }
1164
willy tarreau3242e862005-12-17 12:27:53 +01001165#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001166 {
1167 int skerr, lskerr;
1168
1169 lskerr = sizeof(skerr);
1170 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1171 if (skerr)
1172 ret = -1;
1173 else
1174 ret = recv(fd, b->r, max, 0);
1175 }
willy tarreau3242e862005-12-17 12:27:53 +01001176#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001177 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001178#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001179 if (ret > 0) {
1180 b->r += ret;
1181 b->l += ret;
1182 s->res_cr = RES_DATA;
1183
1184 if (b->r == b->data + BUFSIZE) {
1185 b->r = b->data; /* wrap around the buffer */
1186 }
1187 /* we hope to read more data or to get a close on next round */
1188 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001189 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001190 else if (ret == 0) {
1191 s->res_cr = RES_NULL;
1192 break;
1193 }
1194 else if (errno == EAGAIN) {/* ignore EAGAIN */
1195 break;
1196 }
1197 else {
1198 s->res_cr = RES_ERROR;
1199 fdtab[fd].state = FD_STERROR;
1200 break;
1201 }
1202 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001203 }
1204 else {
1205 s->res_cr = RES_ERROR;
1206 fdtab[fd].state = FD_STERROR;
1207 }
1208
willy tarreau5cbea6f2005-12-17 12:48:26 +01001209 if (s->res_cr != RES_SILENT) {
1210 if (s->proxy->clitimeout)
1211 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1212 else
1213 tv_eternity(&s->crexpire);
1214
1215 task_wakeup(&rq, t);
1216 }
willy tarreau0f7af912005-12-17 12:21:26 +01001217
willy tarreau0f7af912005-12-17 12:21:26 +01001218 return 0;
1219}
1220
1221
1222/*
1223 * this function is called on a read event from a server socket.
1224 * It returns 0.
1225 */
1226int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001227 struct task *t = fdtab[fd].owner;
1228 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001229 struct buffer *b = s->rep;
1230 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001231
1232 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1233
willy tarreau0f7af912005-12-17 12:21:26 +01001234 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001235 while (1) {
1236 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1237 b->r = b->w = b->h = b->lr = b->data;
1238 max = BUFSIZE - MAXREWRITE;
1239 }
1240 else if (b->r > b->w) {
1241 max = b->data + BUFSIZE - MAXREWRITE - b->r;
1242 }
1243 else {
1244 max = b->w - b->r;
1245 if (max > BUFSIZE - MAXREWRITE)
1246 max = BUFSIZE - MAXREWRITE;
1247 }
1248
1249 if (max == 0) { /* not anymore room to store data */
1250 FD_CLR(fd, StaticReadEvent);
1251 break;
1252 }
1253
willy tarreau3242e862005-12-17 12:27:53 +01001254#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001255 {
1256 int skerr, lskerr;
1257
1258 lskerr = sizeof(skerr);
1259 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1260 if (skerr)
1261 ret = -1;
1262 else
1263 ret = recv(fd, b->r, max, 0);
1264 }
willy tarreau3242e862005-12-17 12:27:53 +01001265#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001266 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001267#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268 if (ret > 0) {
1269 b->r += ret;
1270 b->l += ret;
1271 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001272
willy tarreau5cbea6f2005-12-17 12:48:26 +01001273 if (b->r == b->data + BUFSIZE) {
1274 b->r = b->data; /* wrap around the buffer */
1275 }
1276 /* we hope to read more data or to get a close on next round */
1277 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001278 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001279 else if (ret == 0) {
1280 s->res_sr = RES_NULL;
1281 break;
1282 }
1283 else if (errno == EAGAIN) {/* ignore EAGAIN */
1284 break;
1285 }
1286 else {
1287 s->res_sr = RES_ERROR;
1288 fdtab[fd].state = FD_STERROR;
1289 break;
1290 }
1291 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001292 }
1293 else {
1294 s->res_sr = RES_ERROR;
1295 fdtab[fd].state = FD_STERROR;
1296 }
1297
willy tarreau5cbea6f2005-12-17 12:48:26 +01001298 if (s->res_sr != RES_SILENT) {
1299 if (s->proxy->srvtimeout)
1300 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1301 else
1302 tv_eternity(&s->srexpire);
1303
1304 task_wakeup(&rq, t);
1305 }
willy tarreau0f7af912005-12-17 12:21:26 +01001306
willy tarreau0f7af912005-12-17 12:21:26 +01001307 return 0;
1308}
1309
1310/*
1311 * this function is called on a write event from a client socket.
1312 * It returns 0.
1313 */
1314int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001315 struct task *t = fdtab[fd].owner;
1316 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001317 struct buffer *b = s->rep;
1318 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001319
1320 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1321
1322 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001323 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001324 // max = BUFSIZE; BUG !!!!
1325 max = 0;
1326 }
1327 else if (b->r > b->w) {
1328 max = b->r - b->w;
1329 }
1330 else
1331 max = b->data + BUFSIZE - b->w;
1332
1333 if (max == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001334 // FD_CLR(fd, StaticWriteEvent); // useless
willy tarreau0f7af912005-12-17 12:21:26 +01001335 //fprintf(stderr, "cli_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1336 //fd, max, b->data, b->r, b->w, b->l);
1337 s->res_cw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001338 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001339 return 0;
1340 }
1341
willy tarreau0f7af912005-12-17 12:21:26 +01001342 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001343#ifndef MSG_NOSIGNAL
1344 int skerr, lskerr;
1345#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001346 if (max == 0) { /* nothing to write, just make as if we were never called */
1347 s->res_cw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001348 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001349 return 0;
1350 }
1351
willy tarreau3242e862005-12-17 12:27:53 +01001352#ifndef MSG_NOSIGNAL
1353 lskerr=sizeof(skerr);
1354 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1355 if (skerr)
1356 ret = -1;
1357 else
1358 ret = send(fd, b->w, max, MSG_DONTWAIT);
1359#else
willy tarreau0f7af912005-12-17 12:21:26 +01001360 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001361#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001362
1363 if (ret > 0) {
1364 b->l -= ret;
1365 b->w += ret;
1366
1367 s->res_cw = RES_DATA;
1368
1369 if (b->w == b->data + BUFSIZE) {
1370 b->w = b->data; /* wrap around the buffer */
1371 }
1372 }
1373 else if (ret == 0) {
1374 /* nothing written, just make as if we were never called */
1375// s->res_cw = RES_NULL;
1376 return 0;
1377 }
1378 else if (errno == EAGAIN) /* ignore EAGAIN */
1379 return 0;
1380 else {
1381 s->res_cw = RES_ERROR;
1382 fdtab[fd].state = FD_STERROR;
1383 }
1384 }
1385 else {
1386 s->res_cw = RES_ERROR;
1387 fdtab[fd].state = FD_STERROR;
1388 }
1389
1390 if (s->proxy->clitimeout)
1391 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1392 else
1393 tv_eternity(&s->cwexpire);
1394
willy tarreau5cbea6f2005-12-17 12:48:26 +01001395 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001396 return 0;
1397}
1398
1399
1400/*
1401 * this function is called on a write event from a server socket.
1402 * It returns 0.
1403 */
1404int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001405 struct task *t = fdtab[fd].owner;
1406 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001407 struct buffer *b = s->req;
1408 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001409
1410 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1411
1412 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001413 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001414 // max = BUFSIZE; BUG !!!!
1415 max = 0;
1416 }
1417 else if (b->r > b->w) {
1418 max = b->r - b->w;
1419 }
1420 else
1421 max = b->data + BUFSIZE - b->w;
1422
1423 if (max == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001424 /* may be we have received a connection acknowledgement in TCP mode without data */
1425 // FD_CLR(fd, StaticWriteEvent); // useless ?
willy tarreau0f7af912005-12-17 12:21:26 +01001426 //fprintf(stderr, "srv_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1427 //fd, max, b->data, b->r, b->w, b->l);
1428 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001429 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001430 return 0;
1431 }
1432
willy tarreau0f7af912005-12-17 12:21:26 +01001433 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001434#ifndef MSG_NOSIGNAL
1435 int skerr, lskerr;
1436#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001437 fdtab[fd].state = FD_STREADY;
1438 if (max == 0) { /* nothing to write, just make as if we were never called, except to finish a connect() */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001439 //FD_CLR(fd, StaticWriteEvent); // useless ?
willy tarreau0f7af912005-12-17 12:21:26 +01001440 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001441 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001442 return 0;
1443 }
1444
willy tarreau3242e862005-12-17 12:27:53 +01001445#ifndef MSG_NOSIGNAL
1446 lskerr=sizeof(skerr);
1447 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1448 if (skerr)
1449 ret = -1;
1450 else
1451 ret = send(fd, b->w, max, MSG_DONTWAIT);
1452#else
willy tarreau0f7af912005-12-17 12:21:26 +01001453 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001454#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001455 if (ret > 0) {
1456 b->l -= ret;
1457 b->w += ret;
1458
1459 s->res_sw = RES_DATA;
1460
1461 if (b->w == b->data + BUFSIZE) {
1462 b->w = b->data; /* wrap around the buffer */
1463 }
1464 }
1465 else if (ret == 0) {
1466 /* nothing written, just make as if we were never called */
1467 // s->res_sw = RES_NULL;
1468 return 0;
1469 }
1470 else if (errno == EAGAIN) /* ignore EAGAIN */
1471 return 0;
1472 else {
1473 s->res_sw = RES_ERROR;
1474 fdtab[fd].state = FD_STERROR;
1475 }
1476 }
1477 else {
1478 s->res_sw = RES_ERROR;
1479 fdtab[fd].state = FD_STERROR;
1480 }
1481
1482 if (s->proxy->srvtimeout)
1483 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1484 else
1485 tv_eternity(&s->swexpire);
1486
willy tarreau5cbea6f2005-12-17 12:48:26 +01001487 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001488 return 0;
1489}
1490
1491
1492/*
1493 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001494 * to an accept. It tries to accept as many connections as possible.
1495 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001496 */
1497int event_accept(int fd) {
1498 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001499 struct session *s;
1500 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001501 int cfd;
1502 int one = 1;
1503
willy tarreau0f7af912005-12-17 12:21:26 +01001504
willy tarreau5cbea6f2005-12-17 12:48:26 +01001505 while (p->nbconn < p->maxconn) {
1506 struct sockaddr_in addr;
1507 int laddr = sizeof(addr);
1508 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1509 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001510
willy tarreau5cbea6f2005-12-17 12:48:26 +01001511 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1512 Alert("out of memory in event_accept().\n");
1513 FD_CLR(fd, StaticReadEvent);
1514 p->state = PR_STIDLE;
1515 close(cfd);
1516 return 0;
1517 }
willy tarreau0f7af912005-12-17 12:21:26 +01001518
willy tarreau5cbea6f2005-12-17 12:48:26 +01001519 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1520 Alert("out of memory in event_accept().\n");
1521 FD_CLR(fd, StaticReadEvent);
1522 p->state = PR_STIDLE;
1523 close(cfd);
1524 pool_free(session, s);
1525 return 0;
1526 }
willy tarreau0f7af912005-12-17 12:21:26 +01001527
willy tarreau5cbea6f2005-12-17 12:48:26 +01001528 s->cli_addr = addr;
1529 if (cfd >= cfg_maxsock) {
1530 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1531 close(cfd);
1532 pool_free(task, t);
1533 pool_free(session, s);
1534 return 0;
1535 }
willy tarreau0f7af912005-12-17 12:21:26 +01001536
willy tarreau5cbea6f2005-12-17 12:48:26 +01001537 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1538 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1539 (char *) &one, sizeof(one)) == -1)) {
1540 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1541 close(cfd);
1542 pool_free(task, t);
1543 pool_free(session, s);
1544 return 0;
1545 }
willy tarreau0f7af912005-12-17 12:21:26 +01001546
willy tarreau5cbea6f2005-12-17 12:48:26 +01001547 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1548 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1549 struct sockaddr_in peername, sockname;
1550 unsigned char *pn, *sn;
1551 int namelen;
1552 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001553
willy tarreau5cbea6f2005-12-17 12:48:26 +01001554 //namelen = sizeof(peername);
1555 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1556 //pn = (unsigned char *)&peername.sin_addr;
1557 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001558
willy tarreau5cbea6f2005-12-17 12:48:26 +01001559 namelen = sizeof(sockname);
1560 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1561 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1562 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001563
willy tarreau5cbea6f2005-12-17 12:48:26 +01001564 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1565 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1566 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1567 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001568
willy tarreau5cbea6f2005-12-17 12:48:26 +01001569 if (p->logfac1 >= 0)
1570 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1571 if (p->logfac2 >= 0)
1572 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1573 }
willy tarreau0f7af912005-12-17 12:21:26 +01001574
willy tarreau0f7af912005-12-17 12:21:26 +01001575
willy tarreau5cbea6f2005-12-17 12:48:26 +01001576 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1577 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1578 t->state = TASK_IDLE;
1579 t->process = process_session;
1580 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001581
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582 s->task = t;
1583 s->proxy = p;
1584 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1585 s->srv_state = SV_STIDLE;
1586 s->req = s->rep = NULL; /* will be allocated later */
1587 s->flags = 0;
1588 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1589 s->cli_fd = cfd;
1590 s->srv_fd = -1;
1591 s->conn_retries = p->conn_retries;
1592
1593 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1594 close(cfd); /* nothing can be done for this fd without memory */
1595 pool_free(task, t);
1596 pool_free(session, s);
1597 return 0;
1598 }
1599 s->req->l = 0;
1600 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
willy tarreau0f7af912005-12-17 12:21:26 +01001601
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1603 pool_free(buffer, s->req);
1604 close(cfd); /* nothing can be done for this fd without memory */
1605 pool_free(task, t);
1606 pool_free(session, s);
1607 return 0;
1608 }
1609 s->rep->l = 0;
1610 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001611
willy tarreau5cbea6f2005-12-17 12:48:26 +01001612 fdtab[cfd].read = &event_cli_read;
1613 fdtab[cfd].write = &event_cli_write;
1614 fdtab[cfd].owner = t;
1615 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001616
willy tarreau5cbea6f2005-12-17 12:48:26 +01001617 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1618 FD_CLR(cfd, StaticReadEvent);
1619 tv_eternity(&s->crexpire);
1620 shutdown(s->cli_fd, SHUT_RD);
1621 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001622
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1624 s->rep->l = 3;
1625 s->rep->r += 3;
1626 }
1627 else {
1628 FD_SET(cfd, StaticReadEvent);
1629 }
1630
1631 fd_insert(cfd);
1632
1633 tv_eternity(&s->cnexpire);
1634 tv_eternity(&s->srexpire);
1635 tv_eternity(&s->swexpire);
1636 tv_eternity(&s->cwexpire);
1637
1638 if (s->proxy->clitimeout)
1639 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1640 else
1641 tv_eternity(&s->crexpire);
1642
1643 t->expire = s->crexpire;
1644
1645 task_queue(t);
1646 task_wakeup(&rq, t);
1647
1648 p->nbconn++;
1649 actconn++;
1650 totalconn++;
1651
1652 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1653 } /* end of while (p->nbconn < p->maxconn) */
1654 return 0;
1655}
willy tarreau0f7af912005-12-17 12:21:26 +01001656
willy tarreau0f7af912005-12-17 12:21:26 +01001657
willy tarreau5cbea6f2005-12-17 12:48:26 +01001658/*
1659 * This function is used only for server health-checks. It handles
1660 * the connection acknowledgement and returns 1 if the socket is OK,
1661 * or -1 if an error occured.
1662 */
1663int event_srv_hck(int fd) {
1664 struct task *t = fdtab[fd].owner;
1665 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001666
willy tarreau5cbea6f2005-12-17 12:48:26 +01001667 int skerr, lskerr;
1668 lskerr=sizeof(skerr);
1669 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1670 if (skerr)
1671 s->result = -1;
1672 else
1673 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001674
willy tarreau5cbea6f2005-12-17 12:48:26 +01001675 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001676 return 0;
1677}
1678
1679
1680/*
1681 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1682 * and moves <end> just after the end of <str>.
1683 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1684 * the shift value (positive or negative) is returned.
1685 * If there's no space left, the move is not done.
1686 *
1687 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001688int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001689 int delta;
1690 int len;
1691
1692 len = strlen(str);
1693 delta = len - (end - pos);
1694
1695 if (delta + b->r >= b->data + BUFSIZE)
1696 return 0; /* no space left */
1697
1698 /* first, protect the end of the buffer */
1699 memmove(end + delta, end, b->data + b->l - end);
1700
1701 /* now, copy str over pos */
1702 memcpy(pos, str,len);
1703
willy tarreau5cbea6f2005-12-17 12:48:26 +01001704 /* we only move data after the displaced zone */
1705 if (b->r > pos) b->r += delta;
1706 if (b->w > pos) b->w += delta;
1707 if (b->h > pos) b->h += delta;
1708 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001709 b->l += delta;
1710
1711 return delta;
1712}
1713
1714/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001715int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001716 int delta;
1717
1718 delta = len - (end - pos);
1719
1720 if (delta + b->r >= b->data + BUFSIZE)
1721 return 0; /* no space left */
1722
1723 /* first, protect the end of the buffer */
1724 memmove(end + delta, end, b->data + b->l - end);
1725
1726 /* now, copy str over pos */
1727 memcpy(pos, str,len);
1728
willy tarreau5cbea6f2005-12-17 12:48:26 +01001729 /* we only move data after the displaced zone */
1730 if (b->r > pos) b->r += delta;
1731 if (b->w > pos) b->w += delta;
1732 if (b->h > pos) b->h += delta;
1733 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001734 b->l += delta;
1735
1736 return delta;
1737}
1738
1739
1740int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1741 char *old_dst = dst;
1742
1743 while (*str) {
1744 if (*str == '\\') {
1745 str++;
1746 if (isdigit(*str)) {
1747 int len, num;
1748
1749 num = *str - '0';
1750 str++;
1751
1752 if (matches[num].rm_so > -1) {
1753 len = matches[num].rm_eo - matches[num].rm_so;
1754 memcpy(dst, src + matches[num].rm_so, len);
1755 dst += len;
1756 }
1757
1758 }
1759 else if (*str == 'x') {
1760 unsigned char hex1, hex2;
1761 str++;
1762
1763 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1764
1765 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1766 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1767 *dst++ = (hex1<<4) + hex2;
1768 }
1769 else
1770 *dst++ = *str++;
1771 }
1772 else
1773 *dst++ = *str++;
1774 }
1775 *dst = 0;
1776 return dst - old_dst;
1777}
1778
1779/*
1780 * manages the client FSM and its socket. BTW, it also tries to handle the
1781 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1782 * 0 else.
1783 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001784int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001785 int s = t->srv_state;
1786 int c = t->cli_state;
1787 struct buffer *req = t->req;
1788 struct buffer *rep = t->rep;
1789
1790 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1791 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1792 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1793 //);
1794 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001795 /* now parse the partial (or complete) headers */
1796 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1797 char *ptr;
1798 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001799
willy tarreau5cbea6f2005-12-17 12:48:26 +01001800 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001801
willy tarreau0f7af912005-12-17 12:21:26 +01001802 /* look for the end of the current header */
1803 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1804 ptr++;
1805
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 if (ptr == req->h) { /* empty line, end of headers */
1807 char newhdr[MAXREWRITE + 1];
1808 int line, len;
1809 /* we can only get here after an end of headers */
1810 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001811
willy tarreau5cbea6f2005-12-17 12:48:26 +01001812 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1813 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1814 buffer_replace2(req, req->h, req->h, newhdr, len);
1815 }
willy tarreau0f7af912005-12-17 12:21:26 +01001816
willy tarreau5cbea6f2005-12-17 12:48:26 +01001817 t->cli_state = CL_STDATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001818
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 /* FIXME: we'll set the client in a wait state while we try to
1820 * connect to the server. Is this really needed ? wouldn't it be
1821 * better to release the maximum of system buffers instead ? */
1822 FD_CLR(t->cli_fd, StaticReadEvent);
1823 tv_eternity(&t->crexpire);
1824 break;
1825 }
willy tarreau0f7af912005-12-17 12:21:26 +01001826
willy tarreau5cbea6f2005-12-17 12:48:26 +01001827 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1828 if (ptr > req->r - 2) {
1829 /* this is a partial header, let's wait for more to come */
1830 req->lr = ptr;
1831 break;
1832 }
willy tarreau0f7af912005-12-17 12:21:26 +01001833
willy tarreau5cbea6f2005-12-17 12:48:26 +01001834 /* now we know that *ptr is either \r or \n,
1835 * and that there are at least 1 char after it.
1836 */
1837 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1838 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1839 else
1840 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001841
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 /*
1843 * now we know that we have a full header ; we can do whatever
1844 * we want with these pointers :
1845 * req->h = beginning of header
1846 * ptr = end of header (first \r or \n)
1847 * req->lr = beginning of next line (next rep->h)
1848 * req->r = end of data (not used at this stage)
1849 */
willy tarreau0f7af912005-12-17 12:21:26 +01001850
willy tarreau5cbea6f2005-12-17 12:48:26 +01001851 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001852
willy tarreau5cbea6f2005-12-17 12:48:26 +01001853 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1854 int len, max;
1855 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1856 max = ptr - req->h;
1857 UBOUND(max, sizeof(trash) - len - 1);
1858 len += strlcpy(trash + len, req->h, max + 1);
1859 trash[len++] = '\n';
1860 write(1, trash, len);
1861 }
willy tarreau0f7af912005-12-17 12:21:26 +01001862
willy tarreau5cbea6f2005-12-17 12:48:26 +01001863 /* try headers regexps */
1864 if (t->proxy->nb_reqexp) {
1865 struct proxy *p = t->proxy;
1866 int exp;
1867 char term;
1868
1869 term = *ptr;
1870 *ptr = '\0';
1871 for (exp=0; exp < p->nb_reqexp; exp++) {
1872 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1873 if (p->req_exp[exp].replace != NULL) {
1874 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1875 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001876 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001877 else {
1878 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001879 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001880 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001881 }
1882 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001883 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001884 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001885
1886 /* now look for cookies */
1887 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1888 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1889 char *p1, *p2, *p3, *p4;
1890
1891 p1 = req->h + 8; /* first char after 'Cookie: ' */
1892
1893 while (p1 < ptr) {
1894 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1895 p1++;
1896
1897 if (p1 == ptr)
1898 break;
1899 else if (*p1 == ';') { /* next cookie */
1900 ++p1;
1901 continue;
1902 }
1903
1904 /* p1 is at the beginning of the cookie name */
1905 p2 = p1;
1906
1907 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1908 p2++;
1909
1910 if (p2 == ptr)
1911 break;
1912 else if (*p2 == ';') { /* next cookie */
1913 p1=++p2;
1914 continue;
1915 }
1916
1917 p3 = p2 + 1; /* skips the '=' sign */
1918 if (p3 == ptr)
1919 break;
1920
1921 p4=p3;
1922 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1923 p4++;
1924
1925 /* here, we have the cookie name between p1 and p2,
1926 * and its value between p3 and p4.
1927 * we can process it.
1928 */
1929
1930 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1931 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1932 /* Cool... it's the right one */
1933 struct server *srv = t->proxy->srv;
1934
1935 while (srv &&
1936 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1937 srv = srv->next;
1938 }
1939
1940 if (srv) { /* we found the server */
1941 t->flags |= TF_DIRECT;
1942 t->srv = srv;
1943 }
1944
1945 break;
1946 }
1947 else {
1948 // fprintf(stderr,"Ignoring unknown cookie : ");
1949 // write(2, p1, p2-p1);
1950 // fprintf(stderr," = ");
1951 // write(2, p3, p4-p3);
1952 // fprintf(stderr,"\n");
1953 }
1954 /* we'll have to look for another cookie ... */
1955 p1 = p4;
1956 } /* while (p1 < ptr) */
1957 } /* end of cookie processing */
1958
1959 /* let's look if we have to delete this header */
1960 if (delete_header) {
1961 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001962 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001963 req->h = req->lr;
1964 } /* while (req->lr < req->r) */
1965
1966 /* end of header processing (even if incomplete) */
1967
1968 if ((req->l < BUFSIZE - MAXREWRITE) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1969 FD_SET(t->cli_fd, StaticReadEvent);
1970 if (t->proxy->clitimeout)
1971 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1972 else
1973 tv_eternity(&t->crexpire);
1974 }
1975
1976 /* read timeout, read error, or last read : give up */
1977 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL ||
1978 tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1979 //FD_CLR(t->cli_fd, StaticReadEvent);
1980 //FD_CLR(t->cli_fd, StaticWriteEvent);
1981 tv_eternity(&t->crexpire);
1982 fd_delete(t->cli_fd);
1983 //close(t->cli_fd);
1984 t->cli_state = CL_STCLOSE;
1985 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001986 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001987// else if (t->res_cr == RES_SILENT) {
1988// return 0;
1989// }
1990
1991 if (req->l >= BUFSIZE - MAXREWRITE) {
1992 /* buffer full : stop reading till we free some space */
1993 FD_CLR(t->cli_fd, StaticReadEvent);
1994 tv_eternity(&t->crexpire);
1995 }
1996
1997 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01001998 }
1999 else if (c == CL_STDATA) {
2000 /* read or write error */
2001 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002002 tv_eternity(&t->crexpire);
2003 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002004 fd_delete(t->cli_fd);
2005 //FD_CLR(t->cli_fd, StaticReadEvent);
2006 //FD_CLR(t->cli_fd, StaticWriteEvent);
2007 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002008 t->cli_state = CL_STCLOSE;
2009 return 1;
2010 }
2011 /* read timeout, last read, or end of server write */
2012 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2013 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002014 FD_CLR(t->cli_fd, StaticReadEvent);
2015 // if (req->l == 0) /* nothing to write on the server side */
2016 // FD_CLR(t->srv_fd, StaticWriteEvent);
2017 tv_eternity(&t->crexpire);
2018 shutdown(t->cli_fd, SHUT_RD);
2019 t->cli_state = CL_STSHUTR;
2020 return 1;
2021 }
2022 /* write timeout, or last server read and buffer empty */
2023 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2024 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
2025
2026 FD_CLR(t->cli_fd, StaticWriteEvent);
2027 tv_eternity(&t->cwexpire);
2028 shutdown(t->cli_fd, SHUT_WR);
2029 t->cli_state = CL_STSHUTW;
2030 return 1;
2031 }
2032
2033 if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2034 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
2035 FD_CLR(t->cli_fd, StaticReadEvent);
2036 tv_eternity(&t->crexpire);
2037 }
2038 }
2039 else {
2040 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2041 FD_SET(t->cli_fd, StaticReadEvent);
2042 if (t->proxy->clitimeout)
2043 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2044 else
2045 tv_eternity(&t->crexpire);
2046 }
2047 }
2048
2049 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002051 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2052 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2053 tv_eternity(&t->cwexpire);
2054 }
2055 }
2056 else { /* buffer not empty */
2057 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2058 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2059 if (t->proxy->clitimeout)
2060 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2061 else
2062 tv_eternity(&t->cwexpire);
2063 }
2064 }
2065 return 0; /* other cases change nothing */
2066 }
2067 else if (c == CL_STSHUTR) {
2068 if ((t->res_cw == RES_ERROR) ||
2069 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2070 || (tv_cmp2_ms(&t->crexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002071 //FD_CLR(t->cli_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002072 tv_eternity(&t->cwexpire);
2073 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002074 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002075 t->cli_state = CL_STCLOSE;
2076 return 1;
2077 }
2078 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002079 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002080 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2081 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2082 tv_eternity(&t->cwexpire);
2083 }
2084 }
2085 else { /* buffer not empty */
2086 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2087 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2088 if (t->proxy->clitimeout)
2089 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2090 else
2091 tv_eternity(&t->cwexpire);
2092 }
2093 }
2094 return 0;
2095 }
2096 else if (c == CL_STSHUTW) {
2097 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
2098 s == SV_STCLOSE || tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002099 //FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002100 tv_eternity(&t->crexpire);
2101 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002102 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002103 t->cli_state = CL_STCLOSE;
2104 return 1;
2105 }
2106 else if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2107 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
2108 FD_CLR(t->cli_fd, StaticReadEvent);
2109 tv_eternity(&t->crexpire);
2110 }
2111 }
2112 else {
2113 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2114 FD_SET(t->cli_fd, StaticReadEvent);
2115 if (t->proxy->clitimeout)
2116 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2117 else
2118 tv_eternity(&t->crexpire);
2119 }
2120 }
2121 return 0;
2122 }
2123 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002124 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002125 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002126 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002127 write(1, trash, len);
2128 }
2129 return 0;
2130 }
2131 return 0;
2132}
2133
2134
2135/*
2136 * manages the server FSM and its socket. It returns 1 if a state has changed
2137 * (and a resync may be needed), 0 else.
2138 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002139int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002140 int s = t->srv_state;
2141 int c = t->cli_state;
2142 struct buffer *req = t->req;
2143 struct buffer *rep = t->rep;
2144
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2146 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2147 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2148 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2149 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002150 if (s == SV_STIDLE) {
2151 if (c == CL_STHEADERS)
2152 return 0; /* stay in idle, waiting for data to reach the client side */
2153 else if (c == CL_STCLOSE ||
2154 c == CL_STSHUTW ||
2155 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2156 tv_eternity(&t->cnexpire);
2157 t->srv_state = SV_STCLOSE;
2158 return 1;
2159 }
2160 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002161 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002162 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2163 t->srv_state = SV_STCONN;
2164 }
2165 else { /* try again */
2166 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002167 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2168 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2169 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2170 }
2171
2172 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002173 t->srv_state = SV_STCONN;
2174 break;
2175 }
2176 }
2177 if (t->conn_retries < 0) {
2178 /* if conn_retries < 0 or other error, let's abort */
2179 tv_eternity(&t->cnexpire);
2180 t->srv_state = SV_STCLOSE;
2181 }
2182 }
2183 return 1;
2184 }
2185 }
2186 else if (s == SV_STCONN) { /* connection in progress */
2187 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2188 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2189 return 0; /* nothing changed */
2190 }
2191 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2192 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2193 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002194 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002195 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002196 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002197 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002198 if (t->conn_retries >= 0) {
2199 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2200 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2201 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2202 }
2203 if (connect_server(t) == 0)
2204 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002205 }
2206 /* if conn_retries < 0 or other error, let's abort */
2207 tv_eternity(&t->cnexpire);
2208 t->srv_state = SV_STCLOSE;
2209 return 1;
2210 }
2211 else { /* no error or write 0 */
2212 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2213 if (req->l == 0) /* nothing to write */
2214 FD_CLR(t->srv_fd, StaticWriteEvent);
2215 else /* need the right to write */
2216 FD_SET(t->srv_fd, StaticWriteEvent);
2217
2218 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2219 FD_SET(t->srv_fd, StaticReadEvent);
2220 if (t->proxy->srvtimeout)
2221 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2222 else
2223 tv_eternity(&t->srexpire);
2224
2225 t->srv_state = SV_STDATA;
2226 }
2227 else
2228 t->srv_state = SV_STHEADERS;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002229 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002230 return 1;
2231 }
2232 }
2233 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002234
2235 /* now parse the partial (or complete) headers */
2236 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2237 char *ptr;
2238 int delete_header;
2239
2240 ptr = rep->lr;
2241
2242 /* look for the end of the current header */
2243 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2244 ptr++;
2245
2246 if (ptr == rep->h) {
2247 char newhdr[MAXREWRITE + 1];
2248 int line, len;
2249
2250 /* we can only get here after an end of headers */
2251 /* we'll have something else to do here : add new headers ... */
2252
2253 if ((t->srv) && !(t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
2254 /* the server is known, it's not the one the client requested, we have to
2255 * insert a set-cookie here.
2256 */
2257 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2258 t->proxy->cookie_name, t->srv->cookie);
2259 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2260 }
2261
2262 /* headers to be added */
2263 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2264 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2265 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2266 }
2267
2268 t->srv_state = SV_STDATA;
2269 break;
2270 }
2271
2272 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2273 if (ptr > rep->r - 2) {
2274 /* this is a partial header, let's wait for more to come */
2275 rep->lr = ptr;
2276 break;
2277 }
2278
2279 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2280 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2281
2282 /* now we know that *ptr is either \r or \n,
2283 * and that there are at least 1 char after it.
2284 */
2285 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2286 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2287 else
2288 rep->lr = ptr + 2; /* \r\n or \n\r */
2289
2290 /*
2291 * now we know that we have a full header ; we can do whatever
2292 * we want with these pointers :
2293 * rep->h = beginning of header
2294 * ptr = end of header (first \r or \n)
2295 * rep->lr = beginning of next line (next rep->h)
2296 * rep->r = end of data (not used at this stage)
2297 */
2298
2299 delete_header = 0;
2300
2301 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
2302 int len, max;
2303 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2304 max = ptr - rep->h;
2305 UBOUND(max, sizeof(trash) - len - 1);
2306 len += strlcpy(trash + len, rep->h, max + 1);
2307 trash[len++] = '\n';
2308 write(1, trash, len);
2309 }
2310
2311 /* try headers regexps */
2312 if (t->proxy->nb_rspexp) {
2313 struct proxy *p = t->proxy;
2314 int exp;
2315 char term;
2316
2317 term = *ptr;
2318 *ptr = '\0';
2319 for (exp=0; exp < p->nb_rspexp; exp++) {
2320 if (regexec(p->rsp_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2321 if (p->rsp_exp[exp].replace != NULL) {
2322 int len = exp_replace(trash, rep->h, p->rsp_exp[exp].replace, pmatch);
2323 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2324 }
2325 else {
2326 delete_header = 1;
2327 }
2328 break;
2329 }
2330 }
2331 *ptr = term; /* restore the string terminator */
2332 }
2333
2334 /* check for server cookies */
2335 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2336 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2337 char *p1, *p2, *p3, *p4;
2338
2339 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2340
2341 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2342 while (p1 < ptr && (isspace(*p1)))
2343 p1++;
2344
2345 if (p1 == ptr || *p1 == ';') /* end of cookie */
2346 break;
2347
2348 /* p1 is at the beginning of the cookie name */
2349 p2 = p1;
2350
2351 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2352 p2++;
2353
2354 if (p2 == ptr || *p2 == ';') /* next cookie */
2355 break;
2356
2357 p3 = p2 + 1; /* skips the '=' sign */
2358 if (p3 == ptr)
2359 break;
2360
2361 p4 = p3;
2362 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
2363 p4++;
2364
2365 /* here, we have the cookie name between p1 and p2,
2366 * and its value between p3 and p4.
2367 * we can process it.
2368 */
2369
2370 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2371 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2372 /* Cool... it's the right one */
2373
2374 /* If the cookie is in insert mode on a known server, we'll delete
2375 * this occurrence because we'll insert another one later.
2376 * We'll delete it too if the "indirect" option is set and we're in
2377 * a direct access. */
2378 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
2379 ((t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
2380 /* this header must be deleted */
2381 delete_header = 1;
2382 }
2383 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2384 /* replace bytes p3->p4 with the cookie name associated
2385 * with this server since we know it.
2386 */
2387 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2388 }
2389 break;
2390 }
2391 else {
2392 // fprintf(stderr,"Ignoring unknown cookie : ");
2393 // write(2, p1, p2-p1);
2394 // fprintf(stderr," = ");
2395 // write(2, p3, p4-p3);
2396 // fprintf(stderr,"\n");
2397 }
2398 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2399 } /* we're now at the end of the cookie value */
2400 } /* end of cookie processing */
2401
2402 /* let's look if we have to delete this header */
2403 if (delete_header) {
2404 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2405 }
2406 rep->h = rep->lr;
2407 } /* while (rep->lr < rep->r) */
2408
2409 /* end of header processing (even if incomplete) */
2410
2411 if ((rep->l < BUFSIZE - MAXREWRITE) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2412 FD_SET(t->srv_fd, StaticReadEvent);
2413 if (t->proxy->srvtimeout)
2414 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2415 else
2416 tv_eternity(&t->srexpire);
2417 }
willy tarreau0f7af912005-12-17 12:21:26 +01002418
2419 /* read or write error */
2420 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002421 tv_eternity(&t->srexpire);
2422 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002423 //FD_CLR(t->srv_fd, StaticReadEvent);
2424 //FD_CLR(t->srv_fd, StaticWriteEvent);
2425 //close(t->srv_fd);
2426 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002427 t->srv_state = SV_STCLOSE;
2428 return 1;
2429 }
2430 /* read timeout, last read, or end of client write */
2431 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
2432 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2433 FD_CLR(t->srv_fd, StaticReadEvent);
2434 tv_eternity(&t->srexpire);
2435 shutdown(t->srv_fd, SHUT_RD);
2436 t->srv_state = SV_STSHUTR;
2437 return 1;
2438
2439 }
2440 /* write timeout, or last client read and buffer empty */
2441 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2442 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2443 FD_CLR(t->srv_fd, StaticWriteEvent);
2444 tv_eternity(&t->swexpire);
2445 shutdown(t->srv_fd, SHUT_WR);
2446 t->srv_state = SV_STSHUTW;
2447 return 1;
2448 }
2449
2450 if (req->l == 0) {
2451 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2452 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2453 tv_eternity(&t->swexpire);
2454 }
2455 }
2456 else { /* client buffer not empty */
2457 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2458 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2459 if (t->proxy->srvtimeout)
2460 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2461 else
2462 tv_eternity(&t->swexpire);
2463 }
2464 }
2465
2466 if (rep->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2467 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2468 FD_CLR(t->srv_fd, StaticReadEvent);
2469 tv_eternity(&t->srexpire);
2470 }
2471 }
2472
willy tarreau5cbea6f2005-12-17 12:48:26 +01002473 /* be nice with the client side which would like to send a complete header
2474 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2475 * would read all remaining data at once ! The client should not write past rep->lr
2476 * when the server is in header state.
2477 */
2478 //return header_processed;
2479 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002480 }
2481 else if (s == SV_STDATA) {
2482 /* read or write error */
2483 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002484 tv_eternity(&t->srexpire);
2485 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002486 //FD_CLR(t->srv_fd, StaticReadEvent);
2487 //FD_CLR(t->srv_fd, StaticWriteEvent);
2488 //close(t->srv_fd);
2489 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002490 t->srv_state = SV_STCLOSE;
2491 return 1;
2492 }
2493 /* read timeout, last read, or end of client write */
2494 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
2495 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2496
2497 FD_CLR(t->srv_fd, StaticReadEvent);
2498 tv_eternity(&t->srexpire);
2499 shutdown(t->srv_fd, SHUT_RD);
2500 t->srv_state = SV_STSHUTR;
2501 return 1;
2502
2503 }
2504 /* write timeout, or last client read and buffer empty */
2505 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2506 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2507 FD_CLR(t->srv_fd, StaticWriteEvent);
2508 tv_eternity(&t->swexpire);
2509 shutdown(t->srv_fd, SHUT_WR);
2510 t->srv_state = SV_STSHUTW;
2511 return 1;
2512 }
2513 else if (req->l == 0) {
2514 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2515 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2516 tv_eternity(&t->swexpire);
2517 }
2518 }
2519 else { /* buffer not empty */
2520 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2521 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2522 if (t->proxy->srvtimeout)
2523 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2524 else
2525 tv_eternity(&t->swexpire);
2526 }
2527 }
2528
2529 if (rep->l == BUFSIZE) { /* no room to read more data */
2530 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2531 FD_CLR(t->srv_fd, StaticReadEvent);
2532 tv_eternity(&t->srexpire);
2533 }
2534 }
2535 else {
2536 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2537 FD_SET(t->srv_fd, StaticReadEvent);
2538 if (t->proxy->srvtimeout)
2539 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2540 else
2541 tv_eternity(&t->srexpire);
2542 }
2543 }
2544
2545 return 0; /* other cases change nothing */
2546 }
2547 else if (s == SV_STSHUTR) {
2548 if ((t->res_sw == RES_ERROR) ||
2549 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2550 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002551 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002552 tv_eternity(&t->swexpire);
2553 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002554 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002555 t->srv_state = SV_STCLOSE;
2556 return 1;
2557 }
2558 else if (req->l == 0) {
2559 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2560 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2561 tv_eternity(&t->swexpire);
2562 }
2563 }
2564 else { /* buffer not empty */
2565 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2566 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2567 if (t->proxy->srvtimeout)
2568 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2569 else
2570 tv_eternity(&t->swexpire);
2571 }
2572 }
2573 return 0;
2574 }
2575 else if (s == SV_STSHUTW) {
2576 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2577 c == CL_STSHUTW || c == CL_STCLOSE ||
2578 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002579 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002580 tv_eternity(&t->srexpire);
2581 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002582 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002583 t->srv_state = SV_STCLOSE;
2584 return 1;
2585 }
2586 else if (rep->l == BUFSIZE) { /* no room to read more data */
2587 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2588 FD_CLR(t->srv_fd, StaticReadEvent);
2589 tv_eternity(&t->srexpire);
2590 }
2591 }
2592 else {
2593 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2594 FD_SET(t->srv_fd, StaticReadEvent);
2595 if (t->proxy->srvtimeout)
2596 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2597 else
2598 tv_eternity(&t->srexpire);
2599 }
2600 }
2601 return 0;
2602 }
2603 else { /* SV_STCLOSE : nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002604 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002605 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002606 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002607 write(1, trash, len);
2608 }
2609 return 0;
2610 }
2611 return 0;
2612}
2613
2614
willy tarreau5cbea6f2005-12-17 12:48:26 +01002615/* Processes the client and server jobs of a session task, then
2616 * puts it back to the wait queue in a clean state, or
2617 * cleans up its resources if it must be deleted. Returns
2618 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01002619 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620int process_session(struct task *t) {
2621 struct session *s = t->context;
2622 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002623
willy tarreau5cbea6f2005-12-17 12:48:26 +01002624 do {
2625 fsm_resync = 0;
2626 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2627 fsm_resync |= process_cli(s);
2628 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2629 fsm_resync |= process_srv(s);
2630 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2631 } while (fsm_resync);
2632
2633 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002634 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002635 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01002636
willy tarreau5cbea6f2005-12-17 12:48:26 +01002637 tv_min(&min1, &s->crexpire, &s->cwexpire);
2638 tv_min(&min2, &s->srexpire, &s->swexpire);
2639 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002640 tv_min(&t->expire, &min1, &min2);
2641
2642 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002643 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01002644
willy tarreau5cbea6f2005-12-17 12:48:26 +01002645 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01002646 }
2647
willy tarreau5cbea6f2005-12-17 12:48:26 +01002648 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01002649 actconn--;
2650
willy tarreau5cbea6f2005-12-17 12:48:26 +01002651 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002652 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002653 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002654 write(1, trash, len);
2655 }
2656
2657 /* the task MUST not be in the run queue anymore */
2658 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002659 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01002660 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002661 return -1; /* rest in peace for eternity */
2662}
2663
2664
2665
2666/*
2667 * manages a server health-check. Returns
2668 * the time the task accepts to wait, or -1 for infinity.
2669 */
2670int process_chk(struct task *t) {
2671 struct server *s = t->context;
2672 int fd = s->curfd;
2673 int one = 1;
2674
2675 //fprintf(stderr, "process_chk: 1\n");
2676
2677 if (fd < 0) { /* no check currently running */
2678 //fprintf(stderr, "process_chk: 2\n");
2679 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
2680 task_queue(t); /* restore t to its place in the task list */
2681 return tv_remain(&now, &t->expire);
2682 }
2683
2684 /* we'll initiate a new check */
2685 s->result = 0; /* no result yet */
2686 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
2687 if ((fd < cfg_maxsock) &&
2688 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
2689 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
2690 //fprintf(stderr, "process_chk: 3\n");
2691
2692 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
2693 /* OK, connection in progress or established */
2694
2695 //fprintf(stderr, "process_chk: 4\n");
2696
2697 s->curfd = fd; /* that's how we know a test is in progress ;-) */
2698 fdtab[fd].owner = t;
2699 fdtab[fd].read = NULL;
2700 fdtab[fd].write = &event_srv_hck;
2701 fdtab[fd].state = FD_STCONN; /* connection in progress */
2702 FD_SET(fd, StaticWriteEvent); /* for connect status */
2703 fd_insert(fd);
2704 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2705 task_queue(t); /* restore t to its place in the task list */
2706 return tv_remain(&now, &t->expire);
2707 }
2708 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
2709 s->result = -1; /* a real error */
2710 }
2711 }
2712 //fprintf(stderr, "process_chk: 5\n");
2713 close(fd);
2714 }
2715
2716 if (!s->result) { /* nothing done */
2717 //fprintf(stderr, "process_chk: 6\n");
2718 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2719 task_queue(t); /* restore t to its place in the task list */
2720 return tv_remain(&now, &t->expire);
2721 }
2722
2723 /* here, we have seen a failure */
2724 if (s->health > FALLTIME)
2725 s->health--; /* still good */
2726 else {
2727 s->health = 0; /* failure */
2728 s->state &= ~SRV_RUNNING;
2729 }
2730
2731 //fprintf(stderr, "process_chk: 7\n");
2732 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2733 }
2734 else {
2735 //fprintf(stderr, "process_chk: 8\n");
2736 /* there was a test running */
2737 if (s->result > 0) { /* good server detected */
2738 //fprintf(stderr, "process_chk: 9\n");
2739 s->health++; /* was bad, stays for a while */
2740 if (s->health >= FALLTIME) {
2741 s->health = FALLTIME + RISETIME -1; /* OK now */
2742 s->state |= SRV_RUNNING;
2743 }
2744 s->curfd = -1;
2745 FD_CLR(fd, StaticWriteEvent);
2746 fd_delete(fd);
2747 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2748 }
2749 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
2750 //fprintf(stderr, "process_chk: 10\n");
2751 /* failure or timeout detected */
2752 if (s->health > FALLTIME)
2753 s->health--; /* still good */
2754 else {
2755 s->health = 0; /* failure */
2756 s->state &= ~SRV_RUNNING;
2757 }
2758 s->curfd = -1;
2759 FD_CLR(fd, StaticWriteEvent);
2760 fd_delete(fd);
2761 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2762 }
2763 /* if result is 0 and there's no timeout, we have to wait again */
2764 }
2765 //fprintf(stderr, "process_chk: 11\n");
2766 s->result = 0;
2767 task_queue(t); /* restore t to its place in the task list */
2768 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01002769}
2770
2771
willy tarreau5cbea6f2005-12-17 12:48:26 +01002772
willy tarreau0f7af912005-12-17 12:21:26 +01002773#if STATTIME > 0
2774int stats(void);
2775#endif
2776
2777/*
2778 * Main select() loop.
2779 */
2780
2781void select_loop() {
2782 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01002783 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01002784 int status;
2785 int fd,i;
2786 struct timeval delta;
2787 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002788 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01002789
willy tarreau5cbea6f2005-12-17 12:48:26 +01002790 tv_now(&now);
2791
2792 while (1) {
2793 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01002794
willy tarreau5cbea6f2005-12-17 12:48:26 +01002795 /* look for expired tasks and add them to the run queue.
2796 */
2797 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
2798 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
2799 tnext = t->next;
2800
2801 /* wakeup expired entries. It doesn't matter if they are
2802 * already running because of a previous event
2803 */
2804 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
2805 task_wakeup(&rq, t);
2806 }
2807 else {
2808 break;
2809 }
2810 }
2811
2812 /* process each task in the run queue now. Each task may be deleted
2813 * since we only use tnext.
2814 */
2815 tnext = rq;
2816 while ((t = tnext) != NULL) {
2817 int temp_time;
2818
2819 tnext = t->rqnext;
2820 task_sleep(&rq, t);
2821
2822 temp_time = t->process(t);
2823 next_time = MINTIME(temp_time, next_time);
2824 }
2825
2826
2827 /* maintain all proxies in a consistent state. This should quickly become a task */
2828 time2 = maintain_proxies();
2829 next_time = MINTIME(time2, next_time);
2830
2831 /* stop when there's no connection left and we don't allow them anymore */
2832 if (!actconn && listeners == 0)
2833 break;
2834
willy tarreau0f7af912005-12-17 12:21:26 +01002835
2836#if STATTIME > 0
2837 time2 = stats();
2838 // fprintf(stderr," stats = %d\n", time2);
2839 next_time = MINTIME(time2, next_time);
2840#endif
2841
willy tarreau5cbea6f2005-12-17 12:48:26 +01002842 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01002843 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002844 /* to avoid eventual select loops due to timer precision */
2845 next_time += SCHEDULER_RESOLUTION;
2846 delta.tv_sec = next_time / 1000;
2847 delta.tv_usec = (next_time % 1000) * 1000;
2848 }
2849 else if (next_time == 0) { /* allow select to return immediately when needed */
2850 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002851 }
2852
2853
2854 /* let's restore fdset state */
2855
2856 readnotnull = 0; writenotnull = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002857 for (i = 0; i < (cfg_maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01002858 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2859 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2860 }
2861
2862// /* just a verification code, needs to be removed for performance */
2863// for (i=0; i<maxfd; i++) {
2864// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2865// abort();
2866// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2867// abort();
2868//
2869// }
2870
2871 status=select(maxfd,
2872 readnotnull ? ReadEvent : NULL,
2873 writenotnull ? WriteEvent : NULL,
2874 NULL,
2875 (next_time >= 0) ? &delta : NULL);
2876
willy tarreau5cbea6f2005-12-17 12:48:26 +01002877 /* this is an experiment on the separation of the select work */
2878 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2879 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2880
willy tarreau0f7af912005-12-17 12:21:26 +01002881 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002882
willy tarreau0f7af912005-12-17 12:21:26 +01002883 if (status > 0) { /* must proceed with events */
2884
2885 int fds;
2886 char count;
2887
2888 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2889 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2890 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2891
willy tarreau5cbea6f2005-12-17 12:48:26 +01002892 /* if we specify read first, the accepts and zero reads will be
2893 * seen first. Moreover, system buffers will be flushed faster.
2894 */
willy tarreau0f7af912005-12-17 12:21:26 +01002895 if (fdtab[fd].state == FD_STCLOSE)
2896 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002897
2898 if (FD_ISSET(fd, ReadEvent))
2899 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002900
2901 if (fdtab[fd].state == FD_STCLOSE)
2902 continue;
2903
2904 if (FD_ISSET(fd, WriteEvent))
2905 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002906 }
2907 }
2908 else {
2909 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2910 }
willy tarreau0f7af912005-12-17 12:21:26 +01002911 }
2912}
2913
2914
2915#if STATTIME > 0
2916/*
2917 * Display proxy statistics regularly. It is designed to be called from the
2918 * select_loop().
2919 */
2920int stats(void) {
2921 static int lines;
2922 static struct timeval nextevt;
2923 static struct timeval lastevt;
2924 static struct timeval starttime = {0,0};
2925 unsigned long totaltime, deltatime;
2926 int ret;
2927
2928 if (tv_remain(&now, &nextevt) == 0) {
2929 deltatime = (tv_delta(&now, &lastevt)?:1);
2930 totaltime = (tv_delta(&now, &starttime)?:1);
2931
2932 if (mode & MODE_STATS) {
2933 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002934 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01002935 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2936 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01002938 actconn, totalconn,
2939 stats_tsk_new, stats_tsk_good,
2940 stats_tsk_left, stats_tsk_right,
2941 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2942 }
2943 }
2944
2945 tv_delayfrom(&nextevt, &now, STATTIME);
2946
2947 lastevt=now;
2948 }
2949 ret = tv_remain(&now, &nextevt);
2950 return ret;
2951}
2952#endif
2953
2954
2955/*
2956 * this function enables proxies when there are enough free sessions,
2957 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01002958 * select_loop(). It returns the time left before next expiration event
2959 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01002960 */
2961static int maintain_proxies(void) {
2962 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002963 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01002964
2965 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002966 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01002967
2968 /* if there are enough free sessions, we'll activate proxies */
2969 if (actconn < cfg_maxconn) {
2970 while (p) {
2971 if (p->nbconn < p->maxconn) {
2972 if (p->state == PR_STIDLE) {
2973 FD_SET(p->listen_fd, StaticReadEvent);
2974 p->state = PR_STRUN;
2975 }
2976 }
2977 else {
2978 if (p->state == PR_STRUN) {
2979 FD_CLR(p->listen_fd, StaticReadEvent);
2980 p->state = PR_STIDLE;
2981 }
2982 }
2983 p = p->next;
2984 }
2985 }
2986 else { /* block all proxies */
2987 while (p) {
2988 if (p->state == PR_STRUN) {
2989 FD_CLR(p->listen_fd, StaticReadEvent);
2990 p->state = PR_STIDLE;
2991 }
2992 p = p->next;
2993 }
2994 }
2995
willy tarreau5cbea6f2005-12-17 12:48:26 +01002996 if (stopping) {
2997 p = proxy;
2998 while (p) {
2999 if (p->state != PR_STDISABLED) {
3000 int t;
3001 t = tv_remain(&now, &p->stop_time);
3002 if (t == 0) {
3003 //FD_CLR(p->listen_fd, StaticReadEvent);
3004 //close(p->listen_fd);
3005 fd_delete(p->listen_fd);
3006 p->state = PR_STDISABLED;
3007 listeners--;
3008 }
3009 else {
3010 tleft = MINTIME(t, tleft);
3011 }
3012 }
3013 p = p->next;
3014 }
3015 }
3016 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003017}
3018
3019/*
3020 * this function disables health-check servers so that the process will quickly be ignored
3021 * by load balancers.
3022 */
3023static void soft_stop(void) {
3024 struct proxy *p;
3025
3026 stopping = 1;
3027 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003028 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003029 while (p) {
3030 if (p->state != PR_STDISABLED)
3031 tv_delayfrom(&p->stop_time, &now, p->grace);
3032 p = p->next;
3033 }
3034}
3035
3036/*
3037 * upon SIGUSR1, let's have a soft stop.
3038 */
3039void sig_soft_stop(int sig) {
3040 soft_stop();
3041 signal(sig, SIG_IGN);
3042}
3043
3044
3045void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003046 struct task *t, *tnext;
3047 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003048
willy tarreau5cbea6f2005-12-17 12:48:26 +01003049 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3050 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3051 tnext = t->next;
3052 s = t->context;
3053 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3054 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3055 "req=%d, rep=%d, clifd=%d\n",
3056 s, tv_remain(&now, &t->expire),
3057 s->cli_state,
3058 s->srv_state,
3059 FD_ISSET(s->cli_fd, StaticReadEvent),
3060 FD_ISSET(s->cli_fd, StaticWriteEvent),
3061 FD_ISSET(s->srv_fd, StaticReadEvent),
3062 FD_ISSET(s->srv_fd, StaticWriteEvent),
3063 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3064 );
willy tarreau0f7af912005-12-17 12:21:26 +01003065 }
3066}
3067
3068/*
3069 * This function reads and parses the configuration file given in the argument.
3070 * returns 0 if OK, -1 if error.
3071 */
3072int readcfgfile(char *file) {
3073 char thisline[256];
3074 char *line;
3075 FILE *f;
3076 int linenum = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003077 char *end;
3078 char *args[MAX_LINE_ARGS];
willy tarreau0f7af912005-12-17 12:21:26 +01003079 int arg;
3080 int cfgerr = 0;
3081
3082 struct proxy *curproxy = NULL;
3083 struct server *newsrv = NULL;
3084
3085 if ((f=fopen(file,"r")) == NULL)
3086 return -1;
3087
3088 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
3089 linenum++;
willy tarreau0f7af912005-12-17 12:21:26 +01003090
willy tarreau5cbea6f2005-12-17 12:48:26 +01003091 end = line + strlen(line);
willy tarreau0f7af912005-12-17 12:21:26 +01003092
willy tarreau5cbea6f2005-12-17 12:48:26 +01003093 /* skip leading spaces */
3094 while (isspace(*line))
3095 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01003096
willy tarreau5cbea6f2005-12-17 12:48:26 +01003097 arg = 0;
3098 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01003099
willy tarreau5cbea6f2005-12-17 12:48:26 +01003100 while (*line && arg < MAX_LINE_ARGS) {
3101 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
3102 * C equivalent value. Other combinations left unchanged (eg: \1).
3103 */
3104 if (*line == '\\') {
3105 int skip = 0;
3106 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
3107 *line = line[1];
3108 skip = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003109 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003110 else if (line[1] == 'r') {
3111 *line = '\r';
3112 skip = 1;
3113 }
3114 else if (line[1] == 'n') {
3115 *line = '\n';
3116 skip = 1;
3117 }
3118 else if (line[1] == 't') {
3119 *line = '\t';
3120 skip = 1;
3121 }
3122 else if (line[1] == 'x' && (line + 3 < end )) {
3123 unsigned char hex1, hex2;
3124 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
3125 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3126 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3127 *line = (hex1<<4) + hex2;
3128 skip = 3;
3129 }
3130 if (skip) {
3131 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
3132 end -= skip;
3133 }
willy tarreau0f7af912005-12-17 12:21:26 +01003134 line++;
3135 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003136 else {
3137 if (*line == '#' || *line == '\n' || *line == '\r')
3138 *line = 0; /* end of string, end of loop */
3139 else
willy tarreau0f7af912005-12-17 12:21:26 +01003140 line++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003141
3142 /* a non-escaped space is an argument separator */
3143 if (isspace(*line)) {
3144 *line++ = 0;
3145 while (isspace(*line))
3146 line++;
3147 args[++arg] = line;
3148 }
willy tarreau0f7af912005-12-17 12:21:26 +01003149 }
3150 }
3151
willy tarreau5cbea6f2005-12-17 12:48:26 +01003152 /* empty line */
3153 if (!**args)
3154 continue;
3155
3156 /* zero out remaining args */
3157 while (++arg < MAX_LINE_ARGS) {
3158 args[arg] = line;
3159 }
3160
willy tarreau0f7af912005-12-17 12:21:26 +01003161 if (!strcmp(args[0], "listen")) { /* new proxy */
3162 if (strchr(args[2], ':') == NULL) {
3163 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3164 file, linenum);
3165 return -1;
3166 }
3167
3168 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
3169 == NULL) {
3170 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3171 exit(1);
3172 }
3173 curproxy->next = proxy;
3174 proxy = curproxy;
3175 curproxy->id = strdup(args[1]);
3176 curproxy->listen_addr = *str2sa(args[2]);
3177 curproxy->state = PR_STNEW;
willy tarreau0f7af912005-12-17 12:21:26 +01003178 /* set default values */
3179 curproxy->maxconn = cfg_maxpconn;
3180 curproxy->conn_retries = CONN_RETRIES;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003181 curproxy->options = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003182 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3183 curproxy->mode = PR_MODE_TCP;
3184 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3185 continue;
3186 }
3187 else if (curproxy == NULL) {
3188 Alert("parsing [%s:%d] : <listen> expected.\n",
3189 file, linenum);
3190 return -1;
3191 }
3192
3193 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3194 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3195 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3196 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3197 else {
3198 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3199 return -1;
3200 }
3201 }
3202 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3203 curproxy->state = PR_STDISABLED;
3204 }
3205 else if (!strcmp(args[0], "cookie")) { /* cookie name */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003206 int cur_arg;
willy tarreau0f7af912005-12-17 12:21:26 +01003207 if (curproxy->cookie_name != NULL) {
3208 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3209 file, linenum);
3210 continue;
3211 }
3212
3213 if (*(args[1]) == 0) {
3214 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3215 file, linenum);
3216 return -1;
3217 }
3218 curproxy->cookie_name = strdup(args[1]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003219
3220 cur_arg = 2;
3221 while (*(args[cur_arg])) {
3222 if (!strcmp(args[cur_arg], "rewrite")) {
3223 curproxy->options |= PR_O_COOK_RW;
3224 }
3225 else if (!strcmp(args[cur_arg], "indirect")) {
3226 curproxy->options |= PR_O_COOK_IND;
3227 }
3228 else if (!strcmp(args[cur_arg], "insert")) {
3229 curproxy->options |= PR_O_COOK_INS;
3230 }
3231 else {
3232 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
3233 file, linenum);
3234 return -1;
3235 }
3236 cur_arg++;
3237 }
3238 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3239 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3240 file, linenum);
3241 return -1;
3242 }
willy tarreau0f7af912005-12-17 12:21:26 +01003243 }
3244 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3245 if (curproxy->contimeout != 0) {
3246 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
3247 file, linenum);
3248 continue;
3249 }
3250 if (*(args[1]) == 0) {
3251 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3252 file, linenum);
3253 return -1;
3254 }
3255 curproxy->contimeout = atol(args[1]);
3256 }
3257 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3258 if (curproxy->clitimeout != 0) {
3259 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3260 file, linenum);
3261 continue;
3262 }
3263 if (*(args[1]) == 0) {
3264 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3265 file, linenum);
3266 return -1;
3267 }
3268 curproxy->clitimeout = atol(args[1]);
3269 }
3270 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3271 if (curproxy->srvtimeout != 0) {
3272 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
3273 file, linenum);
3274 continue;
3275 }
3276 if (*(args[1]) == 0) {
3277 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
3278 file, linenum);
3279 return -1;
3280 }
3281 curproxy->srvtimeout = atol(args[1]);
3282 }
3283 else if (!strcmp(args[0], "retries")) { /* connection retries */
3284 if (*(args[1]) == 0) {
3285 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3286 file, linenum);
3287 return -1;
3288 }
3289 curproxy->conn_retries = atol(args[1]);
3290 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003291 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3292 /* enable reconnections to dispatch */
3293 curproxy->options |= PR_O_REDISP;
willy tarreau0f7af912005-12-17 12:21:26 +01003294 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003295#ifdef TRANSPARENT
3296 else if (!strcmp(args[0], "transparent")) {
3297 /* enable transparent proxy connections */
3298 curproxy->options |= PR_O_TRANSP;
3299 }
3300#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003301 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3302 if (*(args[1]) == 0) {
3303 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
3304 file, linenum);
3305 return -1;
3306 }
3307 curproxy->maxconn = atol(args[1]);
3308 }
3309 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3310 if (*(args[1]) == 0) {
3311 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
3312 file, linenum);
3313 return -1;
3314 }
3315 curproxy->grace = atol(args[1]);
3316 }
3317 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3318 if (strchr(args[1], ':') == NULL) {
3319 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
3320 file, linenum);
3321 return -1;
3322 }
3323 curproxy->dispatch_addr = *str2sa(args[1]);
3324 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003325 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3326 if (*(args[1])) {
3327 if (!strcmp(args[1], "roundrobin")) {
3328 curproxy->options |= PR_O_BALANCE_RR;
3329 }
3330 else {
3331 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n",
3332 file, linenum);
3333 return -1;
3334 }
3335 }
3336 else /* if no option is set, use round-robin by default */
3337 curproxy->options |= PR_O_BALANCE_RR;
3338 }
willy tarreau0f7af912005-12-17 12:21:26 +01003339 else if (!strcmp(args[0], "server")) { /* server address */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003340 int cur_arg;
3341
willy tarreau0f7af912005-12-17 12:21:26 +01003342 if (strchr(args[2], ':') == NULL) {
3343 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3344 file, linenum);
3345 return -1;
3346 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003347 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3348 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003349 exit(1);
3350 }
3351 newsrv->next = curproxy->srv;
3352 curproxy->srv = newsrv;
3353 newsrv->id = strdup(args[1]);
3354 newsrv->addr = *str2sa(args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003355 newsrv->state = SRV_RUNNING; /* early server setup */
3356 newsrv->health = FALLTIME; /* up, but will fall down at first failure */
3357 newsrv->curfd = -1; /* no health-check in progress */
3358 cur_arg = 3;
3359 while (*args[cur_arg]) {
3360 if (!strcmp(args[cur_arg], "cookie")) {
3361 newsrv->cookie = strdup(args[cur_arg + 1]);
3362 newsrv->cklen = strlen(args[cur_arg + 1]);
3363 cur_arg += 2;
3364 }
3365 else if (!strcmp(args[cur_arg], "check")) {
3366 struct task *t;
3367
3368 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3369 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3370 return -1;
3371 }
3372
3373 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3374 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3375 t->state = TASK_IDLE;
3376 t->process = process_chk;
3377 t->context = newsrv;
3378
3379 tv_delayfrom(&t->expire, &now, CHK_INTERVAL); /* check this every ms */
3380 task_queue(t);
3381 task_wakeup(&rq, t);
3382
3383 cur_arg += 1;
3384 }
3385 else {
3386 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3387 file, linenum, newsrv->id);
3388 return -1;
3389 }
3390 }
3391 curproxy->nbservers++;
willy tarreau0f7af912005-12-17 12:21:26 +01003392 }
3393 else if (!strcmp(args[0], "log")) { /* syslog server address */
3394 struct sockaddr_in *sa;
3395 int facility;
3396
3397 if (*(args[1]) == 0 || *(args[2]) == 0) {
3398 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
3399 file, linenum);
3400 return -1;
3401 }
3402
3403 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3404 if (!strcmp(log_facilities[facility], args[2]))
3405 break;
3406
3407 if (facility >= NB_LOG_FACILITIES) {
3408 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3409 exit(1);
3410 }
3411
3412 sa = str2sa(args[1]);
3413 if (!sa->sin_port)
3414 sa->sin_port = htons(SYSLOG_PORT);
3415
3416 if (curproxy->logfac1 == -1) {
3417 curproxy->logsrv1 = *sa;
3418 curproxy->logfac1 = facility;
3419 }
3420 else if (curproxy->logfac2 == -1) {
3421 curproxy->logsrv2 = *sa;
3422 curproxy->logfac2 = facility;
3423 }
3424 else {
3425 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3426 exit(1);
3427 }
3428
3429 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003430 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003431 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003432 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3433 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003434 file, linenum);
3435 continue;
3436 }
3437
3438 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003439 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003440 file, linenum);
3441 return -1;
3442 }
3443
3444 preg = calloc(1, sizeof(regex_t));
3445 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3446 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3447 return -1;
3448 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003449 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3450 curproxy->req_exp[curproxy->nb_reqexp].replace = strdup(args[2]);
3451 curproxy->nb_reqexp++;
willy tarreau0f7af912005-12-17 12:21:26 +01003452 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003453 else if (!strcmp(args[0], "reqdel")) { /* delete 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",
3457 file, linenum);
3458 continue;
3459 }
3460
3461 if (*(args[1]) == 0) {
3462 Alert("parsing [%s:%d] : <reqdel> expects <search> as an argument.\n",
3463 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 }
3472 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3473 curproxy->req_exp[curproxy->nb_reqexp].replace = NULL; /* means it must be deleted */
3474 curproxy->nb_reqexp++;
3475 }
3476 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3477 if (curproxy->nb_reqadd >= MAX_REGEXP) {
3478 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
3479 file, linenum);
3480 continue;
3481 }
3482
3483 if (*(args[1]) == 0) {
3484 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n",
3485 file, linenum);
3486 return -1;
3487 }
3488
3489 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
3490 }
3491 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3492 regex_t *preg;
3493 if (curproxy->nb_rspexp >= MAX_REGEXP) {
willy tarreau0f7af912005-12-17 12:21:26 +01003494 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3495 file, linenum);
3496 continue;
3497 }
3498
3499 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003500 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003501 file, linenum);
3502 return -1;
3503 }
3504
3505 preg = calloc(1, sizeof(regex_t));
3506 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3507 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3508 return -1;
3509 }
3510 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003511 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3512 curproxy->rsp_exp[curproxy->nb_rspexp].replace = strdup(args[2]);
3513 curproxy->nb_rspexp++;
3514 }
3515 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3516 regex_t *preg;
3517 if (curproxy->nb_rspexp >= MAX_REGEXP) {
3518 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3519 file, linenum);
3520 continue;
3521 }
3522
3523 if (*(args[1]) == 0) {
3524 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n",
3525 file, linenum);
3526 return -1;
3527 }
3528
3529 preg = calloc(1, sizeof(regex_t));
3530 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3531 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3532 return -1;
3533 }
3534 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
3535 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3536 curproxy->rsp_exp[curproxy->nb_rspexp].replace = NULL; /* means it must be deleted */
3537 curproxy->nb_rspexp++;
3538 }
3539 else if (!strcmp(args[0], "rspadd")) { /* add response header */
3540 if (curproxy->nb_rspadd >= 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] : <rspadd> expects <header> as an argument.\n",
3548 file, linenum);
3549 return -1;
3550 }
3551
3552 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01003553 }
3554 else {
3555 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
3556 exit(1);
3557 }
3558 }
3559 fclose(f);
3560
3561 /*
3562 * Now, check for the integrity of all that we have collected.
3563 */
3564
3565 if ((curproxy = proxy) == NULL) {
3566 Alert("parsing %s : no <listen> line. Nothing to do !\n",
3567 file);
3568 return -1;
3569 }
3570
3571 while (curproxy != NULL) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003572 if ((curproxy->mode != PR_MODE_HEALTH) &&
3573 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
3574 (*(int *)&curproxy->dispatch_addr == 0)) {
3575 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
3576 file, curproxy->id);
3577 cfgerr++;
3578 }
3579 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
3580 if (curproxy->options & PR_O_TRANSP) {
3581 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
3582 file, curproxy->id);
3583 cfgerr++;
3584 }
3585 else if (curproxy->srv == NULL) {
3586 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
3587 file, curproxy->id);
3588 cfgerr++;
3589 }
3590 else if (*(int *)&curproxy->dispatch_addr != 0) {
3591 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
3592 file, curproxy->id);
3593 }
3594 }
3595 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01003596 if (curproxy->cookie_name != NULL) {
3597 Warning("parsing %s : cookie will be ignored for listener %s.\n",
3598 file, curproxy->id);
3599 }
3600 if ((newsrv = curproxy->srv) != NULL) {
3601 Warning("parsing %s : servers will be ignored for listener %s.\n",
3602 file, curproxy->id);
3603 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003604 if (curproxy->nb_rspexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003605 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
3606 file, curproxy->id);
3607 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003608 if (curproxy->nb_reqexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003609 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
3610 file, curproxy->id);
3611 }
3612 }
3613 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
3614 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
3615 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
3616 file, curproxy->id);
3617 cfgerr++;
3618 }
3619 else {
3620 while (newsrv != NULL) {
3621 /* nothing to check for now */
3622 newsrv = newsrv->next;
3623 }
3624 }
3625 }
3626 curproxy = curproxy->next;
3627 }
3628 if (cfgerr > 0) {
3629 Alert("Errors found in configuration file, aborting.\n");
3630 return -1;
3631 }
3632 else
3633 return 0;
3634}
3635
3636
3637/*
3638 * This function initializes all the necessary variables. It only returns
3639 * if everything is OK. If something fails, it exits.
3640 */
3641void init(int argc, char **argv) {
3642 int i;
3643 char *old_argv = *argv;
3644 char *tmp;
3645
3646 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003647 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003648 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
3649 sizeof(int)*8);
3650 exit(1);
3651 }
3652
3653 pid = getpid();
3654 progname = *argv;
3655 while ((tmp = strchr(progname, '/')) != NULL)
3656 progname = tmp + 1;
3657
3658 argc--; argv++;
3659 while (argc > 0) {
3660 char *flag;
3661
3662 if (**argv == '-') {
3663 flag = *argv+1;
3664
3665 /* 1 arg */
3666 if (*flag == 'v') {
3667 display_version();
3668 exit(0);
3669 }
3670 else if (*flag == 'd')
3671 mode |= MODE_DEBUG;
3672 else if (*flag == 'D')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003673 mode |= MODE_DAEMON | MODE_QUIET;
3674 else if (*flag == 'q')
3675 mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01003676#if STATTIME > 0
3677 else if (*flag == 's')
3678 mode |= MODE_STATS;
3679 else if (*flag == 'l')
3680 mode |= MODE_LOG;
3681#endif
3682 else { /* >=2 args */
3683 argv++; argc--;
3684 if (argc == 0)
3685 usage(old_argv);
3686
3687 switch (*flag) {
3688 case 'n' : cfg_maxconn = atol(*argv); break;
3689 case 'N' : cfg_maxpconn = atol(*argv); break;
3690 case 'f' : cfg_cfgfile = *argv; break;
3691 default: usage(old_argv);
3692 }
3693 }
3694 }
3695 else
3696 usage(old_argv);
3697 argv++; argc--;
3698 }
3699
3700 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
3701
3702 if (!cfg_cfgfile)
3703 usage(old_argv);
3704
3705 gethostname(hostname, MAX_HOSTNAME_LEN);
3706
3707 if (readcfgfile(cfg_cfgfile) < 0) {
3708 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
3709 exit(1);
3710 }
3711
3712 ReadEvent = (fd_set *)calloc(1,
3713 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003714 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003715 WriteEvent = (fd_set *)calloc(1,
3716 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003717 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003718 StaticReadEvent = (fd_set *)calloc(1,
3719 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003720 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003721 StaticWriteEvent = (fd_set *)calloc(1,
3722 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003723 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003724
3725 fdtab = (struct fdtab *)calloc(1,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003726 sizeof(struct fdtab) * (cfg_maxsock));
3727 for (i = 0; i < cfg_maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003728 fdtab[i].state = FD_STCLOSE;
3729 }
3730}
3731
3732/*
3733 * this function starts all the proxies. It returns 0 if OK, -1 if not.
3734 */
3735int start_proxies() {
3736 struct proxy *curproxy;
3737 int one = 1;
3738 int fd;
3739
3740 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
3741
3742 if (curproxy->state == PR_STDISABLED)
3743 continue;
3744
3745 if ((fd = curproxy->listen_fd =
3746 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
3747 Alert("cannot create listening socket for proxy %s. Aborting.\n",
3748 curproxy->id);
3749 return -1;
3750 }
3751
willy tarreau5cbea6f2005-12-17 12:48:26 +01003752 if (fd >= cfg_maxsock) {
3753 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
3754 curproxy->id);
3755 close(fd);
3756 return -1;
3757 }
3758
willy tarreau0f7af912005-12-17 12:21:26 +01003759 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
3760 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
3761 (char *) &one, sizeof(one)) == -1)) {
3762 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
3763 curproxy->id);
3764 close(fd);
3765 return -1;
3766 }
3767
3768 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
3769 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
3770 curproxy->id);
3771 }
3772
3773 if (bind(fd,
3774 (struct sockaddr *)&curproxy->listen_addr,
3775 sizeof(curproxy->listen_addr)) == -1) {
3776 Alert("cannot bind socket for proxy %s. Aborting.\n",
3777 curproxy->id);
3778 close(fd);
3779 return -1;
3780 }
3781
3782 if (listen(fd, curproxy->maxconn) == -1) {
3783 Alert("cannot listen to socket for proxy %s. Aborting.\n",
3784 curproxy->id);
3785 close(fd);
3786 return -1;
3787 }
3788
3789 /* the function for the accept() event */
3790 fdtab[fd].read = &event_accept;
3791 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003792 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01003793 curproxy->state = PR_STRUN;
3794 fdtab[fd].state = FD_STLISTEN;
3795 FD_SET(fd, StaticReadEvent);
3796 fd_insert(fd);
3797 listeners++;
3798// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3799 }
3800 return 0;
3801}
3802
3803
3804int main(int argc, char **argv) {
3805 init(argc, argv);
3806
3807 if (mode & MODE_DAEMON) {
3808 int ret;
3809
3810 ret = fork();
3811
3812 if (ret > 0)
3813 exit(0); /* parent must leave */
3814 else if (ret < 0) {
3815 Alert("[%s.main()] Cannot fork\n", argv[0]);
3816 exit(1); /* there has been an error */
3817 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003818 setpgid(1, 0);
3819 }
willy tarreau0f7af912005-12-17 12:21:26 +01003820
willy tarreau5cbea6f2005-12-17 12:48:26 +01003821 if (mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01003822 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003823 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01003824 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01003825 }
3826
3827 signal(SIGQUIT, dump);
3828 signal(SIGUSR1, sig_soft_stop);
3829
3830 /* on very high loads, a sigpipe sometimes happen just between the
3831 * getsockopt() which tells "it's OK to write", and the following write :-(
3832 */
willy tarreau3242e862005-12-17 12:27:53 +01003833#ifndef MSG_NOSIGNAL
3834 signal(SIGPIPE, SIG_IGN);
3835#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003836
3837 if (start_proxies() < 0)
3838 exit(1);
3839
3840 select_loop();
3841
3842 exit(0);
3843}