blob: f1e183bc907b2ca6371483920fa02faf2b0fb770 [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 tarreau5cbea6f2005-12-17 12:48:26 +010012 * 2002/03/10
13 * - released 1.1.0
14 * - fixed a few timeout bugs
15 * - rearranged the task scheduler subsystem to improve performance,
16 * add new tasks, and make it easier to later port to librt ;
17 * - allow multiple accept() for one select() wake up ;
18 * - implemented internal load balancing with basic health-check ;
19 * - cookie insertion and header add/replace/delete, with better strings
20 * support.
21 * 2002/03/08
22 * - reworked buffer handling to fix a few rewrite bugs, and
23 * improve overall performance.
24 * - implement the "purge" option to delete server cookies in direct mode.
25 * 2002/03/07
26 * - fixed some error cases where the maxfd was not decreased.
27 * 2002/02/26
28 * - now supports transparent proxying, at least on linux 2.4.
29 * 2002/02/12
30 * - soft stop works again (fixed select timeout computation).
31 * - it seems that TCP proxies sometimes cannot timeout.
32 * - added a "quiet" mode.
33 * - enforce file descriptor limitation on socket() and accept().
34 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010035 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010036 * 2001/12/16 : release of version 1.0.0.
37 * 2001/12/16 : added syslog capability for each accepted connection.
38 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
39 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
40 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
41 * with or without cookies (use keyword http for this).
42 * 2001/09/01 : added client/server header replacing with regexps.
43 * eg:
44 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
45 * srvexp ^Server:\ .* Server:\ Apache
46 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
47 * 2000/11/28 : major rewrite
48 * 2000/11/26 : first write
49 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010050 * TODO:
51 * - handle properly intermediate incomplete server headers. Done ?
52 * - log proxies start/stop
53 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010054 *
55 */
56
57#include <stdio.h>
58#include <stdlib.h>
59#include <unistd.h>
60#include <string.h>
61#include <ctype.h>
62#include <sys/time.h>
63#include <sys/types.h>
64#include <sys/socket.h>
65#include <netinet/tcp.h>
66#include <netinet/in.h>
67#include <arpa/inet.h>
68#include <netdb.h>
69#include <fcntl.h>
70#include <errno.h>
71#include <signal.h>
72#include <stdarg.h>
73#include <sys/resource.h>
74#include <time.h>
75#include <regex.h>
76#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +010077#if defined(TRANSPARENT) && defined(NETFILTER)
78#include <linux/netfilter_ipv4.h>
79#endif
willy tarreau0f7af912005-12-17 12:21:26 +010080
willy tarreau5cbea6f2005-12-17 12:48:26 +010081#define HAPROXY_VERSION "1.1.0"
82#define HAPROXY_DATE "2002/03/10"
willy tarreau0f7af912005-12-17 12:21:26 +010083
84/* this is for libc5 for example */
85#ifndef TCP_NODELAY
86#define TCP_NODELAY 1
87#endif
88
89#ifndef SHUT_RD
90#define SHUT_RD 0
91#endif
92
93#ifndef SHUT_WR
94#define SHUT_WR 1
95#endif
96
97#define BUFSIZE 4096
98
99// reserved buffer space for header rewriting
100#define MAXREWRITE 256
101
willy tarreau5cbea6f2005-12-17 12:48:26 +0100102// max # args on a configuration line
103#define MAX_LINE_ARGS 10
104
willy tarreau0f7af912005-12-17 12:21:26 +0100105// max # of regexps per proxy
106#define MAX_REGEXP 10
107
108// max # of matches per regexp
109#define MAX_MATCH 10
110
willy tarreau5cbea6f2005-12-17 12:48:26 +0100111/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100112#define COOKIENAME_LEN 16
113#define SERVERID_LEN 16
114#define CONN_RETRIES 3
115
willy tarreau5cbea6f2005-12-17 12:48:26 +0100116/* FIXME: this should be user-configurable */
117#define CHK_CONNTIME 2000
118#define CHK_INTERVAL 2000
119#define FALLTIME 3
120#define RISETIME 2
121
willy tarreau0f7af912005-12-17 12:21:26 +0100122/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
123#define INTBITS 5
124
125/* show stats this every millisecond, 0 to disable */
126#ifndef STATTIME
127#define STATTIME 2000
128#endif
129
willy tarreau5cbea6f2005-12-17 12:48:26 +0100130/* this reduces the number of calls to select() by choosing appropriate
131 * sheduler precision in milliseconds. It should be near the minimum
132 * time that is needed by select() to collect all events. All timeouts
133 * are rounded up by adding this value prior to pass it to select().
134 */
135#define SCHEDULER_RESOLUTION 9
136
willy tarreau0f7af912005-12-17 12:21:26 +0100137#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
138#define SETNOW(a) (*a=now)
139
willy tarreau9da061b2005-12-17 12:29:56 +0100140/****** string-specific macros and functions ******/
141/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
142#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
143
144/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
145#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
146
147
148#ifndef HAVE_STRLCPY
149/*
150 * copies at most <size-1> chars from <src> to <dst>. Last char is always
151 * set to 0, unless <size> is 0. The number of chars copied is returned
152 * (excluding the terminating zero).
153 * This code has been optimized for size and speed : on x86, it's 45 bytes
154 * long, uses only registers, and consumes only 4 cycles per char.
155 */
156int strlcpy(char *dst, const char *src, int size) {
157 char *orig = dst;
158 if (size) {
159 while (--size && (*dst = *src)) {
160 src++; dst++;
161 }
162 *dst = 0;
163 }
164 return dst - orig;
165}
166#endif
167
168
willy tarreau0f7af912005-12-17 12:21:26 +0100169#define MEM_OPTIM
170#ifdef MEM_OPTIM
171/*
172 * Returns a pointer to type <type> taken from the
173 * pool <pool_type> or dynamically allocated. In the
174 * first case, <pool_type> is updated to point to the
175 * next element in the list.
176 */
177#define pool_alloc(type) ({ \
178 void *p; \
179 if ((p = pool_##type) == NULL) \
180 p = malloc(sizeof_##type); \
181 else { \
182 pool_##type = *(void **)pool_##type; \
183 } \
184 p; \
185})
186
187/*
188 * Puts a memory area back to the corresponding pool.
189 * Items are chained directly through a pointer that
190 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100191 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100192 * that each memory area is at least as big as one
193 * pointer.
194 */
195#define pool_free(type, ptr) ({ \
196 *(void **)ptr = (void *)pool_##type; \
197 pool_##type = (void *)ptr; \
198})
199
200#else
201#define pool_alloc(type) (calloc(1,sizeof_##type));
202#define pool_free(type, ptr) (free(ptr));
203#endif /* MEM_OPTIM */
204
willy tarreau5cbea6f2005-12-17 12:48:26 +0100205#define sizeof_task sizeof(struct task)
206#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100207#define sizeof_buffer sizeof(struct buffer)
208#define sizeof_fdtab sizeof(struct fdtab)
209#define sizeof_str256 256
210
211
willy tarreau5cbea6f2005-12-17 12:48:26 +0100212/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100213#define FD_STCLOSE 0
214#define FD_STLISTEN 1
215#define FD_STCONN 2
216#define FD_STREADY 3
217#define FD_STERROR 4
218
willy tarreau5cbea6f2005-12-17 12:48:26 +0100219/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100220#define TASK_IDLE 0
221#define TASK_RUNNING 1
222
willy tarreau5cbea6f2005-12-17 12:48:26 +0100223/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100224#define PR_STNEW 0
225#define PR_STIDLE 1
226#define PR_STRUN 2
227#define PR_STDISABLED 3
228
willy tarreau5cbea6f2005-12-17 12:48:26 +0100229/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100230#define PR_MODE_TCP 0
231#define PR_MODE_HTTP 1
232#define PR_MODE_HEALTH 2
233
willy tarreau5cbea6f2005-12-17 12:48:26 +0100234/* bits for proxy->options */
235#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
236#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
237#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
238#define PR_O_COOK_IND 8 /* keep only indirect cookies */
239#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
240#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
241#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
242#define PR_O_BALANCE (PR_O_BALANCE_RR)
243
244/* various task flags */
245#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
246
247/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define CL_STHEADERS 0
249#define CL_STDATA 1
250#define CL_STSHUTR 2
251#define CL_STSHUTW 3
252#define CL_STCLOSE 4
253
willy tarreau5cbea6f2005-12-17 12:48:26 +0100254/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100255#define SV_STIDLE 0
256#define SV_STCONN 1
257#define SV_STHEADERS 2
258#define SV_STDATA 3
259#define SV_STSHUTR 4
260#define SV_STSHUTW 5
261#define SV_STCLOSE 6
262
263/* result of an I/O event */
264#define RES_SILENT 0 /* didn't happen */
265#define RES_DATA 1 /* data were sent or received */
266#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
267#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
268
willy tarreau5cbea6f2005-12-17 12:48:26 +0100269/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100270#define MODE_DEBUG 1
271#define MODE_STATS 2
272#define MODE_LOG 4
273#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100274#define MODE_QUIET 16
275
276/* server flags */
277#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100278
279/*********************************************************************/
280
281#define LIST_HEAD(a) ((void *)(&(a)))
282
283/*********************************************************************/
284
285struct hdr_exp {
286 regex_t *preg; /* expression to look for */
287 char *replace; /* expression to set instead */
288};
289
290struct buffer {
291 unsigned int l; /* data length */
292 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
293 char data[BUFSIZE];
294};
295
296struct server {
297 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100298 int state; /* server state (SRV_*) */
299 int cklen; /* the len of the cookie, to speed up checks */
300 char *cookie; /* the id set in the cookie */
301 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100302 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100303 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
304 int result; /* 0 = connect OK, -1 = connect KO */
305 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100306};
307
willy tarreau5cbea6f2005-12-17 12:48:26 +0100308/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100309struct task {
310 struct task *next, *prev; /* chaining ... */
311 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100312 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100313 int state; /* task state : IDLE or RUNNING */
314 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100315 int (*process)(struct task *t); /* the function which processes the task */
316 void *context; /* the task's context */
317};
318
319/* WARNING: if new fields are added, they must be initialized in event_accept() */
320struct session {
321 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100322 /* application specific below */
323 struct timeval crexpire; /* expiration date for a client read */
324 struct timeval cwexpire; /* expiration date for a client write */
325 struct timeval srexpire; /* expiration date for a server read */
326 struct timeval swexpire; /* expiration date for a server write */
327 struct timeval cnexpire; /* expiration date for a connect */
328 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
329 struct proxy *proxy; /* the proxy this socket belongs to */
330 int cli_fd; /* the client side fd */
331 int srv_fd; /* the server side fd */
332 int cli_state; /* state of the client side */
333 int srv_state; /* state of the server side */
334 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100335 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100336 struct buffer *req; /* request buffer */
337 struct buffer *rep; /* response buffer */
338 struct sockaddr_in cli_addr; /* the client address */
339 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100340 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100341};
342
343struct proxy {
344 int listen_fd; /* the listen socket */
345 int state; /* proxy state */
346 struct sockaddr_in listen_addr; /* the address we listen to */
347 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100348 struct server *srv, *cursrv; /* known servers, current server */
349 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100350 char *cookie_name; /* name of the cookie to look for */
351 int clitimeout; /* client I/O timeout (in milliseconds) */
352 int srvtimeout; /* server I/O timeout (in milliseconds) */
353 int contimeout; /* connect timeout (in milliseconds) */
354 char *id; /* proxy id */
355 int nbconn; /* # of active sessions */
356 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 int conn_retries; /* maximum number of connect retries */
358 int options; /* PR_O_REDISP, PR_O_TRANSP */
359 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100360 struct proxy *next;
361 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
362 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
363 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100364 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
365 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
366 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
367 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100368 int grace; /* grace time after stop request */
369};
370
371/* info about one given fd */
372struct fdtab {
373 int (*read)(int fd); /* read function */
374 int (*write)(int fd); /* write function */
375 struct task *owner; /* the session (or proxy) associated with this fd */
376 int state; /* the state of this fd */
377};
378
379/*********************************************************************/
380
381int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
382int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
383int cfg_maxsock = 0; /* max # of sockets */
384char *cfg_cfgfile = NULL; /* configuration file */
385char *progname = NULL; /* program name */
386int pid; /* current process id */
387/*********************************************************************/
388
389fd_set *ReadEvent,
390 *WriteEvent,
391 *StaticReadEvent,
392 *StaticWriteEvent;
393
394void **pool_session = NULL,
395 **pool_buffer = NULL,
396 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100397 **pool_str256 = NULL,
398 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100399
400struct proxy *proxy = NULL; /* list of all existing proxies */
401struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100402struct task *rq = NULL; /* global run queue */
403struct task wait_queue = { /* global wait queue */
404 prev:LIST_HEAD(wait_queue),
405 next:LIST_HEAD(wait_queue)
406};
willy tarreau0f7af912005-12-17 12:21:26 +0100407
408static int mode = 0; /* MODE_DEBUG, ... */
409static int totalconn = 0; /* total # of terminated sessions */
410static int actconn = 0; /* # of active sessions */
411static int maxfd = 0; /* # of the highest fd + 1 */
412static int listeners = 0; /* # of listeners */
413static int stopping = 0; /* non zero means stopping in progress */
414static struct timeval now = {0,0}; /* the current date at any moment */
415
416static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
417static char trash[BUFSIZE];
418
419/*
420 * Syslog facilities and levels
421 */
422
423#define MAX_SYSLOG_LEN 1024
424#define NB_LOG_FACILITIES 24
425const char *log_facilities[NB_LOG_FACILITIES] = {
426 "kern", "user", "mail", "daemon",
427 "auth", "syslog", "lpr", "news",
428 "uucp", "cron", "auth2", "ftp",
429 "ntp", "audit", "alert", "cron2",
430 "local0", "local1", "local2", "local3",
431 "local4", "local5", "local6", "local7"
432};
433
434
435#define NB_LOG_LEVELS 8
436const char *log_levels[NB_LOG_LEVELS] = {
437 "emerg", "alert", "crit", "err",
438 "warning", "notice", "info", "debug"
439};
440
441#define SYSLOG_PORT 514
442
443const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
444 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
445#define MAX_HOSTNAME_LEN 32
446static char hostname[MAX_HOSTNAME_LEN] = "";
447
448/*********************************************************************/
449/* statistics ******************************************************/
450/*********************************************************************/
451
452static int stats_tsk_lsrch, stats_tsk_rsrch,
453 stats_tsk_good, stats_tsk_right, stats_tsk_left,
454 stats_tsk_new, stats_tsk_nsrch;
455
456
457/*********************************************************************/
458/* function prototypes *********************************************/
459/*********************************************************************/
460
461int event_accept(int fd);
462int event_cli_read(int fd);
463int event_cli_write(int fd);
464int event_srv_read(int fd);
465int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100466int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100467
468/*********************************************************************/
469/* general purpose functions ***************************************/
470/*********************************************************************/
471
472void display_version() {
473 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100474 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100475}
476
477/*
478 * This function prints the command line usage and exits
479 */
480void usage(char *name) {
481 display_version();
482 fprintf(stderr,
483 "Usage : %s -f <cfgfile> [ -vd"
484#if STATTIME > 0
485 "sl"
486#endif
487 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
488 " -v displays version\n"
489 " -d enters debug mode\n"
490#if STATTIME > 0
491 " -s enables statistics output\n"
492 " -l enables long statistics format\n"
493#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100494 " -D goes daemon ; implies -q\n"
495 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100496 " -n sets the maximum total # of connections (%d)\n"
497 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
498 name, cfg_maxconn, cfg_maxpconn);
499 exit(1);
500}
501
502
503/*
504 * Displays the message on stderr with the date and pid.
505 */
506void Alert(char *fmt, ...) {
507 va_list argp;
508 struct timeval tv;
509 struct tm *tm;
510
willy tarreau5cbea6f2005-12-17 12:48:26 +0100511 if (!(mode & MODE_QUIET)) {
512 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100513
willy tarreau5cbea6f2005-12-17 12:48:26 +0100514 gettimeofday(&tv, NULL);
515 tm=localtime(&tv.tv_sec);
516 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
517 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
518 vfprintf(stderr, fmt, argp);
519 fflush(stderr);
520 va_end(argp);
521 }
willy tarreau0f7af912005-12-17 12:21:26 +0100522}
523
524
525/*
526 * Displays the message on stderr with the date and pid.
527 */
528void Warning(char *fmt, ...) {
529 va_list argp;
530 struct timeval tv;
531 struct tm *tm;
532
willy tarreau5cbea6f2005-12-17 12:48:26 +0100533 if (!(mode & MODE_QUIET)) {
534 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100535
willy tarreau5cbea6f2005-12-17 12:48:26 +0100536 gettimeofday(&tv, NULL);
537 tm=localtime(&tv.tv_sec);
538 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
539 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
540 vfprintf(stderr, fmt, argp);
541 fflush(stderr);
542 va_end(argp);
543 }
544}
545
546/*
547 * Displays the message on <out> only if quiet mode is not set.
548 */
549void qfprintf(FILE *out, char *fmt, ...) {
550 va_list argp;
551
552 if (!(mode & MODE_QUIET)) {
553 va_start(argp, fmt);
554 vfprintf(out, fmt, argp);
555 fflush(out);
556 va_end(argp);
557 }
willy tarreau0f7af912005-12-17 12:21:26 +0100558}
559
560
561/*
562 * converts <str> to a struct sockaddr_in* which is locally allocated.
563 * The format is "addr:port", where "addr" can be empty or "*" to indicate
564 * INADDR_ANY.
565 */
566struct sockaddr_in *str2sa(char *str) {
567 static struct sockaddr_in sa;
568 char *c;
569 int port;
570
571 bzero(&sa, sizeof(sa));
572 str=strdup(str);
573
574 if ((c=strrchr(str,':')) != NULL) {
575 *c++=0;
576 port=atol(c);
577 }
578 else
579 port=0;
580
581 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
582 sa.sin_addr.s_addr = INADDR_ANY;
583 }
584 else if (
585#ifndef SOLARIS
586 !inet_aton(str, &sa.sin_addr)
587#else
588 !inet_pton(AF_INET, str, &sa.sin_addr)
589#endif
590 ) {
591 struct hostent *he;
592
593 if ((he = gethostbyname(str)) == NULL) {
594 Alert("Invalid server name: <%s>\n",str);
595 }
596 else
597 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
598 }
599 sa.sin_port=htons(port);
600 sa.sin_family=AF_INET;
601
602 free(str);
603 return &sa;
604}
605
606/*
607 * This function tries to send a syslog message to the syslog server at
608 * address <sa>. It doesn't care about errors nor does it report them.
609 * WARNING! no check is made on the prog+hostname+date length, so the
610 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
611 * the message will be truncated to fit the maximum length.
612 */
613void send_syslog(struct sockaddr_in *sa,
614 int facility, int level, char *message)
615{
616
617 static int logfd = -1; /* syslog UDP socket */
618 struct timeval tv;
619 struct tm *tm;
620 static char logmsg[MAX_SYSLOG_LEN];
621 char *p;
622
623 if (logfd < 0) {
624 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
625 return;
626 }
627
628 if (facility < 0 || level < 0
629 || sa == NULL || progname == NULL || message == NULL)
630 return;
631
632 gettimeofday(&tv, NULL);
633 tm = localtime(&tv.tv_sec);
634
635 p = logmsg;
636 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
637 // facility * 8 + level,
638 // monthname[tm->tm_mon],
639 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
640 // hostname, progname, pid);
641 /* 20011216/WT : other progs don't set the hostname, and syslogd
642 * systematically repeats it which is contrary to RFC3164.
643 */
644 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
645 facility * 8 + level,
646 monthname[tm->tm_mon],
647 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
648 progname, pid);
649
650 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
651 int len = strlen(message);
652 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
653 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
654 memcpy(p, message, len);
655 p += len;
656 }
willy tarreau3242e862005-12-17 12:27:53 +0100657#ifndef MSG_NOSIGNAL
658 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
659 (struct sockaddr *)sa, sizeof(*sa));
660#else
willy tarreau0f7af912005-12-17 12:21:26 +0100661 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
662 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100663#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100664}
665
666
667/* sets <tv> to the current time */
668static inline struct timeval *tv_now(struct timeval *tv) {
669 if (tv)
670 gettimeofday(tv, NULL);
671 return tv;
672}
673
674/*
675 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
676 */
677static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
678 if (!tv || !from)
679 return NULL;
680 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
681 tv->tv_sec = from->tv_sec + (ms/1000);
682 while (tv->tv_usec >= 1000000) {
683 tv->tv_usec -= 1000000;
684 tv->tv_sec++;
685 }
686 return tv;
687}
688
689/*
690 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
691 */
692static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
693 if (tv1->tv_sec > tv2->tv_sec)
694 return 1;
695 else if (tv1->tv_sec < tv2->tv_sec)
696 return -1;
697 else if (tv1->tv_usec > tv2->tv_usec)
698 return 1;
699 else if (tv1->tv_usec < tv2->tv_usec)
700 return -1;
701 else
702 return 0;
703}
704
705/*
706 * returns the absolute difference, in ms, between tv1 and tv2
707 */
708unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
709 int cmp;
710 unsigned long ret;
711
712
713 cmp=tv_cmp(tv1, tv2);
714 if (!cmp)
715 return 0; /* same dates, null diff */
716 else if (cmp<0) {
717 struct timeval *tmp=tv1;
718 tv1=tv2;
719 tv2=tmp;
720 }
721 ret=(tv1->tv_sec - tv2->tv_sec)*1000;
722 if (tv1->tv_usec > tv2->tv_usec)
723 ret+=(tv1->tv_usec - tv2->tv_usec)/1000;
724 else
725 ret-=(tv2->tv_usec - tv1->tv_usec)/1000;
726 return (unsigned long) ret;
727}
728
729/*
730 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
731 */
732static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
733 if ((tv1->tv_sec > tv2->tv_sec + 1) ||
734 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
735 return 1;
736 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
737 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
738 return -1;
739 else
740 return 0;
741}
742
743/*
744 * returns the remaining time between tv1=now and event=tv2
745 * if tv2 is passed, 0 is returned.
746 */
747static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
748 unsigned long ret;
749
750
751 if (tv_cmp_ms(tv1, tv2) >= 0)
752 return 0; /* event elapsed */
753
754 ret=(tv2->tv_sec - tv1->tv_sec)*1000;
755 if (tv2->tv_usec > tv1->tv_usec)
756 ret+=(tv2->tv_usec - tv1->tv_usec)/1000;
757 else
758 ret-=(tv1->tv_usec - tv2->tv_usec)/1000;
759 return (unsigned long) ret;
760}
761
762
763/*
764 * zeroes a struct timeval
765 */
766
767static inline struct timeval *tv_eternity(struct timeval *tv) {
768 tv->tv_sec = tv->tv_usec = 0;
769 return tv;
770}
771
772/*
773 * returns 1 if tv is null, else 0
774 */
775static inline int tv_iseternity(struct timeval *tv) {
776 if (tv->tv_sec == 0 && tv->tv_usec == 0)
777 return 1;
778 else
779 return 0;
780}
781
782/*
783 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
784 * considering that 0 is the eternity.
785 */
786static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
787 if (tv_iseternity(tv1))
788 if (tv_iseternity(tv2))
789 return 0; /* same */
790 else
791 return 1; /* tv1 later than tv2 */
792 else if (tv_iseternity(tv2))
793 return -1; /* tv2 later than tv1 */
794
795 if (tv1->tv_sec > tv2->tv_sec)
796 return 1;
797 else if (tv1->tv_sec < tv2->tv_sec)
798 return -1;
799 else if (tv1->tv_usec > tv2->tv_usec)
800 return 1;
801 else if (tv1->tv_usec < tv2->tv_usec)
802 return -1;
803 else
804 return 0;
805}
806
807/*
808 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
809 * considering that 0 is the eternity.
810 */
811static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
812 if (tv_iseternity(tv1))
813 if (tv_iseternity(tv2))
814 return 0; /* same */
815 else
816 return 1; /* tv1 later than tv2 */
817 else if (tv_iseternity(tv2))
818 return -1; /* tv2 later than tv1 */
819
820 if ((tv1->tv_sec > tv2->tv_sec + 1) ||
821 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
822 return 1;
823 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
824 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
825 return -1;
826 else
827 return 0;
828}
829
830/*
831 * returns the first event between tv1 and tv2 into tvmin.
832 * a zero tv is ignored. tvmin is returned.
833 */
834static inline struct timeval *tv_min(struct timeval *tvmin,
835 struct timeval *tv1, struct timeval *tv2) {
836
837 if (tv_cmp2(tv1, tv2) <= 0)
838 *tvmin = *tv1;
839 else
840 *tvmin = *tv2;
841
842 return tvmin;
843}
844
845
846
847/***********************************************************/
848/* fd management ***************************************/
849/***********************************************************/
850
851
852
willy tarreau5cbea6f2005-12-17 12:48:26 +0100853/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
854 * The file descriptor is also closed.
855 */
willy tarreau0f7af912005-12-17 12:21:26 +0100856static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100857 FD_CLR(fd, StaticReadEvent);
858 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100859 close(fd);
860 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100861
862 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
863 maxfd--;
864}
865
866/* recomputes the maxfd limit from the fd */
867static inline void fd_insert(int fd) {
868 if (fd+1 > maxfd)
869 maxfd = fd+1;
870}
871
872/*************************************************************/
873/* task management ***************************************/
874/*************************************************************/
875
willy tarreau5cbea6f2005-12-17 12:48:26 +0100876/* puts the task <t> in run queue <q>, and returns <t> */
877static inline struct task *task_wakeup(struct task **q, struct task *t) {
878 if (t->state == TASK_RUNNING)
879 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100880 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100881 t->rqnext = *q;
882 t->state = TASK_RUNNING;
883 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100884 }
885}
886
willy tarreau5cbea6f2005-12-17 12:48:26 +0100887/* removes the task <t> from the queue <q>
888 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100889 * set the run queue to point to the next one, and return it
890 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100891static inline struct task *task_sleep(struct task **q, struct task *t) {
892 if (t->state == TASK_RUNNING) {
893 *q = t->rqnext;
894 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100895 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100896 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100897}
898
899/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100900 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100901 * from the run queue. A pointer to the task itself is returned.
902 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100903static inline struct task *task_delete(struct task *t) {
904 t->prev->next = t->next;
905 t->next->prev = t->prev;
906 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100907}
908
909/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100910 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100911 */
912static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100913 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100914}
915
willy tarreau5cbea6f2005-12-17 12:48:26 +0100916/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100917 * may be only moved or left where it was, depending on its timing requirements.
918 * <task> is returned.
919 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100920struct task *task_queue(struct task *task) {
921 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100922 struct task *start_from;
923
924 /* first, test if the task was already in a list */
925 if (task->prev == NULL) {
926 // start_from = list;
927 start_from = list->prev;
928 stats_tsk_new++;
929
930 /* insert the unlinked <task> into the list, searching back from the last entry */
931 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
932 start_from = start_from->prev;
933 stats_tsk_nsrch++;
934 }
935
936 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
937 // start_from = start_from->next;
938 // stats_tsk_nsrch++;
939 // }
940 }
941 else if (task->prev == list ||
942 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
943 start_from = task->next;
944 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
945 stats_tsk_good++;
946 return task; /* it's already in the right place */
947 }
948
949 stats_tsk_right++;
950 /* insert the unlinked <task> into the list, searching after position <start_from> */
951 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
952 start_from = start_from->next;
953 stats_tsk_rsrch++;
954 }
955 /* we need to unlink it now */
956 task_delete(task);
957 }
958 else { /* walk left. */
959 stats_tsk_left++;
960#ifdef LEFT_TO_TOP /* not very good */
961 start_from = list;
962 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
963 start_from = start_from->next;
964 stats_tsk_lsrch++;
965 }
966#else
967 start_from = task->prev->prev; /* valid because of the previous test above */
968 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
969 start_from = start_from->prev;
970 stats_tsk_lsrch++;
971 }
972#endif
973 /* we need to unlink it now */
974 task_delete(task);
975 }
976 task->prev = start_from;
977 task->next = start_from->next;
978 task->next->prev = task;
979 start_from->next = task;
980 return task;
981}
982
983
984/*********************************************************************/
985/* more specific functions ***************************************/
986/*********************************************************************/
987
988/* some prototypes */
989static int maintain_proxies(void);
990
willy tarreau5cbea6f2005-12-17 12:48:26 +0100991/* this either returns the sockname or the original destination address. Code
992 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
993 */
994static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
995#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
996 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
997#else
998#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
999 return getsockname(fd, (struct sockaddr *)sa, salen);
1000#else
1001 return -1;
1002#endif
1003#endif
1004}
1005
1006/*
1007 * frees the context associated to a session. It must have been removed first.
1008 */
1009static inline void session_free(struct session *s) {
1010 if (s->req)
1011 pool_free(buffer, s->req);
1012 if (s->rep)
1013 pool_free(buffer, s->rep);
1014 pool_free(session, s);
1015}
1016
willy tarreau0f7af912005-12-17 12:21:26 +01001017
1018/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001019 * This function initiates a connection to the current server (s->srv) if (s->direct)
1020 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001021 * it's OK, -1 if it's impossible.
1022 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001023int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001024 int one = 1;
1025 int fd;
1026
1027 // fprintf(stderr,"connect_server : s=%p\n",s);
1028
willy tarreau5cbea6f2005-12-17 12:48:26 +01001029 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1030 s->srv_addr = s->srv->addr;
1031 }
1032 else if (s->proxy->options & PR_O_BALANCE) {
1033 if (s->proxy->options & PR_O_BALANCE_RR) {
1034 int retry = s->proxy->nbservers;
1035 do {
1036 if (s->proxy->cursrv == NULL)
1037 s->proxy->cursrv = s->proxy->srv;
1038 if (s->proxy->cursrv->state & SRV_RUNNING)
1039 break;
1040 s->proxy->cursrv = s->proxy->cursrv->next;
1041 } while (retry--);
1042
1043 if (retry == 0) /* no server left */
1044 return -1;
1045
1046 s->srv = s->proxy->cursrv;
1047 s->srv_addr = s->srv->addr;
1048 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001049 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001050 else /* unknown balancing algorithm */
1051 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001052 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001053 else if (*(int *)&s->proxy->dispatch_addr) {
1054 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001055 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001056 }
1057 else if (s->proxy->options & PR_O_TRANSP) {
1058 /* in transparent mode, use the original dest addr if no dispatch specified */
1059 int salen = sizeof(struct sockaddr_in);
1060 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1061 qfprintf(stderr, "Cannot get original server address.\n");
1062 return -1;
1063 }
1064 }
willy tarreau0f7af912005-12-17 12:21:26 +01001065
1066 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001067 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001068 return -1;
1069 }
1070
willy tarreau5cbea6f2005-12-17 12:48:26 +01001071 if (fd >= cfg_maxsock) {
1072 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1073 close(fd);
1074 return -1;
1075 }
1076
willy tarreau0f7af912005-12-17 12:21:26 +01001077 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1078 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001079 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001080 close(fd);
1081 return -1;
1082 }
1083
1084 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1085 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001086 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001087 close(fd);
1088 return -1;
1089 }
1090 else if (errno != EALREADY && errno != EISCONN) {
1091 close(fd);
1092 return -1;
1093 }
1094 }
1095
willy tarreau5cbea6f2005-12-17 12:48:26 +01001096 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001097 fdtab[fd].read = &event_srv_read;
1098 fdtab[fd].write = &event_srv_write;
1099 fdtab[fd].state = FD_STCONN; /* connection in progress */
1100
1101 FD_SET(fd, StaticWriteEvent); /* for connect status */
1102
1103 fd_insert(fd);
1104
1105 if (s->proxy->contimeout)
1106 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1107 else
1108 tv_eternity(&s->cnexpire);
1109 return 0;
1110}
1111
1112/*
1113 * this function is called on a read event from a client socket.
1114 * It returns 0.
1115 */
1116int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117 struct task *t = fdtab[fd].owner;
1118 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001119 struct buffer *b = s->req;
1120 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001121
1122 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1123
willy tarreau0f7af912005-12-17 12:21:26 +01001124 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001125 while (1) {
1126 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1127 b->r = b->w = b->h = b->lr = b->data;
1128 max = BUFSIZE - MAXREWRITE;
1129 }
1130 else if (b->r > b->w) {
1131 max = b->data + BUFSIZE - MAXREWRITE - b->r;
1132 }
1133 else {
1134 max = b->w - b->r;
1135 if (max > BUFSIZE - MAXREWRITE)
1136 max = BUFSIZE - MAXREWRITE;
1137 }
1138
1139 if (max == 0) { /* not anymore room to store data */
1140 FD_CLR(fd, StaticReadEvent);
1141 break;;
1142 }
1143
willy tarreau3242e862005-12-17 12:27:53 +01001144#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001145 {
1146 int skerr, lskerr;
1147
1148 lskerr = sizeof(skerr);
1149 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1150 if (skerr)
1151 ret = -1;
1152 else
1153 ret = recv(fd, b->r, max, 0);
1154 }
willy tarreau3242e862005-12-17 12:27:53 +01001155#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001156 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001157#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001158 if (ret > 0) {
1159 b->r += ret;
1160 b->l += ret;
1161 s->res_cr = RES_DATA;
1162
1163 if (b->r == b->data + BUFSIZE) {
1164 b->r = b->data; /* wrap around the buffer */
1165 }
1166 /* we hope to read more data or to get a close on next round */
1167 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001168 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001169 else if (ret == 0) {
1170 s->res_cr = RES_NULL;
1171 break;
1172 }
1173 else if (errno == EAGAIN) {/* ignore EAGAIN */
1174 break;
1175 }
1176 else {
1177 s->res_cr = RES_ERROR;
1178 fdtab[fd].state = FD_STERROR;
1179 break;
1180 }
1181 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001182 }
1183 else {
1184 s->res_cr = RES_ERROR;
1185 fdtab[fd].state = FD_STERROR;
1186 }
1187
willy tarreau5cbea6f2005-12-17 12:48:26 +01001188 if (s->res_cr != RES_SILENT) {
1189 if (s->proxy->clitimeout)
1190 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1191 else
1192 tv_eternity(&s->crexpire);
1193
1194 task_wakeup(&rq, t);
1195 }
willy tarreau0f7af912005-12-17 12:21:26 +01001196
willy tarreau0f7af912005-12-17 12:21:26 +01001197 return 0;
1198}
1199
1200
1201/*
1202 * this function is called on a read event from a server socket.
1203 * It returns 0.
1204 */
1205int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001206 struct task *t = fdtab[fd].owner;
1207 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001208 struct buffer *b = s->rep;
1209 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001210
1211 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1212
willy tarreau0f7af912005-12-17 12:21:26 +01001213 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001214 while (1) {
1215 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1216 b->r = b->w = b->h = b->lr = b->data;
1217 max = BUFSIZE - MAXREWRITE;
1218 }
1219 else if (b->r > b->w) {
1220 max = b->data + BUFSIZE - MAXREWRITE - b->r;
1221 }
1222 else {
1223 max = b->w - b->r;
1224 if (max > BUFSIZE - MAXREWRITE)
1225 max = BUFSIZE - MAXREWRITE;
1226 }
1227
1228 if (max == 0) { /* not anymore room to store data */
1229 FD_CLR(fd, StaticReadEvent);
1230 break;
1231 }
1232
willy tarreau3242e862005-12-17 12:27:53 +01001233#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001234 {
1235 int skerr, lskerr;
1236
1237 lskerr = sizeof(skerr);
1238 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1239 if (skerr)
1240 ret = -1;
1241 else
1242 ret = recv(fd, b->r, max, 0);
1243 }
willy tarreau3242e862005-12-17 12:27:53 +01001244#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001245 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001246#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001247 if (ret > 0) {
1248 b->r += ret;
1249 b->l += ret;
1250 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001251
willy tarreau5cbea6f2005-12-17 12:48:26 +01001252 if (b->r == b->data + BUFSIZE) {
1253 b->r = b->data; /* wrap around the buffer */
1254 }
1255 /* we hope to read more data or to get a close on next round */
1256 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001257 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001258 else if (ret == 0) {
1259 s->res_sr = RES_NULL;
1260 break;
1261 }
1262 else if (errno == EAGAIN) {/* ignore EAGAIN */
1263 break;
1264 }
1265 else {
1266 s->res_sr = RES_ERROR;
1267 fdtab[fd].state = FD_STERROR;
1268 break;
1269 }
1270 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001271 }
1272 else {
1273 s->res_sr = RES_ERROR;
1274 fdtab[fd].state = FD_STERROR;
1275 }
1276
willy tarreau5cbea6f2005-12-17 12:48:26 +01001277 if (s->res_sr != RES_SILENT) {
1278 if (s->proxy->srvtimeout)
1279 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1280 else
1281 tv_eternity(&s->srexpire);
1282
1283 task_wakeup(&rq, t);
1284 }
willy tarreau0f7af912005-12-17 12:21:26 +01001285
willy tarreau0f7af912005-12-17 12:21:26 +01001286 return 0;
1287}
1288
1289/*
1290 * this function is called on a write event from a client socket.
1291 * It returns 0.
1292 */
1293int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001294 struct task *t = fdtab[fd].owner;
1295 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001296 struct buffer *b = s->rep;
1297 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001298
1299 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1300
1301 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001302 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001303 // max = BUFSIZE; BUG !!!!
1304 max = 0;
1305 }
1306 else if (b->r > b->w) {
1307 max = b->r - b->w;
1308 }
1309 else
1310 max = b->data + BUFSIZE - b->w;
1311
1312 if (max == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001313 // FD_CLR(fd, StaticWriteEvent); // useless
willy tarreau0f7af912005-12-17 12:21:26 +01001314 //fprintf(stderr, "cli_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1315 //fd, max, b->data, b->r, b->w, b->l);
1316 s->res_cw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001317 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001318 return 0;
1319 }
1320
willy tarreau0f7af912005-12-17 12:21:26 +01001321 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001322#ifndef MSG_NOSIGNAL
1323 int skerr, lskerr;
1324#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001325 if (max == 0) { /* nothing to write, just make as if we were never called */
1326 s->res_cw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001327 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001328 return 0;
1329 }
1330
willy tarreau3242e862005-12-17 12:27:53 +01001331#ifndef MSG_NOSIGNAL
1332 lskerr=sizeof(skerr);
1333 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1334 if (skerr)
1335 ret = -1;
1336 else
1337 ret = send(fd, b->w, max, MSG_DONTWAIT);
1338#else
willy tarreau0f7af912005-12-17 12:21:26 +01001339 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001340#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001341
1342 if (ret > 0) {
1343 b->l -= ret;
1344 b->w += ret;
1345
1346 s->res_cw = RES_DATA;
1347
1348 if (b->w == b->data + BUFSIZE) {
1349 b->w = b->data; /* wrap around the buffer */
1350 }
1351 }
1352 else if (ret == 0) {
1353 /* nothing written, just make as if we were never called */
1354// s->res_cw = RES_NULL;
1355 return 0;
1356 }
1357 else if (errno == EAGAIN) /* ignore EAGAIN */
1358 return 0;
1359 else {
1360 s->res_cw = RES_ERROR;
1361 fdtab[fd].state = FD_STERROR;
1362 }
1363 }
1364 else {
1365 s->res_cw = RES_ERROR;
1366 fdtab[fd].state = FD_STERROR;
1367 }
1368
1369 if (s->proxy->clitimeout)
1370 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1371 else
1372 tv_eternity(&s->cwexpire);
1373
willy tarreau5cbea6f2005-12-17 12:48:26 +01001374 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001375 return 0;
1376}
1377
1378
1379/*
1380 * this function is called on a write event from a server socket.
1381 * It returns 0.
1382 */
1383int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001384 struct task *t = fdtab[fd].owner;
1385 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001386 struct buffer *b = s->req;
1387 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001388
1389 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1390
1391 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001392 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001393 // max = BUFSIZE; BUG !!!!
1394 max = 0;
1395 }
1396 else if (b->r > b->w) {
1397 max = b->r - b->w;
1398 }
1399 else
1400 max = b->data + BUFSIZE - b->w;
1401
1402 if (max == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001403 /* may be we have received a connection acknowledgement in TCP mode without data */
1404 // FD_CLR(fd, StaticWriteEvent); // useless ?
willy tarreau0f7af912005-12-17 12:21:26 +01001405 //fprintf(stderr, "srv_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1406 //fd, max, b->data, b->r, b->w, b->l);
1407 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001408 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001409 return 0;
1410 }
1411
willy tarreau0f7af912005-12-17 12:21:26 +01001412 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001413#ifndef MSG_NOSIGNAL
1414 int skerr, lskerr;
1415#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001416 fdtab[fd].state = FD_STREADY;
1417 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 +01001418 //FD_CLR(fd, StaticWriteEvent); // useless ?
willy tarreau0f7af912005-12-17 12:21:26 +01001419 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001420 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001421 return 0;
1422 }
1423
willy tarreau3242e862005-12-17 12:27:53 +01001424#ifndef MSG_NOSIGNAL
1425 lskerr=sizeof(skerr);
1426 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1427 if (skerr)
1428 ret = -1;
1429 else
1430 ret = send(fd, b->w, max, MSG_DONTWAIT);
1431#else
willy tarreau0f7af912005-12-17 12:21:26 +01001432 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001433#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001434 if (ret > 0) {
1435 b->l -= ret;
1436 b->w += ret;
1437
1438 s->res_sw = RES_DATA;
1439
1440 if (b->w == b->data + BUFSIZE) {
1441 b->w = b->data; /* wrap around the buffer */
1442 }
1443 }
1444 else if (ret == 0) {
1445 /* nothing written, just make as if we were never called */
1446 // s->res_sw = RES_NULL;
1447 return 0;
1448 }
1449 else if (errno == EAGAIN) /* ignore EAGAIN */
1450 return 0;
1451 else {
1452 s->res_sw = RES_ERROR;
1453 fdtab[fd].state = FD_STERROR;
1454 }
1455 }
1456 else {
1457 s->res_sw = RES_ERROR;
1458 fdtab[fd].state = FD_STERROR;
1459 }
1460
1461 if (s->proxy->srvtimeout)
1462 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1463 else
1464 tv_eternity(&s->swexpire);
1465
willy tarreau5cbea6f2005-12-17 12:48:26 +01001466 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001467 return 0;
1468}
1469
1470
1471/*
1472 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001473 * to an accept. It tries to accept as many connections as possible.
1474 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001475 */
1476int event_accept(int fd) {
1477 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001478 struct session *s;
1479 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001480 int cfd;
1481 int one = 1;
1482
willy tarreau0f7af912005-12-17 12:21:26 +01001483
willy tarreau5cbea6f2005-12-17 12:48:26 +01001484 while (p->nbconn < p->maxconn) {
1485 struct sockaddr_in addr;
1486 int laddr = sizeof(addr);
1487 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1488 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001489
willy tarreau5cbea6f2005-12-17 12:48:26 +01001490 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1491 Alert("out of memory in event_accept().\n");
1492 FD_CLR(fd, StaticReadEvent);
1493 p->state = PR_STIDLE;
1494 close(cfd);
1495 return 0;
1496 }
willy tarreau0f7af912005-12-17 12:21:26 +01001497
willy tarreau5cbea6f2005-12-17 12:48:26 +01001498 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1499 Alert("out of memory in event_accept().\n");
1500 FD_CLR(fd, StaticReadEvent);
1501 p->state = PR_STIDLE;
1502 close(cfd);
1503 pool_free(session, s);
1504 return 0;
1505 }
willy tarreau0f7af912005-12-17 12:21:26 +01001506
willy tarreau5cbea6f2005-12-17 12:48:26 +01001507 s->cli_addr = addr;
1508 if (cfd >= cfg_maxsock) {
1509 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1510 close(cfd);
1511 pool_free(task, t);
1512 pool_free(session, s);
1513 return 0;
1514 }
willy tarreau0f7af912005-12-17 12:21:26 +01001515
willy tarreau5cbea6f2005-12-17 12:48:26 +01001516 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1517 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1518 (char *) &one, sizeof(one)) == -1)) {
1519 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1520 close(cfd);
1521 pool_free(task, t);
1522 pool_free(session, s);
1523 return 0;
1524 }
willy tarreau0f7af912005-12-17 12:21:26 +01001525
willy tarreau5cbea6f2005-12-17 12:48:26 +01001526 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1527 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1528 struct sockaddr_in peername, sockname;
1529 unsigned char *pn, *sn;
1530 int namelen;
1531 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001532
willy tarreau5cbea6f2005-12-17 12:48:26 +01001533 //namelen = sizeof(peername);
1534 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1535 //pn = (unsigned char *)&peername.sin_addr;
1536 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001537
willy tarreau5cbea6f2005-12-17 12:48:26 +01001538 namelen = sizeof(sockname);
1539 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1540 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1541 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001542
willy tarreau5cbea6f2005-12-17 12:48:26 +01001543 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1544 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1545 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1546 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001547
willy tarreau5cbea6f2005-12-17 12:48:26 +01001548 if (p->logfac1 >= 0)
1549 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1550 if (p->logfac2 >= 0)
1551 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1552 }
willy tarreau0f7af912005-12-17 12:21:26 +01001553
willy tarreau0f7af912005-12-17 12:21:26 +01001554
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1556 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1557 t->state = TASK_IDLE;
1558 t->process = process_session;
1559 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001560
willy tarreau5cbea6f2005-12-17 12:48:26 +01001561 s->task = t;
1562 s->proxy = p;
1563 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1564 s->srv_state = SV_STIDLE;
1565 s->req = s->rep = NULL; /* will be allocated later */
1566 s->flags = 0;
1567 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1568 s->cli_fd = cfd;
1569 s->srv_fd = -1;
1570 s->conn_retries = p->conn_retries;
1571
1572 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1573 close(cfd); /* nothing can be done for this fd without memory */
1574 pool_free(task, t);
1575 pool_free(session, s);
1576 return 0;
1577 }
1578 s->req->l = 0;
1579 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 +01001580
willy tarreau5cbea6f2005-12-17 12:48:26 +01001581 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1582 pool_free(buffer, s->req);
1583 close(cfd); /* nothing can be done for this fd without memory */
1584 pool_free(task, t);
1585 pool_free(session, s);
1586 return 0;
1587 }
1588 s->rep->l = 0;
1589 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001590
willy tarreau5cbea6f2005-12-17 12:48:26 +01001591 fdtab[cfd].read = &event_cli_read;
1592 fdtab[cfd].write = &event_cli_write;
1593 fdtab[cfd].owner = t;
1594 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001595
willy tarreau5cbea6f2005-12-17 12:48:26 +01001596 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1597 FD_CLR(cfd, StaticReadEvent);
1598 tv_eternity(&s->crexpire);
1599 shutdown(s->cli_fd, SHUT_RD);
1600 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001601
willy tarreau5cbea6f2005-12-17 12:48:26 +01001602 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1603 s->rep->l = 3;
1604 s->rep->r += 3;
1605 }
1606 else {
1607 FD_SET(cfd, StaticReadEvent);
1608 }
1609
1610 fd_insert(cfd);
1611
1612 tv_eternity(&s->cnexpire);
1613 tv_eternity(&s->srexpire);
1614 tv_eternity(&s->swexpire);
1615 tv_eternity(&s->cwexpire);
1616
1617 if (s->proxy->clitimeout)
1618 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1619 else
1620 tv_eternity(&s->crexpire);
1621
1622 t->expire = s->crexpire;
1623
1624 task_queue(t);
1625 task_wakeup(&rq, t);
1626
1627 p->nbconn++;
1628 actconn++;
1629 totalconn++;
1630
1631 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1632 } /* end of while (p->nbconn < p->maxconn) */
1633 return 0;
1634}
willy tarreau0f7af912005-12-17 12:21:26 +01001635
willy tarreau0f7af912005-12-17 12:21:26 +01001636
willy tarreau5cbea6f2005-12-17 12:48:26 +01001637/*
1638 * This function is used only for server health-checks. It handles
1639 * the connection acknowledgement and returns 1 if the socket is OK,
1640 * or -1 if an error occured.
1641 */
1642int event_srv_hck(int fd) {
1643 struct task *t = fdtab[fd].owner;
1644 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001645
willy tarreau5cbea6f2005-12-17 12:48:26 +01001646 int skerr, lskerr;
1647 lskerr=sizeof(skerr);
1648 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1649 if (skerr)
1650 s->result = -1;
1651 else
1652 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001653
willy tarreau5cbea6f2005-12-17 12:48:26 +01001654 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001655 return 0;
1656}
1657
1658
1659/*
1660 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1661 * and moves <end> just after the end of <str>.
1662 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1663 * the shift value (positive or negative) is returned.
1664 * If there's no space left, the move is not done.
1665 *
1666 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001667int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001668 int delta;
1669 int len;
1670
1671 len = strlen(str);
1672 delta = len - (end - pos);
1673
1674 if (delta + b->r >= b->data + BUFSIZE)
1675 return 0; /* no space left */
1676
1677 /* first, protect the end of the buffer */
1678 memmove(end + delta, end, b->data + b->l - end);
1679
1680 /* now, copy str over pos */
1681 memcpy(pos, str,len);
1682
willy tarreau5cbea6f2005-12-17 12:48:26 +01001683 /* we only move data after the displaced zone */
1684 if (b->r > pos) b->r += delta;
1685 if (b->w > pos) b->w += delta;
1686 if (b->h > pos) b->h += delta;
1687 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001688 b->l += delta;
1689
1690 return delta;
1691}
1692
1693/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001694int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001695 int delta;
1696
1697 delta = len - (end - pos);
1698
1699 if (delta + b->r >= b->data + BUFSIZE)
1700 return 0; /* no space left */
1701
1702 /* first, protect the end of the buffer */
1703 memmove(end + delta, end, b->data + b->l - end);
1704
1705 /* now, copy str over pos */
1706 memcpy(pos, str,len);
1707
willy tarreau5cbea6f2005-12-17 12:48:26 +01001708 /* we only move data after the displaced zone */
1709 if (b->r > pos) b->r += delta;
1710 if (b->w > pos) b->w += delta;
1711 if (b->h > pos) b->h += delta;
1712 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001713 b->l += delta;
1714
1715 return delta;
1716}
1717
1718
1719int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1720 char *old_dst = dst;
1721
1722 while (*str) {
1723 if (*str == '\\') {
1724 str++;
1725 if (isdigit(*str)) {
1726 int len, num;
1727
1728 num = *str - '0';
1729 str++;
1730
1731 if (matches[num].rm_so > -1) {
1732 len = matches[num].rm_eo - matches[num].rm_so;
1733 memcpy(dst, src + matches[num].rm_so, len);
1734 dst += len;
1735 }
1736
1737 }
1738 else if (*str == 'x') {
1739 unsigned char hex1, hex2;
1740 str++;
1741
1742 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1743
1744 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1745 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1746 *dst++ = (hex1<<4) + hex2;
1747 }
1748 else
1749 *dst++ = *str++;
1750 }
1751 else
1752 *dst++ = *str++;
1753 }
1754 *dst = 0;
1755 return dst - old_dst;
1756}
1757
1758/*
1759 * manages the client FSM and its socket. BTW, it also tries to handle the
1760 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1761 * 0 else.
1762 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001763int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001764 int s = t->srv_state;
1765 int c = t->cli_state;
1766 struct buffer *req = t->req;
1767 struct buffer *rep = t->rep;
1768
1769 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1770 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1771 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1772 //);
1773 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001774 /* now parse the partial (or complete) headers */
1775 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1776 char *ptr;
1777 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001778
willy tarreau5cbea6f2005-12-17 12:48:26 +01001779 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001780
willy tarreau0f7af912005-12-17 12:21:26 +01001781 /* look for the end of the current header */
1782 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1783 ptr++;
1784
willy tarreau5cbea6f2005-12-17 12:48:26 +01001785 if (ptr == req->h) { /* empty line, end of headers */
1786 char newhdr[MAXREWRITE + 1];
1787 int line, len;
1788 /* we can only get here after an end of headers */
1789 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001790
willy tarreau5cbea6f2005-12-17 12:48:26 +01001791 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1792 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1793 buffer_replace2(req, req->h, req->h, newhdr, len);
1794 }
willy tarreau0f7af912005-12-17 12:21:26 +01001795
willy tarreau5cbea6f2005-12-17 12:48:26 +01001796 t->cli_state = CL_STDATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001797
willy tarreau5cbea6f2005-12-17 12:48:26 +01001798 /* FIXME: we'll set the client in a wait state while we try to
1799 * connect to the server. Is this really needed ? wouldn't it be
1800 * better to release the maximum of system buffers instead ? */
1801 FD_CLR(t->cli_fd, StaticReadEvent);
1802 tv_eternity(&t->crexpire);
1803 break;
1804 }
willy tarreau0f7af912005-12-17 12:21:26 +01001805
willy tarreau5cbea6f2005-12-17 12:48:26 +01001806 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1807 if (ptr > req->r - 2) {
1808 /* this is a partial header, let's wait for more to come */
1809 req->lr = ptr;
1810 break;
1811 }
willy tarreau0f7af912005-12-17 12:21:26 +01001812
willy tarreau5cbea6f2005-12-17 12:48:26 +01001813 /* now we know that *ptr is either \r or \n,
1814 * and that there are at least 1 char after it.
1815 */
1816 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1817 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1818 else
1819 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001820
willy tarreau5cbea6f2005-12-17 12:48:26 +01001821 /*
1822 * now we know that we have a full header ; we can do whatever
1823 * we want with these pointers :
1824 * req->h = beginning of header
1825 * ptr = end of header (first \r or \n)
1826 * req->lr = beginning of next line (next rep->h)
1827 * req->r = end of data (not used at this stage)
1828 */
willy tarreau0f7af912005-12-17 12:21:26 +01001829
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001831
willy tarreau5cbea6f2005-12-17 12:48:26 +01001832 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1833 int len, max;
1834 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1835 max = ptr - req->h;
1836 UBOUND(max, sizeof(trash) - len - 1);
1837 len += strlcpy(trash + len, req->h, max + 1);
1838 trash[len++] = '\n';
1839 write(1, trash, len);
1840 }
willy tarreau0f7af912005-12-17 12:21:26 +01001841
willy tarreau5cbea6f2005-12-17 12:48:26 +01001842 /* try headers regexps */
1843 if (t->proxy->nb_reqexp) {
1844 struct proxy *p = t->proxy;
1845 int exp;
1846 char term;
1847
1848 term = *ptr;
1849 *ptr = '\0';
1850 for (exp=0; exp < p->nb_reqexp; exp++) {
1851 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1852 if (p->req_exp[exp].replace != NULL) {
1853 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1854 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001855 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001856 else {
1857 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001858 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001859 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001860 }
1861 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001862 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001863 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001864
1865 /* now look for cookies */
1866 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1867 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1868 char *p1, *p2, *p3, *p4;
1869
1870 p1 = req->h + 8; /* first char after 'Cookie: ' */
1871
1872 while (p1 < ptr) {
1873 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1874 p1++;
1875
1876 if (p1 == ptr)
1877 break;
1878 else if (*p1 == ';') { /* next cookie */
1879 ++p1;
1880 continue;
1881 }
1882
1883 /* p1 is at the beginning of the cookie name */
1884 p2 = p1;
1885
1886 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1887 p2++;
1888
1889 if (p2 == ptr)
1890 break;
1891 else if (*p2 == ';') { /* next cookie */
1892 p1=++p2;
1893 continue;
1894 }
1895
1896 p3 = p2 + 1; /* skips the '=' sign */
1897 if (p3 == ptr)
1898 break;
1899
1900 p4=p3;
1901 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1902 p4++;
1903
1904 /* here, we have the cookie name between p1 and p2,
1905 * and its value between p3 and p4.
1906 * we can process it.
1907 */
1908
1909 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1910 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1911 /* Cool... it's the right one */
1912 struct server *srv = t->proxy->srv;
1913
1914 while (srv &&
1915 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1916 srv = srv->next;
1917 }
1918
1919 if (srv) { /* we found the server */
1920 t->flags |= TF_DIRECT;
1921 t->srv = srv;
1922 }
1923
1924 break;
1925 }
1926 else {
1927 // fprintf(stderr,"Ignoring unknown cookie : ");
1928 // write(2, p1, p2-p1);
1929 // fprintf(stderr," = ");
1930 // write(2, p3, p4-p3);
1931 // fprintf(stderr,"\n");
1932 }
1933 /* we'll have to look for another cookie ... */
1934 p1 = p4;
1935 } /* while (p1 < ptr) */
1936 } /* end of cookie processing */
1937
1938 /* let's look if we have to delete this header */
1939 if (delete_header) {
1940 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001941 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001942 req->h = req->lr;
1943 } /* while (req->lr < req->r) */
1944
1945 /* end of header processing (even if incomplete) */
1946
1947 if ((req->l < BUFSIZE - MAXREWRITE) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1948 FD_SET(t->cli_fd, StaticReadEvent);
1949 if (t->proxy->clitimeout)
1950 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1951 else
1952 tv_eternity(&t->crexpire);
1953 }
1954
1955 /* read timeout, read error, or last read : give up */
1956 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL ||
1957 tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1958 //FD_CLR(t->cli_fd, StaticReadEvent);
1959 //FD_CLR(t->cli_fd, StaticWriteEvent);
1960 tv_eternity(&t->crexpire);
1961 fd_delete(t->cli_fd);
1962 //close(t->cli_fd);
1963 t->cli_state = CL_STCLOSE;
1964 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001965 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001966// else if (t->res_cr == RES_SILENT) {
1967// return 0;
1968// }
1969
1970 if (req->l >= BUFSIZE - MAXREWRITE) {
1971 /* buffer full : stop reading till we free some space */
1972 FD_CLR(t->cli_fd, StaticReadEvent);
1973 tv_eternity(&t->crexpire);
1974 }
1975
1976 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01001977 }
1978 else if (c == CL_STDATA) {
1979 /* read or write error */
1980 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01001981 tv_eternity(&t->crexpire);
1982 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001983 fd_delete(t->cli_fd);
1984 //FD_CLR(t->cli_fd, StaticReadEvent);
1985 //FD_CLR(t->cli_fd, StaticWriteEvent);
1986 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01001987 t->cli_state = CL_STCLOSE;
1988 return 1;
1989 }
1990 /* read timeout, last read, or end of server write */
1991 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
1992 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01001993 FD_CLR(t->cli_fd, StaticReadEvent);
1994 // if (req->l == 0) /* nothing to write on the server side */
1995 // FD_CLR(t->srv_fd, StaticWriteEvent);
1996 tv_eternity(&t->crexpire);
1997 shutdown(t->cli_fd, SHUT_RD);
1998 t->cli_state = CL_STSHUTR;
1999 return 1;
2000 }
2001 /* write timeout, or last server read and buffer empty */
2002 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2003 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
2004
2005 FD_CLR(t->cli_fd, StaticWriteEvent);
2006 tv_eternity(&t->cwexpire);
2007 shutdown(t->cli_fd, SHUT_WR);
2008 t->cli_state = CL_STSHUTW;
2009 return 1;
2010 }
2011
2012 if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2013 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
2014 FD_CLR(t->cli_fd, StaticReadEvent);
2015 tv_eternity(&t->crexpire);
2016 }
2017 }
2018 else {
2019 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2020 FD_SET(t->cli_fd, StaticReadEvent);
2021 if (t->proxy->clitimeout)
2022 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2023 else
2024 tv_eternity(&t->crexpire);
2025 }
2026 }
2027
2028 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002029 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002030 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2031 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2032 tv_eternity(&t->cwexpire);
2033 }
2034 }
2035 else { /* buffer not empty */
2036 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2037 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2038 if (t->proxy->clitimeout)
2039 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2040 else
2041 tv_eternity(&t->cwexpire);
2042 }
2043 }
2044 return 0; /* other cases change nothing */
2045 }
2046 else if (c == CL_STSHUTR) {
2047 if ((t->res_cw == RES_ERROR) ||
2048 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2049 || (tv_cmp2_ms(&t->crexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002050 //FD_CLR(t->cli_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002051 tv_eternity(&t->cwexpire);
2052 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002053 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002054 t->cli_state = CL_STCLOSE;
2055 return 1;
2056 }
2057 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002058 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002059 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2060 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2061 tv_eternity(&t->cwexpire);
2062 }
2063 }
2064 else { /* buffer not empty */
2065 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2066 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2067 if (t->proxy->clitimeout)
2068 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2069 else
2070 tv_eternity(&t->cwexpire);
2071 }
2072 }
2073 return 0;
2074 }
2075 else if (c == CL_STSHUTW) {
2076 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
2077 s == SV_STCLOSE || tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002078 //FD_CLR(t->cli_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002079 tv_eternity(&t->crexpire);
2080 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002081 //close(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002082 t->cli_state = CL_STCLOSE;
2083 return 1;
2084 }
2085 else if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2086 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
2087 FD_CLR(t->cli_fd, StaticReadEvent);
2088 tv_eternity(&t->crexpire);
2089 }
2090 }
2091 else {
2092 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2093 FD_SET(t->cli_fd, StaticReadEvent);
2094 if (t->proxy->clitimeout)
2095 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2096 else
2097 tv_eternity(&t->crexpire);
2098 }
2099 }
2100 return 0;
2101 }
2102 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002103 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002104 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002105 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002106 write(1, trash, len);
2107 }
2108 return 0;
2109 }
2110 return 0;
2111}
2112
2113
2114/*
2115 * manages the server FSM and its socket. It returns 1 if a state has changed
2116 * (and a resync may be needed), 0 else.
2117 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002118int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002119 int s = t->srv_state;
2120 int c = t->cli_state;
2121 struct buffer *req = t->req;
2122 struct buffer *rep = t->rep;
2123
willy tarreau5cbea6f2005-12-17 12:48:26 +01002124 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2125 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2126 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2127 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2128 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002129 if (s == SV_STIDLE) {
2130 if (c == CL_STHEADERS)
2131 return 0; /* stay in idle, waiting for data to reach the client side */
2132 else if (c == CL_STCLOSE ||
2133 c == CL_STSHUTW ||
2134 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2135 tv_eternity(&t->cnexpire);
2136 t->srv_state = SV_STCLOSE;
2137 return 1;
2138 }
2139 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002140 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002141 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2142 t->srv_state = SV_STCONN;
2143 }
2144 else { /* try again */
2145 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002146 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2147 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2148 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2149 }
2150
2151 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002152 t->srv_state = SV_STCONN;
2153 break;
2154 }
2155 }
2156 if (t->conn_retries < 0) {
2157 /* if conn_retries < 0 or other error, let's abort */
2158 tv_eternity(&t->cnexpire);
2159 t->srv_state = SV_STCLOSE;
2160 }
2161 }
2162 return 1;
2163 }
2164 }
2165 else if (s == SV_STCONN) { /* connection in progress */
2166 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2167 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2168 return 0; /* nothing changed */
2169 }
2170 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2171 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2172 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002173 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002174 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002175 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002176 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002177 if (t->conn_retries >= 0) {
2178 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2179 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2180 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2181 }
2182 if (connect_server(t) == 0)
2183 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002184 }
2185 /* if conn_retries < 0 or other error, let's abort */
2186 tv_eternity(&t->cnexpire);
2187 t->srv_state = SV_STCLOSE;
2188 return 1;
2189 }
2190 else { /* no error or write 0 */
2191 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2192 if (req->l == 0) /* nothing to write */
2193 FD_CLR(t->srv_fd, StaticWriteEvent);
2194 else /* need the right to write */
2195 FD_SET(t->srv_fd, StaticWriteEvent);
2196
2197 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2198 FD_SET(t->srv_fd, StaticReadEvent);
2199 if (t->proxy->srvtimeout)
2200 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2201 else
2202 tv_eternity(&t->srexpire);
2203
2204 t->srv_state = SV_STDATA;
2205 }
2206 else
2207 t->srv_state = SV_STHEADERS;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002209 return 1;
2210 }
2211 }
2212 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213
2214 /* now parse the partial (or complete) headers */
2215 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2216 char *ptr;
2217 int delete_header;
2218
2219 ptr = rep->lr;
2220
2221 /* look for the end of the current header */
2222 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2223 ptr++;
2224
2225 if (ptr == rep->h) {
2226 char newhdr[MAXREWRITE + 1];
2227 int line, len;
2228
2229 /* we can only get here after an end of headers */
2230 /* we'll have something else to do here : add new headers ... */
2231
2232 if ((t->srv) && !(t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
2233 /* the server is known, it's not the one the client requested, we have to
2234 * insert a set-cookie here.
2235 */
2236 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2237 t->proxy->cookie_name, t->srv->cookie);
2238 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2239 }
2240
2241 /* headers to be added */
2242 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2243 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2244 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2245 }
2246
2247 t->srv_state = SV_STDATA;
2248 break;
2249 }
2250
2251 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2252 if (ptr > rep->r - 2) {
2253 /* this is a partial header, let's wait for more to come */
2254 rep->lr = ptr;
2255 break;
2256 }
2257
2258 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2259 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2260
2261 /* now we know that *ptr is either \r or \n,
2262 * and that there are at least 1 char after it.
2263 */
2264 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2265 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2266 else
2267 rep->lr = ptr + 2; /* \r\n or \n\r */
2268
2269 /*
2270 * now we know that we have a full header ; we can do whatever
2271 * we want with these pointers :
2272 * rep->h = beginning of header
2273 * ptr = end of header (first \r or \n)
2274 * rep->lr = beginning of next line (next rep->h)
2275 * rep->r = end of data (not used at this stage)
2276 */
2277
2278 delete_header = 0;
2279
2280 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
2281 int len, max;
2282 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2283 max = ptr - rep->h;
2284 UBOUND(max, sizeof(trash) - len - 1);
2285 len += strlcpy(trash + len, rep->h, max + 1);
2286 trash[len++] = '\n';
2287 write(1, trash, len);
2288 }
2289
2290 /* try headers regexps */
2291 if (t->proxy->nb_rspexp) {
2292 struct proxy *p = t->proxy;
2293 int exp;
2294 char term;
2295
2296 term = *ptr;
2297 *ptr = '\0';
2298 for (exp=0; exp < p->nb_rspexp; exp++) {
2299 if (regexec(p->rsp_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2300 if (p->rsp_exp[exp].replace != NULL) {
2301 int len = exp_replace(trash, rep->h, p->rsp_exp[exp].replace, pmatch);
2302 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2303 }
2304 else {
2305 delete_header = 1;
2306 }
2307 break;
2308 }
2309 }
2310 *ptr = term; /* restore the string terminator */
2311 }
2312
2313 /* check for server cookies */
2314 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2315 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2316 char *p1, *p2, *p3, *p4;
2317
2318 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2319
2320 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2321 while (p1 < ptr && (isspace(*p1)))
2322 p1++;
2323
2324 if (p1 == ptr || *p1 == ';') /* end of cookie */
2325 break;
2326
2327 /* p1 is at the beginning of the cookie name */
2328 p2 = p1;
2329
2330 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2331 p2++;
2332
2333 if (p2 == ptr || *p2 == ';') /* next cookie */
2334 break;
2335
2336 p3 = p2 + 1; /* skips the '=' sign */
2337 if (p3 == ptr)
2338 break;
2339
2340 p4 = p3;
2341 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
2342 p4++;
2343
2344 /* here, we have the cookie name between p1 and p2,
2345 * and its value between p3 and p4.
2346 * we can process it.
2347 */
2348
2349 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2350 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2351 /* Cool... it's the right one */
2352
2353 /* If the cookie is in insert mode on a known server, we'll delete
2354 * this occurrence because we'll insert another one later.
2355 * We'll delete it too if the "indirect" option is set and we're in
2356 * a direct access. */
2357 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
2358 ((t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
2359 /* this header must be deleted */
2360 delete_header = 1;
2361 }
2362 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2363 /* replace bytes p3->p4 with the cookie name associated
2364 * with this server since we know it.
2365 */
2366 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2367 }
2368 break;
2369 }
2370 else {
2371 // fprintf(stderr,"Ignoring unknown cookie : ");
2372 // write(2, p1, p2-p1);
2373 // fprintf(stderr," = ");
2374 // write(2, p3, p4-p3);
2375 // fprintf(stderr,"\n");
2376 }
2377 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2378 } /* we're now at the end of the cookie value */
2379 } /* end of cookie processing */
2380
2381 /* let's look if we have to delete this header */
2382 if (delete_header) {
2383 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2384 }
2385 rep->h = rep->lr;
2386 } /* while (rep->lr < rep->r) */
2387
2388 /* end of header processing (even if incomplete) */
2389
2390 if ((rep->l < BUFSIZE - MAXREWRITE) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2391 FD_SET(t->srv_fd, StaticReadEvent);
2392 if (t->proxy->srvtimeout)
2393 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2394 else
2395 tv_eternity(&t->srexpire);
2396 }
willy tarreau0f7af912005-12-17 12:21:26 +01002397
2398 /* read or write error */
2399 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002400 tv_eternity(&t->srexpire);
2401 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002402 //FD_CLR(t->srv_fd, StaticReadEvent);
2403 //FD_CLR(t->srv_fd, StaticWriteEvent);
2404 //close(t->srv_fd);
2405 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002406 t->srv_state = SV_STCLOSE;
2407 return 1;
2408 }
2409 /* read timeout, last read, or end of client write */
2410 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
2411 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2412 FD_CLR(t->srv_fd, StaticReadEvent);
2413 tv_eternity(&t->srexpire);
2414 shutdown(t->srv_fd, SHUT_RD);
2415 t->srv_state = SV_STSHUTR;
2416 return 1;
2417
2418 }
2419 /* write timeout, or last client read and buffer empty */
2420 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2421 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2422 FD_CLR(t->srv_fd, StaticWriteEvent);
2423 tv_eternity(&t->swexpire);
2424 shutdown(t->srv_fd, SHUT_WR);
2425 t->srv_state = SV_STSHUTW;
2426 return 1;
2427 }
2428
2429 if (req->l == 0) {
2430 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2431 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2432 tv_eternity(&t->swexpire);
2433 }
2434 }
2435 else { /* client buffer not empty */
2436 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2437 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2438 if (t->proxy->srvtimeout)
2439 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2440 else
2441 tv_eternity(&t->swexpire);
2442 }
2443 }
2444
2445 if (rep->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
2446 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2447 FD_CLR(t->srv_fd, StaticReadEvent);
2448 tv_eternity(&t->srexpire);
2449 }
2450 }
2451
willy tarreau5cbea6f2005-12-17 12:48:26 +01002452 /* be nice with the client side which would like to send a complete header
2453 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2454 * would read all remaining data at once ! The client should not write past rep->lr
2455 * when the server is in header state.
2456 */
2457 //return header_processed;
2458 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002459 }
2460 else if (s == SV_STDATA) {
2461 /* read or write error */
2462 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002463 tv_eternity(&t->srexpire);
2464 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002465 //FD_CLR(t->srv_fd, StaticReadEvent);
2466 //FD_CLR(t->srv_fd, StaticWriteEvent);
2467 //close(t->srv_fd);
2468 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002469 t->srv_state = SV_STCLOSE;
2470 return 1;
2471 }
2472 /* read timeout, last read, or end of client write */
2473 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
2474 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2475
2476 FD_CLR(t->srv_fd, StaticReadEvent);
2477 tv_eternity(&t->srexpire);
2478 shutdown(t->srv_fd, SHUT_RD);
2479 t->srv_state = SV_STSHUTR;
2480 return 1;
2481
2482 }
2483 /* write timeout, or last client read and buffer empty */
2484 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2485 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2486 FD_CLR(t->srv_fd, StaticWriteEvent);
2487 tv_eternity(&t->swexpire);
2488 shutdown(t->srv_fd, SHUT_WR);
2489 t->srv_state = SV_STSHUTW;
2490 return 1;
2491 }
2492 else if (req->l == 0) {
2493 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2494 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2495 tv_eternity(&t->swexpire);
2496 }
2497 }
2498 else { /* buffer not empty */
2499 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2500 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2501 if (t->proxy->srvtimeout)
2502 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2503 else
2504 tv_eternity(&t->swexpire);
2505 }
2506 }
2507
2508 if (rep->l == BUFSIZE) { /* no room to read more data */
2509 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2510 FD_CLR(t->srv_fd, StaticReadEvent);
2511 tv_eternity(&t->srexpire);
2512 }
2513 }
2514 else {
2515 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2516 FD_SET(t->srv_fd, StaticReadEvent);
2517 if (t->proxy->srvtimeout)
2518 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2519 else
2520 tv_eternity(&t->srexpire);
2521 }
2522 }
2523
2524 return 0; /* other cases change nothing */
2525 }
2526 else if (s == SV_STSHUTR) {
2527 if ((t->res_sw == RES_ERROR) ||
2528 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2529 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002530 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002531 tv_eternity(&t->swexpire);
2532 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002533 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002534 t->srv_state = SV_STCLOSE;
2535 return 1;
2536 }
2537 else if (req->l == 0) {
2538 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2539 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2540 tv_eternity(&t->swexpire);
2541 }
2542 }
2543 else { /* buffer not empty */
2544 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2545 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2546 if (t->proxy->srvtimeout)
2547 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2548 else
2549 tv_eternity(&t->swexpire);
2550 }
2551 }
2552 return 0;
2553 }
2554 else if (s == SV_STSHUTW) {
2555 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2556 c == CL_STSHUTW || c == CL_STCLOSE ||
2557 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002558 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002559 tv_eternity(&t->srexpire);
2560 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002561 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002562 t->srv_state = SV_STCLOSE;
2563 return 1;
2564 }
2565 else if (rep->l == BUFSIZE) { /* no room to read more data */
2566 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2567 FD_CLR(t->srv_fd, StaticReadEvent);
2568 tv_eternity(&t->srexpire);
2569 }
2570 }
2571 else {
2572 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2573 FD_SET(t->srv_fd, StaticReadEvent);
2574 if (t->proxy->srvtimeout)
2575 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2576 else
2577 tv_eternity(&t->srexpire);
2578 }
2579 }
2580 return 0;
2581 }
2582 else { /* SV_STCLOSE : nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002583 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002584 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002585 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002586 write(1, trash, len);
2587 }
2588 return 0;
2589 }
2590 return 0;
2591}
2592
2593
willy tarreau5cbea6f2005-12-17 12:48:26 +01002594/* Processes the client and server jobs of a session task, then
2595 * puts it back to the wait queue in a clean state, or
2596 * cleans up its resources if it must be deleted. Returns
2597 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01002598 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002599int process_session(struct task *t) {
2600 struct session *s = t->context;
2601 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002602
willy tarreau5cbea6f2005-12-17 12:48:26 +01002603 do {
2604 fsm_resync = 0;
2605 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2606 fsm_resync |= process_cli(s);
2607 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2608 fsm_resync |= process_srv(s);
2609 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2610 } while (fsm_resync);
2611
2612 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002613 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002614 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01002615
willy tarreau5cbea6f2005-12-17 12:48:26 +01002616 tv_min(&min1, &s->crexpire, &s->cwexpire);
2617 tv_min(&min2, &s->srexpire, &s->swexpire);
2618 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002619 tv_min(&t->expire, &min1, &min2);
2620
2621 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002622 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01002623
willy tarreau5cbea6f2005-12-17 12:48:26 +01002624 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01002625 }
2626
willy tarreau5cbea6f2005-12-17 12:48:26 +01002627 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01002628 actconn--;
2629
willy tarreau5cbea6f2005-12-17 12:48:26 +01002630 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002631 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002632 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002633 write(1, trash, len);
2634 }
2635
2636 /* the task MUST not be in the run queue anymore */
2637 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002638 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01002639 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 return -1; /* rest in peace for eternity */
2641}
2642
2643
2644
2645/*
2646 * manages a server health-check. Returns
2647 * the time the task accepts to wait, or -1 for infinity.
2648 */
2649int process_chk(struct task *t) {
2650 struct server *s = t->context;
2651 int fd = s->curfd;
2652 int one = 1;
2653
2654 //fprintf(stderr, "process_chk: 1\n");
2655
2656 if (fd < 0) { /* no check currently running */
2657 //fprintf(stderr, "process_chk: 2\n");
2658 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
2659 task_queue(t); /* restore t to its place in the task list */
2660 return tv_remain(&now, &t->expire);
2661 }
2662
2663 /* we'll initiate a new check */
2664 s->result = 0; /* no result yet */
2665 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
2666 if ((fd < cfg_maxsock) &&
2667 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
2668 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
2669 //fprintf(stderr, "process_chk: 3\n");
2670
2671 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
2672 /* OK, connection in progress or established */
2673
2674 //fprintf(stderr, "process_chk: 4\n");
2675
2676 s->curfd = fd; /* that's how we know a test is in progress ;-) */
2677 fdtab[fd].owner = t;
2678 fdtab[fd].read = NULL;
2679 fdtab[fd].write = &event_srv_hck;
2680 fdtab[fd].state = FD_STCONN; /* connection in progress */
2681 FD_SET(fd, StaticWriteEvent); /* for connect status */
2682 fd_insert(fd);
2683 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2684 task_queue(t); /* restore t to its place in the task list */
2685 return tv_remain(&now, &t->expire);
2686 }
2687 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
2688 s->result = -1; /* a real error */
2689 }
2690 }
2691 //fprintf(stderr, "process_chk: 5\n");
2692 close(fd);
2693 }
2694
2695 if (!s->result) { /* nothing done */
2696 //fprintf(stderr, "process_chk: 6\n");
2697 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2698 task_queue(t); /* restore t to its place in the task list */
2699 return tv_remain(&now, &t->expire);
2700 }
2701
2702 /* here, we have seen a failure */
2703 if (s->health > FALLTIME)
2704 s->health--; /* still good */
2705 else {
2706 s->health = 0; /* failure */
2707 s->state &= ~SRV_RUNNING;
2708 }
2709
2710 //fprintf(stderr, "process_chk: 7\n");
2711 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2712 }
2713 else {
2714 //fprintf(stderr, "process_chk: 8\n");
2715 /* there was a test running */
2716 if (s->result > 0) { /* good server detected */
2717 //fprintf(stderr, "process_chk: 9\n");
2718 s->health++; /* was bad, stays for a while */
2719 if (s->health >= FALLTIME) {
2720 s->health = FALLTIME + RISETIME -1; /* OK now */
2721 s->state |= SRV_RUNNING;
2722 }
2723 s->curfd = -1;
2724 FD_CLR(fd, StaticWriteEvent);
2725 fd_delete(fd);
2726 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2727 }
2728 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
2729 //fprintf(stderr, "process_chk: 10\n");
2730 /* failure or timeout detected */
2731 if (s->health > FALLTIME)
2732 s->health--; /* still good */
2733 else {
2734 s->health = 0; /* failure */
2735 s->state &= ~SRV_RUNNING;
2736 }
2737 s->curfd = -1;
2738 FD_CLR(fd, StaticWriteEvent);
2739 fd_delete(fd);
2740 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2741 }
2742 /* if result is 0 and there's no timeout, we have to wait again */
2743 }
2744 //fprintf(stderr, "process_chk: 11\n");
2745 s->result = 0;
2746 task_queue(t); /* restore t to its place in the task list */
2747 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01002748}
2749
2750
willy tarreau5cbea6f2005-12-17 12:48:26 +01002751
willy tarreau0f7af912005-12-17 12:21:26 +01002752#if STATTIME > 0
2753int stats(void);
2754#endif
2755
2756/*
2757 * Main select() loop.
2758 */
2759
2760void select_loop() {
2761 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01002762 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01002763 int status;
2764 int fd,i;
2765 struct timeval delta;
2766 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002767 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01002768
willy tarreau5cbea6f2005-12-17 12:48:26 +01002769 tv_now(&now);
2770
2771 while (1) {
2772 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01002773
willy tarreau5cbea6f2005-12-17 12:48:26 +01002774 /* look for expired tasks and add them to the run queue.
2775 */
2776 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
2777 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
2778 tnext = t->next;
2779
2780 /* wakeup expired entries. It doesn't matter if they are
2781 * already running because of a previous event
2782 */
2783 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
2784 task_wakeup(&rq, t);
2785 }
2786 else {
2787 break;
2788 }
2789 }
2790
2791 /* process each task in the run queue now. Each task may be deleted
2792 * since we only use tnext.
2793 */
2794 tnext = rq;
2795 while ((t = tnext) != NULL) {
2796 int temp_time;
2797
2798 tnext = t->rqnext;
2799 task_sleep(&rq, t);
2800
2801 temp_time = t->process(t);
2802 next_time = MINTIME(temp_time, next_time);
2803 }
2804
2805
2806 /* maintain all proxies in a consistent state. This should quickly become a task */
2807 time2 = maintain_proxies();
2808 next_time = MINTIME(time2, next_time);
2809
2810 /* stop when there's no connection left and we don't allow them anymore */
2811 if (!actconn && listeners == 0)
2812 break;
2813
willy tarreau0f7af912005-12-17 12:21:26 +01002814
2815#if STATTIME > 0
2816 time2 = stats();
2817 // fprintf(stderr," stats = %d\n", time2);
2818 next_time = MINTIME(time2, next_time);
2819#endif
2820
willy tarreau5cbea6f2005-12-17 12:48:26 +01002821 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01002822 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002823 /* to avoid eventual select loops due to timer precision */
2824 next_time += SCHEDULER_RESOLUTION;
2825 delta.tv_sec = next_time / 1000;
2826 delta.tv_usec = (next_time % 1000) * 1000;
2827 }
2828 else if (next_time == 0) { /* allow select to return immediately when needed */
2829 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002830 }
2831
2832
2833 /* let's restore fdset state */
2834
2835 readnotnull = 0; writenotnull = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836 for (i = 0; i < (cfg_maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01002837 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2838 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2839 }
2840
2841// /* just a verification code, needs to be removed for performance */
2842// for (i=0; i<maxfd; i++) {
2843// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2844// abort();
2845// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2846// abort();
2847//
2848// }
2849
2850 status=select(maxfd,
2851 readnotnull ? ReadEvent : NULL,
2852 writenotnull ? WriteEvent : NULL,
2853 NULL,
2854 (next_time >= 0) ? &delta : NULL);
2855
willy tarreau5cbea6f2005-12-17 12:48:26 +01002856 /* this is an experiment on the separation of the select work */
2857 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2858 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2859
willy tarreau0f7af912005-12-17 12:21:26 +01002860 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002861
willy tarreau0f7af912005-12-17 12:21:26 +01002862 if (status > 0) { /* must proceed with events */
2863
2864 int fds;
2865 char count;
2866
2867 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2868 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2869 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2870
willy tarreau5cbea6f2005-12-17 12:48:26 +01002871 /* if we specify read first, the accepts and zero reads will be
2872 * seen first. Moreover, system buffers will be flushed faster.
2873 */
willy tarreau0f7af912005-12-17 12:21:26 +01002874 if (fdtab[fd].state == FD_STCLOSE)
2875 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002876
2877 if (FD_ISSET(fd, ReadEvent))
2878 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879
2880 if (fdtab[fd].state == FD_STCLOSE)
2881 continue;
2882
2883 if (FD_ISSET(fd, WriteEvent))
2884 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002885 }
2886 }
2887 else {
2888 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2889 }
willy tarreau0f7af912005-12-17 12:21:26 +01002890 }
2891}
2892
2893
2894#if STATTIME > 0
2895/*
2896 * Display proxy statistics regularly. It is designed to be called from the
2897 * select_loop().
2898 */
2899int stats(void) {
2900 static int lines;
2901 static struct timeval nextevt;
2902 static struct timeval lastevt;
2903 static struct timeval starttime = {0,0};
2904 unsigned long totaltime, deltatime;
2905 int ret;
2906
2907 if (tv_remain(&now, &nextevt) == 0) {
2908 deltatime = (tv_delta(&now, &lastevt)?:1);
2909 totaltime = (tv_delta(&now, &starttime)?:1);
2910
2911 if (mode & MODE_STATS) {
2912 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002913 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01002914 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2915 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002916 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01002917 actconn, totalconn,
2918 stats_tsk_new, stats_tsk_good,
2919 stats_tsk_left, stats_tsk_right,
2920 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2921 }
2922 }
2923
2924 tv_delayfrom(&nextevt, &now, STATTIME);
2925
2926 lastevt=now;
2927 }
2928 ret = tv_remain(&now, &nextevt);
2929 return ret;
2930}
2931#endif
2932
2933
2934/*
2935 * this function enables proxies when there are enough free sessions,
2936 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937 * select_loop(). It returns the time left before next expiration event
2938 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01002939 */
2940static int maintain_proxies(void) {
2941 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002942 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01002943
2944 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002945 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01002946
2947 /* if there are enough free sessions, we'll activate proxies */
2948 if (actconn < cfg_maxconn) {
2949 while (p) {
2950 if (p->nbconn < p->maxconn) {
2951 if (p->state == PR_STIDLE) {
2952 FD_SET(p->listen_fd, StaticReadEvent);
2953 p->state = PR_STRUN;
2954 }
2955 }
2956 else {
2957 if (p->state == PR_STRUN) {
2958 FD_CLR(p->listen_fd, StaticReadEvent);
2959 p->state = PR_STIDLE;
2960 }
2961 }
2962 p = p->next;
2963 }
2964 }
2965 else { /* block all proxies */
2966 while (p) {
2967 if (p->state == PR_STRUN) {
2968 FD_CLR(p->listen_fd, StaticReadEvent);
2969 p->state = PR_STIDLE;
2970 }
2971 p = p->next;
2972 }
2973 }
2974
willy tarreau5cbea6f2005-12-17 12:48:26 +01002975 if (stopping) {
2976 p = proxy;
2977 while (p) {
2978 if (p->state != PR_STDISABLED) {
2979 int t;
2980 t = tv_remain(&now, &p->stop_time);
2981 if (t == 0) {
2982 //FD_CLR(p->listen_fd, StaticReadEvent);
2983 //close(p->listen_fd);
2984 fd_delete(p->listen_fd);
2985 p->state = PR_STDISABLED;
2986 listeners--;
2987 }
2988 else {
2989 tleft = MINTIME(t, tleft);
2990 }
2991 }
2992 p = p->next;
2993 }
2994 }
2995 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01002996}
2997
2998/*
2999 * this function disables health-check servers so that the process will quickly be ignored
3000 * by load balancers.
3001 */
3002static void soft_stop(void) {
3003 struct proxy *p;
3004
3005 stopping = 1;
3006 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003007 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003008 while (p) {
3009 if (p->state != PR_STDISABLED)
3010 tv_delayfrom(&p->stop_time, &now, p->grace);
3011 p = p->next;
3012 }
3013}
3014
3015/*
3016 * upon SIGUSR1, let's have a soft stop.
3017 */
3018void sig_soft_stop(int sig) {
3019 soft_stop();
3020 signal(sig, SIG_IGN);
3021}
3022
3023
3024void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003025 struct task *t, *tnext;
3026 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003027
willy tarreau5cbea6f2005-12-17 12:48:26 +01003028 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3029 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3030 tnext = t->next;
3031 s = t->context;
3032 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3033 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3034 "req=%d, rep=%d, clifd=%d\n",
3035 s, tv_remain(&now, &t->expire),
3036 s->cli_state,
3037 s->srv_state,
3038 FD_ISSET(s->cli_fd, StaticReadEvent),
3039 FD_ISSET(s->cli_fd, StaticWriteEvent),
3040 FD_ISSET(s->srv_fd, StaticReadEvent),
3041 FD_ISSET(s->srv_fd, StaticWriteEvent),
3042 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3043 );
willy tarreau0f7af912005-12-17 12:21:26 +01003044 }
3045}
3046
3047/*
3048 * This function reads and parses the configuration file given in the argument.
3049 * returns 0 if OK, -1 if error.
3050 */
3051int readcfgfile(char *file) {
3052 char thisline[256];
3053 char *line;
3054 FILE *f;
3055 int linenum = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003056 char *end;
3057 char *args[MAX_LINE_ARGS];
willy tarreau0f7af912005-12-17 12:21:26 +01003058 int arg;
3059 int cfgerr = 0;
3060
3061 struct proxy *curproxy = NULL;
3062 struct server *newsrv = NULL;
3063
3064 if ((f=fopen(file,"r")) == NULL)
3065 return -1;
3066
3067 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
3068 linenum++;
willy tarreau0f7af912005-12-17 12:21:26 +01003069
willy tarreau5cbea6f2005-12-17 12:48:26 +01003070 end = line + strlen(line);
willy tarreau0f7af912005-12-17 12:21:26 +01003071
willy tarreau5cbea6f2005-12-17 12:48:26 +01003072 /* skip leading spaces */
3073 while (isspace(*line))
3074 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01003075
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076 arg = 0;
3077 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01003078
willy tarreau5cbea6f2005-12-17 12:48:26 +01003079 while (*line && arg < MAX_LINE_ARGS) {
3080 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
3081 * C equivalent value. Other combinations left unchanged (eg: \1).
3082 */
3083 if (*line == '\\') {
3084 int skip = 0;
3085 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
3086 *line = line[1];
3087 skip = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003088 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003089 else if (line[1] == 'r') {
3090 *line = '\r';
3091 skip = 1;
3092 }
3093 else if (line[1] == 'n') {
3094 *line = '\n';
3095 skip = 1;
3096 }
3097 else if (line[1] == 't') {
3098 *line = '\t';
3099 skip = 1;
3100 }
3101 else if (line[1] == 'x' && (line + 3 < end )) {
3102 unsigned char hex1, hex2;
3103 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
3104 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3105 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3106 *line = (hex1<<4) + hex2;
3107 skip = 3;
3108 }
3109 if (skip) {
3110 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
3111 end -= skip;
3112 }
willy tarreau0f7af912005-12-17 12:21:26 +01003113 line++;
3114 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003115 else {
3116 if (*line == '#' || *line == '\n' || *line == '\r')
3117 *line = 0; /* end of string, end of loop */
3118 else
willy tarreau0f7af912005-12-17 12:21:26 +01003119 line++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120
3121 /* a non-escaped space is an argument separator */
3122 if (isspace(*line)) {
3123 *line++ = 0;
3124 while (isspace(*line))
3125 line++;
3126 args[++arg] = line;
3127 }
willy tarreau0f7af912005-12-17 12:21:26 +01003128 }
3129 }
3130
willy tarreau5cbea6f2005-12-17 12:48:26 +01003131 /* empty line */
3132 if (!**args)
3133 continue;
3134
3135 /* zero out remaining args */
3136 while (++arg < MAX_LINE_ARGS) {
3137 args[arg] = line;
3138 }
3139
willy tarreau0f7af912005-12-17 12:21:26 +01003140 if (!strcmp(args[0], "listen")) { /* new proxy */
3141 if (strchr(args[2], ':') == NULL) {
3142 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3143 file, linenum);
3144 return -1;
3145 }
3146
3147 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
3148 == NULL) {
3149 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3150 exit(1);
3151 }
3152 curproxy->next = proxy;
3153 proxy = curproxy;
3154 curproxy->id = strdup(args[1]);
3155 curproxy->listen_addr = *str2sa(args[2]);
3156 curproxy->state = PR_STNEW;
willy tarreau0f7af912005-12-17 12:21:26 +01003157 /* set default values */
3158 curproxy->maxconn = cfg_maxpconn;
3159 curproxy->conn_retries = CONN_RETRIES;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003160 curproxy->options = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003161 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3162 curproxy->mode = PR_MODE_TCP;
3163 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3164 continue;
3165 }
3166 else if (curproxy == NULL) {
3167 Alert("parsing [%s:%d] : <listen> expected.\n",
3168 file, linenum);
3169 return -1;
3170 }
3171
3172 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3173 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3174 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3175 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3176 else {
3177 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3178 return -1;
3179 }
3180 }
3181 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3182 curproxy->state = PR_STDISABLED;
3183 }
3184 else if (!strcmp(args[0], "cookie")) { /* cookie name */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003185 int cur_arg;
willy tarreau0f7af912005-12-17 12:21:26 +01003186 if (curproxy->cookie_name != NULL) {
3187 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3188 file, linenum);
3189 continue;
3190 }
3191
3192 if (*(args[1]) == 0) {
3193 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3194 file, linenum);
3195 return -1;
3196 }
3197 curproxy->cookie_name = strdup(args[1]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003198
3199 cur_arg = 2;
3200 while (*(args[cur_arg])) {
3201 if (!strcmp(args[cur_arg], "rewrite")) {
3202 curproxy->options |= PR_O_COOK_RW;
3203 }
3204 else if (!strcmp(args[cur_arg], "indirect")) {
3205 curproxy->options |= PR_O_COOK_IND;
3206 }
3207 else if (!strcmp(args[cur_arg], "insert")) {
3208 curproxy->options |= PR_O_COOK_INS;
3209 }
3210 else {
3211 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
3212 file, linenum);
3213 return -1;
3214 }
3215 cur_arg++;
3216 }
3217 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3218 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3219 file, linenum);
3220 return -1;
3221 }
willy tarreau0f7af912005-12-17 12:21:26 +01003222 }
3223 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3224 if (curproxy->contimeout != 0) {
3225 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
3226 file, linenum);
3227 continue;
3228 }
3229 if (*(args[1]) == 0) {
3230 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3231 file, linenum);
3232 return -1;
3233 }
3234 curproxy->contimeout = atol(args[1]);
3235 }
3236 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3237 if (curproxy->clitimeout != 0) {
3238 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3239 file, linenum);
3240 continue;
3241 }
3242 if (*(args[1]) == 0) {
3243 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3244 file, linenum);
3245 return -1;
3246 }
3247 curproxy->clitimeout = atol(args[1]);
3248 }
3249 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3250 if (curproxy->srvtimeout != 0) {
3251 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
3252 file, linenum);
3253 continue;
3254 }
3255 if (*(args[1]) == 0) {
3256 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
3257 file, linenum);
3258 return -1;
3259 }
3260 curproxy->srvtimeout = atol(args[1]);
3261 }
3262 else if (!strcmp(args[0], "retries")) { /* connection retries */
3263 if (*(args[1]) == 0) {
3264 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3265 file, linenum);
3266 return -1;
3267 }
3268 curproxy->conn_retries = atol(args[1]);
3269 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003270 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3271 /* enable reconnections to dispatch */
3272 curproxy->options |= PR_O_REDISP;
willy tarreau0f7af912005-12-17 12:21:26 +01003273 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003274#ifdef TRANSPARENT
3275 else if (!strcmp(args[0], "transparent")) {
3276 /* enable transparent proxy connections */
3277 curproxy->options |= PR_O_TRANSP;
3278 }
3279#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003280 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3281 if (*(args[1]) == 0) {
3282 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
3283 file, linenum);
3284 return -1;
3285 }
3286 curproxy->maxconn = atol(args[1]);
3287 }
3288 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3289 if (*(args[1]) == 0) {
3290 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
3291 file, linenum);
3292 return -1;
3293 }
3294 curproxy->grace = atol(args[1]);
3295 }
3296 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3297 if (strchr(args[1], ':') == NULL) {
3298 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
3299 file, linenum);
3300 return -1;
3301 }
3302 curproxy->dispatch_addr = *str2sa(args[1]);
3303 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003304 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3305 if (*(args[1])) {
3306 if (!strcmp(args[1], "roundrobin")) {
3307 curproxy->options |= PR_O_BALANCE_RR;
3308 }
3309 else {
3310 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n",
3311 file, linenum);
3312 return -1;
3313 }
3314 }
3315 else /* if no option is set, use round-robin by default */
3316 curproxy->options |= PR_O_BALANCE_RR;
3317 }
willy tarreau0f7af912005-12-17 12:21:26 +01003318 else if (!strcmp(args[0], "server")) { /* server address */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003319 int cur_arg;
3320
willy tarreau0f7af912005-12-17 12:21:26 +01003321 if (strchr(args[2], ':') == NULL) {
3322 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3323 file, linenum);
3324 return -1;
3325 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003326 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3327 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003328 exit(1);
3329 }
3330 newsrv->next = curproxy->srv;
3331 curproxy->srv = newsrv;
3332 newsrv->id = strdup(args[1]);
3333 newsrv->addr = *str2sa(args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003334 newsrv->state = SRV_RUNNING; /* early server setup */
3335 newsrv->health = FALLTIME; /* up, but will fall down at first failure */
3336 newsrv->curfd = -1; /* no health-check in progress */
3337 cur_arg = 3;
3338 while (*args[cur_arg]) {
3339 if (!strcmp(args[cur_arg], "cookie")) {
3340 newsrv->cookie = strdup(args[cur_arg + 1]);
3341 newsrv->cklen = strlen(args[cur_arg + 1]);
3342 cur_arg += 2;
3343 }
3344 else if (!strcmp(args[cur_arg], "check")) {
3345 struct task *t;
3346
3347 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3348 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3349 return -1;
3350 }
3351
3352 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3353 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3354 t->state = TASK_IDLE;
3355 t->process = process_chk;
3356 t->context = newsrv;
3357
3358 tv_delayfrom(&t->expire, &now, CHK_INTERVAL); /* check this every ms */
3359 task_queue(t);
3360 task_wakeup(&rq, t);
3361
3362 cur_arg += 1;
3363 }
3364 else {
3365 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3366 file, linenum, newsrv->id);
3367 return -1;
3368 }
3369 }
3370 curproxy->nbservers++;
willy tarreau0f7af912005-12-17 12:21:26 +01003371 }
3372 else if (!strcmp(args[0], "log")) { /* syslog server address */
3373 struct sockaddr_in *sa;
3374 int facility;
3375
3376 if (*(args[1]) == 0 || *(args[2]) == 0) {
3377 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
3378 file, linenum);
3379 return -1;
3380 }
3381
3382 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3383 if (!strcmp(log_facilities[facility], args[2]))
3384 break;
3385
3386 if (facility >= NB_LOG_FACILITIES) {
3387 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3388 exit(1);
3389 }
3390
3391 sa = str2sa(args[1]);
3392 if (!sa->sin_port)
3393 sa->sin_port = htons(SYSLOG_PORT);
3394
3395 if (curproxy->logfac1 == -1) {
3396 curproxy->logsrv1 = *sa;
3397 curproxy->logfac1 = facility;
3398 }
3399 else if (curproxy->logfac2 == -1) {
3400 curproxy->logsrv2 = *sa;
3401 curproxy->logfac2 = facility;
3402 }
3403 else {
3404 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3405 exit(1);
3406 }
3407
3408 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003409 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003410 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003411 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3412 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003413 file, linenum);
3414 continue;
3415 }
3416
3417 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003418 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003419 file, linenum);
3420 return -1;
3421 }
3422
3423 preg = calloc(1, sizeof(regex_t));
3424 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3425 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3426 return -1;
3427 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003428 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3429 curproxy->req_exp[curproxy->nb_reqexp].replace = strdup(args[2]);
3430 curproxy->nb_reqexp++;
willy tarreau0f7af912005-12-17 12:21:26 +01003431 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003432 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003433 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003434 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3435 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
3436 file, linenum);
3437 continue;
3438 }
3439
3440 if (*(args[1]) == 0) {
3441 Alert("parsing [%s:%d] : <reqdel> expects <search> as an argument.\n",
3442 file, linenum);
3443 return -1;
3444 }
3445
3446 preg = calloc(1, sizeof(regex_t));
3447 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3448 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3449 return -1;
3450 }
3451 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3452 curproxy->req_exp[curproxy->nb_reqexp].replace = NULL; /* means it must be deleted */
3453 curproxy->nb_reqexp++;
3454 }
3455 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3456 if (curproxy->nb_reqadd >= MAX_REGEXP) {
3457 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
3458 file, linenum);
3459 continue;
3460 }
3461
3462 if (*(args[1]) == 0) {
3463 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n",
3464 file, linenum);
3465 return -1;
3466 }
3467
3468 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
3469 }
3470 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3471 regex_t *preg;
3472 if (curproxy->nb_rspexp >= MAX_REGEXP) {
willy tarreau0f7af912005-12-17 12:21:26 +01003473 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3474 file, linenum);
3475 continue;
3476 }
3477
3478 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003479 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003480 file, linenum);
3481 return -1;
3482 }
3483
3484 preg = calloc(1, sizeof(regex_t));
3485 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3486 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3487 return -1;
3488 }
3489 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003490 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3491 curproxy->rsp_exp[curproxy->nb_rspexp].replace = strdup(args[2]);
3492 curproxy->nb_rspexp++;
3493 }
3494 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3495 regex_t *preg;
3496 if (curproxy->nb_rspexp >= MAX_REGEXP) {
3497 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3498 file, linenum);
3499 continue;
3500 }
3501
3502 if (*(args[1]) == 0) {
3503 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n",
3504 file, linenum);
3505 return -1;
3506 }
3507
3508 preg = calloc(1, sizeof(regex_t));
3509 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3510 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3511 return -1;
3512 }
3513 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
3514 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3515 curproxy->rsp_exp[curproxy->nb_rspexp].replace = NULL; /* means it must be deleted */
3516 curproxy->nb_rspexp++;
3517 }
3518 else if (!strcmp(args[0], "rspadd")) { /* add response header */
3519 if (curproxy->nb_rspadd >= MAX_REGEXP) {
3520 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3521 file, linenum);
3522 continue;
3523 }
3524
3525 if (*(args[1]) == 0) {
3526 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n",
3527 file, linenum);
3528 return -1;
3529 }
3530
3531 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01003532 }
3533 else {
3534 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
3535 exit(1);
3536 }
3537 }
3538 fclose(f);
3539
3540 /*
3541 * Now, check for the integrity of all that we have collected.
3542 */
3543
3544 if ((curproxy = proxy) == NULL) {
3545 Alert("parsing %s : no <listen> line. Nothing to do !\n",
3546 file);
3547 return -1;
3548 }
3549
3550 while (curproxy != NULL) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003551 if ((curproxy->mode != PR_MODE_HEALTH) &&
3552 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
3553 (*(int *)&curproxy->dispatch_addr == 0)) {
3554 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
3555 file, curproxy->id);
3556 cfgerr++;
3557 }
3558 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
3559 if (curproxy->options & PR_O_TRANSP) {
3560 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
3561 file, curproxy->id);
3562 cfgerr++;
3563 }
3564 else if (curproxy->srv == NULL) {
3565 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
3566 file, curproxy->id);
3567 cfgerr++;
3568 }
3569 else if (*(int *)&curproxy->dispatch_addr != 0) {
3570 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
3571 file, curproxy->id);
3572 }
3573 }
3574 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01003575 if (curproxy->cookie_name != NULL) {
3576 Warning("parsing %s : cookie will be ignored for listener %s.\n",
3577 file, curproxy->id);
3578 }
3579 if ((newsrv = curproxy->srv) != NULL) {
3580 Warning("parsing %s : servers will be ignored for listener %s.\n",
3581 file, curproxy->id);
3582 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003583 if (curproxy->nb_rspexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003584 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
3585 file, curproxy->id);
3586 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003587 if (curproxy->nb_reqexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003588 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
3589 file, curproxy->id);
3590 }
3591 }
3592 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
3593 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
3594 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
3595 file, curproxy->id);
3596 cfgerr++;
3597 }
3598 else {
3599 while (newsrv != NULL) {
3600 /* nothing to check for now */
3601 newsrv = newsrv->next;
3602 }
3603 }
3604 }
3605 curproxy = curproxy->next;
3606 }
3607 if (cfgerr > 0) {
3608 Alert("Errors found in configuration file, aborting.\n");
3609 return -1;
3610 }
3611 else
3612 return 0;
3613}
3614
3615
3616/*
3617 * This function initializes all the necessary variables. It only returns
3618 * if everything is OK. If something fails, it exits.
3619 */
3620void init(int argc, char **argv) {
3621 int i;
3622 char *old_argv = *argv;
3623 char *tmp;
3624
3625 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003626 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003627 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
3628 sizeof(int)*8);
3629 exit(1);
3630 }
3631
3632 pid = getpid();
3633 progname = *argv;
3634 while ((tmp = strchr(progname, '/')) != NULL)
3635 progname = tmp + 1;
3636
3637 argc--; argv++;
3638 while (argc > 0) {
3639 char *flag;
3640
3641 if (**argv == '-') {
3642 flag = *argv+1;
3643
3644 /* 1 arg */
3645 if (*flag == 'v') {
3646 display_version();
3647 exit(0);
3648 }
3649 else if (*flag == 'd')
3650 mode |= MODE_DEBUG;
3651 else if (*flag == 'D')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003652 mode |= MODE_DAEMON | MODE_QUIET;
3653 else if (*flag == 'q')
3654 mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01003655#if STATTIME > 0
3656 else if (*flag == 's')
3657 mode |= MODE_STATS;
3658 else if (*flag == 'l')
3659 mode |= MODE_LOG;
3660#endif
3661 else { /* >=2 args */
3662 argv++; argc--;
3663 if (argc == 0)
3664 usage(old_argv);
3665
3666 switch (*flag) {
3667 case 'n' : cfg_maxconn = atol(*argv); break;
3668 case 'N' : cfg_maxpconn = atol(*argv); break;
3669 case 'f' : cfg_cfgfile = *argv; break;
3670 default: usage(old_argv);
3671 }
3672 }
3673 }
3674 else
3675 usage(old_argv);
3676 argv++; argc--;
3677 }
3678
3679 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
3680
3681 if (!cfg_cfgfile)
3682 usage(old_argv);
3683
3684 gethostname(hostname, MAX_HOSTNAME_LEN);
3685
3686 if (readcfgfile(cfg_cfgfile) < 0) {
3687 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
3688 exit(1);
3689 }
3690
3691 ReadEvent = (fd_set *)calloc(1,
3692 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003693 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003694 WriteEvent = (fd_set *)calloc(1,
3695 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003696 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003697 StaticReadEvent = (fd_set *)calloc(1,
3698 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003699 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003700 StaticWriteEvent = (fd_set *)calloc(1,
3701 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003702 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003703
3704 fdtab = (struct fdtab *)calloc(1,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003705 sizeof(struct fdtab) * (cfg_maxsock));
3706 for (i = 0; i < cfg_maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003707 fdtab[i].state = FD_STCLOSE;
3708 }
3709}
3710
3711/*
3712 * this function starts all the proxies. It returns 0 if OK, -1 if not.
3713 */
3714int start_proxies() {
3715 struct proxy *curproxy;
3716 int one = 1;
3717 int fd;
3718
3719 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
3720
3721 if (curproxy->state == PR_STDISABLED)
3722 continue;
3723
3724 if ((fd = curproxy->listen_fd =
3725 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
3726 Alert("cannot create listening socket for proxy %s. Aborting.\n",
3727 curproxy->id);
3728 return -1;
3729 }
3730
willy tarreau5cbea6f2005-12-17 12:48:26 +01003731 if (fd >= cfg_maxsock) {
3732 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
3733 curproxy->id);
3734 close(fd);
3735 return -1;
3736 }
3737
willy tarreau0f7af912005-12-17 12:21:26 +01003738 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
3739 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
3740 (char *) &one, sizeof(one)) == -1)) {
3741 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
3742 curproxy->id);
3743 close(fd);
3744 return -1;
3745 }
3746
3747 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
3748 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
3749 curproxy->id);
3750 }
3751
3752 if (bind(fd,
3753 (struct sockaddr *)&curproxy->listen_addr,
3754 sizeof(curproxy->listen_addr)) == -1) {
3755 Alert("cannot bind socket for proxy %s. Aborting.\n",
3756 curproxy->id);
3757 close(fd);
3758 return -1;
3759 }
3760
3761 if (listen(fd, curproxy->maxconn) == -1) {
3762 Alert("cannot listen to socket for proxy %s. Aborting.\n",
3763 curproxy->id);
3764 close(fd);
3765 return -1;
3766 }
3767
3768 /* the function for the accept() event */
3769 fdtab[fd].read = &event_accept;
3770 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003771 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01003772 curproxy->state = PR_STRUN;
3773 fdtab[fd].state = FD_STLISTEN;
3774 FD_SET(fd, StaticReadEvent);
3775 fd_insert(fd);
3776 listeners++;
3777// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3778 }
3779 return 0;
3780}
3781
3782
3783int main(int argc, char **argv) {
3784 init(argc, argv);
3785
3786 if (mode & MODE_DAEMON) {
3787 int ret;
3788
3789 ret = fork();
3790
3791 if (ret > 0)
3792 exit(0); /* parent must leave */
3793 else if (ret < 0) {
3794 Alert("[%s.main()] Cannot fork\n", argv[0]);
3795 exit(1); /* there has been an error */
3796 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003797 setpgid(1, 0);
3798 }
willy tarreau0f7af912005-12-17 12:21:26 +01003799
willy tarreau5cbea6f2005-12-17 12:48:26 +01003800 if (mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01003801 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003802 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01003803 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01003804 }
3805
3806 signal(SIGQUIT, dump);
3807 signal(SIGUSR1, sig_soft_stop);
3808
3809 /* on very high loads, a sigpipe sometimes happen just between the
3810 * getsockopt() which tells "it's OK to write", and the following write :-(
3811 */
willy tarreau3242e862005-12-17 12:27:53 +01003812#ifndef MSG_NOSIGNAL
3813 signal(SIGPIPE, SIG_IGN);
3814#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003815
3816 if (start_proxies() < 0)
3817 exit(1);
3818
3819 select_loop();
3820
3821 exit(0);
3822}