blob: 9c9d65944139ae8e9253e54928ac556affca2ea5 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
3 * 2000-2002 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreauef900ab2005-12-17 12:52:52 +010010 * Pending bugs :
11 * - cookie in insert+indirect mode sometimes segfaults !
12 * - a proxy with an invalid config will prevent the startup even if disabled.
13 *
willy tarreau0f7af912005-12-17 12:21:26 +010014 * ChangeLog :
15 *
willy tarreaue47c8d72005-12-17 12:55:52 +010016 * 2002/03/25
17 * - released 1.1.4
18 * - made rise/fall/interval time configurable
willy tarreaub719f002005-12-17 12:55:07 +010019 * 2002/03/22
20 * - released 1.1.3
21 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
22 * which could lead to loops.
willy tarreauef900ab2005-12-17 12:52:52 +010023 * 2002/03/21
24 * - released 1.1.2
25 * - fixed a bug in buffer management where we could have a loop
26 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
27 * => implemented an adjustable buffer limit.
28 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
29 * and running tasks are skipped.
30 * - added some debug lines for accept events.
31 * - send warnings for servers up/down.
willy tarreauefae1842005-12-17 12:51:03 +010032 * 2002/03/12
33 * - released 1.1.1
34 * - fixed a bug in total failure handling
35 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreau5cbea6f2005-12-17 12:48:26 +010036 * 2002/03/10
37 * - released 1.1.0
38 * - fixed a few timeout bugs
39 * - rearranged the task scheduler subsystem to improve performance,
40 * add new tasks, and make it easier to later port to librt ;
41 * - allow multiple accept() for one select() wake up ;
42 * - implemented internal load balancing with basic health-check ;
43 * - cookie insertion and header add/replace/delete, with better strings
44 * support.
45 * 2002/03/08
46 * - reworked buffer handling to fix a few rewrite bugs, and
47 * improve overall performance.
48 * - implement the "purge" option to delete server cookies in direct mode.
49 * 2002/03/07
50 * - fixed some error cases where the maxfd was not decreased.
51 * 2002/02/26
52 * - now supports transparent proxying, at least on linux 2.4.
53 * 2002/02/12
54 * - soft stop works again (fixed select timeout computation).
55 * - it seems that TCP proxies sometimes cannot timeout.
56 * - added a "quiet" mode.
57 * - enforce file descriptor limitation on socket() and accept().
58 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010059 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010060 * 2001/12/16 : release of version 1.0.0.
61 * 2001/12/16 : added syslog capability for each accepted connection.
62 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
63 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
64 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
65 * with or without cookies (use keyword http for this).
66 * 2001/09/01 : added client/server header replacing with regexps.
67 * eg:
68 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
69 * srvexp ^Server:\ .* Server:\ Apache
70 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
71 * 2000/11/28 : major rewrite
72 * 2000/11/26 : first write
73 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010074 * TODO:
75 * - handle properly intermediate incomplete server headers. Done ?
76 * - log proxies start/stop
77 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010078 *
79 */
80
81#include <stdio.h>
82#include <stdlib.h>
83#include <unistd.h>
84#include <string.h>
85#include <ctype.h>
86#include <sys/time.h>
87#include <sys/types.h>
88#include <sys/socket.h>
89#include <netinet/tcp.h>
90#include <netinet/in.h>
91#include <arpa/inet.h>
92#include <netdb.h>
93#include <fcntl.h>
94#include <errno.h>
95#include <signal.h>
96#include <stdarg.h>
97#include <sys/resource.h>
98#include <time.h>
99#include <regex.h>
100#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +0100101#if defined(TRANSPARENT) && defined(NETFILTER)
102#include <linux/netfilter_ipv4.h>
103#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100104
willy tarreaue47c8d72005-12-17 12:55:52 +0100105#define HAPROXY_VERSION "1.1.4"
106#define HAPROXY_DATE "2002/03/25"
willy tarreau0f7af912005-12-17 12:21:26 +0100107
108/* this is for libc5 for example */
109#ifndef TCP_NODELAY
110#define TCP_NODELAY 1
111#endif
112
113#ifndef SHUT_RD
114#define SHUT_RD 0
115#endif
116
117#ifndef SHUT_WR
118#define SHUT_WR 1
119#endif
120
121#define BUFSIZE 4096
122
123// reserved buffer space for header rewriting
124#define MAXREWRITE 256
125
willy tarreau5cbea6f2005-12-17 12:48:26 +0100126// max # args on a configuration line
127#define MAX_LINE_ARGS 10
128
willy tarreau0f7af912005-12-17 12:21:26 +0100129// max # of regexps per proxy
130#define MAX_REGEXP 10
131
132// max # of matches per regexp
133#define MAX_MATCH 10
134
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100136#define COOKIENAME_LEN 16
137#define SERVERID_LEN 16
138#define CONN_RETRIES 3
139
willy tarreau5cbea6f2005-12-17 12:48:26 +0100140/* FIXME: this should be user-configurable */
141#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100142#define DEF_CHKINTR 2000
143#define DEF_FALLTIME 3
144#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100145
willy tarreau0f7af912005-12-17 12:21:26 +0100146/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
147#define INTBITS 5
148
149/* show stats this every millisecond, 0 to disable */
150#ifndef STATTIME
151#define STATTIME 2000
152#endif
153
willy tarreau5cbea6f2005-12-17 12:48:26 +0100154/* this reduces the number of calls to select() by choosing appropriate
155 * sheduler precision in milliseconds. It should be near the minimum
156 * time that is needed by select() to collect all events. All timeouts
157 * are rounded up by adding this value prior to pass it to select().
158 */
159#define SCHEDULER_RESOLUTION 9
160
willy tarreau0f7af912005-12-17 12:21:26 +0100161#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
162#define SETNOW(a) (*a=now)
163
willy tarreau9da061b2005-12-17 12:29:56 +0100164/****** string-specific macros and functions ******/
165/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
166#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
167
168/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
169#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
170
171
172#ifndef HAVE_STRLCPY
173/*
174 * copies at most <size-1> chars from <src> to <dst>. Last char is always
175 * set to 0, unless <size> is 0. The number of chars copied is returned
176 * (excluding the terminating zero).
177 * This code has been optimized for size and speed : on x86, it's 45 bytes
178 * long, uses only registers, and consumes only 4 cycles per char.
179 */
180int strlcpy(char *dst, const char *src, int size) {
181 char *orig = dst;
182 if (size) {
183 while (--size && (*dst = *src)) {
184 src++; dst++;
185 }
186 *dst = 0;
187 }
188 return dst - orig;
189}
190#endif
191
192
willy tarreau0f7af912005-12-17 12:21:26 +0100193#define MEM_OPTIM
194#ifdef MEM_OPTIM
195/*
196 * Returns a pointer to type <type> taken from the
197 * pool <pool_type> or dynamically allocated. In the
198 * first case, <pool_type> is updated to point to the
199 * next element in the list.
200 */
201#define pool_alloc(type) ({ \
202 void *p; \
203 if ((p = pool_##type) == NULL) \
204 p = malloc(sizeof_##type); \
205 else { \
206 pool_##type = *(void **)pool_##type; \
207 } \
208 p; \
209})
210
211/*
212 * Puts a memory area back to the corresponding pool.
213 * Items are chained directly through a pointer that
214 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100215 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100216 * that each memory area is at least as big as one
217 * pointer.
218 */
219#define pool_free(type, ptr) ({ \
220 *(void **)ptr = (void *)pool_##type; \
221 pool_##type = (void *)ptr; \
222})
223
224#else
225#define pool_alloc(type) (calloc(1,sizeof_##type));
226#define pool_free(type, ptr) (free(ptr));
227#endif /* MEM_OPTIM */
228
willy tarreau5cbea6f2005-12-17 12:48:26 +0100229#define sizeof_task sizeof(struct task)
230#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100231#define sizeof_buffer sizeof(struct buffer)
232#define sizeof_fdtab sizeof(struct fdtab)
233#define sizeof_str256 256
234
235
willy tarreau5cbea6f2005-12-17 12:48:26 +0100236/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100237#define FD_STCLOSE 0
238#define FD_STLISTEN 1
239#define FD_STCONN 2
240#define FD_STREADY 3
241#define FD_STERROR 4
242
willy tarreau5cbea6f2005-12-17 12:48:26 +0100243/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100244#define TASK_IDLE 0
245#define TASK_RUNNING 1
246
willy tarreau5cbea6f2005-12-17 12:48:26 +0100247/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define PR_STNEW 0
249#define PR_STIDLE 1
250#define PR_STRUN 2
251#define PR_STDISABLED 3
252
willy tarreau5cbea6f2005-12-17 12:48:26 +0100253/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100254#define PR_MODE_TCP 0
255#define PR_MODE_HTTP 1
256#define PR_MODE_HEALTH 2
257
willy tarreau5cbea6f2005-12-17 12:48:26 +0100258/* bits for proxy->options */
259#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
260#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
261#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
262#define PR_O_COOK_IND 8 /* keep only indirect cookies */
263#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
264#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
265#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
266#define PR_O_BALANCE (PR_O_BALANCE_RR)
267
268/* various task flags */
269#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
270
271/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100272#define CL_STHEADERS 0
273#define CL_STDATA 1
274#define CL_STSHUTR 2
275#define CL_STSHUTW 3
276#define CL_STCLOSE 4
277
willy tarreau5cbea6f2005-12-17 12:48:26 +0100278/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100279#define SV_STIDLE 0
280#define SV_STCONN 1
281#define SV_STHEADERS 2
282#define SV_STDATA 3
283#define SV_STSHUTR 4
284#define SV_STSHUTW 5
285#define SV_STCLOSE 6
286
287/* result of an I/O event */
288#define RES_SILENT 0 /* didn't happen */
289#define RES_DATA 1 /* data were sent or received */
290#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
291#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define MODE_DEBUG 1
295#define MODE_STATS 2
296#define MODE_LOG 4
297#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100298#define MODE_QUIET 16
299
300/* server flags */
301#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100302
303/*********************************************************************/
304
305#define LIST_HEAD(a) ((void *)(&(a)))
306
307/*********************************************************************/
308
309struct hdr_exp {
310 regex_t *preg; /* expression to look for */
311 char *replace; /* expression to set instead */
312};
313
314struct buffer {
315 unsigned int l; /* data length */
316 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100317 char *rlim; /* read limit, used for header rewriting */
willy tarreau0f7af912005-12-17 12:21:26 +0100318 char data[BUFSIZE];
319};
320
321struct server {
322 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100323 int state; /* server state (SRV_*) */
324 int cklen; /* the len of the cookie, to speed up checks */
325 char *cookie; /* the id set in the cookie */
326 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100327 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100329 int rise, fall; /* time in iterations */
330 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100331 int result; /* 0 = connect OK, -1 = connect KO */
332 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100333};
334
willy tarreau5cbea6f2005-12-17 12:48:26 +0100335/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100336struct task {
337 struct task *next, *prev; /* chaining ... */
338 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100339 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100340 int state; /* task state : IDLE or RUNNING */
341 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100342 int (*process)(struct task *t); /* the function which processes the task */
343 void *context; /* the task's context */
344};
345
346/* WARNING: if new fields are added, they must be initialized in event_accept() */
347struct session {
348 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100349 /* application specific below */
350 struct timeval crexpire; /* expiration date for a client read */
351 struct timeval cwexpire; /* expiration date for a client write */
352 struct timeval srexpire; /* expiration date for a server read */
353 struct timeval swexpire; /* expiration date for a server write */
354 struct timeval cnexpire; /* expiration date for a connect */
355 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
356 struct proxy *proxy; /* the proxy this socket belongs to */
357 int cli_fd; /* the client side fd */
358 int srv_fd; /* the server side fd */
359 int cli_state; /* state of the client side */
360 int srv_state; /* state of the server side */
361 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100363 struct buffer *req; /* request buffer */
364 struct buffer *rep; /* response buffer */
365 struct sockaddr_in cli_addr; /* the client address */
366 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100368};
369
370struct proxy {
371 int listen_fd; /* the listen socket */
372 int state; /* proxy state */
373 struct sockaddr_in listen_addr; /* the address we listen to */
374 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100375 struct server *srv, *cursrv; /* known servers, current server */
376 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100377 char *cookie_name; /* name of the cookie to look for */
378 int clitimeout; /* client I/O timeout (in milliseconds) */
379 int srvtimeout; /* server I/O timeout (in milliseconds) */
380 int contimeout; /* connect timeout (in milliseconds) */
381 char *id; /* proxy id */
382 int nbconn; /* # of active sessions */
383 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100384 int conn_retries; /* maximum number of connect retries */
385 int options; /* PR_O_REDISP, PR_O_TRANSP */
386 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100387 struct proxy *next;
388 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
389 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
390 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100391 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
392 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
393 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
394 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100395 int grace; /* grace time after stop request */
396};
397
398/* info about one given fd */
399struct fdtab {
400 int (*read)(int fd); /* read function */
401 int (*write)(int fd); /* write function */
402 struct task *owner; /* the session (or proxy) associated with this fd */
403 int state; /* the state of this fd */
404};
405
406/*********************************************************************/
407
408int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
409int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
410int cfg_maxsock = 0; /* max # of sockets */
411char *cfg_cfgfile = NULL; /* configuration file */
412char *progname = NULL; /* program name */
413int pid; /* current process id */
414/*********************************************************************/
415
416fd_set *ReadEvent,
417 *WriteEvent,
418 *StaticReadEvent,
419 *StaticWriteEvent;
420
421void **pool_session = NULL,
422 **pool_buffer = NULL,
423 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424 **pool_str256 = NULL,
425 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100426
427struct proxy *proxy = NULL; /* list of all existing proxies */
428struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100429struct task *rq = NULL; /* global run queue */
430struct task wait_queue = { /* global wait queue */
431 prev:LIST_HEAD(wait_queue),
432 next:LIST_HEAD(wait_queue)
433};
willy tarreau0f7af912005-12-17 12:21:26 +0100434
435static int mode = 0; /* MODE_DEBUG, ... */
436static int totalconn = 0; /* total # of terminated sessions */
437static int actconn = 0; /* # of active sessions */
438static int maxfd = 0; /* # of the highest fd + 1 */
439static int listeners = 0; /* # of listeners */
440static int stopping = 0; /* non zero means stopping in progress */
441static struct timeval now = {0,0}; /* the current date at any moment */
442
443static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
444static char trash[BUFSIZE];
445
446/*
447 * Syslog facilities and levels
448 */
449
450#define MAX_SYSLOG_LEN 1024
451#define NB_LOG_FACILITIES 24
452const char *log_facilities[NB_LOG_FACILITIES] = {
453 "kern", "user", "mail", "daemon",
454 "auth", "syslog", "lpr", "news",
455 "uucp", "cron", "auth2", "ftp",
456 "ntp", "audit", "alert", "cron2",
457 "local0", "local1", "local2", "local3",
458 "local4", "local5", "local6", "local7"
459};
460
461
462#define NB_LOG_LEVELS 8
463const char *log_levels[NB_LOG_LEVELS] = {
464 "emerg", "alert", "crit", "err",
465 "warning", "notice", "info", "debug"
466};
467
468#define SYSLOG_PORT 514
469
470const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
471 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
472#define MAX_HOSTNAME_LEN 32
473static char hostname[MAX_HOSTNAME_LEN] = "";
474
475/*********************************************************************/
476/* statistics ******************************************************/
477/*********************************************************************/
478
479static int stats_tsk_lsrch, stats_tsk_rsrch,
480 stats_tsk_good, stats_tsk_right, stats_tsk_left,
481 stats_tsk_new, stats_tsk_nsrch;
482
483
484/*********************************************************************/
485/* function prototypes *********************************************/
486/*********************************************************************/
487
488int event_accept(int fd);
489int event_cli_read(int fd);
490int event_cli_write(int fd);
491int event_srv_read(int fd);
492int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100493int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100494
495/*********************************************************************/
496/* general purpose functions ***************************************/
497/*********************************************************************/
498
499void display_version() {
500 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100502}
503
504/*
505 * This function prints the command line usage and exits
506 */
507void usage(char *name) {
508 display_version();
509 fprintf(stderr,
510 "Usage : %s -f <cfgfile> [ -vd"
511#if STATTIME > 0
512 "sl"
513#endif
514 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
515 " -v displays version\n"
516 " -d enters debug mode\n"
517#if STATTIME > 0
518 " -s enables statistics output\n"
519 " -l enables long statistics format\n"
520#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521 " -D goes daemon ; implies -q\n"
522 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100523 " -n sets the maximum total # of connections (%d)\n"
524 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
525 name, cfg_maxconn, cfg_maxpconn);
526 exit(1);
527}
528
529
530/*
531 * Displays the message on stderr with the date and pid.
532 */
533void Alert(char *fmt, ...) {
534 va_list argp;
535 struct timeval tv;
536 struct tm *tm;
537
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 if (!(mode & MODE_QUIET)) {
539 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100540
willy tarreau5cbea6f2005-12-17 12:48:26 +0100541 gettimeofday(&tv, NULL);
542 tm=localtime(&tv.tv_sec);
543 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
544 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
545 vfprintf(stderr, fmt, argp);
546 fflush(stderr);
547 va_end(argp);
548 }
willy tarreau0f7af912005-12-17 12:21:26 +0100549}
550
551
552/*
553 * Displays the message on stderr with the date and pid.
554 */
555void Warning(char *fmt, ...) {
556 va_list argp;
557 struct timeval tv;
558 struct tm *tm;
559
willy tarreau5cbea6f2005-12-17 12:48:26 +0100560 if (!(mode & MODE_QUIET)) {
561 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100562
willy tarreau5cbea6f2005-12-17 12:48:26 +0100563 gettimeofday(&tv, NULL);
564 tm=localtime(&tv.tv_sec);
565 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
566 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
567 vfprintf(stderr, fmt, argp);
568 fflush(stderr);
569 va_end(argp);
570 }
571}
572
573/*
574 * Displays the message on <out> only if quiet mode is not set.
575 */
576void qfprintf(FILE *out, char *fmt, ...) {
577 va_list argp;
578
579 if (!(mode & MODE_QUIET)) {
580 va_start(argp, fmt);
581 vfprintf(out, fmt, argp);
582 fflush(out);
583 va_end(argp);
584 }
willy tarreau0f7af912005-12-17 12:21:26 +0100585}
586
587
588/*
589 * converts <str> to a struct sockaddr_in* which is locally allocated.
590 * The format is "addr:port", where "addr" can be empty or "*" to indicate
591 * INADDR_ANY.
592 */
593struct sockaddr_in *str2sa(char *str) {
594 static struct sockaddr_in sa;
595 char *c;
596 int port;
597
598 bzero(&sa, sizeof(sa));
599 str=strdup(str);
600
601 if ((c=strrchr(str,':')) != NULL) {
602 *c++=0;
603 port=atol(c);
604 }
605 else
606 port=0;
607
608 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
609 sa.sin_addr.s_addr = INADDR_ANY;
610 }
611 else if (
612#ifndef SOLARIS
613 !inet_aton(str, &sa.sin_addr)
614#else
615 !inet_pton(AF_INET, str, &sa.sin_addr)
616#endif
617 ) {
618 struct hostent *he;
619
620 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100621 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100622 }
623 else
624 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
625 }
626 sa.sin_port=htons(port);
627 sa.sin_family=AF_INET;
628
629 free(str);
630 return &sa;
631}
632
633/*
634 * This function tries to send a syslog message to the syslog server at
635 * address <sa>. It doesn't care about errors nor does it report them.
636 * WARNING! no check is made on the prog+hostname+date length, so the
637 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
638 * the message will be truncated to fit the maximum length.
639 */
640void send_syslog(struct sockaddr_in *sa,
641 int facility, int level, char *message)
642{
643
644 static int logfd = -1; /* syslog UDP socket */
645 struct timeval tv;
646 struct tm *tm;
647 static char logmsg[MAX_SYSLOG_LEN];
648 char *p;
649
650 if (logfd < 0) {
651 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
652 return;
653 }
654
655 if (facility < 0 || level < 0
656 || sa == NULL || progname == NULL || message == NULL)
657 return;
658
659 gettimeofday(&tv, NULL);
660 tm = localtime(&tv.tv_sec);
661
662 p = logmsg;
663 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
664 // facility * 8 + level,
665 // monthname[tm->tm_mon],
666 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
667 // hostname, progname, pid);
668 /* 20011216/WT : other progs don't set the hostname, and syslogd
669 * systematically repeats it which is contrary to RFC3164.
670 */
671 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
672 facility * 8 + level,
673 monthname[tm->tm_mon],
674 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
675 progname, pid);
676
677 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
678 int len = strlen(message);
679 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
680 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
681 memcpy(p, message, len);
682 p += len;
683 }
willy tarreau3242e862005-12-17 12:27:53 +0100684#ifndef MSG_NOSIGNAL
685 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
686 (struct sockaddr *)sa, sizeof(*sa));
687#else
willy tarreau0f7af912005-12-17 12:21:26 +0100688 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
689 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100690#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100691}
692
693
694/* sets <tv> to the current time */
695static inline struct timeval *tv_now(struct timeval *tv) {
696 if (tv)
697 gettimeofday(tv, NULL);
698 return tv;
699}
700
701/*
702 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
703 */
704static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
705 if (!tv || !from)
706 return NULL;
707 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
708 tv->tv_sec = from->tv_sec + (ms/1000);
709 while (tv->tv_usec >= 1000000) {
710 tv->tv_usec -= 1000000;
711 tv->tv_sec++;
712 }
713 return tv;
714}
715
716/*
717 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
718 */
719static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
720 if (tv1->tv_sec > tv2->tv_sec)
721 return 1;
722 else if (tv1->tv_sec < tv2->tv_sec)
723 return -1;
724 else if (tv1->tv_usec > tv2->tv_usec)
725 return 1;
726 else if (tv1->tv_usec < tv2->tv_usec)
727 return -1;
728 else
729 return 0;
730}
731
732/*
733 * returns the absolute difference, in ms, between tv1 and tv2
734 */
735unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
736 int cmp;
737 unsigned long ret;
738
739
willy tarreauef900ab2005-12-17 12:52:52 +0100740 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100741 if (!cmp)
742 return 0; /* same dates, null diff */
743 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100744 struct timeval *tmp = tv1;
745 tv1 = tv2;
746 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100747 }
willy tarreauef900ab2005-12-17 12:52:52 +0100748 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100749 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100750 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100751 else
willy tarreauef900ab2005-12-17 12:52:52 +0100752 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100753 return (unsigned long) ret;
754}
755
756/*
757 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
758 */
759static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100760 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100761 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100762 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100763 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100764 return -1;
765 else
766 return 0;
767 }
768 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100769 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100770 return 1;
771 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100772 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100773 return -1;
774 else
775 return 0;
776}
777
778/*
779 * returns the remaining time between tv1=now and event=tv2
780 * if tv2 is passed, 0 is returned.
781 */
782static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
783 unsigned long ret;
784
willy tarreau0f7af912005-12-17 12:21:26 +0100785 if (tv_cmp_ms(tv1, tv2) >= 0)
786 return 0; /* event elapsed */
787
willy tarreauef900ab2005-12-17 12:52:52 +0100788 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100789 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100790 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100791 else
willy tarreauef900ab2005-12-17 12:52:52 +0100792 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100793 return (unsigned long) ret;
794}
795
796
797/*
798 * zeroes a struct timeval
799 */
800
801static inline struct timeval *tv_eternity(struct timeval *tv) {
802 tv->tv_sec = tv->tv_usec = 0;
803 return tv;
804}
805
806/*
807 * returns 1 if tv is null, else 0
808 */
809static inline int tv_iseternity(struct timeval *tv) {
810 if (tv->tv_sec == 0 && tv->tv_usec == 0)
811 return 1;
812 else
813 return 0;
814}
815
816/*
817 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
818 * considering that 0 is the eternity.
819 */
820static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
821 if (tv_iseternity(tv1))
822 if (tv_iseternity(tv2))
823 return 0; /* same */
824 else
825 return 1; /* tv1 later than tv2 */
826 else if (tv_iseternity(tv2))
827 return -1; /* tv2 later than tv1 */
828
829 if (tv1->tv_sec > tv2->tv_sec)
830 return 1;
831 else if (tv1->tv_sec < tv2->tv_sec)
832 return -1;
833 else if (tv1->tv_usec > tv2->tv_usec)
834 return 1;
835 else if (tv1->tv_usec < tv2->tv_usec)
836 return -1;
837 else
838 return 0;
839}
840
841/*
842 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
843 * considering that 0 is the eternity.
844 */
845static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
846 if (tv_iseternity(tv1))
847 if (tv_iseternity(tv2))
848 return 0; /* same */
849 else
850 return 1; /* tv1 later than tv2 */
851 else if (tv_iseternity(tv2))
852 return -1; /* tv2 later than tv1 */
853
willy tarreauefae1842005-12-17 12:51:03 +0100854 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100855 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100856 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100857 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100858 return -1;
859 else
860 return 0;
861 }
862 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100863 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100864 return 1;
865 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100866 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100867 return -1;
868 else
869 return 0;
870}
871
872/*
873 * returns the first event between tv1 and tv2 into tvmin.
874 * a zero tv is ignored. tvmin is returned.
875 */
876static inline struct timeval *tv_min(struct timeval *tvmin,
877 struct timeval *tv1, struct timeval *tv2) {
878
879 if (tv_cmp2(tv1, tv2) <= 0)
880 *tvmin = *tv1;
881 else
882 *tvmin = *tv2;
883
884 return tvmin;
885}
886
887
888
889/***********************************************************/
890/* fd management ***************************************/
891/***********************************************************/
892
893
894
willy tarreau5cbea6f2005-12-17 12:48:26 +0100895/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
896 * The file descriptor is also closed.
897 */
willy tarreau0f7af912005-12-17 12:21:26 +0100898static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100899 FD_CLR(fd, StaticReadEvent);
900 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100901 close(fd);
902 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100903
904 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
905 maxfd--;
906}
907
908/* recomputes the maxfd limit from the fd */
909static inline void fd_insert(int fd) {
910 if (fd+1 > maxfd)
911 maxfd = fd+1;
912}
913
914/*************************************************************/
915/* task management ***************************************/
916/*************************************************************/
917
willy tarreau5cbea6f2005-12-17 12:48:26 +0100918/* puts the task <t> in run queue <q>, and returns <t> */
919static inline struct task *task_wakeup(struct task **q, struct task *t) {
920 if (t->state == TASK_RUNNING)
921 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100922 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100923 t->rqnext = *q;
924 t->state = TASK_RUNNING;
925 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100926 }
927}
928
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929/* removes the task <t> from the queue <q>
930 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100931 * set the run queue to point to the next one, and return it
932 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933static inline struct task *task_sleep(struct task **q, struct task *t) {
934 if (t->state == TASK_RUNNING) {
935 *q = t->rqnext;
936 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100937 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100938 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100939}
940
941/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100942 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100943 * from the run queue. A pointer to the task itself is returned.
944 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100945static inline struct task *task_delete(struct task *t) {
946 t->prev->next = t->next;
947 t->next->prev = t->prev;
948 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100949}
950
951/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100952 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100953 */
954static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100955 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100956}
957
willy tarreau5cbea6f2005-12-17 12:48:26 +0100958/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100959 * may be only moved or left where it was, depending on its timing requirements.
960 * <task> is returned.
961 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100962struct task *task_queue(struct task *task) {
963 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100964 struct task *start_from;
965
966 /* first, test if the task was already in a list */
967 if (task->prev == NULL) {
968 // start_from = list;
969 start_from = list->prev;
970 stats_tsk_new++;
971
972 /* insert the unlinked <task> into the list, searching back from the last entry */
973 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
974 start_from = start_from->prev;
975 stats_tsk_nsrch++;
976 }
977
978 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
979 // start_from = start_from->next;
980 // stats_tsk_nsrch++;
981 // }
982 }
983 else if (task->prev == list ||
984 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
985 start_from = task->next;
986 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
987 stats_tsk_good++;
988 return task; /* it's already in the right place */
989 }
990
991 stats_tsk_right++;
992 /* insert the unlinked <task> into the list, searching after position <start_from> */
993 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
994 start_from = start_from->next;
995 stats_tsk_rsrch++;
996 }
997 /* we need to unlink it now */
998 task_delete(task);
999 }
1000 else { /* walk left. */
1001 stats_tsk_left++;
1002#ifdef LEFT_TO_TOP /* not very good */
1003 start_from = list;
1004 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1005 start_from = start_from->next;
1006 stats_tsk_lsrch++;
1007 }
1008#else
1009 start_from = task->prev->prev; /* valid because of the previous test above */
1010 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1011 start_from = start_from->prev;
1012 stats_tsk_lsrch++;
1013 }
1014#endif
1015 /* we need to unlink it now */
1016 task_delete(task);
1017 }
1018 task->prev = start_from;
1019 task->next = start_from->next;
1020 task->next->prev = task;
1021 start_from->next = task;
1022 return task;
1023}
1024
1025
1026/*********************************************************************/
1027/* more specific functions ***************************************/
1028/*********************************************************************/
1029
1030/* some prototypes */
1031static int maintain_proxies(void);
1032
willy tarreau5cbea6f2005-12-17 12:48:26 +01001033/* this either returns the sockname or the original destination address. Code
1034 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1035 */
1036static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
1037#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
1038 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1039#else
1040#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
1041 return getsockname(fd, (struct sockaddr *)sa, salen);
1042#else
1043 return -1;
1044#endif
1045#endif
1046}
1047
1048/*
1049 * frees the context associated to a session. It must have been removed first.
1050 */
1051static inline void session_free(struct session *s) {
1052 if (s->req)
1053 pool_free(buffer, s->req);
1054 if (s->rep)
1055 pool_free(buffer, s->rep);
1056 pool_free(session, s);
1057}
1058
willy tarreau0f7af912005-12-17 12:21:26 +01001059
1060/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001061 * This function initiates a connection to the current server (s->srv) if (s->direct)
1062 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001063 * it's OK, -1 if it's impossible.
1064 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001065int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001066 int one = 1;
1067 int fd;
1068
1069 // fprintf(stderr,"connect_server : s=%p\n",s);
1070
willy tarreau5cbea6f2005-12-17 12:48:26 +01001071 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1072 s->srv_addr = s->srv->addr;
1073 }
1074 else if (s->proxy->options & PR_O_BALANCE) {
1075 if (s->proxy->options & PR_O_BALANCE_RR) {
1076 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001077 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001078 if (s->proxy->cursrv == NULL)
1079 s->proxy->cursrv = s->proxy->srv;
1080 if (s->proxy->cursrv->state & SRV_RUNNING)
1081 break;
1082 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001083 retry--;
1084 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001085
1086 if (retry == 0) /* no server left */
1087 return -1;
1088
1089 s->srv = s->proxy->cursrv;
1090 s->srv_addr = s->srv->addr;
1091 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001092 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001093 else /* unknown balancing algorithm */
1094 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001095 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001096 else if (*(int *)&s->proxy->dispatch_addr) {
1097 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001098 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001099 }
1100 else if (s->proxy->options & PR_O_TRANSP) {
1101 /* in transparent mode, use the original dest addr if no dispatch specified */
1102 int salen = sizeof(struct sockaddr_in);
1103 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1104 qfprintf(stderr, "Cannot get original server address.\n");
1105 return -1;
1106 }
1107 }
willy tarreau0f7af912005-12-17 12:21:26 +01001108
1109 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001110 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001111 return -1;
1112 }
1113
willy tarreau5cbea6f2005-12-17 12:48:26 +01001114 if (fd >= cfg_maxsock) {
1115 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1116 close(fd);
1117 return -1;
1118 }
1119
willy tarreau0f7af912005-12-17 12:21:26 +01001120 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1121 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001122 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001123 close(fd);
1124 return -1;
1125 }
1126
1127 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1128 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001129 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001130 close(fd);
1131 return -1;
1132 }
1133 else if (errno != EALREADY && errno != EISCONN) {
1134 close(fd);
1135 return -1;
1136 }
1137 }
1138
willy tarreau5cbea6f2005-12-17 12:48:26 +01001139 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001140 fdtab[fd].read = &event_srv_read;
1141 fdtab[fd].write = &event_srv_write;
1142 fdtab[fd].state = FD_STCONN; /* connection in progress */
1143
1144 FD_SET(fd, StaticWriteEvent); /* for connect status */
1145
1146 fd_insert(fd);
1147
1148 if (s->proxy->contimeout)
1149 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1150 else
1151 tv_eternity(&s->cnexpire);
1152 return 0;
1153}
1154
1155/*
1156 * this function is called on a read event from a client socket.
1157 * It returns 0.
1158 */
1159int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001160 struct task *t = fdtab[fd].owner;
1161 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001162 struct buffer *b = s->req;
1163 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001164
1165 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1166
willy tarreau0f7af912005-12-17 12:21:26 +01001167 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001168 while (1) {
1169 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1170 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001171 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001172 }
1173 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001174 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001175 }
1176 else {
1177 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001178 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1179 * since it means that the rewrite protection has been removed. This
1180 * implies that the if statement can be removed.
1181 */
1182 if (max > b->rlim - b->data)
1183 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001184 }
1185
1186 if (max == 0) { /* not anymore room to store data */
1187 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001188 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001189 }
1190
willy tarreau3242e862005-12-17 12:27:53 +01001191#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001192 {
1193 int skerr, lskerr;
1194
1195 lskerr = sizeof(skerr);
1196 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1197 if (skerr)
1198 ret = -1;
1199 else
1200 ret = recv(fd, b->r, max, 0);
1201 }
willy tarreau3242e862005-12-17 12:27:53 +01001202#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001203 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001204#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001205 if (ret > 0) {
1206 b->r += ret;
1207 b->l += ret;
1208 s->res_cr = RES_DATA;
1209
1210 if (b->r == b->data + BUFSIZE) {
1211 b->r = b->data; /* wrap around the buffer */
1212 }
1213 /* we hope to read more data or to get a close on next round */
1214 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001215 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001216 else if (ret == 0) {
1217 s->res_cr = RES_NULL;
1218 break;
1219 }
1220 else if (errno == EAGAIN) {/* ignore EAGAIN */
1221 break;
1222 }
1223 else {
1224 s->res_cr = RES_ERROR;
1225 fdtab[fd].state = FD_STERROR;
1226 break;
1227 }
1228 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001229 }
1230 else {
1231 s->res_cr = RES_ERROR;
1232 fdtab[fd].state = FD_STERROR;
1233 }
1234
willy tarreau5cbea6f2005-12-17 12:48:26 +01001235 if (s->res_cr != RES_SILENT) {
1236 if (s->proxy->clitimeout)
1237 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1238 else
1239 tv_eternity(&s->crexpire);
1240
1241 task_wakeup(&rq, t);
1242 }
willy tarreau0f7af912005-12-17 12:21:26 +01001243
willy tarreau0f7af912005-12-17 12:21:26 +01001244 return 0;
1245}
1246
1247
1248/*
1249 * this function is called on a read event from a server socket.
1250 * It returns 0.
1251 */
1252int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001253 struct task *t = fdtab[fd].owner;
1254 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001255 struct buffer *b = s->rep;
1256 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001257
1258 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1259
willy tarreau0f7af912005-12-17 12:21:26 +01001260 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001261 while (1) {
1262 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1263 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001264 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001265 }
1266 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001267 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268 }
1269 else {
1270 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001271 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1272 * since it means that the rewrite protection has been removed. This
1273 * implies that the if statement can be removed.
1274 */
1275 if (max > b->rlim - b->data)
1276 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001277 }
1278
1279 if (max == 0) { /* not anymore room to store data */
1280 FD_CLR(fd, StaticReadEvent);
1281 break;
1282 }
1283
willy tarreau3242e862005-12-17 12:27:53 +01001284#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001285 {
1286 int skerr, lskerr;
1287
1288 lskerr = sizeof(skerr);
1289 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1290 if (skerr)
1291 ret = -1;
1292 else
1293 ret = recv(fd, b->r, max, 0);
1294 }
willy tarreau3242e862005-12-17 12:27:53 +01001295#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001296 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001297#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001298 if (ret > 0) {
1299 b->r += ret;
1300 b->l += ret;
1301 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001302
willy tarreau5cbea6f2005-12-17 12:48:26 +01001303 if (b->r == b->data + BUFSIZE) {
1304 b->r = b->data; /* wrap around the buffer */
1305 }
1306 /* we hope to read more data or to get a close on next round */
1307 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001308 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001309 else if (ret == 0) {
1310 s->res_sr = RES_NULL;
1311 break;
1312 }
1313 else if (errno == EAGAIN) {/* ignore EAGAIN */
1314 break;
1315 }
1316 else {
1317 s->res_sr = RES_ERROR;
1318 fdtab[fd].state = FD_STERROR;
1319 break;
1320 }
1321 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001322 }
1323 else {
1324 s->res_sr = RES_ERROR;
1325 fdtab[fd].state = FD_STERROR;
1326 }
1327
willy tarreau5cbea6f2005-12-17 12:48:26 +01001328 if (s->res_sr != RES_SILENT) {
1329 if (s->proxy->srvtimeout)
1330 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1331 else
1332 tv_eternity(&s->srexpire);
1333
1334 task_wakeup(&rq, t);
1335 }
willy tarreau0f7af912005-12-17 12:21:26 +01001336
willy tarreau0f7af912005-12-17 12:21:26 +01001337 return 0;
1338}
1339
1340/*
1341 * this function is called on a write event from a client socket.
1342 * It returns 0.
1343 */
1344int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001345 struct task *t = fdtab[fd].owner;
1346 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001347 struct buffer *b = s->rep;
1348 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001349
1350 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1351
1352 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001353 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001354 // max = BUFSIZE; BUG !!!!
1355 max = 0;
1356 }
1357 else if (b->r > b->w) {
1358 max = b->r - b->w;
1359 }
1360 else
1361 max = b->data + BUFSIZE - b->w;
1362
willy tarreau0f7af912005-12-17 12:21:26 +01001363 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001364#ifndef MSG_NOSIGNAL
1365 int skerr, lskerr;
1366#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001367
1368 if (max == 0) {
1369 s->res_cw = RES_NULL;
1370 task_wakeup(&rq, t);
1371 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 }
1373
willy tarreau3242e862005-12-17 12:27:53 +01001374#ifndef MSG_NOSIGNAL
1375 lskerr=sizeof(skerr);
1376 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1377 if (skerr)
1378 ret = -1;
1379 else
1380 ret = send(fd, b->w, max, MSG_DONTWAIT);
1381#else
willy tarreau0f7af912005-12-17 12:21:26 +01001382 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001383#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001384
1385 if (ret > 0) {
1386 b->l -= ret;
1387 b->w += ret;
1388
1389 s->res_cw = RES_DATA;
1390
1391 if (b->w == b->data + BUFSIZE) {
1392 b->w = b->data; /* wrap around the buffer */
1393 }
1394 }
1395 else if (ret == 0) {
1396 /* nothing written, just make as if we were never called */
1397// s->res_cw = RES_NULL;
1398 return 0;
1399 }
1400 else if (errno == EAGAIN) /* ignore EAGAIN */
1401 return 0;
1402 else {
1403 s->res_cw = RES_ERROR;
1404 fdtab[fd].state = FD_STERROR;
1405 }
1406 }
1407 else {
1408 s->res_cw = RES_ERROR;
1409 fdtab[fd].state = FD_STERROR;
1410 }
1411
1412 if (s->proxy->clitimeout)
1413 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1414 else
1415 tv_eternity(&s->cwexpire);
1416
willy tarreau5cbea6f2005-12-17 12:48:26 +01001417 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001418 return 0;
1419}
1420
1421
1422/*
1423 * this function is called on a write event from a server socket.
1424 * It returns 0.
1425 */
1426int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001427 struct task *t = fdtab[fd].owner;
1428 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001429 struct buffer *b = s->req;
1430 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001431
1432 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1433
1434 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001435 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001436 // max = BUFSIZE; BUG !!!!
1437 max = 0;
1438 }
1439 else if (b->r > b->w) {
1440 max = b->r - b->w;
1441 }
1442 else
1443 max = b->data + BUFSIZE - b->w;
1444
willy tarreau0f7af912005-12-17 12:21:26 +01001445 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001446#ifndef MSG_NOSIGNAL
1447 int skerr, lskerr;
1448#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001449 if (max == 0) {
1450 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001451 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001452 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001453 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001454 return 0;
1455 }
1456
willy tarreauef900ab2005-12-17 12:52:52 +01001457
willy tarreau3242e862005-12-17 12:27:53 +01001458#ifndef MSG_NOSIGNAL
1459 lskerr=sizeof(skerr);
1460 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1461 if (skerr)
1462 ret = -1;
1463 else
1464 ret = send(fd, b->w, max, MSG_DONTWAIT);
1465#else
willy tarreau0f7af912005-12-17 12:21:26 +01001466 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001467#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001468 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (ret > 0) {
1470 b->l -= ret;
1471 b->w += ret;
1472
1473 s->res_sw = RES_DATA;
1474
1475 if (b->w == b->data + BUFSIZE) {
1476 b->w = b->data; /* wrap around the buffer */
1477 }
1478 }
1479 else if (ret == 0) {
1480 /* nothing written, just make as if we were never called */
1481 // s->res_sw = RES_NULL;
1482 return 0;
1483 }
1484 else if (errno == EAGAIN) /* ignore EAGAIN */
1485 return 0;
1486 else {
1487 s->res_sw = RES_ERROR;
1488 fdtab[fd].state = FD_STERROR;
1489 }
1490 }
1491 else {
1492 s->res_sw = RES_ERROR;
1493 fdtab[fd].state = FD_STERROR;
1494 }
1495
1496 if (s->proxy->srvtimeout)
1497 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1498 else
1499 tv_eternity(&s->swexpire);
1500
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001502 return 0;
1503}
1504
1505
1506/*
1507 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001508 * to an accept. It tries to accept as many connections as possible.
1509 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001510 */
1511int event_accept(int fd) {
1512 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001513 struct session *s;
1514 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001515 int cfd;
1516 int one = 1;
1517
willy tarreau5cbea6f2005-12-17 12:48:26 +01001518 while (p->nbconn < p->maxconn) {
1519 struct sockaddr_in addr;
1520 int laddr = sizeof(addr);
1521 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1522 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001523
willy tarreau5cbea6f2005-12-17 12:48:26 +01001524 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1525 Alert("out of memory in event_accept().\n");
1526 FD_CLR(fd, StaticReadEvent);
1527 p->state = PR_STIDLE;
1528 close(cfd);
1529 return 0;
1530 }
willy tarreau0f7af912005-12-17 12:21:26 +01001531
willy tarreau5cbea6f2005-12-17 12:48:26 +01001532 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1533 Alert("out of memory in event_accept().\n");
1534 FD_CLR(fd, StaticReadEvent);
1535 p->state = PR_STIDLE;
1536 close(cfd);
1537 pool_free(session, s);
1538 return 0;
1539 }
willy tarreau0f7af912005-12-17 12:21:26 +01001540
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 s->cli_addr = addr;
1542 if (cfd >= cfg_maxsock) {
1543 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1544 close(cfd);
1545 pool_free(task, t);
1546 pool_free(session, s);
1547 return 0;
1548 }
willy tarreau0f7af912005-12-17 12:21:26 +01001549
willy tarreau5cbea6f2005-12-17 12:48:26 +01001550 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1551 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1552 (char *) &one, sizeof(one)) == -1)) {
1553 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1554 close(cfd);
1555 pool_free(task, t);
1556 pool_free(session, s);
1557 return 0;
1558 }
willy tarreau0f7af912005-12-17 12:21:26 +01001559
willy tarreau5cbea6f2005-12-17 12:48:26 +01001560 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1561 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1562 struct sockaddr_in peername, sockname;
1563 unsigned char *pn, *sn;
1564 int namelen;
1565 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001566
willy tarreau5cbea6f2005-12-17 12:48:26 +01001567 //namelen = sizeof(peername);
1568 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1569 //pn = (unsigned char *)&peername.sin_addr;
1570 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001571
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 namelen = sizeof(sockname);
1573 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1574 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1575 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001576
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1578 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1579 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1580 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001581
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582 if (p->logfac1 >= 0)
1583 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1584 if (p->logfac2 >= 0)
1585 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1586 }
willy tarreau0f7af912005-12-17 12:21:26 +01001587
willy tarreauef900ab2005-12-17 12:52:52 +01001588 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1589 int len;
1590 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1591 write(1, trash, len);
1592 }
willy tarreau0f7af912005-12-17 12:21:26 +01001593
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1595 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1596 t->state = TASK_IDLE;
1597 t->process = process_session;
1598 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001599
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600 s->task = t;
1601 s->proxy = p;
1602 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1603 s->srv_state = SV_STIDLE;
1604 s->req = s->rep = NULL; /* will be allocated later */
1605 s->flags = 0;
1606 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1607 s->cli_fd = cfd;
1608 s->srv_fd = -1;
1609 s->conn_retries = p->conn_retries;
1610
1611 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1612 close(cfd); /* nothing can be done for this fd without memory */
1613 pool_free(task, t);
1614 pool_free(session, s);
1615 return 0;
1616 }
1617 s->req->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001618 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1619 s->req->rlim = s->req->data + BUFSIZE;
1620 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1621 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001622
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1624 pool_free(buffer, s->req);
1625 close(cfd); /* nothing can be done for this fd without memory */
1626 pool_free(task, t);
1627 pool_free(session, s);
1628 return 0;
1629 }
1630 s->rep->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001631 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->rlim = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633 fdtab[cfd].read = &event_cli_read;
1634 fdtab[cfd].write = &event_cli_write;
1635 fdtab[cfd].owner = t;
1636 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001637
willy tarreau5cbea6f2005-12-17 12:48:26 +01001638 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1639 FD_CLR(cfd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001640 FD_SET(cfd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641 tv_eternity(&s->crexpire);
1642 shutdown(s->cli_fd, SHUT_RD);
1643 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001644
willy tarreau5cbea6f2005-12-17 12:48:26 +01001645 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1646 s->rep->l = 3;
1647 s->rep->r += 3;
1648 }
1649 else {
1650 FD_SET(cfd, StaticReadEvent);
1651 }
1652
1653 fd_insert(cfd);
1654
1655 tv_eternity(&s->cnexpire);
1656 tv_eternity(&s->srexpire);
1657 tv_eternity(&s->swexpire);
1658 tv_eternity(&s->cwexpire);
1659
1660 if (s->proxy->clitimeout)
1661 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1662 else
1663 tv_eternity(&s->crexpire);
1664
1665 t->expire = s->crexpire;
1666
1667 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001668
1669 if (p->mode != PR_MODE_HEALTH)
1670 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671
1672 p->nbconn++;
1673 actconn++;
1674 totalconn++;
1675
1676 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1677 } /* end of while (p->nbconn < p->maxconn) */
1678 return 0;
1679}
willy tarreau0f7af912005-12-17 12:21:26 +01001680
willy tarreau0f7af912005-12-17 12:21:26 +01001681
willy tarreau5cbea6f2005-12-17 12:48:26 +01001682/*
1683 * This function is used only for server health-checks. It handles
1684 * the connection acknowledgement and returns 1 if the socket is OK,
1685 * or -1 if an error occured.
1686 */
1687int event_srv_hck(int fd) {
1688 struct task *t = fdtab[fd].owner;
1689 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001690
willy tarreau5cbea6f2005-12-17 12:48:26 +01001691 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001692 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001693 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1694 if (skerr)
1695 s->result = -1;
1696 else
1697 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001698
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001700 return 0;
1701}
1702
1703
1704/*
1705 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1706 * and moves <end> just after the end of <str>.
1707 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1708 * the shift value (positive or negative) is returned.
1709 * If there's no space left, the move is not done.
1710 *
1711 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001712int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001713 int delta;
1714 int len;
1715
1716 len = strlen(str);
1717 delta = len - (end - pos);
1718
1719 if (delta + b->r >= b->data + BUFSIZE)
1720 return 0; /* no space left */
1721
1722 /* first, protect the end of the buffer */
1723 memmove(end + delta, end, b->data + b->l - end);
1724
1725 /* now, copy str over pos */
1726 memcpy(pos, str,len);
1727
willy tarreau5cbea6f2005-12-17 12:48:26 +01001728 /* we only move data after the displaced zone */
1729 if (b->r > pos) b->r += delta;
1730 if (b->w > pos) b->w += delta;
1731 if (b->h > pos) b->h += delta;
1732 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001733 b->l += delta;
1734
1735 return delta;
1736}
1737
1738/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001739int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001740 int delta;
1741
1742 delta = len - (end - pos);
1743
1744 if (delta + b->r >= b->data + BUFSIZE)
1745 return 0; /* no space left */
1746
1747 /* first, protect the end of the buffer */
1748 memmove(end + delta, end, b->data + b->l - end);
1749
1750 /* now, copy str over pos */
1751 memcpy(pos, str,len);
1752
willy tarreau5cbea6f2005-12-17 12:48:26 +01001753 /* we only move data after the displaced zone */
1754 if (b->r > pos) b->r += delta;
1755 if (b->w > pos) b->w += delta;
1756 if (b->h > pos) b->h += delta;
1757 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001758 b->l += delta;
1759
1760 return delta;
1761}
1762
1763
1764int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1765 char *old_dst = dst;
1766
1767 while (*str) {
1768 if (*str == '\\') {
1769 str++;
1770 if (isdigit(*str)) {
1771 int len, num;
1772
1773 num = *str - '0';
1774 str++;
1775
1776 if (matches[num].rm_so > -1) {
1777 len = matches[num].rm_eo - matches[num].rm_so;
1778 memcpy(dst, src + matches[num].rm_so, len);
1779 dst += len;
1780 }
1781
1782 }
1783 else if (*str == 'x') {
1784 unsigned char hex1, hex2;
1785 str++;
1786
1787 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1788
1789 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1790 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1791 *dst++ = (hex1<<4) + hex2;
1792 }
1793 else
1794 *dst++ = *str++;
1795 }
1796 else
1797 *dst++ = *str++;
1798 }
1799 *dst = 0;
1800 return dst - old_dst;
1801}
1802
1803/*
1804 * manages the client FSM and its socket. BTW, it also tries to handle the
1805 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1806 * 0 else.
1807 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001809 int s = t->srv_state;
1810 int c = t->cli_state;
1811 struct buffer *req = t->req;
1812 struct buffer *rep = t->rep;
1813
1814 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1815 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1816 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1817 //);
1818 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 /* now parse the partial (or complete) headers */
1820 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1821 char *ptr;
1822 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001823
willy tarreau5cbea6f2005-12-17 12:48:26 +01001824 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001825
willy tarreau0f7af912005-12-17 12:21:26 +01001826 /* look for the end of the current header */
1827 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1828 ptr++;
1829
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 if (ptr == req->h) { /* empty line, end of headers */
1831 char newhdr[MAXREWRITE + 1];
1832 int line, len;
1833 /* we can only get here after an end of headers */
1834 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001835
willy tarreau5cbea6f2005-12-17 12:48:26 +01001836 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1837 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1838 buffer_replace2(req, req->h, req->h, newhdr, len);
1839 }
willy tarreau0f7af912005-12-17 12:21:26 +01001840
willy tarreau5cbea6f2005-12-17 12:48:26 +01001841 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01001842 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01001843
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 /* FIXME: we'll set the client in a wait state while we try to
1845 * connect to the server. Is this really needed ? wouldn't it be
1846 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01001847 //FD_CLR(t->cli_fd, StaticReadEvent);
1848 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001849 break;
1850 }
willy tarreau0f7af912005-12-17 12:21:26 +01001851
willy tarreau5cbea6f2005-12-17 12:48:26 +01001852 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1853 if (ptr > req->r - 2) {
1854 /* this is a partial header, let's wait for more to come */
1855 req->lr = ptr;
1856 break;
1857 }
willy tarreau0f7af912005-12-17 12:21:26 +01001858
willy tarreau5cbea6f2005-12-17 12:48:26 +01001859 /* now we know that *ptr is either \r or \n,
1860 * and that there are at least 1 char after it.
1861 */
1862 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1863 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1864 else
1865 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001866
willy tarreau5cbea6f2005-12-17 12:48:26 +01001867 /*
1868 * now we know that we have a full header ; we can do whatever
1869 * we want with these pointers :
1870 * req->h = beginning of header
1871 * ptr = end of header (first \r or \n)
1872 * req->lr = beginning of next line (next rep->h)
1873 * req->r = end of data (not used at this stage)
1874 */
willy tarreau0f7af912005-12-17 12:21:26 +01001875
willy tarreau5cbea6f2005-12-17 12:48:26 +01001876 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001877
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1879 int len, max;
1880 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1881 max = ptr - req->h;
1882 UBOUND(max, sizeof(trash) - len - 1);
1883 len += strlcpy(trash + len, req->h, max + 1);
1884 trash[len++] = '\n';
1885 write(1, trash, len);
1886 }
willy tarreau0f7af912005-12-17 12:21:26 +01001887
willy tarreau5cbea6f2005-12-17 12:48:26 +01001888 /* try headers regexps */
1889 if (t->proxy->nb_reqexp) {
1890 struct proxy *p = t->proxy;
1891 int exp;
1892 char term;
1893
1894 term = *ptr;
1895 *ptr = '\0';
1896 for (exp=0; exp < p->nb_reqexp; exp++) {
1897 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1898 if (p->req_exp[exp].replace != NULL) {
1899 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1900 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001901 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 else {
1903 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001904 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001905 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001906 }
1907 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001908 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001909 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001910
1911 /* now look for cookies */
1912 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1913 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1914 char *p1, *p2, *p3, *p4;
1915
1916 p1 = req->h + 8; /* first char after 'Cookie: ' */
1917
1918 while (p1 < ptr) {
1919 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1920 p1++;
1921
1922 if (p1 == ptr)
1923 break;
1924 else if (*p1 == ';') { /* next cookie */
1925 ++p1;
1926 continue;
1927 }
1928
1929 /* p1 is at the beginning of the cookie name */
1930 p2 = p1;
1931
1932 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1933 p2++;
1934
1935 if (p2 == ptr)
1936 break;
1937 else if (*p2 == ';') { /* next cookie */
1938 p1=++p2;
1939 continue;
1940 }
1941
1942 p3 = p2 + 1; /* skips the '=' sign */
1943 if (p3 == ptr)
1944 break;
1945
1946 p4=p3;
1947 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1948 p4++;
1949
1950 /* here, we have the cookie name between p1 and p2,
1951 * and its value between p3 and p4.
1952 * we can process it.
1953 */
1954
1955 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1956 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1957 /* Cool... it's the right one */
1958 struct server *srv = t->proxy->srv;
1959
1960 while (srv &&
1961 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1962 srv = srv->next;
1963 }
1964
1965 if (srv) { /* we found the server */
1966 t->flags |= TF_DIRECT;
1967 t->srv = srv;
1968 }
1969
1970 break;
1971 }
1972 else {
1973 // fprintf(stderr,"Ignoring unknown cookie : ");
1974 // write(2, p1, p2-p1);
1975 // fprintf(stderr," = ");
1976 // write(2, p3, p4-p3);
1977 // fprintf(stderr,"\n");
1978 }
1979 /* we'll have to look for another cookie ... */
1980 p1 = p4;
1981 } /* while (p1 < ptr) */
1982 } /* end of cookie processing */
1983
1984 /* let's look if we have to delete this header */
1985 if (delete_header) {
1986 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001987 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001988 req->h = req->lr;
1989 } /* while (req->lr < req->r) */
1990
1991 /* end of header processing (even if incomplete) */
1992
willy tarreauef900ab2005-12-17 12:52:52 +01001993
1994 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1995 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1996 * full. We cannot loop here since event_cli_read will disable it only if
1997 * req->l == rlim-data
1998 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 FD_SET(t->cli_fd, StaticReadEvent);
2000 if (t->proxy->clitimeout)
2001 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2002 else
2003 tv_eternity(&t->crexpire);
2004 }
2005
willy tarreauef900ab2005-12-17 12:52:52 +01002006 /* read timeout, read error, or last read : give up.
2007 * since we are in header mode, if there's no space left for headers, we
2008 * won't be able to free more later, so the session will never terminate.
2009 */
2010 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2011 || req->l >= req->rlim - req->data || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 tv_eternity(&t->crexpire);
2013 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 t->cli_state = CL_STCLOSE;
2015 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002016 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017
2018 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002019 }
2020 else if (c == CL_STDATA) {
2021 /* read or write error */
2022 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002023 tv_eternity(&t->crexpire);
2024 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002026 t->cli_state = CL_STCLOSE;
2027 return 1;
2028 }
2029 /* read timeout, last read, or end of server write */
2030 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2031 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002032 FD_CLR(t->cli_fd, StaticReadEvent);
2033 // if (req->l == 0) /* nothing to write on the server side */
2034 // FD_CLR(t->srv_fd, StaticWriteEvent);
2035 tv_eternity(&t->crexpire);
2036 shutdown(t->cli_fd, SHUT_RD);
2037 t->cli_state = CL_STSHUTR;
2038 return 1;
2039 }
2040 /* write timeout, or last server read and buffer empty */
2041 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2042 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002043 FD_CLR(t->cli_fd, StaticWriteEvent);
2044 tv_eternity(&t->cwexpire);
2045 shutdown(t->cli_fd, SHUT_WR);
2046 t->cli_state = CL_STSHUTW;
2047 return 1;
2048 }
2049
willy tarreauef900ab2005-12-17 12:52:52 +01002050 if (req->l >= req->rlim - req->data) {
2051 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002052 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002053 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002054 FD_CLR(t->cli_fd, StaticReadEvent);
2055 tv_eternity(&t->crexpire);
2056 }
2057 }
2058 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002059 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002060 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2061 FD_SET(t->cli_fd, StaticReadEvent);
2062 if (t->proxy->clitimeout)
2063 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2064 else
2065 tv_eternity(&t->crexpire);
2066 }
2067 }
2068
2069 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002071 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2072 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2073 tv_eternity(&t->cwexpire);
2074 }
2075 }
2076 else { /* buffer not empty */
2077 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2078 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2079 if (t->proxy->clitimeout)
2080 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2081 else
2082 tv_eternity(&t->cwexpire);
2083 }
2084 }
2085 return 0; /* other cases change nothing */
2086 }
2087 else if (c == CL_STSHUTR) {
2088 if ((t->res_cw == RES_ERROR) ||
2089 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002090 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002091 tv_eternity(&t->cwexpire);
2092 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002093 t->cli_state = CL_STCLOSE;
2094 return 1;
2095 }
2096 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002097 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002098 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2099 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2100 tv_eternity(&t->cwexpire);
2101 }
2102 }
2103 else { /* buffer not empty */
2104 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2105 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2106 if (t->proxy->clitimeout)
2107 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2108 else
2109 tv_eternity(&t->cwexpire);
2110 }
2111 }
2112 return 0;
2113 }
2114 else if (c == CL_STSHUTW) {
2115 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002116 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002117 tv_eternity(&t->crexpire);
2118 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002119 t->cli_state = CL_STCLOSE;
2120 return 1;
2121 }
willy tarreauef900ab2005-12-17 12:52:52 +01002122 else if (req->l >= req->rlim - req->data) {
2123 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002124 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002125 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002126 FD_CLR(t->cli_fd, StaticReadEvent);
2127 tv_eternity(&t->crexpire);
2128 }
2129 }
2130 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002131 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002132 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2133 FD_SET(t->cli_fd, StaticReadEvent);
2134 if (t->proxy->clitimeout)
2135 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2136 else
2137 tv_eternity(&t->crexpire);
2138 }
2139 }
2140 return 0;
2141 }
2142 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002144 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002146 write(1, trash, len);
2147 }
2148 return 0;
2149 }
2150 return 0;
2151}
2152
2153
2154/*
2155 * manages the server FSM and its socket. It returns 1 if a state has changed
2156 * (and a resync may be needed), 0 else.
2157 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002158int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002159 int s = t->srv_state;
2160 int c = t->cli_state;
2161 struct buffer *req = t->req;
2162 struct buffer *rep = t->rep;
2163
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2165 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2166 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2167 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2168 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002169 if (s == SV_STIDLE) {
2170 if (c == CL_STHEADERS)
2171 return 0; /* stay in idle, waiting for data to reach the client side */
2172 else if (c == CL_STCLOSE ||
2173 c == CL_STSHUTW ||
2174 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2175 tv_eternity(&t->cnexpire);
2176 t->srv_state = SV_STCLOSE;
2177 return 1;
2178 }
2179 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002180 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002181 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2182 t->srv_state = SV_STCONN;
2183 }
2184 else { /* try again */
2185 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002186 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2187 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2188 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2189 }
2190
2191 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002192 t->srv_state = SV_STCONN;
2193 break;
2194 }
2195 }
2196 if (t->conn_retries < 0) {
2197 /* if conn_retries < 0 or other error, let's abort */
2198 tv_eternity(&t->cnexpire);
2199 t->srv_state = SV_STCLOSE;
2200 }
2201 }
2202 return 1;
2203 }
2204 }
2205 else if (s == SV_STCONN) { /* connection in progress */
2206 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2207 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2208 return 0; /* nothing changed */
2209 }
2210 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2211 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2212 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002213 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002214 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002215 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002216 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002217 if (t->conn_retries >= 0) {
2218 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2219 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2220 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2221 }
2222 if (connect_server(t) == 0)
2223 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002224 }
2225 /* if conn_retries < 0 or other error, let's abort */
2226 tv_eternity(&t->cnexpire);
2227 t->srv_state = SV_STCLOSE;
2228 return 1;
2229 }
2230 else { /* no error or write 0 */
2231 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2232 if (req->l == 0) /* nothing to write */
2233 FD_CLR(t->srv_fd, StaticWriteEvent);
2234 else /* need the right to write */
2235 FD_SET(t->srv_fd, StaticWriteEvent);
2236
2237 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2238 FD_SET(t->srv_fd, StaticReadEvent);
2239 if (t->proxy->srvtimeout)
2240 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2241 else
2242 tv_eternity(&t->srexpire);
2243
2244 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002245 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002246 }
willy tarreauef900ab2005-12-17 12:52:52 +01002247 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002248 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002249 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2250 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002251 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002252 return 1;
2253 }
2254 }
2255 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002256
2257 /* now parse the partial (or complete) headers */
2258 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2259 char *ptr;
2260 int delete_header;
2261
2262 ptr = rep->lr;
2263
2264 /* look for the end of the current header */
2265 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2266 ptr++;
2267
2268 if (ptr == rep->h) {
2269 char newhdr[MAXREWRITE + 1];
2270 int line, len;
2271
2272 /* we can only get here after an end of headers */
2273 /* we'll have something else to do here : add new headers ... */
2274
2275 if ((t->srv) && !(t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
2276 /* the server is known, it's not the one the client requested, we have to
2277 * insert a set-cookie here.
2278 */
2279 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2280 t->proxy->cookie_name, t->srv->cookie);
2281 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2282 }
2283
2284 /* headers to be added */
2285 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2286 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2287 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2288 }
2289
2290 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002291 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002292 break;
2293 }
2294
2295 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2296 if (ptr > rep->r - 2) {
2297 /* this is a partial header, let's wait for more to come */
2298 rep->lr = ptr;
2299 break;
2300 }
2301
2302 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2303 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2304
2305 /* now we know that *ptr is either \r or \n,
2306 * and that there are at least 1 char after it.
2307 */
2308 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2309 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2310 else
2311 rep->lr = ptr + 2; /* \r\n or \n\r */
2312
2313 /*
2314 * now we know that we have a full header ; we can do whatever
2315 * we want with these pointers :
2316 * rep->h = beginning of header
2317 * ptr = end of header (first \r or \n)
2318 * rep->lr = beginning of next line (next rep->h)
2319 * rep->r = end of data (not used at this stage)
2320 */
2321
2322 delete_header = 0;
2323
2324 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
2325 int len, max;
2326 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2327 max = ptr - rep->h;
2328 UBOUND(max, sizeof(trash) - len - 1);
2329 len += strlcpy(trash + len, rep->h, max + 1);
2330 trash[len++] = '\n';
2331 write(1, trash, len);
2332 }
2333
2334 /* try headers regexps */
2335 if (t->proxy->nb_rspexp) {
2336 struct proxy *p = t->proxy;
2337 int exp;
2338 char term;
2339
2340 term = *ptr;
2341 *ptr = '\0';
2342 for (exp=0; exp < p->nb_rspexp; exp++) {
2343 if (regexec(p->rsp_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2344 if (p->rsp_exp[exp].replace != NULL) {
2345 int len = exp_replace(trash, rep->h, p->rsp_exp[exp].replace, pmatch);
2346 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2347 }
2348 else {
2349 delete_header = 1;
2350 }
2351 break;
2352 }
2353 }
2354 *ptr = term; /* restore the string terminator */
2355 }
2356
2357 /* check for server cookies */
2358 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2359 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2360 char *p1, *p2, *p3, *p4;
2361
2362 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2363
2364 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2365 while (p1 < ptr && (isspace(*p1)))
2366 p1++;
2367
2368 if (p1 == ptr || *p1 == ';') /* end of cookie */
2369 break;
2370
2371 /* p1 is at the beginning of the cookie name */
2372 p2 = p1;
2373
2374 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2375 p2++;
2376
2377 if (p2 == ptr || *p2 == ';') /* next cookie */
2378 break;
2379
2380 p3 = p2 + 1; /* skips the '=' sign */
2381 if (p3 == ptr)
2382 break;
2383
2384 p4 = p3;
2385 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
2386 p4++;
2387
2388 /* here, we have the cookie name between p1 and p2,
2389 * and its value between p3 and p4.
2390 * we can process it.
2391 */
2392
2393 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2394 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2395 /* Cool... it's the right one */
2396
2397 /* If the cookie is in insert mode on a known server, we'll delete
2398 * this occurrence because we'll insert another one later.
2399 * We'll delete it too if the "indirect" option is set and we're in
2400 * a direct access. */
2401 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
2402 ((t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
2403 /* this header must be deleted */
2404 delete_header = 1;
2405 }
2406 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2407 /* replace bytes p3->p4 with the cookie name associated
2408 * with this server since we know it.
2409 */
2410 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2411 }
2412 break;
2413 }
2414 else {
2415 // fprintf(stderr,"Ignoring unknown cookie : ");
2416 // write(2, p1, p2-p1);
2417 // fprintf(stderr," = ");
2418 // write(2, p3, p4-p3);
2419 // fprintf(stderr,"\n");
2420 }
2421 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2422 } /* we're now at the end of the cookie value */
2423 } /* end of cookie processing */
2424
2425 /* let's look if we have to delete this header */
2426 if (delete_header) {
2427 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2428 }
2429 rep->h = rep->lr;
2430 } /* while (rep->lr < rep->r) */
2431
2432 /* end of header processing (even if incomplete) */
2433
willy tarreauef900ab2005-12-17 12:52:52 +01002434 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2435 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2436 * full. We cannot loop here since event_srv_read will disable it only if
2437 * rep->l == rlim-data
2438 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002439 FD_SET(t->srv_fd, StaticReadEvent);
2440 if (t->proxy->srvtimeout)
2441 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2442 else
2443 tv_eternity(&t->srexpire);
2444 }
willy tarreau0f7af912005-12-17 12:21:26 +01002445
2446 /* read or write error */
2447 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002448 tv_eternity(&t->srexpire);
2449 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002450 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002451 t->srv_state = SV_STCLOSE;
2452 return 1;
2453 }
willy tarreauef900ab2005-12-17 12:52:52 +01002454 /* read timeout, last read, or end of client write
2455 * since we are in header mode, if there's no space left for headers, we
2456 * won't be able to free more later, so the session will never terminate.
2457 */
2458 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2459 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002460 FD_CLR(t->srv_fd, StaticReadEvent);
2461 tv_eternity(&t->srexpire);
2462 shutdown(t->srv_fd, SHUT_RD);
2463 t->srv_state = SV_STSHUTR;
2464 return 1;
2465
2466 }
2467 /* write timeout, or last client read and buffer empty */
2468 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2469 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2470 FD_CLR(t->srv_fd, StaticWriteEvent);
2471 tv_eternity(&t->swexpire);
2472 shutdown(t->srv_fd, SHUT_WR);
2473 t->srv_state = SV_STSHUTW;
2474 return 1;
2475 }
2476
2477 if (req->l == 0) {
2478 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2479 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2480 tv_eternity(&t->swexpire);
2481 }
2482 }
2483 else { /* client buffer not empty */
2484 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2485 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2486 if (t->proxy->srvtimeout)
2487 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2488 else
2489 tv_eternity(&t->swexpire);
2490 }
2491 }
2492
willy tarreau5cbea6f2005-12-17 12:48:26 +01002493 /* be nice with the client side which would like to send a complete header
2494 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2495 * would read all remaining data at once ! The client should not write past rep->lr
2496 * when the server is in header state.
2497 */
2498 //return header_processed;
2499 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002500 }
2501 else if (s == SV_STDATA) {
2502 /* read or write error */
2503 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002504 tv_eternity(&t->srexpire);
2505 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002506 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002507 t->srv_state = SV_STCLOSE;
2508 return 1;
2509 }
2510 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002511 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2512 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002513 FD_CLR(t->srv_fd, StaticReadEvent);
2514 tv_eternity(&t->srexpire);
2515 shutdown(t->srv_fd, SHUT_RD);
2516 t->srv_state = SV_STSHUTR;
2517 return 1;
2518
2519 }
2520 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002521 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2522 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002523 FD_CLR(t->srv_fd, StaticWriteEvent);
2524 tv_eternity(&t->swexpire);
2525 shutdown(t->srv_fd, SHUT_WR);
2526 t->srv_state = SV_STSHUTW;
2527 return 1;
2528 }
2529 else if (req->l == 0) {
2530 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2531 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2532 tv_eternity(&t->swexpire);
2533 }
2534 }
2535 else { /* buffer not empty */
2536 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2537 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2538 if (t->proxy->srvtimeout)
2539 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2540 else
2541 tv_eternity(&t->swexpire);
2542 }
2543 }
2544
2545 if (rep->l == BUFSIZE) { /* no room to read more data */
2546 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2547 FD_CLR(t->srv_fd, StaticReadEvent);
2548 tv_eternity(&t->srexpire);
2549 }
2550 }
2551 else {
2552 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2553 FD_SET(t->srv_fd, StaticReadEvent);
2554 if (t->proxy->srvtimeout)
2555 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2556 else
2557 tv_eternity(&t->srexpire);
2558 }
2559 }
2560
2561 return 0; /* other cases change nothing */
2562 }
2563 else if (s == SV_STSHUTR) {
2564 if ((t->res_sw == RES_ERROR) ||
2565 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2566 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002567 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002568 tv_eternity(&t->swexpire);
2569 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002570 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002571 t->srv_state = SV_STCLOSE;
2572 return 1;
2573 }
2574 else if (req->l == 0) {
2575 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2576 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2577 tv_eternity(&t->swexpire);
2578 }
2579 }
2580 else { /* buffer not empty */
2581 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2582 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2583 if (t->proxy->srvtimeout)
2584 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2585 else
2586 tv_eternity(&t->swexpire);
2587 }
2588 }
2589 return 0;
2590 }
2591 else if (s == SV_STSHUTW) {
2592 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2593 c == CL_STSHUTW || c == CL_STCLOSE ||
2594 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002595 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002596 tv_eternity(&t->srexpire);
2597 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002598 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002599 t->srv_state = SV_STCLOSE;
2600 return 1;
2601 }
2602 else if (rep->l == BUFSIZE) { /* no room to read more data */
2603 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2604 FD_CLR(t->srv_fd, StaticReadEvent);
2605 tv_eternity(&t->srexpire);
2606 }
2607 }
2608 else {
2609 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2610 FD_SET(t->srv_fd, StaticReadEvent);
2611 if (t->proxy->srvtimeout)
2612 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2613 else
2614 tv_eternity(&t->srexpire);
2615 }
2616 }
2617 return 0;
2618 }
2619 else { /* SV_STCLOSE : nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002620 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002621 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002622 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002623 write(1, trash, len);
2624 }
2625 return 0;
2626 }
2627 return 0;
2628}
2629
2630
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631/* Processes the client and server jobs of a session task, then
2632 * puts it back to the wait queue in a clean state, or
2633 * cleans up its resources if it must be deleted. Returns
2634 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01002635 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002636int process_session(struct task *t) {
2637 struct session *s = t->context;
2638 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002639
willy tarreau5cbea6f2005-12-17 12:48:26 +01002640 do {
2641 fsm_resync = 0;
2642 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2643 fsm_resync |= process_cli(s);
2644 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2645 fsm_resync |= process_srv(s);
2646 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2647 } while (fsm_resync);
2648
2649 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002650 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002651 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01002652
willy tarreau5cbea6f2005-12-17 12:48:26 +01002653 tv_min(&min1, &s->crexpire, &s->cwexpire);
2654 tv_min(&min2, &s->srexpire, &s->swexpire);
2655 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002656 tv_min(&t->expire, &min1, &min2);
2657
2658 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002659 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01002660
willy tarreau5cbea6f2005-12-17 12:48:26 +01002661 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01002662 }
2663
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01002665 actconn--;
2666
willy tarreau5cbea6f2005-12-17 12:48:26 +01002667 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002668 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002669 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002670 write(1, trash, len);
2671 }
2672
2673 /* the task MUST not be in the run queue anymore */
2674 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002675 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01002676 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002677 return -1; /* rest in peace for eternity */
2678}
2679
2680
2681
2682/*
2683 * manages a server health-check. Returns
2684 * the time the task accepts to wait, or -1 for infinity.
2685 */
2686int process_chk(struct task *t) {
2687 struct server *s = t->context;
2688 int fd = s->curfd;
2689 int one = 1;
2690
willy tarreauef900ab2005-12-17 12:52:52 +01002691 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002692
2693 if (fd < 0) { /* no check currently running */
2694 //fprintf(stderr, "process_chk: 2\n");
2695 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
2696 task_queue(t); /* restore t to its place in the task list */
2697 return tv_remain(&now, &t->expire);
2698 }
2699
2700 /* we'll initiate a new check */
2701 s->result = 0; /* no result yet */
2702 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
2703 if ((fd < cfg_maxsock) &&
2704 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
2705 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
2706 //fprintf(stderr, "process_chk: 3\n");
2707
2708 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
2709 /* OK, connection in progress or established */
2710
2711 //fprintf(stderr, "process_chk: 4\n");
2712
2713 s->curfd = fd; /* that's how we know a test is in progress ;-) */
2714 fdtab[fd].owner = t;
2715 fdtab[fd].read = NULL;
2716 fdtab[fd].write = &event_srv_hck;
2717 fdtab[fd].state = FD_STCONN; /* connection in progress */
2718 FD_SET(fd, StaticWriteEvent); /* for connect status */
2719 fd_insert(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01002720 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
2721 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002722 task_queue(t); /* restore t to its place in the task list */
2723 return tv_remain(&now, &t->expire);
2724 }
2725 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
2726 s->result = -1; /* a real error */
2727 }
2728 }
2729 //fprintf(stderr, "process_chk: 5\n");
2730 close(fd);
2731 }
2732
2733 if (!s->result) { /* nothing done */
2734 //fprintf(stderr, "process_chk: 6\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01002735 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002736 task_queue(t); /* restore t to its place in the task list */
2737 return tv_remain(&now, &t->expire);
2738 }
2739
2740 /* here, we have seen a failure */
willy tarreaue47c8d72005-12-17 12:55:52 +01002741 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002742 s->health--; /* still good */
2743 else {
willy tarreaue47c8d72005-12-17 12:55:52 +01002744 if (s->health == s->rise && !(mode & MODE_QUIET))
willy tarreauef900ab2005-12-17 12:52:52 +01002745 Warning("server %s DOWN.\n", s->id);
2746
willy tarreau5cbea6f2005-12-17 12:48:26 +01002747 s->health = 0; /* failure */
2748 s->state &= ~SRV_RUNNING;
2749 }
2750
2751 //fprintf(stderr, "process_chk: 7\n");
willy tarreaue47c8d72005-12-17 12:55:52 +01002752 /* FIXME: we allow up to <inter> for a connection to establish, but we should use another parameter */
2753 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002754 }
2755 else {
2756 //fprintf(stderr, "process_chk: 8\n");
2757 /* there was a test running */
2758 if (s->result > 0) { /* good server detected */
2759 //fprintf(stderr, "process_chk: 9\n");
2760 s->health++; /* was bad, stays for a while */
willy tarreaue47c8d72005-12-17 12:55:52 +01002761 if (s->health >= s->rise) {
2762 if (s->health == s->rise && !(mode & MODE_QUIET))
willy tarreauef900ab2005-12-17 12:52:52 +01002763 Warning("server %s UP.\n", s->id);
2764
willy tarreaue47c8d72005-12-17 12:55:52 +01002765 s->health = s->rise + s->fall - 1; /* OK now */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002766 s->state |= SRV_RUNNING;
2767 }
willy tarreauef900ab2005-12-17 12:52:52 +01002768 s->curfd = -1; /* no check running anymore */
2769 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002770 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01002771 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002772 }
2773 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
2774 //fprintf(stderr, "process_chk: 10\n");
2775 /* failure or timeout detected */
willy tarreaue47c8d72005-12-17 12:55:52 +01002776 if (s->health > s->rise)
willy tarreau5cbea6f2005-12-17 12:48:26 +01002777 s->health--; /* still good */
2778 else {
willy tarreaue47c8d72005-12-17 12:55:52 +01002779 if (s->health == s->rise && !(mode & MODE_QUIET))
willy tarreauef900ab2005-12-17 12:52:52 +01002780 Warning("server %s DOWN.\n", s->id);
2781
willy tarreau5cbea6f2005-12-17 12:48:26 +01002782 s->health = 0; /* failure */
2783 s->state &= ~SRV_RUNNING;
2784 }
2785 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01002786 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002787 fd_delete(fd);
willy tarreaue47c8d72005-12-17 12:55:52 +01002788 tv_delayfrom(&t->expire, &now, s->inter);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002789 }
2790 /* if result is 0 and there's no timeout, we have to wait again */
2791 }
2792 //fprintf(stderr, "process_chk: 11\n");
2793 s->result = 0;
2794 task_queue(t); /* restore t to its place in the task list */
2795 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01002796}
2797
2798
willy tarreau5cbea6f2005-12-17 12:48:26 +01002799
willy tarreau0f7af912005-12-17 12:21:26 +01002800#if STATTIME > 0
2801int stats(void);
2802#endif
2803
2804/*
2805 * Main select() loop.
2806 */
2807
2808void select_loop() {
2809 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01002810 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01002811 int status;
2812 int fd,i;
2813 struct timeval delta;
2814 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01002816
willy tarreau5cbea6f2005-12-17 12:48:26 +01002817 tv_now(&now);
2818
2819 while (1) {
2820 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01002821
willy tarreau5cbea6f2005-12-17 12:48:26 +01002822 /* look for expired tasks and add them to the run queue.
2823 */
2824 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
2825 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
2826 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01002827 if (t->state & TASK_RUNNING)
2828 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002829
2830 /* wakeup expired entries. It doesn't matter if they are
2831 * already running because of a previous event
2832 */
2833 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01002834 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002835 task_wakeup(&rq, t);
2836 }
2837 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002838 /* first non-runnable task. Use its expiration date as an upper bound */
2839 int temp_time = tv_remain(&now, &t->expire);
2840 if (temp_time)
2841 next_time = temp_time;
2842 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002843 break;
2844 }
2845 }
2846
2847 /* process each task in the run queue now. Each task may be deleted
2848 * since we only use tnext.
2849 */
2850 tnext = rq;
2851 while ((t = tnext) != NULL) {
2852 int temp_time;
2853
2854 tnext = t->rqnext;
2855 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002856 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002857 temp_time = t->process(t);
2858 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01002859 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002860 }
2861
willy tarreauef900ab2005-12-17 12:52:52 +01002862 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002863
2864 /* maintain all proxies in a consistent state. This should quickly become a task */
2865 time2 = maintain_proxies();
2866 next_time = MINTIME(time2, next_time);
2867
2868 /* stop when there's no connection left and we don't allow them anymore */
2869 if (!actconn && listeners == 0)
2870 break;
2871
willy tarreau0f7af912005-12-17 12:21:26 +01002872
2873#if STATTIME > 0
2874 time2 = stats();
2875 // fprintf(stderr," stats = %d\n", time2);
2876 next_time = MINTIME(time2, next_time);
2877#endif
2878
willy tarreau5cbea6f2005-12-17 12:48:26 +01002879 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01002880 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002881 /* to avoid eventual select loops due to timer precision */
2882 next_time += SCHEDULER_RESOLUTION;
2883 delta.tv_sec = next_time / 1000;
2884 delta.tv_usec = (next_time % 1000) * 1000;
2885 }
2886 else if (next_time == 0) { /* allow select to return immediately when needed */
2887 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002888 }
2889
2890
2891 /* let's restore fdset state */
2892
2893 readnotnull = 0; writenotnull = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002894 for (i = 0; i < (cfg_maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01002895 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2896 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2897 }
2898
2899// /* just a verification code, needs to be removed for performance */
2900// for (i=0; i<maxfd; i++) {
2901// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2902// abort();
2903// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2904// abort();
2905//
2906// }
2907
2908 status=select(maxfd,
2909 readnotnull ? ReadEvent : NULL,
2910 writenotnull ? WriteEvent : NULL,
2911 NULL,
2912 (next_time >= 0) ? &delta : NULL);
2913
willy tarreau5cbea6f2005-12-17 12:48:26 +01002914 /* this is an experiment on the separation of the select work */
2915 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2916 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2917
willy tarreau0f7af912005-12-17 12:21:26 +01002918 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002919
willy tarreau0f7af912005-12-17 12:21:26 +01002920 if (status > 0) { /* must proceed with events */
2921
2922 int fds;
2923 char count;
2924
2925 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2926 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2927 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2928
willy tarreau5cbea6f2005-12-17 12:48:26 +01002929 /* if we specify read first, the accepts and zero reads will be
2930 * seen first. Moreover, system buffers will be flushed faster.
2931 */
willy tarreau0f7af912005-12-17 12:21:26 +01002932 if (fdtab[fd].state == FD_STCLOSE)
2933 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002934
2935 if (FD_ISSET(fd, ReadEvent))
2936 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002937
willy tarreau5cbea6f2005-12-17 12:48:26 +01002938 if (FD_ISSET(fd, WriteEvent))
2939 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002940 }
2941 }
2942 else {
2943 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2944 }
willy tarreau0f7af912005-12-17 12:21:26 +01002945 }
2946}
2947
2948
2949#if STATTIME > 0
2950/*
2951 * Display proxy statistics regularly. It is designed to be called from the
2952 * select_loop().
2953 */
2954int stats(void) {
2955 static int lines;
2956 static struct timeval nextevt;
2957 static struct timeval lastevt;
2958 static struct timeval starttime = {0,0};
2959 unsigned long totaltime, deltatime;
2960 int ret;
2961
2962 if (tv_remain(&now, &nextevt) == 0) {
2963 deltatime = (tv_delta(&now, &lastevt)?:1);
2964 totaltime = (tv_delta(&now, &starttime)?:1);
2965
2966 if (mode & MODE_STATS) {
2967 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002968 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01002969 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2970 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002971 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01002972 actconn, totalconn,
2973 stats_tsk_new, stats_tsk_good,
2974 stats_tsk_left, stats_tsk_right,
2975 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2976 }
2977 }
2978
2979 tv_delayfrom(&nextevt, &now, STATTIME);
2980
2981 lastevt=now;
2982 }
2983 ret = tv_remain(&now, &nextevt);
2984 return ret;
2985}
2986#endif
2987
2988
2989/*
2990 * this function enables proxies when there are enough free sessions,
2991 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01002992 * select_loop(). It returns the time left before next expiration event
2993 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01002994 */
2995static int maintain_proxies(void) {
2996 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002997 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01002998
2999 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003000 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01003001
3002 /* if there are enough free sessions, we'll activate proxies */
3003 if (actconn < cfg_maxconn) {
3004 while (p) {
3005 if (p->nbconn < p->maxconn) {
3006 if (p->state == PR_STIDLE) {
3007 FD_SET(p->listen_fd, StaticReadEvent);
3008 p->state = PR_STRUN;
3009 }
3010 }
3011 else {
3012 if (p->state == PR_STRUN) {
3013 FD_CLR(p->listen_fd, StaticReadEvent);
3014 p->state = PR_STIDLE;
3015 }
3016 }
3017 p = p->next;
3018 }
3019 }
3020 else { /* block all proxies */
3021 while (p) {
3022 if (p->state == PR_STRUN) {
3023 FD_CLR(p->listen_fd, StaticReadEvent);
3024 p->state = PR_STIDLE;
3025 }
3026 p = p->next;
3027 }
3028 }
3029
willy tarreau5cbea6f2005-12-17 12:48:26 +01003030 if (stopping) {
3031 p = proxy;
3032 while (p) {
3033 if (p->state != PR_STDISABLED) {
3034 int t;
3035 t = tv_remain(&now, &p->stop_time);
3036 if (t == 0) {
3037 //FD_CLR(p->listen_fd, StaticReadEvent);
3038 //close(p->listen_fd);
3039 fd_delete(p->listen_fd);
3040 p->state = PR_STDISABLED;
3041 listeners--;
3042 }
3043 else {
3044 tleft = MINTIME(t, tleft);
3045 }
3046 }
3047 p = p->next;
3048 }
3049 }
3050 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003051}
3052
3053/*
3054 * this function disables health-check servers so that the process will quickly be ignored
3055 * by load balancers.
3056 */
3057static void soft_stop(void) {
3058 struct proxy *p;
3059
3060 stopping = 1;
3061 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003062 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003063 while (p) {
3064 if (p->state != PR_STDISABLED)
3065 tv_delayfrom(&p->stop_time, &now, p->grace);
3066 p = p->next;
3067 }
3068}
3069
3070/*
3071 * upon SIGUSR1, let's have a soft stop.
3072 */
3073void sig_soft_stop(int sig) {
3074 soft_stop();
3075 signal(sig, SIG_IGN);
3076}
3077
3078
3079void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003080 struct task *t, *tnext;
3081 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003082
willy tarreau5cbea6f2005-12-17 12:48:26 +01003083 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3084 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3085 tnext = t->next;
3086 s = t->context;
3087 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3088 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3089 "req=%d, rep=%d, clifd=%d\n",
3090 s, tv_remain(&now, &t->expire),
3091 s->cli_state,
3092 s->srv_state,
3093 FD_ISSET(s->cli_fd, StaticReadEvent),
3094 FD_ISSET(s->cli_fd, StaticWriteEvent),
3095 FD_ISSET(s->srv_fd, StaticReadEvent),
3096 FD_ISSET(s->srv_fd, StaticWriteEvent),
3097 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3098 );
willy tarreau0f7af912005-12-17 12:21:26 +01003099 }
3100}
3101
3102/*
3103 * This function reads and parses the configuration file given in the argument.
3104 * returns 0 if OK, -1 if error.
3105 */
3106int readcfgfile(char *file) {
3107 char thisline[256];
3108 char *line;
3109 FILE *f;
3110 int linenum = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003111 char *end;
3112 char *args[MAX_LINE_ARGS];
willy tarreau0f7af912005-12-17 12:21:26 +01003113 int arg;
3114 int cfgerr = 0;
3115
3116 struct proxy *curproxy = NULL;
3117 struct server *newsrv = NULL;
3118
3119 if ((f=fopen(file,"r")) == NULL)
3120 return -1;
3121
3122 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
3123 linenum++;
willy tarreau0f7af912005-12-17 12:21:26 +01003124
willy tarreau5cbea6f2005-12-17 12:48:26 +01003125 end = line + strlen(line);
willy tarreau0f7af912005-12-17 12:21:26 +01003126
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 /* skip leading spaces */
3128 while (isspace(*line))
3129 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01003130
willy tarreau5cbea6f2005-12-17 12:48:26 +01003131 arg = 0;
3132 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01003133
willy tarreau5cbea6f2005-12-17 12:48:26 +01003134 while (*line && arg < MAX_LINE_ARGS) {
3135 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
3136 * C equivalent value. Other combinations left unchanged (eg: \1).
3137 */
3138 if (*line == '\\') {
3139 int skip = 0;
3140 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
3141 *line = line[1];
3142 skip = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003143 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003144 else if (line[1] == 'r') {
3145 *line = '\r';
3146 skip = 1;
3147 }
3148 else if (line[1] == 'n') {
3149 *line = '\n';
3150 skip = 1;
3151 }
3152 else if (line[1] == 't') {
3153 *line = '\t';
3154 skip = 1;
3155 }
3156 else if (line[1] == 'x' && (line + 3 < end )) {
3157 unsigned char hex1, hex2;
3158 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
3159 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3160 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3161 *line = (hex1<<4) + hex2;
3162 skip = 3;
3163 }
3164 if (skip) {
3165 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
3166 end -= skip;
3167 }
willy tarreau0f7af912005-12-17 12:21:26 +01003168 line++;
3169 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003170 else {
3171 if (*line == '#' || *line == '\n' || *line == '\r')
3172 *line = 0; /* end of string, end of loop */
3173 else
willy tarreau0f7af912005-12-17 12:21:26 +01003174 line++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003175
3176 /* a non-escaped space is an argument separator */
3177 if (isspace(*line)) {
3178 *line++ = 0;
3179 while (isspace(*line))
3180 line++;
3181 args[++arg] = line;
3182 }
willy tarreau0f7af912005-12-17 12:21:26 +01003183 }
3184 }
3185
willy tarreau5cbea6f2005-12-17 12:48:26 +01003186 /* empty line */
3187 if (!**args)
3188 continue;
3189
3190 /* zero out remaining args */
3191 while (++arg < MAX_LINE_ARGS) {
3192 args[arg] = line;
3193 }
3194
willy tarreau0f7af912005-12-17 12:21:26 +01003195 if (!strcmp(args[0], "listen")) { /* new proxy */
3196 if (strchr(args[2], ':') == NULL) {
3197 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3198 file, linenum);
3199 return -1;
3200 }
3201
3202 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
3203 == NULL) {
3204 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3205 exit(1);
3206 }
3207 curproxy->next = proxy;
3208 proxy = curproxy;
3209 curproxy->id = strdup(args[1]);
3210 curproxy->listen_addr = *str2sa(args[2]);
3211 curproxy->state = PR_STNEW;
willy tarreau0f7af912005-12-17 12:21:26 +01003212 /* set default values */
3213 curproxy->maxconn = cfg_maxpconn;
3214 curproxy->conn_retries = CONN_RETRIES;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003215 curproxy->options = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003216 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3217 curproxy->mode = PR_MODE_TCP;
3218 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3219 continue;
3220 }
3221 else if (curproxy == NULL) {
3222 Alert("parsing [%s:%d] : <listen> expected.\n",
3223 file, linenum);
3224 return -1;
3225 }
3226
3227 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3228 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3229 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3230 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3231 else {
3232 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3233 return -1;
3234 }
3235 }
3236 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3237 curproxy->state = PR_STDISABLED;
3238 }
3239 else if (!strcmp(args[0], "cookie")) { /* cookie name */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003240 int cur_arg;
willy tarreau0f7af912005-12-17 12:21:26 +01003241 if (curproxy->cookie_name != NULL) {
3242 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3243 file, linenum);
3244 continue;
3245 }
3246
3247 if (*(args[1]) == 0) {
3248 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3249 file, linenum);
3250 return -1;
3251 }
3252 curproxy->cookie_name = strdup(args[1]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003253
3254 cur_arg = 2;
3255 while (*(args[cur_arg])) {
3256 if (!strcmp(args[cur_arg], "rewrite")) {
3257 curproxy->options |= PR_O_COOK_RW;
3258 }
3259 else if (!strcmp(args[cur_arg], "indirect")) {
3260 curproxy->options |= PR_O_COOK_IND;
3261 }
3262 else if (!strcmp(args[cur_arg], "insert")) {
3263 curproxy->options |= PR_O_COOK_INS;
3264 }
3265 else {
3266 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
3267 file, linenum);
3268 return -1;
3269 }
3270 cur_arg++;
3271 }
3272 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3273 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3274 file, linenum);
3275 return -1;
3276 }
willy tarreau0f7af912005-12-17 12:21:26 +01003277 }
3278 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3279 if (curproxy->contimeout != 0) {
3280 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
3281 file, linenum);
3282 continue;
3283 }
3284 if (*(args[1]) == 0) {
3285 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3286 file, linenum);
3287 return -1;
3288 }
3289 curproxy->contimeout = atol(args[1]);
3290 }
3291 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3292 if (curproxy->clitimeout != 0) {
3293 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3294 file, linenum);
3295 continue;
3296 }
3297 if (*(args[1]) == 0) {
3298 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3299 file, linenum);
3300 return -1;
3301 }
3302 curproxy->clitimeout = atol(args[1]);
3303 }
3304 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3305 if (curproxy->srvtimeout != 0) {
3306 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
3307 file, linenum);
3308 continue;
3309 }
3310 if (*(args[1]) == 0) {
3311 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
3312 file, linenum);
3313 return -1;
3314 }
3315 curproxy->srvtimeout = atol(args[1]);
3316 }
3317 else if (!strcmp(args[0], "retries")) { /* connection retries */
3318 if (*(args[1]) == 0) {
3319 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3320 file, linenum);
3321 return -1;
3322 }
3323 curproxy->conn_retries = atol(args[1]);
3324 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003325 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3326 /* enable reconnections to dispatch */
3327 curproxy->options |= PR_O_REDISP;
willy tarreau0f7af912005-12-17 12:21:26 +01003328 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003329#ifdef TRANSPARENT
3330 else if (!strcmp(args[0], "transparent")) {
3331 /* enable transparent proxy connections */
3332 curproxy->options |= PR_O_TRANSP;
3333 }
3334#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003335 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3336 if (*(args[1]) == 0) {
3337 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
3338 file, linenum);
3339 return -1;
3340 }
3341 curproxy->maxconn = atol(args[1]);
3342 }
3343 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3344 if (*(args[1]) == 0) {
3345 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
3346 file, linenum);
3347 return -1;
3348 }
3349 curproxy->grace = atol(args[1]);
3350 }
3351 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3352 if (strchr(args[1], ':') == NULL) {
3353 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
3354 file, linenum);
3355 return -1;
3356 }
3357 curproxy->dispatch_addr = *str2sa(args[1]);
3358 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003359 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3360 if (*(args[1])) {
3361 if (!strcmp(args[1], "roundrobin")) {
3362 curproxy->options |= PR_O_BALANCE_RR;
3363 }
3364 else {
3365 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n",
3366 file, linenum);
3367 return -1;
3368 }
3369 }
3370 else /* if no option is set, use round-robin by default */
3371 curproxy->options |= PR_O_BALANCE_RR;
3372 }
willy tarreau0f7af912005-12-17 12:21:26 +01003373 else if (!strcmp(args[0], "server")) { /* server address */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374 int cur_arg;
3375
willy tarreau0f7af912005-12-17 12:21:26 +01003376 if (strchr(args[2], ':') == NULL) {
3377 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3378 file, linenum);
3379 return -1;
3380 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003381 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3382 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003383 exit(1);
3384 }
3385 newsrv->next = curproxy->srv;
3386 curproxy->srv = newsrv;
3387 newsrv->id = strdup(args[1]);
3388 newsrv->addr = *str2sa(args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003389 newsrv->state = SRV_RUNNING; /* early server setup */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003390 newsrv->curfd = -1; /* no health-check in progress */
willy tarreaue47c8d72005-12-17 12:55:52 +01003391 newsrv->inter = DEF_CHKINTR;
3392 newsrv->rise = DEF_RISETIME;
3393 newsrv->fall = DEF_FALLTIME;
3394 newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003395 cur_arg = 3;
3396 while (*args[cur_arg]) {
3397 if (!strcmp(args[cur_arg], "cookie")) {
3398 newsrv->cookie = strdup(args[cur_arg + 1]);
3399 newsrv->cklen = strlen(args[cur_arg + 1]);
3400 cur_arg += 2;
3401 }
willy tarreaue47c8d72005-12-17 12:55:52 +01003402 else if (!strcmp(args[cur_arg], "rise")) {
3403 newsrv->rise = atol(args[cur_arg + 1]);
3404 newsrv->health = newsrv->rise;
3405 cur_arg += 2;
3406 }
3407 else if (!strcmp(args[cur_arg], "fall")) {
3408 newsrv->fall = atol(args[cur_arg + 1]);
3409 cur_arg += 2;
3410 }
3411 else if (!strcmp(args[cur_arg], "inter")) {
3412 newsrv->inter = atol(args[cur_arg + 1]);
3413 cur_arg += 2;
3414 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003415 else if (!strcmp(args[cur_arg], "check")) {
3416 struct task *t;
3417
3418 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3419 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3420 return -1;
3421 }
3422
3423 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3424 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3425 t->state = TASK_IDLE;
3426 t->process = process_chk;
3427 t->context = newsrv;
3428
willy tarreaue47c8d72005-12-17 12:55:52 +01003429 if (curproxy->state != PR_STDISABLED) {
3430 tv_delayfrom(&t->expire, &now, newsrv->inter); /* check this every ms */
3431 task_queue(t);
3432 task_wakeup(&rq, t);
3433 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003434
3435 cur_arg += 1;
3436 }
3437 else {
3438 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3439 file, linenum, newsrv->id);
3440 return -1;
3441 }
3442 }
3443 curproxy->nbservers++;
willy tarreau0f7af912005-12-17 12:21:26 +01003444 }
3445 else if (!strcmp(args[0], "log")) { /* syslog server address */
3446 struct sockaddr_in *sa;
3447 int facility;
3448
3449 if (*(args[1]) == 0 || *(args[2]) == 0) {
3450 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
3451 file, linenum);
3452 return -1;
3453 }
3454
3455 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3456 if (!strcmp(log_facilities[facility], args[2]))
3457 break;
3458
3459 if (facility >= NB_LOG_FACILITIES) {
3460 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3461 exit(1);
3462 }
3463
3464 sa = str2sa(args[1]);
3465 if (!sa->sin_port)
3466 sa->sin_port = htons(SYSLOG_PORT);
3467
3468 if (curproxy->logfac1 == -1) {
3469 curproxy->logsrv1 = *sa;
3470 curproxy->logfac1 = facility;
3471 }
3472 else if (curproxy->logfac2 == -1) {
3473 curproxy->logsrv2 = *sa;
3474 curproxy->logfac2 = facility;
3475 }
3476 else {
3477 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3478 exit(1);
3479 }
3480
3481 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003483 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003484 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3485 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003486 file, linenum);
3487 continue;
3488 }
3489
3490 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003491 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003492 file, linenum);
3493 return -1;
3494 }
3495
3496 preg = calloc(1, sizeof(regex_t));
3497 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3498 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3499 return -1;
3500 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003501 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3502 curproxy->req_exp[curproxy->nb_reqexp].replace = strdup(args[2]);
3503 curproxy->nb_reqexp++;
willy tarreau0f7af912005-12-17 12:21:26 +01003504 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003505 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003506 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003507 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3508 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
3509 file, linenum);
3510 continue;
3511 }
3512
3513 if (*(args[1]) == 0) {
3514 Alert("parsing [%s:%d] : <reqdel> expects <search> as an argument.\n",
3515 file, linenum);
3516 return -1;
3517 }
3518
3519 preg = calloc(1, sizeof(regex_t));
3520 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3521 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3522 return -1;
3523 }
3524 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3525 curproxy->req_exp[curproxy->nb_reqexp].replace = NULL; /* means it must be deleted */
3526 curproxy->nb_reqexp++;
3527 }
3528 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3529 if (curproxy->nb_reqadd >= MAX_REGEXP) {
3530 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
3531 file, linenum);
3532 continue;
3533 }
3534
3535 if (*(args[1]) == 0) {
3536 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n",
3537 file, linenum);
3538 return -1;
3539 }
3540
3541 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
3542 }
3543 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3544 regex_t *preg;
3545 if (curproxy->nb_rspexp >= MAX_REGEXP) {
willy tarreau0f7af912005-12-17 12:21:26 +01003546 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3547 file, linenum);
3548 continue;
3549 }
3550
3551 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003552 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003553 file, linenum);
3554 return -1;
3555 }
3556
3557 preg = calloc(1, sizeof(regex_t));
3558 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3559 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3560 return -1;
3561 }
3562 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003563 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3564 curproxy->rsp_exp[curproxy->nb_rspexp].replace = strdup(args[2]);
3565 curproxy->nb_rspexp++;
3566 }
3567 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3568 regex_t *preg;
3569 if (curproxy->nb_rspexp >= MAX_REGEXP) {
3570 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3571 file, linenum);
3572 continue;
3573 }
3574
3575 if (*(args[1]) == 0) {
3576 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n",
3577 file, linenum);
3578 return -1;
3579 }
3580
3581 preg = calloc(1, sizeof(regex_t));
3582 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3583 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3584 return -1;
3585 }
3586 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
3587 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3588 curproxy->rsp_exp[curproxy->nb_rspexp].replace = NULL; /* means it must be deleted */
3589 curproxy->nb_rspexp++;
3590 }
3591 else if (!strcmp(args[0], "rspadd")) { /* add response header */
3592 if (curproxy->nb_rspadd >= MAX_REGEXP) {
3593 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3594 file, linenum);
3595 continue;
3596 }
3597
3598 if (*(args[1]) == 0) {
3599 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n",
3600 file, linenum);
3601 return -1;
3602 }
3603
3604 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01003605 }
3606 else {
3607 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
3608 exit(1);
3609 }
3610 }
3611 fclose(f);
3612
3613 /*
3614 * Now, check for the integrity of all that we have collected.
3615 */
3616
3617 if ((curproxy = proxy) == NULL) {
3618 Alert("parsing %s : no <listen> line. Nothing to do !\n",
3619 file);
3620 return -1;
3621 }
3622
3623 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01003624 if (curproxy->state == PR_STDISABLED) {
3625 curproxy = curproxy->next;
3626 continue;
3627 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003628 if ((curproxy->mode != PR_MODE_HEALTH) &&
3629 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
3630 (*(int *)&curproxy->dispatch_addr == 0)) {
3631 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
3632 file, curproxy->id);
3633 cfgerr++;
3634 }
3635 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
3636 if (curproxy->options & PR_O_TRANSP) {
3637 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
3638 file, curproxy->id);
3639 cfgerr++;
3640 }
3641 else if (curproxy->srv == NULL) {
3642 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
3643 file, curproxy->id);
3644 cfgerr++;
3645 }
3646 else if (*(int *)&curproxy->dispatch_addr != 0) {
3647 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
3648 file, curproxy->id);
3649 }
3650 }
3651 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01003652 if (curproxy->cookie_name != NULL) {
3653 Warning("parsing %s : cookie will be ignored for listener %s.\n",
3654 file, curproxy->id);
3655 }
3656 if ((newsrv = curproxy->srv) != NULL) {
3657 Warning("parsing %s : servers will be ignored for listener %s.\n",
3658 file, curproxy->id);
3659 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003660 if (curproxy->nb_rspexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003661 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
3662 file, curproxy->id);
3663 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003664 if (curproxy->nb_reqexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003665 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
3666 file, curproxy->id);
3667 }
3668 }
3669 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
3670 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
3671 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
3672 file, curproxy->id);
3673 cfgerr++;
3674 }
3675 else {
3676 while (newsrv != NULL) {
3677 /* nothing to check for now */
3678 newsrv = newsrv->next;
3679 }
3680 }
3681 }
3682 curproxy = curproxy->next;
3683 }
3684 if (cfgerr > 0) {
3685 Alert("Errors found in configuration file, aborting.\n");
3686 return -1;
3687 }
3688 else
3689 return 0;
3690}
3691
3692
3693/*
3694 * This function initializes all the necessary variables. It only returns
3695 * if everything is OK. If something fails, it exits.
3696 */
3697void init(int argc, char **argv) {
3698 int i;
3699 char *old_argv = *argv;
3700 char *tmp;
3701
3702 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003703 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003704 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
3705 sizeof(int)*8);
3706 exit(1);
3707 }
3708
3709 pid = getpid();
3710 progname = *argv;
3711 while ((tmp = strchr(progname, '/')) != NULL)
3712 progname = tmp + 1;
3713
3714 argc--; argv++;
3715 while (argc > 0) {
3716 char *flag;
3717
3718 if (**argv == '-') {
3719 flag = *argv+1;
3720
3721 /* 1 arg */
3722 if (*flag == 'v') {
3723 display_version();
3724 exit(0);
3725 }
3726 else if (*flag == 'd')
3727 mode |= MODE_DEBUG;
3728 else if (*flag == 'D')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003729 mode |= MODE_DAEMON | MODE_QUIET;
3730 else if (*flag == 'q')
3731 mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01003732#if STATTIME > 0
3733 else if (*flag == 's')
3734 mode |= MODE_STATS;
3735 else if (*flag == 'l')
3736 mode |= MODE_LOG;
3737#endif
3738 else { /* >=2 args */
3739 argv++; argc--;
3740 if (argc == 0)
3741 usage(old_argv);
3742
3743 switch (*flag) {
3744 case 'n' : cfg_maxconn = atol(*argv); break;
3745 case 'N' : cfg_maxpconn = atol(*argv); break;
3746 case 'f' : cfg_cfgfile = *argv; break;
3747 default: usage(old_argv);
3748 }
3749 }
3750 }
3751 else
3752 usage(old_argv);
3753 argv++; argc--;
3754 }
3755
3756 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
3757
3758 if (!cfg_cfgfile)
3759 usage(old_argv);
3760
3761 gethostname(hostname, MAX_HOSTNAME_LEN);
3762
3763 if (readcfgfile(cfg_cfgfile) < 0) {
3764 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
3765 exit(1);
3766 }
3767
3768 ReadEvent = (fd_set *)calloc(1,
3769 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003770 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003771 WriteEvent = (fd_set *)calloc(1,
3772 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003773 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003774 StaticReadEvent = (fd_set *)calloc(1,
3775 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003776 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003777 StaticWriteEvent = (fd_set *)calloc(1,
3778 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003779 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003780
3781 fdtab = (struct fdtab *)calloc(1,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003782 sizeof(struct fdtab) * (cfg_maxsock));
3783 for (i = 0; i < cfg_maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003784 fdtab[i].state = FD_STCLOSE;
3785 }
3786}
3787
3788/*
3789 * this function starts all the proxies. It returns 0 if OK, -1 if not.
3790 */
3791int start_proxies() {
3792 struct proxy *curproxy;
3793 int one = 1;
3794 int fd;
3795
3796 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
3797
3798 if (curproxy->state == PR_STDISABLED)
3799 continue;
3800
3801 if ((fd = curproxy->listen_fd =
3802 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
3803 Alert("cannot create listening socket for proxy %s. Aborting.\n",
3804 curproxy->id);
3805 return -1;
3806 }
3807
willy tarreau5cbea6f2005-12-17 12:48:26 +01003808 if (fd >= cfg_maxsock) {
3809 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
3810 curproxy->id);
3811 close(fd);
3812 return -1;
3813 }
3814
willy tarreau0f7af912005-12-17 12:21:26 +01003815 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
3816 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
3817 (char *) &one, sizeof(one)) == -1)) {
3818 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
3819 curproxy->id);
3820 close(fd);
3821 return -1;
3822 }
3823
3824 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
3825 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
3826 curproxy->id);
3827 }
3828
3829 if (bind(fd,
3830 (struct sockaddr *)&curproxy->listen_addr,
3831 sizeof(curproxy->listen_addr)) == -1) {
3832 Alert("cannot bind socket for proxy %s. Aborting.\n",
3833 curproxy->id);
3834 close(fd);
3835 return -1;
3836 }
3837
3838 if (listen(fd, curproxy->maxconn) == -1) {
3839 Alert("cannot listen to socket for proxy %s. Aborting.\n",
3840 curproxy->id);
3841 close(fd);
3842 return -1;
3843 }
3844
3845 /* the function for the accept() event */
3846 fdtab[fd].read = &event_accept;
3847 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003848 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01003849 curproxy->state = PR_STRUN;
3850 fdtab[fd].state = FD_STLISTEN;
3851 FD_SET(fd, StaticReadEvent);
3852 fd_insert(fd);
3853 listeners++;
3854// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3855 }
3856 return 0;
3857}
3858
3859
3860int main(int argc, char **argv) {
3861 init(argc, argv);
3862
3863 if (mode & MODE_DAEMON) {
3864 int ret;
3865
3866 ret = fork();
3867
3868 if (ret > 0)
3869 exit(0); /* parent must leave */
3870 else if (ret < 0) {
3871 Alert("[%s.main()] Cannot fork\n", argv[0]);
3872 exit(1); /* there has been an error */
3873 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003874 setpgid(1, 0);
3875 }
willy tarreau0f7af912005-12-17 12:21:26 +01003876
willy tarreau5cbea6f2005-12-17 12:48:26 +01003877 if (mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01003878 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003879 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01003880 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01003881 }
3882
3883 signal(SIGQUIT, dump);
3884 signal(SIGUSR1, sig_soft_stop);
3885
3886 /* on very high loads, a sigpipe sometimes happen just between the
3887 * getsockopt() which tells "it's OK to write", and the following write :-(
3888 */
willy tarreau3242e862005-12-17 12:27:53 +01003889#ifndef MSG_NOSIGNAL
3890 signal(SIGPIPE, SIG_IGN);
3891#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003892
3893 if (start_proxies() < 0)
3894 exit(1);
3895
3896 select_loop();
3897
3898 exit(0);
3899}