blob: db2779af9c552ee48d171637d77517cda183c418 [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 tarreaub719f002005-12-17 12:55:07 +010016 * 2002/03/22
17 * - released 1.1.3
18 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
19 * which could lead to loops.
willy tarreauef900ab2005-12-17 12:52:52 +010020 * 2002/03/21
21 * - released 1.1.2
22 * - fixed a bug in buffer management where we could have a loop
23 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
24 * => implemented an adjustable buffer limit.
25 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
26 * and running tasks are skipped.
27 * - added some debug lines for accept events.
28 * - send warnings for servers up/down.
willy tarreauefae1842005-12-17 12:51:03 +010029 * 2002/03/12
30 * - released 1.1.1
31 * - fixed a bug in total failure handling
32 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreau5cbea6f2005-12-17 12:48:26 +010033 * 2002/03/10
34 * - released 1.1.0
35 * - fixed a few timeout bugs
36 * - rearranged the task scheduler subsystem to improve performance,
37 * add new tasks, and make it easier to later port to librt ;
38 * - allow multiple accept() for one select() wake up ;
39 * - implemented internal load balancing with basic health-check ;
40 * - cookie insertion and header add/replace/delete, with better strings
41 * support.
42 * 2002/03/08
43 * - reworked buffer handling to fix a few rewrite bugs, and
44 * improve overall performance.
45 * - implement the "purge" option to delete server cookies in direct mode.
46 * 2002/03/07
47 * - fixed some error cases where the maxfd was not decreased.
48 * 2002/02/26
49 * - now supports transparent proxying, at least on linux 2.4.
50 * 2002/02/12
51 * - soft stop works again (fixed select timeout computation).
52 * - it seems that TCP proxies sometimes cannot timeout.
53 * - added a "quiet" mode.
54 * - enforce file descriptor limitation on socket() and accept().
55 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010056 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010057 * 2001/12/16 : release of version 1.0.0.
58 * 2001/12/16 : added syslog capability for each accepted connection.
59 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
60 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
61 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
62 * with or without cookies (use keyword http for this).
63 * 2001/09/01 : added client/server header replacing with regexps.
64 * eg:
65 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
66 * srvexp ^Server:\ .* Server:\ Apache
67 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
68 * 2000/11/28 : major rewrite
69 * 2000/11/26 : first write
70 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010071 * TODO:
72 * - handle properly intermediate incomplete server headers. Done ?
73 * - log proxies start/stop
74 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010075 *
76 */
77
78#include <stdio.h>
79#include <stdlib.h>
80#include <unistd.h>
81#include <string.h>
82#include <ctype.h>
83#include <sys/time.h>
84#include <sys/types.h>
85#include <sys/socket.h>
86#include <netinet/tcp.h>
87#include <netinet/in.h>
88#include <arpa/inet.h>
89#include <netdb.h>
90#include <fcntl.h>
91#include <errno.h>
92#include <signal.h>
93#include <stdarg.h>
94#include <sys/resource.h>
95#include <time.h>
96#include <regex.h>
97#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +010098#if defined(TRANSPARENT) && defined(NETFILTER)
99#include <linux/netfilter_ipv4.h>
100#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100101
willy tarreaub719f002005-12-17 12:55:07 +0100102#define HAPROXY_VERSION "1.1.3"
willy tarreauef900ab2005-12-17 12:52:52 +0100103#define HAPROXY_DATE "2002/03/22"
willy tarreau0f7af912005-12-17 12:21:26 +0100104
105/* this is for libc5 for example */
106#ifndef TCP_NODELAY
107#define TCP_NODELAY 1
108#endif
109
110#ifndef SHUT_RD
111#define SHUT_RD 0
112#endif
113
114#ifndef SHUT_WR
115#define SHUT_WR 1
116#endif
117
118#define BUFSIZE 4096
119
120// reserved buffer space for header rewriting
121#define MAXREWRITE 256
122
willy tarreau5cbea6f2005-12-17 12:48:26 +0100123// max # args on a configuration line
124#define MAX_LINE_ARGS 10
125
willy tarreau0f7af912005-12-17 12:21:26 +0100126// max # of regexps per proxy
127#define MAX_REGEXP 10
128
129// max # of matches per regexp
130#define MAX_MATCH 10
131
willy tarreau5cbea6f2005-12-17 12:48:26 +0100132/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100133#define COOKIENAME_LEN 16
134#define SERVERID_LEN 16
135#define CONN_RETRIES 3
136
willy tarreau5cbea6f2005-12-17 12:48:26 +0100137/* FIXME: this should be user-configurable */
138#define CHK_CONNTIME 2000
139#define CHK_INTERVAL 2000
140#define FALLTIME 3
141#define RISETIME 2
142
willy tarreau0f7af912005-12-17 12:21:26 +0100143/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
144#define INTBITS 5
145
146/* show stats this every millisecond, 0 to disable */
147#ifndef STATTIME
148#define STATTIME 2000
149#endif
150
willy tarreau5cbea6f2005-12-17 12:48:26 +0100151/* this reduces the number of calls to select() by choosing appropriate
152 * sheduler precision in milliseconds. It should be near the minimum
153 * time that is needed by select() to collect all events. All timeouts
154 * are rounded up by adding this value prior to pass it to select().
155 */
156#define SCHEDULER_RESOLUTION 9
157
willy tarreau0f7af912005-12-17 12:21:26 +0100158#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
159#define SETNOW(a) (*a=now)
160
willy tarreau9da061b2005-12-17 12:29:56 +0100161/****** string-specific macros and functions ******/
162/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
163#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
164
165/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
166#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
167
168
169#ifndef HAVE_STRLCPY
170/*
171 * copies at most <size-1> chars from <src> to <dst>. Last char is always
172 * set to 0, unless <size> is 0. The number of chars copied is returned
173 * (excluding the terminating zero).
174 * This code has been optimized for size and speed : on x86, it's 45 bytes
175 * long, uses only registers, and consumes only 4 cycles per char.
176 */
177int strlcpy(char *dst, const char *src, int size) {
178 char *orig = dst;
179 if (size) {
180 while (--size && (*dst = *src)) {
181 src++; dst++;
182 }
183 *dst = 0;
184 }
185 return dst - orig;
186}
187#endif
188
189
willy tarreau0f7af912005-12-17 12:21:26 +0100190#define MEM_OPTIM
191#ifdef MEM_OPTIM
192/*
193 * Returns a pointer to type <type> taken from the
194 * pool <pool_type> or dynamically allocated. In the
195 * first case, <pool_type> is updated to point to the
196 * next element in the list.
197 */
198#define pool_alloc(type) ({ \
199 void *p; \
200 if ((p = pool_##type) == NULL) \
201 p = malloc(sizeof_##type); \
202 else { \
203 pool_##type = *(void **)pool_##type; \
204 } \
205 p; \
206})
207
208/*
209 * Puts a memory area back to the corresponding pool.
210 * Items are chained directly through a pointer that
211 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100212 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100213 * that each memory area is at least as big as one
214 * pointer.
215 */
216#define pool_free(type, ptr) ({ \
217 *(void **)ptr = (void *)pool_##type; \
218 pool_##type = (void *)ptr; \
219})
220
221#else
222#define pool_alloc(type) (calloc(1,sizeof_##type));
223#define pool_free(type, ptr) (free(ptr));
224#endif /* MEM_OPTIM */
225
willy tarreau5cbea6f2005-12-17 12:48:26 +0100226#define sizeof_task sizeof(struct task)
227#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100228#define sizeof_buffer sizeof(struct buffer)
229#define sizeof_fdtab sizeof(struct fdtab)
230#define sizeof_str256 256
231
232
willy tarreau5cbea6f2005-12-17 12:48:26 +0100233/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100234#define FD_STCLOSE 0
235#define FD_STLISTEN 1
236#define FD_STCONN 2
237#define FD_STREADY 3
238#define FD_STERROR 4
239
willy tarreau5cbea6f2005-12-17 12:48:26 +0100240/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100241#define TASK_IDLE 0
242#define TASK_RUNNING 1
243
willy tarreau5cbea6f2005-12-17 12:48:26 +0100244/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100245#define PR_STNEW 0
246#define PR_STIDLE 1
247#define PR_STRUN 2
248#define PR_STDISABLED 3
249
willy tarreau5cbea6f2005-12-17 12:48:26 +0100250/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100251#define PR_MODE_TCP 0
252#define PR_MODE_HTTP 1
253#define PR_MODE_HEALTH 2
254
willy tarreau5cbea6f2005-12-17 12:48:26 +0100255/* bits for proxy->options */
256#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
257#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
258#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
259#define PR_O_COOK_IND 8 /* keep only indirect cookies */
260#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
261#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
262#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
263#define PR_O_BALANCE (PR_O_BALANCE_RR)
264
265/* various task flags */
266#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
267
268/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100269#define CL_STHEADERS 0
270#define CL_STDATA 1
271#define CL_STSHUTR 2
272#define CL_STSHUTW 3
273#define CL_STCLOSE 4
274
willy tarreau5cbea6f2005-12-17 12:48:26 +0100275/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100276#define SV_STIDLE 0
277#define SV_STCONN 1
278#define SV_STHEADERS 2
279#define SV_STDATA 3
280#define SV_STSHUTR 4
281#define SV_STSHUTW 5
282#define SV_STCLOSE 6
283
284/* result of an I/O event */
285#define RES_SILENT 0 /* didn't happen */
286#define RES_DATA 1 /* data were sent or received */
287#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
288#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
289
willy tarreau5cbea6f2005-12-17 12:48:26 +0100290/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100291#define MODE_DEBUG 1
292#define MODE_STATS 2
293#define MODE_LOG 4
294#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100295#define MODE_QUIET 16
296
297/* server flags */
298#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100299
300/*********************************************************************/
301
302#define LIST_HEAD(a) ((void *)(&(a)))
303
304/*********************************************************************/
305
306struct hdr_exp {
307 regex_t *preg; /* expression to look for */
308 char *replace; /* expression to set instead */
309};
310
311struct buffer {
312 unsigned int l; /* data length */
313 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100314 char *rlim; /* read limit, used for header rewriting */
willy tarreau0f7af912005-12-17 12:21:26 +0100315 char data[BUFSIZE];
316};
317
318struct server {
319 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100320 int state; /* server state (SRV_*) */
321 int cklen; /* the len of the cookie, to speed up checks */
322 char *cookie; /* the id set in the cookie */
323 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100324 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100325 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
326 int result; /* 0 = connect OK, -1 = connect KO */
327 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100328};
329
willy tarreau5cbea6f2005-12-17 12:48:26 +0100330/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100331struct task {
332 struct task *next, *prev; /* chaining ... */
333 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100334 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100335 int state; /* task state : IDLE or RUNNING */
336 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100337 int (*process)(struct task *t); /* the function which processes the task */
338 void *context; /* the task's context */
339};
340
341/* WARNING: if new fields are added, they must be initialized in event_accept() */
342struct session {
343 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100344 /* application specific below */
345 struct timeval crexpire; /* expiration date for a client read */
346 struct timeval cwexpire; /* expiration date for a client write */
347 struct timeval srexpire; /* expiration date for a server read */
348 struct timeval swexpire; /* expiration date for a server write */
349 struct timeval cnexpire; /* expiration date for a connect */
350 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
351 struct proxy *proxy; /* the proxy this socket belongs to */
352 int cli_fd; /* the client side fd */
353 int srv_fd; /* the server side fd */
354 int cli_state; /* state of the client side */
355 int srv_state; /* state of the server side */
356 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100357 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100358 struct buffer *req; /* request buffer */
359 struct buffer *rep; /* response buffer */
360 struct sockaddr_in cli_addr; /* the client address */
361 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100363};
364
365struct proxy {
366 int listen_fd; /* the listen socket */
367 int state; /* proxy state */
368 struct sockaddr_in listen_addr; /* the address we listen to */
369 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100370 struct server *srv, *cursrv; /* known servers, current server */
371 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100372 char *cookie_name; /* name of the cookie to look for */
373 int clitimeout; /* client I/O timeout (in milliseconds) */
374 int srvtimeout; /* server I/O timeout (in milliseconds) */
375 int contimeout; /* connect timeout (in milliseconds) */
376 char *id; /* proxy id */
377 int nbconn; /* # of active sessions */
378 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100379 int conn_retries; /* maximum number of connect retries */
380 int options; /* PR_O_REDISP, PR_O_TRANSP */
381 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100382 struct proxy *next;
383 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
384 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
385 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100386 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
387 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
388 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
389 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100390 int grace; /* grace time after stop request */
391};
392
393/* info about one given fd */
394struct fdtab {
395 int (*read)(int fd); /* read function */
396 int (*write)(int fd); /* write function */
397 struct task *owner; /* the session (or proxy) associated with this fd */
398 int state; /* the state of this fd */
399};
400
401/*********************************************************************/
402
403int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
404int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
405int cfg_maxsock = 0; /* max # of sockets */
406char *cfg_cfgfile = NULL; /* configuration file */
407char *progname = NULL; /* program name */
408int pid; /* current process id */
409/*********************************************************************/
410
411fd_set *ReadEvent,
412 *WriteEvent,
413 *StaticReadEvent,
414 *StaticWriteEvent;
415
416void **pool_session = NULL,
417 **pool_buffer = NULL,
418 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100419 **pool_str256 = NULL,
420 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100421
422struct proxy *proxy = NULL; /* list of all existing proxies */
423struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424struct task *rq = NULL; /* global run queue */
425struct task wait_queue = { /* global wait queue */
426 prev:LIST_HEAD(wait_queue),
427 next:LIST_HEAD(wait_queue)
428};
willy tarreau0f7af912005-12-17 12:21:26 +0100429
430static int mode = 0; /* MODE_DEBUG, ... */
431static int totalconn = 0; /* total # of terminated sessions */
432static int actconn = 0; /* # of active sessions */
433static int maxfd = 0; /* # of the highest fd + 1 */
434static int listeners = 0; /* # of listeners */
435static int stopping = 0; /* non zero means stopping in progress */
436static struct timeval now = {0,0}; /* the current date at any moment */
437
438static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
439static char trash[BUFSIZE];
440
441/*
442 * Syslog facilities and levels
443 */
444
445#define MAX_SYSLOG_LEN 1024
446#define NB_LOG_FACILITIES 24
447const char *log_facilities[NB_LOG_FACILITIES] = {
448 "kern", "user", "mail", "daemon",
449 "auth", "syslog", "lpr", "news",
450 "uucp", "cron", "auth2", "ftp",
451 "ntp", "audit", "alert", "cron2",
452 "local0", "local1", "local2", "local3",
453 "local4", "local5", "local6", "local7"
454};
455
456
457#define NB_LOG_LEVELS 8
458const char *log_levels[NB_LOG_LEVELS] = {
459 "emerg", "alert", "crit", "err",
460 "warning", "notice", "info", "debug"
461};
462
463#define SYSLOG_PORT 514
464
465const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
466 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
467#define MAX_HOSTNAME_LEN 32
468static char hostname[MAX_HOSTNAME_LEN] = "";
469
470/*********************************************************************/
471/* statistics ******************************************************/
472/*********************************************************************/
473
474static int stats_tsk_lsrch, stats_tsk_rsrch,
475 stats_tsk_good, stats_tsk_right, stats_tsk_left,
476 stats_tsk_new, stats_tsk_nsrch;
477
478
479/*********************************************************************/
480/* function prototypes *********************************************/
481/*********************************************************************/
482
483int event_accept(int fd);
484int event_cli_read(int fd);
485int event_cli_write(int fd);
486int event_srv_read(int fd);
487int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100488int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100489
490/*********************************************************************/
491/* general purpose functions ***************************************/
492/*********************************************************************/
493
494void display_version() {
495 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100496 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100497}
498
499/*
500 * This function prints the command line usage and exits
501 */
502void usage(char *name) {
503 display_version();
504 fprintf(stderr,
505 "Usage : %s -f <cfgfile> [ -vd"
506#if STATTIME > 0
507 "sl"
508#endif
509 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
510 " -v displays version\n"
511 " -d enters debug mode\n"
512#if STATTIME > 0
513 " -s enables statistics output\n"
514 " -l enables long statistics format\n"
515#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100516 " -D goes daemon ; implies -q\n"
517 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100518 " -n sets the maximum total # of connections (%d)\n"
519 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
520 name, cfg_maxconn, cfg_maxpconn);
521 exit(1);
522}
523
524
525/*
526 * Displays the message on stderr with the date and pid.
527 */
528void Alert(char *fmt, ...) {
529 va_list argp;
530 struct timeval tv;
531 struct tm *tm;
532
willy tarreau5cbea6f2005-12-17 12:48:26 +0100533 if (!(mode & MODE_QUIET)) {
534 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100535
willy tarreau5cbea6f2005-12-17 12:48:26 +0100536 gettimeofday(&tv, NULL);
537 tm=localtime(&tv.tv_sec);
538 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
539 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
540 vfprintf(stderr, fmt, argp);
541 fflush(stderr);
542 va_end(argp);
543 }
willy tarreau0f7af912005-12-17 12:21:26 +0100544}
545
546
547/*
548 * Displays the message on stderr with the date and pid.
549 */
550void Warning(char *fmt, ...) {
551 va_list argp;
552 struct timeval tv;
553 struct tm *tm;
554
willy tarreau5cbea6f2005-12-17 12:48:26 +0100555 if (!(mode & MODE_QUIET)) {
556 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100557
willy tarreau5cbea6f2005-12-17 12:48:26 +0100558 gettimeofday(&tv, NULL);
559 tm=localtime(&tv.tv_sec);
560 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
561 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
562 vfprintf(stderr, fmt, argp);
563 fflush(stderr);
564 va_end(argp);
565 }
566}
567
568/*
569 * Displays the message on <out> only if quiet mode is not set.
570 */
571void qfprintf(FILE *out, char *fmt, ...) {
572 va_list argp;
573
574 if (!(mode & MODE_QUIET)) {
575 va_start(argp, fmt);
576 vfprintf(out, fmt, argp);
577 fflush(out);
578 va_end(argp);
579 }
willy tarreau0f7af912005-12-17 12:21:26 +0100580}
581
582
583/*
584 * converts <str> to a struct sockaddr_in* which is locally allocated.
585 * The format is "addr:port", where "addr" can be empty or "*" to indicate
586 * INADDR_ANY.
587 */
588struct sockaddr_in *str2sa(char *str) {
589 static struct sockaddr_in sa;
590 char *c;
591 int port;
592
593 bzero(&sa, sizeof(sa));
594 str=strdup(str);
595
596 if ((c=strrchr(str,':')) != NULL) {
597 *c++=0;
598 port=atol(c);
599 }
600 else
601 port=0;
602
603 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
604 sa.sin_addr.s_addr = INADDR_ANY;
605 }
606 else if (
607#ifndef SOLARIS
608 !inet_aton(str, &sa.sin_addr)
609#else
610 !inet_pton(AF_INET, str, &sa.sin_addr)
611#endif
612 ) {
613 struct hostent *he;
614
615 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100616 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100617 }
618 else
619 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
620 }
621 sa.sin_port=htons(port);
622 sa.sin_family=AF_INET;
623
624 free(str);
625 return &sa;
626}
627
628/*
629 * This function tries to send a syslog message to the syslog server at
630 * address <sa>. It doesn't care about errors nor does it report them.
631 * WARNING! no check is made on the prog+hostname+date length, so the
632 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
633 * the message will be truncated to fit the maximum length.
634 */
635void send_syslog(struct sockaddr_in *sa,
636 int facility, int level, char *message)
637{
638
639 static int logfd = -1; /* syslog UDP socket */
640 struct timeval tv;
641 struct tm *tm;
642 static char logmsg[MAX_SYSLOG_LEN];
643 char *p;
644
645 if (logfd < 0) {
646 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
647 return;
648 }
649
650 if (facility < 0 || level < 0
651 || sa == NULL || progname == NULL || message == NULL)
652 return;
653
654 gettimeofday(&tv, NULL);
655 tm = localtime(&tv.tv_sec);
656
657 p = logmsg;
658 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
659 // facility * 8 + level,
660 // monthname[tm->tm_mon],
661 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
662 // hostname, progname, pid);
663 /* 20011216/WT : other progs don't set the hostname, and syslogd
664 * systematically repeats it which is contrary to RFC3164.
665 */
666 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
667 facility * 8 + level,
668 monthname[tm->tm_mon],
669 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
670 progname, pid);
671
672 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
673 int len = strlen(message);
674 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
675 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
676 memcpy(p, message, len);
677 p += len;
678 }
willy tarreau3242e862005-12-17 12:27:53 +0100679#ifndef MSG_NOSIGNAL
680 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
681 (struct sockaddr *)sa, sizeof(*sa));
682#else
willy tarreau0f7af912005-12-17 12:21:26 +0100683 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
684 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100685#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100686}
687
688
689/* sets <tv> to the current time */
690static inline struct timeval *tv_now(struct timeval *tv) {
691 if (tv)
692 gettimeofday(tv, NULL);
693 return tv;
694}
695
696/*
697 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
698 */
699static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
700 if (!tv || !from)
701 return NULL;
702 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
703 tv->tv_sec = from->tv_sec + (ms/1000);
704 while (tv->tv_usec >= 1000000) {
705 tv->tv_usec -= 1000000;
706 tv->tv_sec++;
707 }
708 return tv;
709}
710
711/*
712 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
713 */
714static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
715 if (tv1->tv_sec > tv2->tv_sec)
716 return 1;
717 else if (tv1->tv_sec < tv2->tv_sec)
718 return -1;
719 else if (tv1->tv_usec > tv2->tv_usec)
720 return 1;
721 else if (tv1->tv_usec < tv2->tv_usec)
722 return -1;
723 else
724 return 0;
725}
726
727/*
728 * returns the absolute difference, in ms, between tv1 and tv2
729 */
730unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
731 int cmp;
732 unsigned long ret;
733
734
willy tarreauef900ab2005-12-17 12:52:52 +0100735 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100736 if (!cmp)
737 return 0; /* same dates, null diff */
738 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100739 struct timeval *tmp = tv1;
740 tv1 = tv2;
741 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100742 }
willy tarreauef900ab2005-12-17 12:52:52 +0100743 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100744 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100745 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100746 else
willy tarreauef900ab2005-12-17 12:52:52 +0100747 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100748 return (unsigned long) ret;
749}
750
751/*
752 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
753 */
754static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100755 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100756 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100757 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100758 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100759 return -1;
760 else
761 return 0;
762 }
763 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100764 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100765 return 1;
766 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100767 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100768 return -1;
769 else
770 return 0;
771}
772
773/*
774 * returns the remaining time between tv1=now and event=tv2
775 * if tv2 is passed, 0 is returned.
776 */
777static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
778 unsigned long ret;
779
willy tarreau0f7af912005-12-17 12:21:26 +0100780 if (tv_cmp_ms(tv1, tv2) >= 0)
781 return 0; /* event elapsed */
782
willy tarreauef900ab2005-12-17 12:52:52 +0100783 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100784 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100785 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100786 else
willy tarreauef900ab2005-12-17 12:52:52 +0100787 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100788 return (unsigned long) ret;
789}
790
791
792/*
793 * zeroes a struct timeval
794 */
795
796static inline struct timeval *tv_eternity(struct timeval *tv) {
797 tv->tv_sec = tv->tv_usec = 0;
798 return tv;
799}
800
801/*
802 * returns 1 if tv is null, else 0
803 */
804static inline int tv_iseternity(struct timeval *tv) {
805 if (tv->tv_sec == 0 && tv->tv_usec == 0)
806 return 1;
807 else
808 return 0;
809}
810
811/*
812 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
813 * considering that 0 is the eternity.
814 */
815static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
816 if (tv_iseternity(tv1))
817 if (tv_iseternity(tv2))
818 return 0; /* same */
819 else
820 return 1; /* tv1 later than tv2 */
821 else if (tv_iseternity(tv2))
822 return -1; /* tv2 later than tv1 */
823
824 if (tv1->tv_sec > tv2->tv_sec)
825 return 1;
826 else if (tv1->tv_sec < tv2->tv_sec)
827 return -1;
828 else if (tv1->tv_usec > tv2->tv_usec)
829 return 1;
830 else if (tv1->tv_usec < tv2->tv_usec)
831 return -1;
832 else
833 return 0;
834}
835
836/*
837 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
838 * considering that 0 is the eternity.
839 */
840static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
841 if (tv_iseternity(tv1))
842 if (tv_iseternity(tv2))
843 return 0; /* same */
844 else
845 return 1; /* tv1 later than tv2 */
846 else if (tv_iseternity(tv2))
847 return -1; /* tv2 later than tv1 */
848
willy tarreauefae1842005-12-17 12:51:03 +0100849 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100850 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100851 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100852 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100853 return -1;
854 else
855 return 0;
856 }
857 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100858 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100859 return 1;
860 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100861 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100862 return -1;
863 else
864 return 0;
865}
866
867/*
868 * returns the first event between tv1 and tv2 into tvmin.
869 * a zero tv is ignored. tvmin is returned.
870 */
871static inline struct timeval *tv_min(struct timeval *tvmin,
872 struct timeval *tv1, struct timeval *tv2) {
873
874 if (tv_cmp2(tv1, tv2) <= 0)
875 *tvmin = *tv1;
876 else
877 *tvmin = *tv2;
878
879 return tvmin;
880}
881
882
883
884/***********************************************************/
885/* fd management ***************************************/
886/***********************************************************/
887
888
889
willy tarreau5cbea6f2005-12-17 12:48:26 +0100890/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
891 * The file descriptor is also closed.
892 */
willy tarreau0f7af912005-12-17 12:21:26 +0100893static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100894 FD_CLR(fd, StaticReadEvent);
895 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100896 close(fd);
897 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100898
899 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
900 maxfd--;
901}
902
903/* recomputes the maxfd limit from the fd */
904static inline void fd_insert(int fd) {
905 if (fd+1 > maxfd)
906 maxfd = fd+1;
907}
908
909/*************************************************************/
910/* task management ***************************************/
911/*************************************************************/
912
willy tarreau5cbea6f2005-12-17 12:48:26 +0100913/* puts the task <t> in run queue <q>, and returns <t> */
914static inline struct task *task_wakeup(struct task **q, struct task *t) {
915 if (t->state == TASK_RUNNING)
916 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100917 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100918 t->rqnext = *q;
919 t->state = TASK_RUNNING;
920 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100921 }
922}
923
willy tarreau5cbea6f2005-12-17 12:48:26 +0100924/* removes the task <t> from the queue <q>
925 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100926 * set the run queue to point to the next one, and return it
927 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100928static inline struct task *task_sleep(struct task **q, struct task *t) {
929 if (t->state == TASK_RUNNING) {
930 *q = t->rqnext;
931 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100932 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100934}
935
936/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100937 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100938 * from the run queue. A pointer to the task itself is returned.
939 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100940static inline struct task *task_delete(struct task *t) {
941 t->prev->next = t->next;
942 t->next->prev = t->prev;
943 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100944}
945
946/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100947 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100948 */
949static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100950 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100951}
952
willy tarreau5cbea6f2005-12-17 12:48:26 +0100953/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100954 * may be only moved or left where it was, depending on its timing requirements.
955 * <task> is returned.
956 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100957struct task *task_queue(struct task *task) {
958 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100959 struct task *start_from;
960
961 /* first, test if the task was already in a list */
962 if (task->prev == NULL) {
963 // start_from = list;
964 start_from = list->prev;
965 stats_tsk_new++;
966
967 /* insert the unlinked <task> into the list, searching back from the last entry */
968 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
969 start_from = start_from->prev;
970 stats_tsk_nsrch++;
971 }
972
973 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
974 // start_from = start_from->next;
975 // stats_tsk_nsrch++;
976 // }
977 }
978 else if (task->prev == list ||
979 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
980 start_from = task->next;
981 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
982 stats_tsk_good++;
983 return task; /* it's already in the right place */
984 }
985
986 stats_tsk_right++;
987 /* insert the unlinked <task> into the list, searching after position <start_from> */
988 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
989 start_from = start_from->next;
990 stats_tsk_rsrch++;
991 }
992 /* we need to unlink it now */
993 task_delete(task);
994 }
995 else { /* walk left. */
996 stats_tsk_left++;
997#ifdef LEFT_TO_TOP /* not very good */
998 start_from = list;
999 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1000 start_from = start_from->next;
1001 stats_tsk_lsrch++;
1002 }
1003#else
1004 start_from = task->prev->prev; /* valid because of the previous test above */
1005 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1006 start_from = start_from->prev;
1007 stats_tsk_lsrch++;
1008 }
1009#endif
1010 /* we need to unlink it now */
1011 task_delete(task);
1012 }
1013 task->prev = start_from;
1014 task->next = start_from->next;
1015 task->next->prev = task;
1016 start_from->next = task;
1017 return task;
1018}
1019
1020
1021/*********************************************************************/
1022/* more specific functions ***************************************/
1023/*********************************************************************/
1024
1025/* some prototypes */
1026static int maintain_proxies(void);
1027
willy tarreau5cbea6f2005-12-17 12:48:26 +01001028/* this either returns the sockname or the original destination address. Code
1029 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1030 */
1031static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
1032#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
1033 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1034#else
1035#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
1036 return getsockname(fd, (struct sockaddr *)sa, salen);
1037#else
1038 return -1;
1039#endif
1040#endif
1041}
1042
1043/*
1044 * frees the context associated to a session. It must have been removed first.
1045 */
1046static inline void session_free(struct session *s) {
1047 if (s->req)
1048 pool_free(buffer, s->req);
1049 if (s->rep)
1050 pool_free(buffer, s->rep);
1051 pool_free(session, s);
1052}
1053
willy tarreau0f7af912005-12-17 12:21:26 +01001054
1055/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001056 * This function initiates a connection to the current server (s->srv) if (s->direct)
1057 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001058 * it's OK, -1 if it's impossible.
1059 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001060int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001061 int one = 1;
1062 int fd;
1063
1064 // fprintf(stderr,"connect_server : s=%p\n",s);
1065
willy tarreau5cbea6f2005-12-17 12:48:26 +01001066 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1067 s->srv_addr = s->srv->addr;
1068 }
1069 else if (s->proxy->options & PR_O_BALANCE) {
1070 if (s->proxy->options & PR_O_BALANCE_RR) {
1071 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001072 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001073 if (s->proxy->cursrv == NULL)
1074 s->proxy->cursrv = s->proxy->srv;
1075 if (s->proxy->cursrv->state & SRV_RUNNING)
1076 break;
1077 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001078 retry--;
1079 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001080
1081 if (retry == 0) /* no server left */
1082 return -1;
1083
1084 s->srv = s->proxy->cursrv;
1085 s->srv_addr = s->srv->addr;
1086 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001087 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001088 else /* unknown balancing algorithm */
1089 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001090 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001091 else if (*(int *)&s->proxy->dispatch_addr) {
1092 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001093 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001094 }
1095 else if (s->proxy->options & PR_O_TRANSP) {
1096 /* in transparent mode, use the original dest addr if no dispatch specified */
1097 int salen = sizeof(struct sockaddr_in);
1098 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1099 qfprintf(stderr, "Cannot get original server address.\n");
1100 return -1;
1101 }
1102 }
willy tarreau0f7af912005-12-17 12:21:26 +01001103
1104 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001105 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001106 return -1;
1107 }
1108
willy tarreau5cbea6f2005-12-17 12:48:26 +01001109 if (fd >= cfg_maxsock) {
1110 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1111 close(fd);
1112 return -1;
1113 }
1114
willy tarreau0f7af912005-12-17 12:21:26 +01001115 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1116 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001117 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001118 close(fd);
1119 return -1;
1120 }
1121
1122 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1123 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001124 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001125 close(fd);
1126 return -1;
1127 }
1128 else if (errno != EALREADY && errno != EISCONN) {
1129 close(fd);
1130 return -1;
1131 }
1132 }
1133
willy tarreau5cbea6f2005-12-17 12:48:26 +01001134 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001135 fdtab[fd].read = &event_srv_read;
1136 fdtab[fd].write = &event_srv_write;
1137 fdtab[fd].state = FD_STCONN; /* connection in progress */
1138
1139 FD_SET(fd, StaticWriteEvent); /* for connect status */
1140
1141 fd_insert(fd);
1142
1143 if (s->proxy->contimeout)
1144 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1145 else
1146 tv_eternity(&s->cnexpire);
1147 return 0;
1148}
1149
1150/*
1151 * this function is called on a read event from a client socket.
1152 * It returns 0.
1153 */
1154int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001155 struct task *t = fdtab[fd].owner;
1156 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001157 struct buffer *b = s->req;
1158 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001159
1160 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1161
willy tarreau0f7af912005-12-17 12:21:26 +01001162 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001163 while (1) {
1164 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1165 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001166 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001167 }
1168 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001169 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001170 }
1171 else {
1172 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001173 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1174 * since it means that the rewrite protection has been removed. This
1175 * implies that the if statement can be removed.
1176 */
1177 if (max > b->rlim - b->data)
1178 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001179 }
1180
1181 if (max == 0) { /* not anymore room to store data */
1182 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001183 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001184 }
1185
willy tarreau3242e862005-12-17 12:27:53 +01001186#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001187 {
1188 int skerr, lskerr;
1189
1190 lskerr = sizeof(skerr);
1191 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1192 if (skerr)
1193 ret = -1;
1194 else
1195 ret = recv(fd, b->r, max, 0);
1196 }
willy tarreau3242e862005-12-17 12:27:53 +01001197#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001198 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001199#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001200 if (ret > 0) {
1201 b->r += ret;
1202 b->l += ret;
1203 s->res_cr = RES_DATA;
1204
1205 if (b->r == b->data + BUFSIZE) {
1206 b->r = b->data; /* wrap around the buffer */
1207 }
1208 /* we hope to read more data or to get a close on next round */
1209 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001210 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001211 else if (ret == 0) {
1212 s->res_cr = RES_NULL;
1213 break;
1214 }
1215 else if (errno == EAGAIN) {/* ignore EAGAIN */
1216 break;
1217 }
1218 else {
1219 s->res_cr = RES_ERROR;
1220 fdtab[fd].state = FD_STERROR;
1221 break;
1222 }
1223 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001224 }
1225 else {
1226 s->res_cr = RES_ERROR;
1227 fdtab[fd].state = FD_STERROR;
1228 }
1229
willy tarreau5cbea6f2005-12-17 12:48:26 +01001230 if (s->res_cr != RES_SILENT) {
1231 if (s->proxy->clitimeout)
1232 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1233 else
1234 tv_eternity(&s->crexpire);
1235
1236 task_wakeup(&rq, t);
1237 }
willy tarreau0f7af912005-12-17 12:21:26 +01001238
willy tarreau0f7af912005-12-17 12:21:26 +01001239 return 0;
1240}
1241
1242
1243/*
1244 * this function is called on a read event from a server socket.
1245 * It returns 0.
1246 */
1247int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001248 struct task *t = fdtab[fd].owner;
1249 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001250 struct buffer *b = s->rep;
1251 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001252
1253 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1254
willy tarreau0f7af912005-12-17 12:21:26 +01001255 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001256 while (1) {
1257 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1258 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001259 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001260 }
1261 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001262 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001263 }
1264 else {
1265 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001266 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1267 * since it means that the rewrite protection has been removed. This
1268 * implies that the if statement can be removed.
1269 */
1270 if (max > b->rlim - b->data)
1271 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001272 }
1273
1274 if (max == 0) { /* not anymore room to store data */
1275 FD_CLR(fd, StaticReadEvent);
1276 break;
1277 }
1278
willy tarreau3242e862005-12-17 12:27:53 +01001279#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001280 {
1281 int skerr, lskerr;
1282
1283 lskerr = sizeof(skerr);
1284 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1285 if (skerr)
1286 ret = -1;
1287 else
1288 ret = recv(fd, b->r, max, 0);
1289 }
willy tarreau3242e862005-12-17 12:27:53 +01001290#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001291 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001292#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001293 if (ret > 0) {
1294 b->r += ret;
1295 b->l += ret;
1296 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001297
willy tarreau5cbea6f2005-12-17 12:48:26 +01001298 if (b->r == b->data + BUFSIZE) {
1299 b->r = b->data; /* wrap around the buffer */
1300 }
1301 /* we hope to read more data or to get a close on next round */
1302 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001303 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001304 else if (ret == 0) {
1305 s->res_sr = RES_NULL;
1306 break;
1307 }
1308 else if (errno == EAGAIN) {/* ignore EAGAIN */
1309 break;
1310 }
1311 else {
1312 s->res_sr = RES_ERROR;
1313 fdtab[fd].state = FD_STERROR;
1314 break;
1315 }
1316 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001317 }
1318 else {
1319 s->res_sr = RES_ERROR;
1320 fdtab[fd].state = FD_STERROR;
1321 }
1322
willy tarreau5cbea6f2005-12-17 12:48:26 +01001323 if (s->res_sr != RES_SILENT) {
1324 if (s->proxy->srvtimeout)
1325 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1326 else
1327 tv_eternity(&s->srexpire);
1328
1329 task_wakeup(&rq, t);
1330 }
willy tarreau0f7af912005-12-17 12:21:26 +01001331
willy tarreau0f7af912005-12-17 12:21:26 +01001332 return 0;
1333}
1334
1335/*
1336 * this function is called on a write event from a client socket.
1337 * It returns 0.
1338 */
1339int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001340 struct task *t = fdtab[fd].owner;
1341 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001342 struct buffer *b = s->rep;
1343 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001344
1345 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1346
1347 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001348 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001349 // max = BUFSIZE; BUG !!!!
1350 max = 0;
1351 }
1352 else if (b->r > b->w) {
1353 max = b->r - b->w;
1354 }
1355 else
1356 max = b->data + BUFSIZE - b->w;
1357
willy tarreau0f7af912005-12-17 12:21:26 +01001358 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001359#ifndef MSG_NOSIGNAL
1360 int skerr, lskerr;
1361#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001362
1363 if (max == 0) {
1364 s->res_cw = RES_NULL;
1365 task_wakeup(&rq, t);
1366 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001367 }
1368
willy tarreau3242e862005-12-17 12:27:53 +01001369#ifndef MSG_NOSIGNAL
1370 lskerr=sizeof(skerr);
1371 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1372 if (skerr)
1373 ret = -1;
1374 else
1375 ret = send(fd, b->w, max, MSG_DONTWAIT);
1376#else
willy tarreau0f7af912005-12-17 12:21:26 +01001377 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001378#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001379
1380 if (ret > 0) {
1381 b->l -= ret;
1382 b->w += ret;
1383
1384 s->res_cw = RES_DATA;
1385
1386 if (b->w == b->data + BUFSIZE) {
1387 b->w = b->data; /* wrap around the buffer */
1388 }
1389 }
1390 else if (ret == 0) {
1391 /* nothing written, just make as if we were never called */
1392// s->res_cw = RES_NULL;
1393 return 0;
1394 }
1395 else if (errno == EAGAIN) /* ignore EAGAIN */
1396 return 0;
1397 else {
1398 s->res_cw = RES_ERROR;
1399 fdtab[fd].state = FD_STERROR;
1400 }
1401 }
1402 else {
1403 s->res_cw = RES_ERROR;
1404 fdtab[fd].state = FD_STERROR;
1405 }
1406
1407 if (s->proxy->clitimeout)
1408 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1409 else
1410 tv_eternity(&s->cwexpire);
1411
willy tarreau5cbea6f2005-12-17 12:48:26 +01001412 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001413 return 0;
1414}
1415
1416
1417/*
1418 * this function is called on a write event from a server socket.
1419 * It returns 0.
1420 */
1421int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001422 struct task *t = fdtab[fd].owner;
1423 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001424 struct buffer *b = s->req;
1425 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001426
1427 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1428
1429 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001430 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001431 // max = BUFSIZE; BUG !!!!
1432 max = 0;
1433 }
1434 else if (b->r > b->w) {
1435 max = b->r - b->w;
1436 }
1437 else
1438 max = b->data + BUFSIZE - b->w;
1439
willy tarreau0f7af912005-12-17 12:21:26 +01001440 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001441#ifndef MSG_NOSIGNAL
1442 int skerr, lskerr;
1443#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001444 if (max == 0) {
1445 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001446 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001447 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001448 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001449 return 0;
1450 }
1451
willy tarreauef900ab2005-12-17 12:52:52 +01001452
willy tarreau3242e862005-12-17 12:27:53 +01001453#ifndef MSG_NOSIGNAL
1454 lskerr=sizeof(skerr);
1455 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1456 if (skerr)
1457 ret = -1;
1458 else
1459 ret = send(fd, b->w, max, MSG_DONTWAIT);
1460#else
willy tarreau0f7af912005-12-17 12:21:26 +01001461 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001462#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001463 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001464 if (ret > 0) {
1465 b->l -= ret;
1466 b->w += ret;
1467
1468 s->res_sw = RES_DATA;
1469
1470 if (b->w == b->data + BUFSIZE) {
1471 b->w = b->data; /* wrap around the buffer */
1472 }
1473 }
1474 else if (ret == 0) {
1475 /* nothing written, just make as if we were never called */
1476 // s->res_sw = RES_NULL;
1477 return 0;
1478 }
1479 else if (errno == EAGAIN) /* ignore EAGAIN */
1480 return 0;
1481 else {
1482 s->res_sw = RES_ERROR;
1483 fdtab[fd].state = FD_STERROR;
1484 }
1485 }
1486 else {
1487 s->res_sw = RES_ERROR;
1488 fdtab[fd].state = FD_STERROR;
1489 }
1490
1491 if (s->proxy->srvtimeout)
1492 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1493 else
1494 tv_eternity(&s->swexpire);
1495
willy tarreau5cbea6f2005-12-17 12:48:26 +01001496 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001497 return 0;
1498}
1499
1500
1501/*
1502 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001503 * to an accept. It tries to accept as many connections as possible.
1504 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001505 */
1506int event_accept(int fd) {
1507 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001508 struct session *s;
1509 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001510 int cfd;
1511 int one = 1;
1512
willy tarreau5cbea6f2005-12-17 12:48:26 +01001513 while (p->nbconn < p->maxconn) {
1514 struct sockaddr_in addr;
1515 int laddr = sizeof(addr);
1516 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1517 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001518
willy tarreau5cbea6f2005-12-17 12:48:26 +01001519 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1520 Alert("out of memory in event_accept().\n");
1521 FD_CLR(fd, StaticReadEvent);
1522 p->state = PR_STIDLE;
1523 close(cfd);
1524 return 0;
1525 }
willy tarreau0f7af912005-12-17 12:21:26 +01001526
willy tarreau5cbea6f2005-12-17 12:48:26 +01001527 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1528 Alert("out of memory in event_accept().\n");
1529 FD_CLR(fd, StaticReadEvent);
1530 p->state = PR_STIDLE;
1531 close(cfd);
1532 pool_free(session, s);
1533 return 0;
1534 }
willy tarreau0f7af912005-12-17 12:21:26 +01001535
willy tarreau5cbea6f2005-12-17 12:48:26 +01001536 s->cli_addr = addr;
1537 if (cfd >= cfg_maxsock) {
1538 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1539 close(cfd);
1540 pool_free(task, t);
1541 pool_free(session, s);
1542 return 0;
1543 }
willy tarreau0f7af912005-12-17 12:21:26 +01001544
willy tarreau5cbea6f2005-12-17 12:48:26 +01001545 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1546 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1547 (char *) &one, sizeof(one)) == -1)) {
1548 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1549 close(cfd);
1550 pool_free(task, t);
1551 pool_free(session, s);
1552 return 0;
1553 }
willy tarreau0f7af912005-12-17 12:21:26 +01001554
willy tarreau5cbea6f2005-12-17 12:48:26 +01001555 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1556 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1557 struct sockaddr_in peername, sockname;
1558 unsigned char *pn, *sn;
1559 int namelen;
1560 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001561
willy tarreau5cbea6f2005-12-17 12:48:26 +01001562 //namelen = sizeof(peername);
1563 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1564 //pn = (unsigned char *)&peername.sin_addr;
1565 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001566
willy tarreau5cbea6f2005-12-17 12:48:26 +01001567 namelen = sizeof(sockname);
1568 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1569 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1570 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001571
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1573 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1574 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1575 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001576
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577 if (p->logfac1 >= 0)
1578 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1579 if (p->logfac2 >= 0)
1580 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1581 }
willy tarreau0f7af912005-12-17 12:21:26 +01001582
willy tarreauef900ab2005-12-17 12:52:52 +01001583 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1584 int len;
1585 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1586 write(1, trash, len);
1587 }
willy tarreau0f7af912005-12-17 12:21:26 +01001588
willy tarreau5cbea6f2005-12-17 12:48:26 +01001589 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1590 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1591 t->state = TASK_IDLE;
1592 t->process = process_session;
1593 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001594
willy tarreau5cbea6f2005-12-17 12:48:26 +01001595 s->task = t;
1596 s->proxy = p;
1597 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1598 s->srv_state = SV_STIDLE;
1599 s->req = s->rep = NULL; /* will be allocated later */
1600 s->flags = 0;
1601 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1602 s->cli_fd = cfd;
1603 s->srv_fd = -1;
1604 s->conn_retries = p->conn_retries;
1605
1606 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1607 close(cfd); /* nothing can be done for this fd without memory */
1608 pool_free(task, t);
1609 pool_free(session, s);
1610 return 0;
1611 }
1612 s->req->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001613 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1614 s->req->rlim = s->req->data + BUFSIZE;
1615 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1616 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001617
willy tarreau5cbea6f2005-12-17 12:48:26 +01001618 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1619 pool_free(buffer, s->req);
1620 close(cfd); /* nothing can be done for this fd without memory */
1621 pool_free(task, t);
1622 pool_free(session, s);
1623 return 0;
1624 }
1625 s->rep->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001626 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 +01001627
willy tarreau5cbea6f2005-12-17 12:48:26 +01001628 fdtab[cfd].read = &event_cli_read;
1629 fdtab[cfd].write = &event_cli_write;
1630 fdtab[cfd].owner = t;
1631 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1634 FD_CLR(cfd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001635 FD_SET(cfd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001636 tv_eternity(&s->crexpire);
1637 shutdown(s->cli_fd, SHUT_RD);
1638 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001639
willy tarreau5cbea6f2005-12-17 12:48:26 +01001640 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1641 s->rep->l = 3;
1642 s->rep->r += 3;
1643 }
1644 else {
1645 FD_SET(cfd, StaticReadEvent);
1646 }
1647
1648 fd_insert(cfd);
1649
1650 tv_eternity(&s->cnexpire);
1651 tv_eternity(&s->srexpire);
1652 tv_eternity(&s->swexpire);
1653 tv_eternity(&s->cwexpire);
1654
1655 if (s->proxy->clitimeout)
1656 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1657 else
1658 tv_eternity(&s->crexpire);
1659
1660 t->expire = s->crexpire;
1661
1662 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001663
1664 if (p->mode != PR_MODE_HEALTH)
1665 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001666
1667 p->nbconn++;
1668 actconn++;
1669 totalconn++;
1670
1671 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1672 } /* end of while (p->nbconn < p->maxconn) */
1673 return 0;
1674}
willy tarreau0f7af912005-12-17 12:21:26 +01001675
willy tarreau0f7af912005-12-17 12:21:26 +01001676
willy tarreau5cbea6f2005-12-17 12:48:26 +01001677/*
1678 * This function is used only for server health-checks. It handles
1679 * the connection acknowledgement and returns 1 if the socket is OK,
1680 * or -1 if an error occured.
1681 */
1682int event_srv_hck(int fd) {
1683 struct task *t = fdtab[fd].owner;
1684 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001685
willy tarreau5cbea6f2005-12-17 12:48:26 +01001686 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001687 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001688 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1689 if (skerr)
1690 s->result = -1;
1691 else
1692 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001693
willy tarreau5cbea6f2005-12-17 12:48:26 +01001694 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001695 return 0;
1696}
1697
1698
1699/*
1700 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1701 * and moves <end> just after the end of <str>.
1702 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1703 * the shift value (positive or negative) is returned.
1704 * If there's no space left, the move is not done.
1705 *
1706 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001707int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001708 int delta;
1709 int len;
1710
1711 len = strlen(str);
1712 delta = len - (end - pos);
1713
1714 if (delta + b->r >= b->data + BUFSIZE)
1715 return 0; /* no space left */
1716
1717 /* first, protect the end of the buffer */
1718 memmove(end + delta, end, b->data + b->l - end);
1719
1720 /* now, copy str over pos */
1721 memcpy(pos, str,len);
1722
willy tarreau5cbea6f2005-12-17 12:48:26 +01001723 /* we only move data after the displaced zone */
1724 if (b->r > pos) b->r += delta;
1725 if (b->w > pos) b->w += delta;
1726 if (b->h > pos) b->h += delta;
1727 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001728 b->l += delta;
1729
1730 return delta;
1731}
1732
1733/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001734int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001735 int delta;
1736
1737 delta = len - (end - pos);
1738
1739 if (delta + b->r >= b->data + BUFSIZE)
1740 return 0; /* no space left */
1741
1742 /* first, protect the end of the buffer */
1743 memmove(end + delta, end, b->data + b->l - end);
1744
1745 /* now, copy str over pos */
1746 memcpy(pos, str,len);
1747
willy tarreau5cbea6f2005-12-17 12:48:26 +01001748 /* we only move data after the displaced zone */
1749 if (b->r > pos) b->r += delta;
1750 if (b->w > pos) b->w += delta;
1751 if (b->h > pos) b->h += delta;
1752 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001753 b->l += delta;
1754
1755 return delta;
1756}
1757
1758
1759int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1760 char *old_dst = dst;
1761
1762 while (*str) {
1763 if (*str == '\\') {
1764 str++;
1765 if (isdigit(*str)) {
1766 int len, num;
1767
1768 num = *str - '0';
1769 str++;
1770
1771 if (matches[num].rm_so > -1) {
1772 len = matches[num].rm_eo - matches[num].rm_so;
1773 memcpy(dst, src + matches[num].rm_so, len);
1774 dst += len;
1775 }
1776
1777 }
1778 else if (*str == 'x') {
1779 unsigned char hex1, hex2;
1780 str++;
1781
1782 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1783
1784 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1785 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1786 *dst++ = (hex1<<4) + hex2;
1787 }
1788 else
1789 *dst++ = *str++;
1790 }
1791 else
1792 *dst++ = *str++;
1793 }
1794 *dst = 0;
1795 return dst - old_dst;
1796}
1797
1798/*
1799 * manages the client FSM and its socket. BTW, it also tries to handle the
1800 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1801 * 0 else.
1802 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001803int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001804 int s = t->srv_state;
1805 int c = t->cli_state;
1806 struct buffer *req = t->req;
1807 struct buffer *rep = t->rep;
1808
1809 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1810 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1811 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1812 //);
1813 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001814 /* now parse the partial (or complete) headers */
1815 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1816 char *ptr;
1817 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001818
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001820
willy tarreau0f7af912005-12-17 12:21:26 +01001821 /* look for the end of the current header */
1822 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1823 ptr++;
1824
willy tarreau5cbea6f2005-12-17 12:48:26 +01001825 if (ptr == req->h) { /* empty line, end of headers */
1826 char newhdr[MAXREWRITE + 1];
1827 int line, len;
1828 /* we can only get here after an end of headers */
1829 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001830
willy tarreau5cbea6f2005-12-17 12:48:26 +01001831 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1832 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1833 buffer_replace2(req, req->h, req->h, newhdr, len);
1834 }
willy tarreau0f7af912005-12-17 12:21:26 +01001835
willy tarreau5cbea6f2005-12-17 12:48:26 +01001836 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01001837 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01001838
willy tarreau5cbea6f2005-12-17 12:48:26 +01001839 /* FIXME: we'll set the client in a wait state while we try to
1840 * connect to the server. Is this really needed ? wouldn't it be
1841 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01001842 //FD_CLR(t->cli_fd, StaticReadEvent);
1843 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 break;
1845 }
willy tarreau0f7af912005-12-17 12:21:26 +01001846
willy tarreau5cbea6f2005-12-17 12:48:26 +01001847 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1848 if (ptr > req->r - 2) {
1849 /* this is a partial header, let's wait for more to come */
1850 req->lr = ptr;
1851 break;
1852 }
willy tarreau0f7af912005-12-17 12:21:26 +01001853
willy tarreau5cbea6f2005-12-17 12:48:26 +01001854 /* now we know that *ptr is either \r or \n,
1855 * and that there are at least 1 char after it.
1856 */
1857 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1858 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1859 else
1860 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001861
willy tarreau5cbea6f2005-12-17 12:48:26 +01001862 /*
1863 * now we know that we have a full header ; we can do whatever
1864 * we want with these pointers :
1865 * req->h = beginning of header
1866 * ptr = end of header (first \r or \n)
1867 * req->lr = beginning of next line (next rep->h)
1868 * req->r = end of data (not used at this stage)
1869 */
willy tarreau0f7af912005-12-17 12:21:26 +01001870
willy tarreau5cbea6f2005-12-17 12:48:26 +01001871 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001872
willy tarreau5cbea6f2005-12-17 12:48:26 +01001873 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1874 int len, max;
1875 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1876 max = ptr - req->h;
1877 UBOUND(max, sizeof(trash) - len - 1);
1878 len += strlcpy(trash + len, req->h, max + 1);
1879 trash[len++] = '\n';
1880 write(1, trash, len);
1881 }
willy tarreau0f7af912005-12-17 12:21:26 +01001882
willy tarreau5cbea6f2005-12-17 12:48:26 +01001883 /* try headers regexps */
1884 if (t->proxy->nb_reqexp) {
1885 struct proxy *p = t->proxy;
1886 int exp;
1887 char term;
1888
1889 term = *ptr;
1890 *ptr = '\0';
1891 for (exp=0; exp < p->nb_reqexp; exp++) {
1892 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1893 if (p->req_exp[exp].replace != NULL) {
1894 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1895 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001896 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001897 else {
1898 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001899 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001900 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001901 }
1902 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001903 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001904 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001905
1906 /* now look for cookies */
1907 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1908 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1909 char *p1, *p2, *p3, *p4;
1910
1911 p1 = req->h + 8; /* first char after 'Cookie: ' */
1912
1913 while (p1 < ptr) {
1914 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1915 p1++;
1916
1917 if (p1 == ptr)
1918 break;
1919 else if (*p1 == ';') { /* next cookie */
1920 ++p1;
1921 continue;
1922 }
1923
1924 /* p1 is at the beginning of the cookie name */
1925 p2 = p1;
1926
1927 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1928 p2++;
1929
1930 if (p2 == ptr)
1931 break;
1932 else if (*p2 == ';') { /* next cookie */
1933 p1=++p2;
1934 continue;
1935 }
1936
1937 p3 = p2 + 1; /* skips the '=' sign */
1938 if (p3 == ptr)
1939 break;
1940
1941 p4=p3;
1942 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1943 p4++;
1944
1945 /* here, we have the cookie name between p1 and p2,
1946 * and its value between p3 and p4.
1947 * we can process it.
1948 */
1949
1950 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1951 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1952 /* Cool... it's the right one */
1953 struct server *srv = t->proxy->srv;
1954
1955 while (srv &&
1956 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1957 srv = srv->next;
1958 }
1959
1960 if (srv) { /* we found the server */
1961 t->flags |= TF_DIRECT;
1962 t->srv = srv;
1963 }
1964
1965 break;
1966 }
1967 else {
1968 // fprintf(stderr,"Ignoring unknown cookie : ");
1969 // write(2, p1, p2-p1);
1970 // fprintf(stderr," = ");
1971 // write(2, p3, p4-p3);
1972 // fprintf(stderr,"\n");
1973 }
1974 /* we'll have to look for another cookie ... */
1975 p1 = p4;
1976 } /* while (p1 < ptr) */
1977 } /* end of cookie processing */
1978
1979 /* let's look if we have to delete this header */
1980 if (delete_header) {
1981 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001982 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001983 req->h = req->lr;
1984 } /* while (req->lr < req->r) */
1985
1986 /* end of header processing (even if incomplete) */
1987
willy tarreauef900ab2005-12-17 12:52:52 +01001988
1989 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1990 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1991 * full. We cannot loop here since event_cli_read will disable it only if
1992 * req->l == rlim-data
1993 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001994 FD_SET(t->cli_fd, StaticReadEvent);
1995 if (t->proxy->clitimeout)
1996 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1997 else
1998 tv_eternity(&t->crexpire);
1999 }
2000
willy tarreauef900ab2005-12-17 12:52:52 +01002001 /* read timeout, read error, or last read : give up.
2002 * since we are in header mode, if there's no space left for headers, we
2003 * won't be able to free more later, so the session will never terminate.
2004 */
2005 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2006 || req->l >= req->rlim - req->data || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002007 tv_eternity(&t->crexpire);
2008 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002009 t->cli_state = CL_STCLOSE;
2010 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002011 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012
2013 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002014 }
2015 else if (c == CL_STDATA) {
2016 /* read or write error */
2017 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002018 tv_eternity(&t->crexpire);
2019 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002020 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002021 t->cli_state = CL_STCLOSE;
2022 return 1;
2023 }
2024 /* read timeout, last read, or end of server write */
2025 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2026 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002027 FD_CLR(t->cli_fd, StaticReadEvent);
2028 // if (req->l == 0) /* nothing to write on the server side */
2029 // FD_CLR(t->srv_fd, StaticWriteEvent);
2030 tv_eternity(&t->crexpire);
2031 shutdown(t->cli_fd, SHUT_RD);
2032 t->cli_state = CL_STSHUTR;
2033 return 1;
2034 }
2035 /* write timeout, or last server read and buffer empty */
2036 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2037 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002038 FD_CLR(t->cli_fd, StaticWriteEvent);
2039 tv_eternity(&t->cwexpire);
2040 shutdown(t->cli_fd, SHUT_WR);
2041 t->cli_state = CL_STSHUTW;
2042 return 1;
2043 }
2044
willy tarreauef900ab2005-12-17 12:52:52 +01002045 if (req->l >= req->rlim - req->data) {
2046 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002047 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002048 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002049 FD_CLR(t->cli_fd, StaticReadEvent);
2050 tv_eternity(&t->crexpire);
2051 }
2052 }
2053 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002054 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002055 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2056 FD_SET(t->cli_fd, StaticReadEvent);
2057 if (t->proxy->clitimeout)
2058 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2059 else
2060 tv_eternity(&t->crexpire);
2061 }
2062 }
2063
2064 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002065 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002066 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2067 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2068 tv_eternity(&t->cwexpire);
2069 }
2070 }
2071 else { /* buffer not empty */
2072 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2073 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2074 if (t->proxy->clitimeout)
2075 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2076 else
2077 tv_eternity(&t->cwexpire);
2078 }
2079 }
2080 return 0; /* other cases change nothing */
2081 }
2082 else if (c == CL_STSHUTR) {
2083 if ((t->res_cw == RES_ERROR) ||
2084 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002085 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002086 tv_eternity(&t->cwexpire);
2087 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002088 t->cli_state = CL_STCLOSE;
2089 return 1;
2090 }
2091 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002092 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002093 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2094 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2095 tv_eternity(&t->cwexpire);
2096 }
2097 }
2098 else { /* buffer not empty */
2099 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2100 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2101 if (t->proxy->clitimeout)
2102 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2103 else
2104 tv_eternity(&t->cwexpire);
2105 }
2106 }
2107 return 0;
2108 }
2109 else if (c == CL_STSHUTW) {
2110 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002111 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002112 tv_eternity(&t->crexpire);
2113 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002114 t->cli_state = CL_STCLOSE;
2115 return 1;
2116 }
willy tarreauef900ab2005-12-17 12:52:52 +01002117 else if (req->l >= req->rlim - req->data) {
2118 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002119 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002120 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002121 FD_CLR(t->cli_fd, StaticReadEvent);
2122 tv_eternity(&t->crexpire);
2123 }
2124 }
2125 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002126 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002127 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2128 FD_SET(t->cli_fd, StaticReadEvent);
2129 if (t->proxy->clitimeout)
2130 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2131 else
2132 tv_eternity(&t->crexpire);
2133 }
2134 }
2135 return 0;
2136 }
2137 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002138 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002139 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002140 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002141 write(1, trash, len);
2142 }
2143 return 0;
2144 }
2145 return 0;
2146}
2147
2148
2149/*
2150 * manages the server FSM and its socket. It returns 1 if a state has changed
2151 * (and a resync may be needed), 0 else.
2152 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002153int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002154 int s = t->srv_state;
2155 int c = t->cli_state;
2156 struct buffer *req = t->req;
2157 struct buffer *rep = t->rep;
2158
willy tarreau5cbea6f2005-12-17 12:48:26 +01002159 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2160 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2161 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2162 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2163 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002164 if (s == SV_STIDLE) {
2165 if (c == CL_STHEADERS)
2166 return 0; /* stay in idle, waiting for data to reach the client side */
2167 else if (c == CL_STCLOSE ||
2168 c == CL_STSHUTW ||
2169 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2170 tv_eternity(&t->cnexpire);
2171 t->srv_state = SV_STCLOSE;
2172 return 1;
2173 }
2174 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002175 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002176 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2177 t->srv_state = SV_STCONN;
2178 }
2179 else { /* try again */
2180 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002181 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2182 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2183 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2184 }
2185
2186 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002187 t->srv_state = SV_STCONN;
2188 break;
2189 }
2190 }
2191 if (t->conn_retries < 0) {
2192 /* if conn_retries < 0 or other error, let's abort */
2193 tv_eternity(&t->cnexpire);
2194 t->srv_state = SV_STCLOSE;
2195 }
2196 }
2197 return 1;
2198 }
2199 }
2200 else if (s == SV_STCONN) { /* connection in progress */
2201 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
2202 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
2203 return 0; /* nothing changed */
2204 }
2205 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
2206 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2207 /* timeout, connect error or first write error */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002208 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002209 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002210 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002211 t->conn_retries--;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002212 if (t->conn_retries >= 0) {
2213 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2214 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2215 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2216 }
2217 if (connect_server(t) == 0)
2218 return 0; /* no state changed */
willy tarreau0f7af912005-12-17 12:21:26 +01002219 }
2220 /* if conn_retries < 0 or other error, let's abort */
2221 tv_eternity(&t->cnexpire);
2222 t->srv_state = SV_STCLOSE;
2223 return 1;
2224 }
2225 else { /* no error or write 0 */
2226 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2227 if (req->l == 0) /* nothing to write */
2228 FD_CLR(t->srv_fd, StaticWriteEvent);
2229 else /* need the right to write */
2230 FD_SET(t->srv_fd, StaticWriteEvent);
2231
2232 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
2233 FD_SET(t->srv_fd, StaticReadEvent);
2234 if (t->proxy->srvtimeout)
2235 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2236 else
2237 tv_eternity(&t->srexpire);
2238
2239 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002240 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01002241 }
willy tarreauef900ab2005-12-17 12:52:52 +01002242 else {
willy tarreau0f7af912005-12-17 12:21:26 +01002243 t->srv_state = SV_STHEADERS;
willy tarreauef900ab2005-12-17 12:52:52 +01002244 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2245 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002246 tv_eternity(&t->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002247 return 1;
2248 }
2249 }
2250 else if (s == SV_STHEADERS) { /* receiving server headers */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002251
2252 /* now parse the partial (or complete) headers */
2253 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2254 char *ptr;
2255 int delete_header;
2256
2257 ptr = rep->lr;
2258
2259 /* look for the end of the current header */
2260 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2261 ptr++;
2262
2263 if (ptr == rep->h) {
2264 char newhdr[MAXREWRITE + 1];
2265 int line, len;
2266
2267 /* we can only get here after an end of headers */
2268 /* we'll have something else to do here : add new headers ... */
2269
2270 if ((t->srv) && !(t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_INS)) {
2271 /* the server is known, it's not the one the client requested, we have to
2272 * insert a set-cookie here.
2273 */
2274 len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
2275 t->proxy->cookie_name, t->srv->cookie);
2276 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2277 }
2278
2279 /* headers to be added */
2280 for (line = 0; line < t->proxy->nb_rspadd; line++) {
2281 len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
2282 buffer_replace2(rep, rep->h, rep->h, newhdr, len);
2283 }
2284
2285 t->srv_state = SV_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01002286 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002287 break;
2288 }
2289
2290 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2291 if (ptr > rep->r - 2) {
2292 /* this is a partial header, let's wait for more to come */
2293 rep->lr = ptr;
2294 break;
2295 }
2296
2297 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2298 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2299
2300 /* now we know that *ptr is either \r or \n,
2301 * and that there are at least 1 char after it.
2302 */
2303 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2304 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2305 else
2306 rep->lr = ptr + 2; /* \r\n or \n\r */
2307
2308 /*
2309 * now we know that we have a full header ; we can do whatever
2310 * we want with these pointers :
2311 * rep->h = beginning of header
2312 * ptr = end of header (first \r or \n)
2313 * rep->lr = beginning of next line (next rep->h)
2314 * rep->r = end of data (not used at this stage)
2315 */
2316
2317 delete_header = 0;
2318
2319 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
2320 int len, max;
2321 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2322 max = ptr - rep->h;
2323 UBOUND(max, sizeof(trash) - len - 1);
2324 len += strlcpy(trash + len, rep->h, max + 1);
2325 trash[len++] = '\n';
2326 write(1, trash, len);
2327 }
2328
2329 /* try headers regexps */
2330 if (t->proxy->nb_rspexp) {
2331 struct proxy *p = t->proxy;
2332 int exp;
2333 char term;
2334
2335 term = *ptr;
2336 *ptr = '\0';
2337 for (exp=0; exp < p->nb_rspexp; exp++) {
2338 if (regexec(p->rsp_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2339 if (p->rsp_exp[exp].replace != NULL) {
2340 int len = exp_replace(trash, rep->h, p->rsp_exp[exp].replace, pmatch);
2341 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2342 }
2343 else {
2344 delete_header = 1;
2345 }
2346 break;
2347 }
2348 }
2349 *ptr = term; /* restore the string terminator */
2350 }
2351
2352 /* check for server cookies */
2353 if (!delete_header && (t->proxy->options & PR_O_COOK_ANY) && (rep->r >= rep->h + 12) &&
2354 (t->proxy->cookie_name != NULL) && (strncmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2355 char *p1, *p2, *p3, *p4;
2356
2357 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2358
2359 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2360 while (p1 < ptr && (isspace(*p1)))
2361 p1++;
2362
2363 if (p1 == ptr || *p1 == ';') /* end of cookie */
2364 break;
2365
2366 /* p1 is at the beginning of the cookie name */
2367 p2 = p1;
2368
2369 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2370 p2++;
2371
2372 if (p2 == ptr || *p2 == ';') /* next cookie */
2373 break;
2374
2375 p3 = p2 + 1; /* skips the '=' sign */
2376 if (p3 == ptr)
2377 break;
2378
2379 p4 = p3;
2380 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
2381 p4++;
2382
2383 /* here, we have the cookie name between p1 and p2,
2384 * and its value between p3 and p4.
2385 * we can process it.
2386 */
2387
2388 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
2389 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
2390 /* Cool... it's the right one */
2391
2392 /* If the cookie is in insert mode on a known server, we'll delete
2393 * this occurrence because we'll insert another one later.
2394 * We'll delete it too if the "indirect" option is set and we're in
2395 * a direct access. */
2396 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
2397 ((t->flags & TF_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
2398 /* this header must be deleted */
2399 delete_header = 1;
2400 }
2401 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
2402 /* replace bytes p3->p4 with the cookie name associated
2403 * with this server since we know it.
2404 */
2405 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2406 }
2407 break;
2408 }
2409 else {
2410 // fprintf(stderr,"Ignoring unknown cookie : ");
2411 // write(2, p1, p2-p1);
2412 // fprintf(stderr," = ");
2413 // write(2, p3, p4-p3);
2414 // fprintf(stderr,"\n");
2415 }
2416 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2417 } /* we're now at the end of the cookie value */
2418 } /* end of cookie processing */
2419
2420 /* let's look if we have to delete this header */
2421 if (delete_header) {
2422 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2423 }
2424 rep->h = rep->lr;
2425 } /* while (rep->lr < rep->r) */
2426
2427 /* end of header processing (even if incomplete) */
2428
willy tarreauef900ab2005-12-17 12:52:52 +01002429 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2430 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
2431 * full. We cannot loop here since event_srv_read will disable it only if
2432 * rep->l == rlim-data
2433 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002434 FD_SET(t->srv_fd, StaticReadEvent);
2435 if (t->proxy->srvtimeout)
2436 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2437 else
2438 tv_eternity(&t->srexpire);
2439 }
willy tarreau0f7af912005-12-17 12:21:26 +01002440
2441 /* read or write error */
2442 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002443 tv_eternity(&t->srexpire);
2444 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002445 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002446 t->srv_state = SV_STCLOSE;
2447 return 1;
2448 }
willy tarreauef900ab2005-12-17 12:52:52 +01002449 /* read timeout, last read, or end of client write
2450 * since we are in header mode, if there's no space left for headers, we
2451 * won't be able to free more later, so the session will never terminate.
2452 */
2453 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2454 || rep->l >= rep->rlim - rep->data || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002455 FD_CLR(t->srv_fd, StaticReadEvent);
2456 tv_eternity(&t->srexpire);
2457 shutdown(t->srv_fd, SHUT_RD);
2458 t->srv_state = SV_STSHUTR;
2459 return 1;
2460
2461 }
2462 /* write timeout, or last client read and buffer empty */
2463 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2464 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2465 FD_CLR(t->srv_fd, StaticWriteEvent);
2466 tv_eternity(&t->swexpire);
2467 shutdown(t->srv_fd, SHUT_WR);
2468 t->srv_state = SV_STSHUTW;
2469 return 1;
2470 }
2471
2472 if (req->l == 0) {
2473 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2474 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2475 tv_eternity(&t->swexpire);
2476 }
2477 }
2478 else { /* client buffer not empty */
2479 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2480 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2481 if (t->proxy->srvtimeout)
2482 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2483 else
2484 tv_eternity(&t->swexpire);
2485 }
2486 }
2487
willy tarreau5cbea6f2005-12-17 12:48:26 +01002488 /* be nice with the client side which would like to send a complete header
2489 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2490 * would read all remaining data at once ! The client should not write past rep->lr
2491 * when the server is in header state.
2492 */
2493 //return header_processed;
2494 return t->srv_state != SV_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002495 }
2496 else if (s == SV_STDATA) {
2497 /* read or write error */
2498 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002499 tv_eternity(&t->srexpire);
2500 tv_eternity(&t->swexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002501 fd_delete(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002502 t->srv_state = SV_STCLOSE;
2503 return 1;
2504 }
2505 /* read timeout, last read, or end of client write */
willy tarreauef900ab2005-12-17 12:52:52 +01002506 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
2507 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002508 FD_CLR(t->srv_fd, StaticReadEvent);
2509 tv_eternity(&t->srexpire);
2510 shutdown(t->srv_fd, SHUT_RD);
2511 t->srv_state = SV_STSHUTR;
2512 return 1;
2513
2514 }
2515 /* write timeout, or last client read and buffer empty */
willy tarreauef900ab2005-12-17 12:52:52 +01002516 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
2517 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002518 FD_CLR(t->srv_fd, StaticWriteEvent);
2519 tv_eternity(&t->swexpire);
2520 shutdown(t->srv_fd, SHUT_WR);
2521 t->srv_state = SV_STSHUTW;
2522 return 1;
2523 }
2524 else if (req->l == 0) {
2525 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2526 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2527 tv_eternity(&t->swexpire);
2528 }
2529 }
2530 else { /* buffer not empty */
2531 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2532 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2533 if (t->proxy->srvtimeout)
2534 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2535 else
2536 tv_eternity(&t->swexpire);
2537 }
2538 }
2539
2540 if (rep->l == BUFSIZE) { /* no room to read more data */
2541 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2542 FD_CLR(t->srv_fd, StaticReadEvent);
2543 tv_eternity(&t->srexpire);
2544 }
2545 }
2546 else {
2547 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2548 FD_SET(t->srv_fd, StaticReadEvent);
2549 if (t->proxy->srvtimeout)
2550 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2551 else
2552 tv_eternity(&t->srexpire);
2553 }
2554 }
2555
2556 return 0; /* other cases change nothing */
2557 }
2558 else if (s == SV_STSHUTR) {
2559 if ((t->res_sw == RES_ERROR) ||
2560 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2561 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002562 //FD_CLR(t->srv_fd, StaticWriteEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002563 tv_eternity(&t->swexpire);
2564 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002565 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002566 t->srv_state = SV_STCLOSE;
2567 return 1;
2568 }
2569 else if (req->l == 0) {
2570 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2571 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2572 tv_eternity(&t->swexpire);
2573 }
2574 }
2575 else { /* buffer not empty */
2576 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2577 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2578 if (t->proxy->srvtimeout)
2579 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2580 else
2581 tv_eternity(&t->swexpire);
2582 }
2583 }
2584 return 0;
2585 }
2586 else if (s == SV_STSHUTW) {
2587 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2588 c == CL_STSHUTW || c == CL_STCLOSE ||
2589 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002590 //FD_CLR(t->srv_fd, StaticReadEvent);
willy tarreau0f7af912005-12-17 12:21:26 +01002591 tv_eternity(&t->srexpire);
2592 fd_delete(t->srv_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002593 //close(t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002594 t->srv_state = SV_STCLOSE;
2595 return 1;
2596 }
2597 else if (rep->l == BUFSIZE) { /* no room to read more data */
2598 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2599 FD_CLR(t->srv_fd, StaticReadEvent);
2600 tv_eternity(&t->srexpire);
2601 }
2602 }
2603 else {
2604 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2605 FD_SET(t->srv_fd, StaticReadEvent);
2606 if (t->proxy->srvtimeout)
2607 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2608 else
2609 tv_eternity(&t->srexpire);
2610 }
2611 }
2612 return 0;
2613 }
2614 else { /* SV_STCLOSE : nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002615 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002616 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002617 len = sprintf(trash, "srvcls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002618 write(1, trash, len);
2619 }
2620 return 0;
2621 }
2622 return 0;
2623}
2624
2625
willy tarreau5cbea6f2005-12-17 12:48:26 +01002626/* Processes the client and server jobs of a session task, then
2627 * puts it back to the wait queue in a clean state, or
2628 * cleans up its resources if it must be deleted. Returns
2629 * the time the task accepts to wait, or -1 for infinity
willy tarreau0f7af912005-12-17 12:21:26 +01002630 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002631int process_session(struct task *t) {
2632 struct session *s = t->context;
2633 int fsm_resync = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002634
willy tarreau5cbea6f2005-12-17 12:48:26 +01002635 do {
2636 fsm_resync = 0;
2637 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2638 fsm_resync |= process_cli(s);
2639 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2640 fsm_resync |= process_srv(s);
2641 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2642 } while (fsm_resync);
2643
2644 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
willy tarreau0f7af912005-12-17 12:21:26 +01002645 struct timeval min1, min2;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002646 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
willy tarreau0f7af912005-12-17 12:21:26 +01002647
willy tarreau5cbea6f2005-12-17 12:48:26 +01002648 tv_min(&min1, &s->crexpire, &s->cwexpire);
2649 tv_min(&min2, &s->srexpire, &s->swexpire);
2650 tv_min(&min1, &min1, &s->cnexpire);
willy tarreau0f7af912005-12-17 12:21:26 +01002651 tv_min(&t->expire, &min1, &min2);
2652
2653 /* restore t to its place in the task list */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002654 task_queue(t);
willy tarreau0f7af912005-12-17 12:21:26 +01002655
willy tarreau5cbea6f2005-12-17 12:48:26 +01002656 return tv_remain(&now, &t->expire); /* nothing more to do */
willy tarreau0f7af912005-12-17 12:21:26 +01002657 }
2658
willy tarreau5cbea6f2005-12-17 12:48:26 +01002659 s->proxy->nbconn--;
willy tarreau0f7af912005-12-17 12:21:26 +01002660 actconn--;
2661
willy tarreau5cbea6f2005-12-17 12:48:26 +01002662 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002663 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002664 len = sprintf(trash, "closed[%04x:%04x]\n", (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002665 write(1, trash, len);
2666 }
2667
2668 /* the task MUST not be in the run queue anymore */
2669 task_delete(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002670 session_free(s);
willy tarreau0f7af912005-12-17 12:21:26 +01002671 task_free(t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002672 return -1; /* rest in peace for eternity */
2673}
2674
2675
2676
2677/*
2678 * manages a server health-check. Returns
2679 * the time the task accepts to wait, or -1 for infinity.
2680 */
2681int process_chk(struct task *t) {
2682 struct server *s = t->context;
2683 int fd = s->curfd;
2684 int one = 1;
2685
willy tarreauef900ab2005-12-17 12:52:52 +01002686 //fprintf(stderr, "process_chk: task=%p\n", t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002687
2688 if (fd < 0) { /* no check currently running */
2689 //fprintf(stderr, "process_chk: 2\n");
2690 if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
2691 task_queue(t); /* restore t to its place in the task list */
2692 return tv_remain(&now, &t->expire);
2693 }
2694
2695 /* we'll initiate a new check */
2696 s->result = 0; /* no result yet */
2697 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
2698 if ((fd < cfg_maxsock) &&
2699 (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
2700 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
2701 //fprintf(stderr, "process_chk: 3\n");
2702
2703 if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
2704 /* OK, connection in progress or established */
2705
2706 //fprintf(stderr, "process_chk: 4\n");
2707
2708 s->curfd = fd; /* that's how we know a test is in progress ;-) */
2709 fdtab[fd].owner = t;
2710 fdtab[fd].read = NULL;
2711 fdtab[fd].write = &event_srv_hck;
2712 fdtab[fd].state = FD_STCONN; /* connection in progress */
2713 FD_SET(fd, StaticWriteEvent); /* for connect status */
2714 fd_insert(fd);
2715 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2716 task_queue(t); /* restore t to its place in the task list */
2717 return tv_remain(&now, &t->expire);
2718 }
2719 else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
2720 s->result = -1; /* a real error */
2721 }
2722 }
2723 //fprintf(stderr, "process_chk: 5\n");
2724 close(fd);
2725 }
2726
2727 if (!s->result) { /* nothing done */
2728 //fprintf(stderr, "process_chk: 6\n");
2729 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2730 task_queue(t); /* restore t to its place in the task list */
2731 return tv_remain(&now, &t->expire);
2732 }
2733
2734 /* here, we have seen a failure */
2735 if (s->health > FALLTIME)
2736 s->health--; /* still good */
2737 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002738 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2739 Warning("server %s DOWN.\n", s->id);
2740
willy tarreau5cbea6f2005-12-17 12:48:26 +01002741 s->health = 0; /* failure */
2742 s->state &= ~SRV_RUNNING;
2743 }
2744
2745 //fprintf(stderr, "process_chk: 7\n");
2746 tv_delayfrom(&t->expire, &now, CHK_CONNTIME);
2747 }
2748 else {
2749 //fprintf(stderr, "process_chk: 8\n");
2750 /* there was a test running */
2751 if (s->result > 0) { /* good server detected */
2752 //fprintf(stderr, "process_chk: 9\n");
2753 s->health++; /* was bad, stays for a while */
2754 if (s->health >= FALLTIME) {
willy tarreauef900ab2005-12-17 12:52:52 +01002755 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2756 Warning("server %s UP.\n", s->id);
2757
willy tarreau5cbea6f2005-12-17 12:48:26 +01002758 s->health = FALLTIME + RISETIME -1; /* OK now */
2759 s->state |= SRV_RUNNING;
2760 }
willy tarreauef900ab2005-12-17 12:52:52 +01002761 s->curfd = -1; /* no check running anymore */
2762 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002763 fd_delete(fd);
2764 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2765 }
2766 else if (s->result < 0 || tv_cmp2_ms(&t->expire, &now) <= 0) {
2767 //fprintf(stderr, "process_chk: 10\n");
2768 /* failure or timeout detected */
2769 if (s->health > FALLTIME)
2770 s->health--; /* still good */
2771 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002772 if (s->health == FALLTIME && !(mode & MODE_QUIET))
2773 Warning("server %s DOWN.\n", s->id);
2774
willy tarreau5cbea6f2005-12-17 12:48:26 +01002775 s->health = 0; /* failure */
2776 s->state &= ~SRV_RUNNING;
2777 }
2778 s->curfd = -1;
willy tarreauef900ab2005-12-17 12:52:52 +01002779 //FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002780 fd_delete(fd);
2781 tv_delayfrom(&t->expire, &now, CHK_INTERVAL);
2782 }
2783 /* if result is 0 and there's no timeout, we have to wait again */
2784 }
2785 //fprintf(stderr, "process_chk: 11\n");
2786 s->result = 0;
2787 task_queue(t); /* restore t to its place in the task list */
2788 return tv_remain(&now, &t->expire);
willy tarreau0f7af912005-12-17 12:21:26 +01002789}
2790
2791
willy tarreau5cbea6f2005-12-17 12:48:26 +01002792
willy tarreau0f7af912005-12-17 12:21:26 +01002793#if STATTIME > 0
2794int stats(void);
2795#endif
2796
2797/*
2798 * Main select() loop.
2799 */
2800
2801void select_loop() {
2802 int next_time;
willy tarreau0f7af912005-12-17 12:21:26 +01002803 int time2;
willy tarreau0f7af912005-12-17 12:21:26 +01002804 int status;
2805 int fd,i;
2806 struct timeval delta;
2807 int readnotnull, writenotnull;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002808 struct task *t, *tnext;
willy tarreau0f7af912005-12-17 12:21:26 +01002809
willy tarreau5cbea6f2005-12-17 12:48:26 +01002810 tv_now(&now);
2811
2812 while (1) {
2813 next_time = -1; /* set the timer to wait eternally first */
willy tarreau0f7af912005-12-17 12:21:26 +01002814
willy tarreau5cbea6f2005-12-17 12:48:26 +01002815 /* look for expired tasks and add them to the run queue.
2816 */
2817 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
2818 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
2819 tnext = t->next;
willy tarreauef900ab2005-12-17 12:52:52 +01002820 if (t->state & TASK_RUNNING)
2821 continue;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002822
2823 /* wakeup expired entries. It doesn't matter if they are
2824 * already running because of a previous event
2825 */
2826 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
willy tarreauef900ab2005-12-17 12:52:52 +01002827 //fprintf(stderr,"task_wakeup(%p, %p)\n", &rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002828 task_wakeup(&rq, t);
2829 }
2830 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002831 /* first non-runnable task. Use its expiration date as an upper bound */
2832 int temp_time = tv_remain(&now, &t->expire);
2833 if (temp_time)
2834 next_time = temp_time;
2835 //fprintf(stderr,"no_task_wakeup(%p, %p) : expire in %d ms\n", &rq, t, temp_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002836 break;
2837 }
2838 }
2839
2840 /* process each task in the run queue now. Each task may be deleted
2841 * since we only use tnext.
2842 */
2843 tnext = rq;
2844 while ((t = tnext) != NULL) {
2845 int temp_time;
2846
2847 tnext = t->rqnext;
2848 task_sleep(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01002849 //fprintf(stderr,"task %p\n",t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002850 temp_time = t->process(t);
2851 next_time = MINTIME(temp_time, next_time);
willy tarreauef900ab2005-12-17 12:52:52 +01002852 //fprintf(stderr,"process(%p)=%d -> next_time=%d)\n", t, temp_time, next_time);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002853 }
2854
willy tarreauef900ab2005-12-17 12:52:52 +01002855 //fprintf(stderr,"---end of run---\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +01002856
2857 /* maintain all proxies in a consistent state. This should quickly become a task */
2858 time2 = maintain_proxies();
2859 next_time = MINTIME(time2, next_time);
2860
2861 /* stop when there's no connection left and we don't allow them anymore */
2862 if (!actconn && listeners == 0)
2863 break;
2864
willy tarreau0f7af912005-12-17 12:21:26 +01002865
2866#if STATTIME > 0
2867 time2 = stats();
2868 // fprintf(stderr," stats = %d\n", time2);
2869 next_time = MINTIME(time2, next_time);
2870#endif
2871
willy tarreau5cbea6f2005-12-17 12:48:26 +01002872 if (next_time > 0) { /* FIXME */
willy tarreau0f7af912005-12-17 12:21:26 +01002873 /* Convert to timeval */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002874 /* to avoid eventual select loops due to timer precision */
2875 next_time += SCHEDULER_RESOLUTION;
2876 delta.tv_sec = next_time / 1000;
2877 delta.tv_usec = (next_time % 1000) * 1000;
2878 }
2879 else if (next_time == 0) { /* allow select to return immediately when needed */
2880 delta.tv_sec = delta.tv_usec = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01002881 }
2882
2883
2884 /* let's restore fdset state */
2885
2886 readnotnull = 0; writenotnull = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002887 for (i = 0; i < (cfg_maxsock + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01002888 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2889 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2890 }
2891
2892// /* just a verification code, needs to be removed for performance */
2893// for (i=0; i<maxfd; i++) {
2894// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2895// abort();
2896// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2897// abort();
2898//
2899// }
2900
2901 status=select(maxfd,
2902 readnotnull ? ReadEvent : NULL,
2903 writenotnull ? WriteEvent : NULL,
2904 NULL,
2905 (next_time >= 0) ? &delta : NULL);
2906
willy tarreau5cbea6f2005-12-17 12:48:26 +01002907 /* this is an experiment on the separation of the select work */
2908 // status = (readnotnull ? select(maxfd, ReadEvent, NULL, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2909 // status |= (writenotnull ? select(maxfd, NULL, WriteEvent, NULL, (next_time >= 0) ? &delta : NULL) : 0);
2910
willy tarreau0f7af912005-12-17 12:21:26 +01002911 tv_now(&now);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002912
willy tarreau0f7af912005-12-17 12:21:26 +01002913 if (status > 0) { /* must proceed with events */
2914
2915 int fds;
2916 char count;
2917
2918 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2919 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2920 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2921
willy tarreau5cbea6f2005-12-17 12:48:26 +01002922 /* if we specify read first, the accepts and zero reads will be
2923 * seen first. Moreover, system buffers will be flushed faster.
2924 */
willy tarreau0f7af912005-12-17 12:21:26 +01002925 if (fdtab[fd].state == FD_STCLOSE)
2926 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01002927
2928 if (FD_ISSET(fd, ReadEvent))
2929 fdtab[fd].read(fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002930
willy tarreau5cbea6f2005-12-17 12:48:26 +01002931 if (FD_ISSET(fd, WriteEvent))
2932 fdtab[fd].write(fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002933 }
2934 }
2935 else {
2936 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2937 }
willy tarreau0f7af912005-12-17 12:21:26 +01002938 }
2939}
2940
2941
2942#if STATTIME > 0
2943/*
2944 * Display proxy statistics regularly. It is designed to be called from the
2945 * select_loop().
2946 */
2947int stats(void) {
2948 static int lines;
2949 static struct timeval nextevt;
2950 static struct timeval lastevt;
2951 static struct timeval starttime = {0,0};
2952 unsigned long totaltime, deltatime;
2953 int ret;
2954
2955 if (tv_remain(&now, &nextevt) == 0) {
2956 deltatime = (tv_delta(&now, &lastevt)?:1);
2957 totaltime = (tv_delta(&now, &starttime)?:1);
2958
2959 if (mode & MODE_STATS) {
2960 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
willy tarreau5cbea6f2005-12-17 12:48:26 +01002961 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01002962 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2963 if (lines>1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002964 qfprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
willy tarreau0f7af912005-12-17 12:21:26 +01002965 actconn, totalconn,
2966 stats_tsk_new, stats_tsk_good,
2967 stats_tsk_left, stats_tsk_right,
2968 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2969 }
2970 }
2971
2972 tv_delayfrom(&nextevt, &now, STATTIME);
2973
2974 lastevt=now;
2975 }
2976 ret = tv_remain(&now, &nextevt);
2977 return ret;
2978}
2979#endif
2980
2981
2982/*
2983 * this function enables proxies when there are enough free sessions,
2984 * or stops them when the table is full. It is designed to be called from the
willy tarreau5cbea6f2005-12-17 12:48:26 +01002985 * select_loop(). It returns the time left before next expiration event
2986 * during stop time, -1 otherwise.
willy tarreau0f7af912005-12-17 12:21:26 +01002987 */
2988static int maintain_proxies(void) {
2989 struct proxy *p;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002990 int tleft; /* time left */
willy tarreau0f7af912005-12-17 12:21:26 +01002991
2992 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002993 tleft = -1; /* infinite time */
willy tarreau0f7af912005-12-17 12:21:26 +01002994
2995 /* if there are enough free sessions, we'll activate proxies */
2996 if (actconn < cfg_maxconn) {
2997 while (p) {
2998 if (p->nbconn < p->maxconn) {
2999 if (p->state == PR_STIDLE) {
3000 FD_SET(p->listen_fd, StaticReadEvent);
3001 p->state = PR_STRUN;
3002 }
3003 }
3004 else {
3005 if (p->state == PR_STRUN) {
3006 FD_CLR(p->listen_fd, StaticReadEvent);
3007 p->state = PR_STIDLE;
3008 }
3009 }
3010 p = p->next;
3011 }
3012 }
3013 else { /* block all proxies */
3014 while (p) {
3015 if (p->state == PR_STRUN) {
3016 FD_CLR(p->listen_fd, StaticReadEvent);
3017 p->state = PR_STIDLE;
3018 }
3019 p = p->next;
3020 }
3021 }
3022
willy tarreau5cbea6f2005-12-17 12:48:26 +01003023 if (stopping) {
3024 p = proxy;
3025 while (p) {
3026 if (p->state != PR_STDISABLED) {
3027 int t;
3028 t = tv_remain(&now, &p->stop_time);
3029 if (t == 0) {
3030 //FD_CLR(p->listen_fd, StaticReadEvent);
3031 //close(p->listen_fd);
3032 fd_delete(p->listen_fd);
3033 p->state = PR_STDISABLED;
3034 listeners--;
3035 }
3036 else {
3037 tleft = MINTIME(t, tleft);
3038 }
3039 }
3040 p = p->next;
3041 }
3042 }
3043 return tleft;
willy tarreau0f7af912005-12-17 12:21:26 +01003044}
3045
3046/*
3047 * this function disables health-check servers so that the process will quickly be ignored
3048 * by load balancers.
3049 */
3050static void soft_stop(void) {
3051 struct proxy *p;
3052
3053 stopping = 1;
3054 p = proxy;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003055 tv_now(&now); /* else, the old time before select will be used */
willy tarreau0f7af912005-12-17 12:21:26 +01003056 while (p) {
3057 if (p->state != PR_STDISABLED)
3058 tv_delayfrom(&p->stop_time, &now, p->grace);
3059 p = p->next;
3060 }
3061}
3062
3063/*
3064 * upon SIGUSR1, let's have a soft stop.
3065 */
3066void sig_soft_stop(int sig) {
3067 soft_stop();
3068 signal(sig, SIG_IGN);
3069}
3070
3071
3072void dump(int sig) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003073 struct task *t, *tnext;
3074 struct session *s;
willy tarreau0f7af912005-12-17 12:21:26 +01003075
willy tarreau5cbea6f2005-12-17 12:48:26 +01003076 tnext = ((struct task *)LIST_HEAD(wait_queue))->next;
3077 while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */
3078 tnext = t->next;
3079 s = t->context;
3080 qfprintf(stderr,"[dump] wq: task %p, still %ld ms, "
3081 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
3082 "req=%d, rep=%d, clifd=%d\n",
3083 s, tv_remain(&now, &t->expire),
3084 s->cli_state,
3085 s->srv_state,
3086 FD_ISSET(s->cli_fd, StaticReadEvent),
3087 FD_ISSET(s->cli_fd, StaticWriteEvent),
3088 FD_ISSET(s->srv_fd, StaticReadEvent),
3089 FD_ISSET(s->srv_fd, StaticWriteEvent),
3090 s->req->l, s->rep?s->rep->l:0, s->cli_fd
3091 );
willy tarreau0f7af912005-12-17 12:21:26 +01003092 }
3093}
3094
3095/*
3096 * This function reads and parses the configuration file given in the argument.
3097 * returns 0 if OK, -1 if error.
3098 */
3099int readcfgfile(char *file) {
3100 char thisline[256];
3101 char *line;
3102 FILE *f;
3103 int linenum = 0;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003104 char *end;
3105 char *args[MAX_LINE_ARGS];
willy tarreau0f7af912005-12-17 12:21:26 +01003106 int arg;
3107 int cfgerr = 0;
3108
3109 struct proxy *curproxy = NULL;
3110 struct server *newsrv = NULL;
3111
3112 if ((f=fopen(file,"r")) == NULL)
3113 return -1;
3114
3115 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
3116 linenum++;
willy tarreau0f7af912005-12-17 12:21:26 +01003117
willy tarreau5cbea6f2005-12-17 12:48:26 +01003118 end = line + strlen(line);
willy tarreau0f7af912005-12-17 12:21:26 +01003119
willy tarreau5cbea6f2005-12-17 12:48:26 +01003120 /* skip leading spaces */
3121 while (isspace(*line))
3122 line++;
willy tarreau0f7af912005-12-17 12:21:26 +01003123
willy tarreau5cbea6f2005-12-17 12:48:26 +01003124 arg = 0;
3125 args[arg] = line;
willy tarreau0f7af912005-12-17 12:21:26 +01003126
willy tarreau5cbea6f2005-12-17 12:48:26 +01003127 while (*line && arg < MAX_LINE_ARGS) {
3128 /* first, we'll replace \\, \<space>, \#, \r, \n, \t, \xXX with their
3129 * C equivalent value. Other combinations left unchanged (eg: \1).
3130 */
3131 if (*line == '\\') {
3132 int skip = 0;
3133 if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') {
3134 *line = line[1];
3135 skip = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01003136 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003137 else if (line[1] == 'r') {
3138 *line = '\r';
3139 skip = 1;
3140 }
3141 else if (line[1] == 'n') {
3142 *line = '\n';
3143 skip = 1;
3144 }
3145 else if (line[1] == 't') {
3146 *line = '\t';
3147 skip = 1;
3148 }
3149 else if (line[1] == 'x' && (line + 3 < end )) {
3150 unsigned char hex1, hex2;
3151 hex1 = toupper(line[2]) - '0'; hex2 = toupper(line[3]) - '0';
3152 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
3153 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
3154 *line = (hex1<<4) + hex2;
3155 skip = 3;
3156 }
3157 if (skip) {
3158 memmove(line + 1, line + 1 + skip, end - (line + skip + 1));
3159 end -= skip;
3160 }
willy tarreau0f7af912005-12-17 12:21:26 +01003161 line++;
3162 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003163 else {
3164 if (*line == '#' || *line == '\n' || *line == '\r')
3165 *line = 0; /* end of string, end of loop */
3166 else
willy tarreau0f7af912005-12-17 12:21:26 +01003167 line++;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003168
3169 /* a non-escaped space is an argument separator */
3170 if (isspace(*line)) {
3171 *line++ = 0;
3172 while (isspace(*line))
3173 line++;
3174 args[++arg] = line;
3175 }
willy tarreau0f7af912005-12-17 12:21:26 +01003176 }
3177 }
3178
willy tarreau5cbea6f2005-12-17 12:48:26 +01003179 /* empty line */
3180 if (!**args)
3181 continue;
3182
3183 /* zero out remaining args */
3184 while (++arg < MAX_LINE_ARGS) {
3185 args[arg] = line;
3186 }
3187
willy tarreau0f7af912005-12-17 12:21:26 +01003188 if (!strcmp(args[0], "listen")) { /* new proxy */
3189 if (strchr(args[2], ':') == NULL) {
3190 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
3191 file, linenum);
3192 return -1;
3193 }
3194
3195 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
3196 == NULL) {
3197 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
3198 exit(1);
3199 }
3200 curproxy->next = proxy;
3201 proxy = curproxy;
3202 curproxy->id = strdup(args[1]);
3203 curproxy->listen_addr = *str2sa(args[2]);
3204 curproxy->state = PR_STNEW;
willy tarreau0f7af912005-12-17 12:21:26 +01003205 /* set default values */
3206 curproxy->maxconn = cfg_maxpconn;
3207 curproxy->conn_retries = CONN_RETRIES;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003208 curproxy->options = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01003209 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
3210 curproxy->mode = PR_MODE_TCP;
3211 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
3212 continue;
3213 }
3214 else if (curproxy == NULL) {
3215 Alert("parsing [%s:%d] : <listen> expected.\n",
3216 file, linenum);
3217 return -1;
3218 }
3219
3220 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
3221 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
3222 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
3223 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
3224 else {
3225 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
3226 return -1;
3227 }
3228 }
3229 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
3230 curproxy->state = PR_STDISABLED;
3231 }
3232 else if (!strcmp(args[0], "cookie")) { /* cookie name */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003233 int cur_arg;
willy tarreau0f7af912005-12-17 12:21:26 +01003234 if (curproxy->cookie_name != NULL) {
3235 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
3236 file, linenum);
3237 continue;
3238 }
3239
3240 if (*(args[1]) == 0) {
3241 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
3242 file, linenum);
3243 return -1;
3244 }
3245 curproxy->cookie_name = strdup(args[1]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003246
3247 cur_arg = 2;
3248 while (*(args[cur_arg])) {
3249 if (!strcmp(args[cur_arg], "rewrite")) {
3250 curproxy->options |= PR_O_COOK_RW;
3251 }
3252 else if (!strcmp(args[cur_arg], "indirect")) {
3253 curproxy->options |= PR_O_COOK_IND;
3254 }
3255 else if (!strcmp(args[cur_arg], "insert")) {
3256 curproxy->options |= PR_O_COOK_INS;
3257 }
3258 else {
3259 Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert' and 'indirect' options.\n",
3260 file, linenum);
3261 return -1;
3262 }
3263 cur_arg++;
3264 }
3265 if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
3266 Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
3267 file, linenum);
3268 return -1;
3269 }
willy tarreau0f7af912005-12-17 12:21:26 +01003270 }
3271 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
3272 if (curproxy->contimeout != 0) {
3273 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
3274 file, linenum);
3275 continue;
3276 }
3277 if (*(args[1]) == 0) {
3278 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
3279 file, linenum);
3280 return -1;
3281 }
3282 curproxy->contimeout = atol(args[1]);
3283 }
3284 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
3285 if (curproxy->clitimeout != 0) {
3286 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
3287 file, linenum);
3288 continue;
3289 }
3290 if (*(args[1]) == 0) {
3291 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
3292 file, linenum);
3293 return -1;
3294 }
3295 curproxy->clitimeout = atol(args[1]);
3296 }
3297 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
3298 if (curproxy->srvtimeout != 0) {
3299 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
3300 file, linenum);
3301 continue;
3302 }
3303 if (*(args[1]) == 0) {
3304 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
3305 file, linenum);
3306 return -1;
3307 }
3308 curproxy->srvtimeout = atol(args[1]);
3309 }
3310 else if (!strcmp(args[0], "retries")) { /* connection retries */
3311 if (*(args[1]) == 0) {
3312 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
3313 file, linenum);
3314 return -1;
3315 }
3316 curproxy->conn_retries = atol(args[1]);
3317 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003318 else if (!strcmp(args[0], "redispatch") || !strcmp(args[0], "redisp")) {
3319 /* enable reconnections to dispatch */
3320 curproxy->options |= PR_O_REDISP;
willy tarreau0f7af912005-12-17 12:21:26 +01003321 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003322#ifdef TRANSPARENT
3323 else if (!strcmp(args[0], "transparent")) {
3324 /* enable transparent proxy connections */
3325 curproxy->options |= PR_O_TRANSP;
3326 }
3327#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003328 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
3329 if (*(args[1]) == 0) {
3330 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
3331 file, linenum);
3332 return -1;
3333 }
3334 curproxy->maxconn = atol(args[1]);
3335 }
3336 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
3337 if (*(args[1]) == 0) {
3338 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
3339 file, linenum);
3340 return -1;
3341 }
3342 curproxy->grace = atol(args[1]);
3343 }
3344 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
3345 if (strchr(args[1], ':') == NULL) {
3346 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
3347 file, linenum);
3348 return -1;
3349 }
3350 curproxy->dispatch_addr = *str2sa(args[1]);
3351 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003352 else if (!strcmp(args[0], "balance")) { /* set balancing with optionnal algorithm */
3353 if (*(args[1])) {
3354 if (!strcmp(args[1], "roundrobin")) {
3355 curproxy->options |= PR_O_BALANCE_RR;
3356 }
3357 else {
3358 Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n",
3359 file, linenum);
3360 return -1;
3361 }
3362 }
3363 else /* if no option is set, use round-robin by default */
3364 curproxy->options |= PR_O_BALANCE_RR;
3365 }
willy tarreau0f7af912005-12-17 12:21:26 +01003366 else if (!strcmp(args[0], "server")) { /* server address */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003367 int cur_arg;
3368
willy tarreau0f7af912005-12-17 12:21:26 +01003369 if (strchr(args[2], ':') == NULL) {
3370 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
3371 file, linenum);
3372 return -1;
3373 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003374 if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
3375 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
willy tarreau0f7af912005-12-17 12:21:26 +01003376 exit(1);
3377 }
3378 newsrv->next = curproxy->srv;
3379 curproxy->srv = newsrv;
3380 newsrv->id = strdup(args[1]);
3381 newsrv->addr = *str2sa(args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003382 newsrv->state = SRV_RUNNING; /* early server setup */
3383 newsrv->health = FALLTIME; /* up, but will fall down at first failure */
3384 newsrv->curfd = -1; /* no health-check in progress */
3385 cur_arg = 3;
3386 while (*args[cur_arg]) {
3387 if (!strcmp(args[cur_arg], "cookie")) {
3388 newsrv->cookie = strdup(args[cur_arg + 1]);
3389 newsrv->cklen = strlen(args[cur_arg + 1]);
3390 cur_arg += 2;
3391 }
3392 else if (!strcmp(args[cur_arg], "check")) {
3393 struct task *t;
3394
3395 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
3396 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
3397 return -1;
3398 }
3399
3400 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
3401 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
3402 t->state = TASK_IDLE;
3403 t->process = process_chk;
3404 t->context = newsrv;
3405
3406 tv_delayfrom(&t->expire, &now, CHK_INTERVAL); /* check this every ms */
3407 task_queue(t);
3408 task_wakeup(&rq, t);
3409
3410 cur_arg += 1;
3411 }
3412 else {
3413 Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
3414 file, linenum, newsrv->id);
3415 return -1;
3416 }
3417 }
3418 curproxy->nbservers++;
willy tarreau0f7af912005-12-17 12:21:26 +01003419 }
3420 else if (!strcmp(args[0], "log")) { /* syslog server address */
3421 struct sockaddr_in *sa;
3422 int facility;
3423
3424 if (*(args[1]) == 0 || *(args[2]) == 0) {
3425 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
3426 file, linenum);
3427 return -1;
3428 }
3429
3430 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
3431 if (!strcmp(log_facilities[facility], args[2]))
3432 break;
3433
3434 if (facility >= NB_LOG_FACILITIES) {
3435 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
3436 exit(1);
3437 }
3438
3439 sa = str2sa(args[1]);
3440 if (!sa->sin_port)
3441 sa->sin_port = htons(SYSLOG_PORT);
3442
3443 if (curproxy->logfac1 == -1) {
3444 curproxy->logsrv1 = *sa;
3445 curproxy->logfac1 = facility;
3446 }
3447 else if (curproxy->logfac2 == -1) {
3448 curproxy->logsrv2 = *sa;
3449 curproxy->logfac2 = facility;
3450 }
3451 else {
3452 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
3453 exit(1);
3454 }
3455
3456 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003457 else if (!strcmp(args[0], "cliexp") || !strcmp(args[0], "reqrep")) { /* replace request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003458 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003459 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3460 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003461 file, linenum);
3462 continue;
3463 }
3464
3465 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003466 Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003467 file, linenum);
3468 return -1;
3469 }
3470
3471 preg = calloc(1, sizeof(regex_t));
3472 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3473 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3474 return -1;
3475 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003476 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3477 curproxy->req_exp[curproxy->nb_reqexp].replace = strdup(args[2]);
3478 curproxy->nb_reqexp++;
willy tarreau0f7af912005-12-17 12:21:26 +01003479 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003480 else if (!strcmp(args[0], "reqdel")) { /* delete request header from a regex */
willy tarreau0f7af912005-12-17 12:21:26 +01003481 regex_t *preg;
willy tarreau5cbea6f2005-12-17 12:48:26 +01003482 if (curproxy->nb_reqexp >= MAX_REGEXP) {
3483 Alert("parsing [%s:%d] : too many request expressions. Continuing.\n",
3484 file, linenum);
3485 continue;
3486 }
3487
3488 if (*(args[1]) == 0) {
3489 Alert("parsing [%s:%d] : <reqdel> expects <search> as an argument.\n",
3490 file, linenum);
3491 return -1;
3492 }
3493
3494 preg = calloc(1, sizeof(regex_t));
3495 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3496 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3497 return -1;
3498 }
3499 curproxy->req_exp[curproxy->nb_reqexp].preg = preg;
3500 curproxy->req_exp[curproxy->nb_reqexp].replace = NULL; /* means it must be deleted */
3501 curproxy->nb_reqexp++;
3502 }
3503 else if (!strcmp(args[0], "reqadd")) { /* add request header */
3504 if (curproxy->nb_reqadd >= MAX_REGEXP) {
3505 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
3506 file, linenum);
3507 continue;
3508 }
3509
3510 if (*(args[1]) == 0) {
3511 Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n",
3512 file, linenum);
3513 return -1;
3514 }
3515
3516 curproxy->req_add[curproxy->nb_reqadd++] = strdup(args[1]);
3517 }
3518 else if (!strcmp(args[0], "srvexp") || !strcmp(args[0], "rsprep")) { /* replace response header from a regex */
3519 regex_t *preg;
3520 if (curproxy->nb_rspexp >= MAX_REGEXP) {
willy tarreau0f7af912005-12-17 12:21:26 +01003521 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3522 file, linenum);
3523 continue;
3524 }
3525
3526 if (*(args[1]) == 0 || *(args[2]) == 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003527 Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
willy tarreau0f7af912005-12-17 12:21:26 +01003528 file, linenum);
3529 return -1;
3530 }
3531
3532 preg = calloc(1, sizeof(regex_t));
3533 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3534 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3535 return -1;
3536 }
3537 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
willy tarreau5cbea6f2005-12-17 12:48:26 +01003538 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3539 curproxy->rsp_exp[curproxy->nb_rspexp].replace = strdup(args[2]);
3540 curproxy->nb_rspexp++;
3541 }
3542 else if (!strcmp(args[0], "rspdel")) { /* delete response header from a regex */
3543 regex_t *preg;
3544 if (curproxy->nb_rspexp >= MAX_REGEXP) {
3545 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3546 file, linenum);
3547 continue;
3548 }
3549
3550 if (*(args[1]) == 0) {
3551 Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n",
3552 file, linenum);
3553 return -1;
3554 }
3555
3556 preg = calloc(1, sizeof(regex_t));
3557 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
3558 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
3559 return -1;
3560 }
3561 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
3562 curproxy->rsp_exp[curproxy->nb_rspexp].preg = preg;
3563 curproxy->rsp_exp[curproxy->nb_rspexp].replace = NULL; /* means it must be deleted */
3564 curproxy->nb_rspexp++;
3565 }
3566 else if (!strcmp(args[0], "rspadd")) { /* add response header */
3567 if (curproxy->nb_rspadd >= MAX_REGEXP) {
3568 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
3569 file, linenum);
3570 continue;
3571 }
3572
3573 if (*(args[1]) == 0) {
3574 Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n",
3575 file, linenum);
3576 return -1;
3577 }
3578
3579 curproxy->rsp_add[curproxy->nb_rspadd++] = strdup(args[1]);
willy tarreau0f7af912005-12-17 12:21:26 +01003580 }
3581 else {
3582 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
3583 exit(1);
3584 }
3585 }
3586 fclose(f);
3587
3588 /*
3589 * Now, check for the integrity of all that we have collected.
3590 */
3591
3592 if ((curproxy = proxy) == NULL) {
3593 Alert("parsing %s : no <listen> line. Nothing to do !\n",
3594 file);
3595 return -1;
3596 }
3597
3598 while (curproxy != NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +01003599 if (curproxy->state == PR_STDISABLED) {
3600 curproxy = curproxy->next;
3601 continue;
3602 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003603 if ((curproxy->mode != PR_MODE_HEALTH) &&
3604 !(curproxy->options & (PR_O_TRANSP | PR_O_BALANCE)) &&
3605 (*(int *)&curproxy->dispatch_addr == 0)) {
3606 Alert("parsing %s : listener %s has no dispatch address and is not in transparent or balance mode.\n",
3607 file, curproxy->id);
3608 cfgerr++;
3609 }
3610 else if ((curproxy->mode != PR_MODE_HEALTH) && (curproxy->options & PR_O_BALANCE)) {
3611 if (curproxy->options & PR_O_TRANSP) {
3612 Alert("parsing %s : listener %s cannot use both transparent and balance mode.\n",
3613 file, curproxy->id);
3614 cfgerr++;
3615 }
3616 else if (curproxy->srv == NULL) {
3617 Alert("parsing %s : listener %s needs at least 1 server in balance mode.\n",
3618 file, curproxy->id);
3619 cfgerr++;
3620 }
3621 else if (*(int *)&curproxy->dispatch_addr != 0) {
3622 Warning("parsing %s : dispatch address of listener %s will be ignored in balance mode.\n",
3623 file, curproxy->id);
3624 }
3625 }
3626 else if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
willy tarreau0f7af912005-12-17 12:21:26 +01003627 if (curproxy->cookie_name != NULL) {
3628 Warning("parsing %s : cookie will be ignored for listener %s.\n",
3629 file, curproxy->id);
3630 }
3631 if ((newsrv = curproxy->srv) != NULL) {
3632 Warning("parsing %s : servers will be ignored for listener %s.\n",
3633 file, curproxy->id);
3634 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003635 if (curproxy->nb_rspexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003636 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
3637 file, curproxy->id);
3638 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003639 if (curproxy->nb_reqexp) {
willy tarreau0f7af912005-12-17 12:21:26 +01003640 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
3641 file, curproxy->id);
3642 }
3643 }
3644 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
3645 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
3646 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
3647 file, curproxy->id);
3648 cfgerr++;
3649 }
3650 else {
3651 while (newsrv != NULL) {
3652 /* nothing to check for now */
3653 newsrv = newsrv->next;
3654 }
3655 }
3656 }
3657 curproxy = curproxy->next;
3658 }
3659 if (cfgerr > 0) {
3660 Alert("Errors found in configuration file, aborting.\n");
3661 return -1;
3662 }
3663 else
3664 return 0;
3665}
3666
3667
3668/*
3669 * This function initializes all the necessary variables. It only returns
3670 * if everything is OK. If something fails, it exits.
3671 */
3672void init(int argc, char **argv) {
3673 int i;
3674 char *old_argv = *argv;
3675 char *tmp;
3676
3677 if (1<<INTBITS != sizeof(int)*8) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01003678 qfprintf(stderr,
willy tarreau0f7af912005-12-17 12:21:26 +01003679 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
3680 sizeof(int)*8);
3681 exit(1);
3682 }
3683
3684 pid = getpid();
3685 progname = *argv;
3686 while ((tmp = strchr(progname, '/')) != NULL)
3687 progname = tmp + 1;
3688
3689 argc--; argv++;
3690 while (argc > 0) {
3691 char *flag;
3692
3693 if (**argv == '-') {
3694 flag = *argv+1;
3695
3696 /* 1 arg */
3697 if (*flag == 'v') {
3698 display_version();
3699 exit(0);
3700 }
3701 else if (*flag == 'd')
3702 mode |= MODE_DEBUG;
3703 else if (*flag == 'D')
willy tarreau5cbea6f2005-12-17 12:48:26 +01003704 mode |= MODE_DAEMON | MODE_QUIET;
3705 else if (*flag == 'q')
3706 mode |= MODE_QUIET;
willy tarreau0f7af912005-12-17 12:21:26 +01003707#if STATTIME > 0
3708 else if (*flag == 's')
3709 mode |= MODE_STATS;
3710 else if (*flag == 'l')
3711 mode |= MODE_LOG;
3712#endif
3713 else { /* >=2 args */
3714 argv++; argc--;
3715 if (argc == 0)
3716 usage(old_argv);
3717
3718 switch (*flag) {
3719 case 'n' : cfg_maxconn = atol(*argv); break;
3720 case 'N' : cfg_maxpconn = atol(*argv); break;
3721 case 'f' : cfg_cfgfile = *argv; break;
3722 default: usage(old_argv);
3723 }
3724 }
3725 }
3726 else
3727 usage(old_argv);
3728 argv++; argc--;
3729 }
3730
3731 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
3732
3733 if (!cfg_cfgfile)
3734 usage(old_argv);
3735
3736 gethostname(hostname, MAX_HOSTNAME_LEN);
3737
3738 if (readcfgfile(cfg_cfgfile) < 0) {
3739 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
3740 exit(1);
3741 }
3742
3743 ReadEvent = (fd_set *)calloc(1,
3744 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003745 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003746 WriteEvent = (fd_set *)calloc(1,
3747 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003748 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003749 StaticReadEvent = (fd_set *)calloc(1,
3750 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003751 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003752 StaticWriteEvent = (fd_set *)calloc(1,
3753 sizeof(fd_set) *
willy tarreau5cbea6f2005-12-17 12:48:26 +01003754 (cfg_maxsock + FD_SETSIZE - 1) / FD_SETSIZE);
willy tarreau0f7af912005-12-17 12:21:26 +01003755
3756 fdtab = (struct fdtab *)calloc(1,
willy tarreau5cbea6f2005-12-17 12:48:26 +01003757 sizeof(struct fdtab) * (cfg_maxsock));
3758 for (i = 0; i < cfg_maxsock; i++) {
willy tarreau0f7af912005-12-17 12:21:26 +01003759 fdtab[i].state = FD_STCLOSE;
3760 }
3761}
3762
3763/*
3764 * this function starts all the proxies. It returns 0 if OK, -1 if not.
3765 */
3766int start_proxies() {
3767 struct proxy *curproxy;
3768 int one = 1;
3769 int fd;
3770
3771 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
3772
3773 if (curproxy->state == PR_STDISABLED)
3774 continue;
3775
3776 if ((fd = curproxy->listen_fd =
3777 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
3778 Alert("cannot create listening socket for proxy %s. Aborting.\n",
3779 curproxy->id);
3780 return -1;
3781 }
3782
willy tarreau5cbea6f2005-12-17 12:48:26 +01003783 if (fd >= cfg_maxsock) {
3784 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
3785 curproxy->id);
3786 close(fd);
3787 return -1;
3788 }
3789
willy tarreau0f7af912005-12-17 12:21:26 +01003790 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
3791 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
3792 (char *) &one, sizeof(one)) == -1)) {
3793 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
3794 curproxy->id);
3795 close(fd);
3796 return -1;
3797 }
3798
3799 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
3800 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
3801 curproxy->id);
3802 }
3803
3804 if (bind(fd,
3805 (struct sockaddr *)&curproxy->listen_addr,
3806 sizeof(curproxy->listen_addr)) == -1) {
3807 Alert("cannot bind socket for proxy %s. Aborting.\n",
3808 curproxy->id);
3809 close(fd);
3810 return -1;
3811 }
3812
3813 if (listen(fd, curproxy->maxconn) == -1) {
3814 Alert("cannot listen to socket for proxy %s. Aborting.\n",
3815 curproxy->id);
3816 close(fd);
3817 return -1;
3818 }
3819
3820 /* the function for the accept() event */
3821 fdtab[fd].read = &event_accept;
3822 fdtab[fd].write = NULL; /* never called */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003823 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
willy tarreau0f7af912005-12-17 12:21:26 +01003824 curproxy->state = PR_STRUN;
3825 fdtab[fd].state = FD_STLISTEN;
3826 FD_SET(fd, StaticReadEvent);
3827 fd_insert(fd);
3828 listeners++;
3829// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3830 }
3831 return 0;
3832}
3833
3834
3835int main(int argc, char **argv) {
3836 init(argc, argv);
3837
3838 if (mode & MODE_DAEMON) {
3839 int ret;
3840
3841 ret = fork();
3842
3843 if (ret > 0)
3844 exit(0); /* parent must leave */
3845 else if (ret < 0) {
3846 Alert("[%s.main()] Cannot fork\n", argv[0]);
3847 exit(1); /* there has been an error */
3848 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01003849 setpgid(1, 0);
3850 }
willy tarreau0f7af912005-12-17 12:21:26 +01003851
willy tarreau5cbea6f2005-12-17 12:48:26 +01003852 if (mode & MODE_QUIET) {
willy tarreau0f7af912005-12-17 12:21:26 +01003853 /* detach from the tty */
willy tarreau5cbea6f2005-12-17 12:48:26 +01003854 fclose(stdin); fclose(stdout); fclose(stderr);
willy tarreau0f7af912005-12-17 12:21:26 +01003855 close(0); close(1); close(2);
willy tarreau0f7af912005-12-17 12:21:26 +01003856 }
3857
3858 signal(SIGQUIT, dump);
3859 signal(SIGUSR1, sig_soft_stop);
3860
3861 /* on very high loads, a sigpipe sometimes happen just between the
3862 * getsockopt() which tells "it's OK to write", and the following write :-(
3863 */
willy tarreau3242e862005-12-17 12:27:53 +01003864#ifndef MSG_NOSIGNAL
3865 signal(SIGPIPE, SIG_IGN);
3866#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003867
3868 if (start_proxies() < 0)
3869 exit(1);
3870
3871 select_loop();
3872
3873 exit(0);
3874}