blob: 9c9d65944139ae8e9253e54928ac556affca2ea5 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01002 * HA-Proxy : High Availability-enabled HTTP/TCP proxy
3 * 2000-2002 - Willy Tarreau - willy AT meta-x DOT org.
willy tarreau0f7af912005-12-17 12:21:26 +01004 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
willy tarreauef900ab2005-12-17 12:52:52 +010010 * Pending bugs :
11 * - cookie in insert+indirect mode sometimes segfaults !
12 * - a proxy with an invalid config will prevent the startup even if disabled.
13 *
willy tarreau0f7af912005-12-17 12:21:26 +010014 * ChangeLog :
15 *
willy tarreaue47c8d72005-12-17 12:55:52 +010016 * 2002/03/25
17 * - released 1.1.4
18 * - made rise/fall/interval time configurable
willy tarreaub719f002005-12-17 12:55:07 +010019 * 2002/03/22
20 * - released 1.1.3
21 * - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
22 * which could lead to loops.
willy tarreauef900ab2005-12-17 12:52:52 +010023 * 2002/03/21
24 * - released 1.1.2
25 * - fixed a bug in buffer management where we could have a loop
26 * between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
27 * => implemented an adjustable buffer limit.
28 * - fixed a bug : expiration of tasks in wait queue timeout is used again,
29 * and running tasks are skipped.
30 * - added some debug lines for accept events.
31 * - send warnings for servers up/down.
willy tarreauefae1842005-12-17 12:51:03 +010032 * 2002/03/12
33 * - released 1.1.1
34 * - fixed a bug in total failure handling
35 * - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
willy tarreau5cbea6f2005-12-17 12:48:26 +010036 * 2002/03/10
37 * - released 1.1.0
38 * - fixed a few timeout bugs
39 * - rearranged the task scheduler subsystem to improve performance,
40 * add new tasks, and make it easier to later port to librt ;
41 * - allow multiple accept() for one select() wake up ;
42 * - implemented internal load balancing with basic health-check ;
43 * - cookie insertion and header add/replace/delete, with better strings
44 * support.
45 * 2002/03/08
46 * - reworked buffer handling to fix a few rewrite bugs, and
47 * improve overall performance.
48 * - implement the "purge" option to delete server cookies in direct mode.
49 * 2002/03/07
50 * - fixed some error cases where the maxfd was not decreased.
51 * 2002/02/26
52 * - now supports transparent proxying, at least on linux 2.4.
53 * 2002/02/12
54 * - soft stop works again (fixed select timeout computation).
55 * - it seems that TCP proxies sometimes cannot timeout.
56 * - added a "quiet" mode.
57 * - enforce file descriptor limitation on socket() and accept().
58 * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010059 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010060 * 2001/12/16 : release of version 1.0.0.
61 * 2001/12/16 : added syslog capability for each accepted connection.
62 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
63 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
64 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
65 * with or without cookies (use keyword http for this).
66 * 2001/09/01 : added client/server header replacing with regexps.
67 * eg:
68 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
69 * srvexp ^Server:\ .* Server:\ Apache
70 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
71 * 2000/11/28 : major rewrite
72 * 2000/11/26 : first write
73 *
willy tarreau5cbea6f2005-12-17 12:48:26 +010074 * TODO:
75 * - handle properly intermediate incomplete server headers. Done ?
76 * - log proxies start/stop
77 * - handle hot-reconfiguration
willy tarreau0f7af912005-12-17 12:21:26 +010078 *
79 */
80
81#include <stdio.h>
82#include <stdlib.h>
83#include <unistd.h>
84#include <string.h>
85#include <ctype.h>
86#include <sys/time.h>
87#include <sys/types.h>
88#include <sys/socket.h>
89#include <netinet/tcp.h>
90#include <netinet/in.h>
91#include <arpa/inet.h>
92#include <netdb.h>
93#include <fcntl.h>
94#include <errno.h>
95#include <signal.h>
96#include <stdarg.h>
97#include <sys/resource.h>
98#include <time.h>
99#include <regex.h>
100#include <syslog.h>
willy tarreau5cbea6f2005-12-17 12:48:26 +0100101#if defined(TRANSPARENT) && defined(NETFILTER)
102#include <linux/netfilter_ipv4.h>
103#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100104
willy tarreaue47c8d72005-12-17 12:55:52 +0100105#define HAPROXY_VERSION "1.1.4"
106#define HAPROXY_DATE "2002/03/25"
willy tarreau0f7af912005-12-17 12:21:26 +0100107
108/* this is for libc5 for example */
109#ifndef TCP_NODELAY
110#define TCP_NODELAY 1
111#endif
112
113#ifndef SHUT_RD
114#define SHUT_RD 0
115#endif
116
117#ifndef SHUT_WR
118#define SHUT_WR 1
119#endif
120
121#define BUFSIZE 4096
122
123// reserved buffer space for header rewriting
124#define MAXREWRITE 256
125
willy tarreau5cbea6f2005-12-17 12:48:26 +0100126// max # args on a configuration line
127#define MAX_LINE_ARGS 10
128
willy tarreau0f7af912005-12-17 12:21:26 +0100129// max # of regexps per proxy
130#define MAX_REGEXP 10
131
132// max # of matches per regexp
133#define MAX_MATCH 10
134
willy tarreau5cbea6f2005-12-17 12:48:26 +0100135/* FIXME: serverid_len and cookiename_len are no longer checked in configuration file */
willy tarreau0f7af912005-12-17 12:21:26 +0100136#define COOKIENAME_LEN 16
137#define SERVERID_LEN 16
138#define CONN_RETRIES 3
139
willy tarreau5cbea6f2005-12-17 12:48:26 +0100140/* FIXME: this should be user-configurable */
141#define CHK_CONNTIME 2000
willy tarreaue47c8d72005-12-17 12:55:52 +0100142#define DEF_CHKINTR 2000
143#define DEF_FALLTIME 3
144#define DEF_RISETIME 2
willy tarreau5cbea6f2005-12-17 12:48:26 +0100145
willy tarreau0f7af912005-12-17 12:21:26 +0100146/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
147#define INTBITS 5
148
149/* show stats this every millisecond, 0 to disable */
150#ifndef STATTIME
151#define STATTIME 2000
152#endif
153
willy tarreau5cbea6f2005-12-17 12:48:26 +0100154/* this reduces the number of calls to select() by choosing appropriate
155 * sheduler precision in milliseconds. It should be near the minimum
156 * time that is needed by select() to collect all events. All timeouts
157 * are rounded up by adding this value prior to pass it to select().
158 */
159#define SCHEDULER_RESOLUTION 9
160
willy tarreau0f7af912005-12-17 12:21:26 +0100161#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
162#define SETNOW(a) (*a=now)
163
willy tarreau9da061b2005-12-17 12:29:56 +0100164/****** string-specific macros and functions ******/
165/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
166#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
167
168/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
169#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
170
171
172#ifndef HAVE_STRLCPY
173/*
174 * copies at most <size-1> chars from <src> to <dst>. Last char is always
175 * set to 0, unless <size> is 0. The number of chars copied is returned
176 * (excluding the terminating zero).
177 * This code has been optimized for size and speed : on x86, it's 45 bytes
178 * long, uses only registers, and consumes only 4 cycles per char.
179 */
180int strlcpy(char *dst, const char *src, int size) {
181 char *orig = dst;
182 if (size) {
183 while (--size && (*dst = *src)) {
184 src++; dst++;
185 }
186 *dst = 0;
187 }
188 return dst - orig;
189}
190#endif
191
192
willy tarreau0f7af912005-12-17 12:21:26 +0100193#define MEM_OPTIM
194#ifdef MEM_OPTIM
195/*
196 * Returns a pointer to type <type> taken from the
197 * pool <pool_type> or dynamically allocated. In the
198 * first case, <pool_type> is updated to point to the
199 * next element in the list.
200 */
201#define pool_alloc(type) ({ \
202 void *p; \
203 if ((p = pool_##type) == NULL) \
204 p = malloc(sizeof_##type); \
205 else { \
206 pool_##type = *(void **)pool_##type; \
207 } \
208 p; \
209})
210
211/*
212 * Puts a memory area back to the corresponding pool.
213 * Items are chained directly through a pointer that
214 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100215 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100216 * that each memory area is at least as big as one
217 * pointer.
218 */
219#define pool_free(type, ptr) ({ \
220 *(void **)ptr = (void *)pool_##type; \
221 pool_##type = (void *)ptr; \
222})
223
224#else
225#define pool_alloc(type) (calloc(1,sizeof_##type));
226#define pool_free(type, ptr) (free(ptr));
227#endif /* MEM_OPTIM */
228
willy tarreau5cbea6f2005-12-17 12:48:26 +0100229#define sizeof_task sizeof(struct task)
230#define sizeof_session sizeof(struct session)
willy tarreau0f7af912005-12-17 12:21:26 +0100231#define sizeof_buffer sizeof(struct buffer)
232#define sizeof_fdtab sizeof(struct fdtab)
233#define sizeof_str256 256
234
235
willy tarreau5cbea6f2005-12-17 12:48:26 +0100236/* different possible states for the sockets */
willy tarreau0f7af912005-12-17 12:21:26 +0100237#define FD_STCLOSE 0
238#define FD_STLISTEN 1
239#define FD_STCONN 2
240#define FD_STREADY 3
241#define FD_STERROR 4
242
willy tarreau5cbea6f2005-12-17 12:48:26 +0100243/* values for task->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100244#define TASK_IDLE 0
245#define TASK_RUNNING 1
246
willy tarreau5cbea6f2005-12-17 12:48:26 +0100247/* values for proxy->state */
willy tarreau0f7af912005-12-17 12:21:26 +0100248#define PR_STNEW 0
249#define PR_STIDLE 1
250#define PR_STRUN 2
251#define PR_STDISABLED 3
252
willy tarreau5cbea6f2005-12-17 12:48:26 +0100253/* values for proxy->mode */
willy tarreau0f7af912005-12-17 12:21:26 +0100254#define PR_MODE_TCP 0
255#define PR_MODE_HTTP 1
256#define PR_MODE_HEALTH 2
257
willy tarreau5cbea6f2005-12-17 12:48:26 +0100258/* bits for proxy->options */
259#define PR_O_REDISP 1 /* allow reconnection to dispatch in case of errors */
260#define PR_O_TRANSP 2 /* transparent mode : use original DEST as dispatch */
261#define PR_O_COOK_RW 4 /* rewrite all direct cookies with the right serverid */
262#define PR_O_COOK_IND 8 /* keep only indirect cookies */
263#define PR_O_COOK_INS 16 /* insert cookies when not accessing a server directly */
264#define PR_O_COOK_ANY (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS)
265#define PR_O_BALANCE_RR 32 /* balance in round-robin mode */
266#define PR_O_BALANCE (PR_O_BALANCE_RR)
267
268/* various task flags */
269#define TF_DIRECT 1 /* connection made on the server matching the client cookie */
270
271/* different possible states for the client side */
willy tarreau0f7af912005-12-17 12:21:26 +0100272#define CL_STHEADERS 0
273#define CL_STDATA 1
274#define CL_STSHUTR 2
275#define CL_STSHUTW 3
276#define CL_STCLOSE 4
277
willy tarreau5cbea6f2005-12-17 12:48:26 +0100278/* different possible states for the server side */
willy tarreau0f7af912005-12-17 12:21:26 +0100279#define SV_STIDLE 0
280#define SV_STCONN 1
281#define SV_STHEADERS 2
282#define SV_STDATA 3
283#define SV_STSHUTR 4
284#define SV_STSHUTW 5
285#define SV_STCLOSE 6
286
287/* result of an I/O event */
288#define RES_SILENT 0 /* didn't happen */
289#define RES_DATA 1 /* data were sent or received */
290#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
291#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
292
willy tarreau5cbea6f2005-12-17 12:48:26 +0100293/* modes of operation (global variable "mode") */
willy tarreau0f7af912005-12-17 12:21:26 +0100294#define MODE_DEBUG 1
295#define MODE_STATS 2
296#define MODE_LOG 4
297#define MODE_DAEMON 8
willy tarreau5cbea6f2005-12-17 12:48:26 +0100298#define MODE_QUIET 16
299
300/* server flags */
301#define SRV_RUNNING 1
willy tarreau0f7af912005-12-17 12:21:26 +0100302
303/*********************************************************************/
304
305#define LIST_HEAD(a) ((void *)(&(a)))
306
307/*********************************************************************/
308
309struct hdr_exp {
310 regex_t *preg; /* expression to look for */
311 char *replace; /* expression to set instead */
312};
313
314struct buffer {
315 unsigned int l; /* data length */
316 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
willy tarreauef900ab2005-12-17 12:52:52 +0100317 char *rlim; /* read limit, used for header rewriting */
willy tarreau0f7af912005-12-17 12:21:26 +0100318 char data[BUFSIZE];
319};
320
321struct server {
322 struct server *next;
willy tarreau5cbea6f2005-12-17 12:48:26 +0100323 int state; /* server state (SRV_*) */
324 int cklen; /* the len of the cookie, to speed up checks */
325 char *cookie; /* the id set in the cookie */
326 char *id; /* just for identification */
willy tarreau0f7af912005-12-17 12:21:26 +0100327 struct sockaddr_in addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100328 int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
willy tarreaue47c8d72005-12-17 12:55:52 +0100329 int rise, fall; /* time in iterations */
330 int inter; /* time in milliseconds */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100331 int result; /* 0 = connect OK, -1 = connect KO */
332 int curfd; /* file desc used for current test, or -1 if not in test */
willy tarreau0f7af912005-12-17 12:21:26 +0100333};
334
willy tarreau5cbea6f2005-12-17 12:48:26 +0100335/* The base for all tasks */
willy tarreau0f7af912005-12-17 12:21:26 +0100336struct task {
337 struct task *next, *prev; /* chaining ... */
338 struct task *rqnext; /* chaining in run queue ... */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100339 struct task *wq; /* the wait queue this task is in */
willy tarreau0f7af912005-12-17 12:21:26 +0100340 int state; /* task state : IDLE or RUNNING */
341 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100342 int (*process)(struct task *t); /* the function which processes the task */
343 void *context; /* the task's context */
344};
345
346/* WARNING: if new fields are added, they must be initialized in event_accept() */
347struct session {
348 struct task *task; /* the task associated with this session */
willy tarreau0f7af912005-12-17 12:21:26 +0100349 /* application specific below */
350 struct timeval crexpire; /* expiration date for a client read */
351 struct timeval cwexpire; /* expiration date for a client write */
352 struct timeval srexpire; /* expiration date for a server read */
353 struct timeval swexpire; /* expiration date for a server write */
354 struct timeval cnexpire; /* expiration date for a connect */
355 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
356 struct proxy *proxy; /* the proxy this socket belongs to */
357 int cli_fd; /* the client side fd */
358 int srv_fd; /* the server side fd */
359 int cli_state; /* state of the client side */
360 int srv_state; /* state of the server side */
361 int conn_retries; /* number of connect retries left */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100362 int flags; /* some flags describing the session */
willy tarreau0f7af912005-12-17 12:21:26 +0100363 struct buffer *req; /* request buffer */
364 struct buffer *rep; /* response buffer */
365 struct sockaddr_in cli_addr; /* the client address */
366 struct sockaddr_in srv_addr; /* the address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100367 struct server *srv; /* the server being used */
willy tarreau0f7af912005-12-17 12:21:26 +0100368};
369
370struct proxy {
371 int listen_fd; /* the listen socket */
372 int state; /* proxy state */
373 struct sockaddr_in listen_addr; /* the address we listen to */
374 struct sockaddr_in dispatch_addr; /* the default address to connect to */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100375 struct server *srv, *cursrv; /* known servers, current server */
376 int nbservers; /* # of servers */
willy tarreau0f7af912005-12-17 12:21:26 +0100377 char *cookie_name; /* name of the cookie to look for */
378 int clitimeout; /* client I/O timeout (in milliseconds) */
379 int srvtimeout; /* server I/O timeout (in milliseconds) */
380 int contimeout; /* connect timeout (in milliseconds) */
381 char *id; /* proxy id */
382 int nbconn; /* # of active sessions */
383 int maxconn; /* max # of active sessions */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100384 int conn_retries; /* maximum number of connect retries */
385 int options; /* PR_O_REDISP, PR_O_TRANSP */
386 int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
willy tarreau0f7af912005-12-17 12:21:26 +0100387 struct proxy *next;
388 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
389 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
390 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100391 int nb_reqexp, nb_rspexp, nb_reqadd, nb_rspadd;
392 struct hdr_exp req_exp[MAX_REGEXP]; /* regular expressions for request headers */
393 struct hdr_exp rsp_exp[MAX_REGEXP]; /* regular expressions for response headers */
394 char *req_add[MAX_REGEXP], *rsp_add[MAX_REGEXP]; /* headers to be added */
willy tarreau0f7af912005-12-17 12:21:26 +0100395 int grace; /* grace time after stop request */
396};
397
398/* info about one given fd */
399struct fdtab {
400 int (*read)(int fd); /* read function */
401 int (*write)(int fd); /* write function */
402 struct task *owner; /* the session (or proxy) associated with this fd */
403 int state; /* the state of this fd */
404};
405
406/*********************************************************************/
407
408int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
409int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
410int cfg_maxsock = 0; /* max # of sockets */
411char *cfg_cfgfile = NULL; /* configuration file */
412char *progname = NULL; /* program name */
413int pid; /* current process id */
414/*********************************************************************/
415
416fd_set *ReadEvent,
417 *WriteEvent,
418 *StaticReadEvent,
419 *StaticWriteEvent;
420
421void **pool_session = NULL,
422 **pool_buffer = NULL,
423 **pool_fdtab = NULL,
willy tarreau5cbea6f2005-12-17 12:48:26 +0100424 **pool_str256 = NULL,
425 **pool_task = NULL;
willy tarreau0f7af912005-12-17 12:21:26 +0100426
427struct proxy *proxy = NULL; /* list of all existing proxies */
428struct fdtab *fdtab = NULL; /* array of all the file descriptors */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100429struct task *rq = NULL; /* global run queue */
430struct task wait_queue = { /* global wait queue */
431 prev:LIST_HEAD(wait_queue),
432 next:LIST_HEAD(wait_queue)
433};
willy tarreau0f7af912005-12-17 12:21:26 +0100434
435static int mode = 0; /* MODE_DEBUG, ... */
436static int totalconn = 0; /* total # of terminated sessions */
437static int actconn = 0; /* # of active sessions */
438static int maxfd = 0; /* # of the highest fd + 1 */
439static int listeners = 0; /* # of listeners */
440static int stopping = 0; /* non zero means stopping in progress */
441static struct timeval now = {0,0}; /* the current date at any moment */
442
443static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
444static char trash[BUFSIZE];
445
446/*
447 * Syslog facilities and levels
448 */
449
450#define MAX_SYSLOG_LEN 1024
451#define NB_LOG_FACILITIES 24
452const char *log_facilities[NB_LOG_FACILITIES] = {
453 "kern", "user", "mail", "daemon",
454 "auth", "syslog", "lpr", "news",
455 "uucp", "cron", "auth2", "ftp",
456 "ntp", "audit", "alert", "cron2",
457 "local0", "local1", "local2", "local3",
458 "local4", "local5", "local6", "local7"
459};
460
461
462#define NB_LOG_LEVELS 8
463const char *log_levels[NB_LOG_LEVELS] = {
464 "emerg", "alert", "crit", "err",
465 "warning", "notice", "info", "debug"
466};
467
468#define SYSLOG_PORT 514
469
470const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
471 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
472#define MAX_HOSTNAME_LEN 32
473static char hostname[MAX_HOSTNAME_LEN] = "";
474
475/*********************************************************************/
476/* statistics ******************************************************/
477/*********************************************************************/
478
479static int stats_tsk_lsrch, stats_tsk_rsrch,
480 stats_tsk_good, stats_tsk_right, stats_tsk_left,
481 stats_tsk_new, stats_tsk_nsrch;
482
483
484/*********************************************************************/
485/* function prototypes *********************************************/
486/*********************************************************************/
487
488int event_accept(int fd);
489int event_cli_read(int fd);
490int event_cli_write(int fd);
491int event_srv_read(int fd);
492int event_srv_write(int fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100493int process_session(struct task *t);
willy tarreau0f7af912005-12-17 12:21:26 +0100494
495/*********************************************************************/
496/* general purpose functions ***************************************/
497/*********************************************************************/
498
499void display_version() {
500 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
willy tarreau5cbea6f2005-12-17 12:48:26 +0100501 printf("Copyright 2000-2002 Willy Tarreau <willy AT meta-x DOT org>\n\n");
willy tarreau0f7af912005-12-17 12:21:26 +0100502}
503
504/*
505 * This function prints the command line usage and exits
506 */
507void usage(char *name) {
508 display_version();
509 fprintf(stderr,
510 "Usage : %s -f <cfgfile> [ -vd"
511#if STATTIME > 0
512 "sl"
513#endif
514 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
515 " -v displays version\n"
516 " -d enters debug mode\n"
517#if STATTIME > 0
518 " -s enables statistics output\n"
519 " -l enables long statistics format\n"
520#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +0100521 " -D goes daemon ; implies -q\n"
522 " -q quiet mode : don't display messages\n"
willy tarreau0f7af912005-12-17 12:21:26 +0100523 " -n sets the maximum total # of connections (%d)\n"
524 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
525 name, cfg_maxconn, cfg_maxpconn);
526 exit(1);
527}
528
529
530/*
531 * Displays the message on stderr with the date and pid.
532 */
533void Alert(char *fmt, ...) {
534 va_list argp;
535 struct timeval tv;
536 struct tm *tm;
537
willy tarreau5cbea6f2005-12-17 12:48:26 +0100538 if (!(mode & MODE_QUIET)) {
539 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100540
willy tarreau5cbea6f2005-12-17 12:48:26 +0100541 gettimeofday(&tv, NULL);
542 tm=localtime(&tv.tv_sec);
543 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
544 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
545 vfprintf(stderr, fmt, argp);
546 fflush(stderr);
547 va_end(argp);
548 }
willy tarreau0f7af912005-12-17 12:21:26 +0100549}
550
551
552/*
553 * Displays the message on stderr with the date and pid.
554 */
555void Warning(char *fmt, ...) {
556 va_list argp;
557 struct timeval tv;
558 struct tm *tm;
559
willy tarreau5cbea6f2005-12-17 12:48:26 +0100560 if (!(mode & MODE_QUIET)) {
561 va_start(argp, fmt);
willy tarreau0f7af912005-12-17 12:21:26 +0100562
willy tarreau5cbea6f2005-12-17 12:48:26 +0100563 gettimeofday(&tv, NULL);
564 tm=localtime(&tv.tv_sec);
565 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
566 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
567 vfprintf(stderr, fmt, argp);
568 fflush(stderr);
569 va_end(argp);
570 }
571}
572
573/*
574 * Displays the message on <out> only if quiet mode is not set.
575 */
576void qfprintf(FILE *out, char *fmt, ...) {
577 va_list argp;
578
579 if (!(mode & MODE_QUIET)) {
580 va_start(argp, fmt);
581 vfprintf(out, fmt, argp);
582 fflush(out);
583 va_end(argp);
584 }
willy tarreau0f7af912005-12-17 12:21:26 +0100585}
586
587
588/*
589 * converts <str> to a struct sockaddr_in* which is locally allocated.
590 * The format is "addr:port", where "addr" can be empty or "*" to indicate
591 * INADDR_ANY.
592 */
593struct sockaddr_in *str2sa(char *str) {
594 static struct sockaddr_in sa;
595 char *c;
596 int port;
597
598 bzero(&sa, sizeof(sa));
599 str=strdup(str);
600
601 if ((c=strrchr(str,':')) != NULL) {
602 *c++=0;
603 port=atol(c);
604 }
605 else
606 port=0;
607
608 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
609 sa.sin_addr.s_addr = INADDR_ANY;
610 }
611 else if (
612#ifndef SOLARIS
613 !inet_aton(str, &sa.sin_addr)
614#else
615 !inet_pton(AF_INET, str, &sa.sin_addr)
616#endif
617 ) {
618 struct hostent *he;
619
620 if ((he = gethostbyname(str)) == NULL) {
willy tarreauef900ab2005-12-17 12:52:52 +0100621 Alert("Invalid server name: <%s>\n", str);
willy tarreau0f7af912005-12-17 12:21:26 +0100622 }
623 else
624 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
625 }
626 sa.sin_port=htons(port);
627 sa.sin_family=AF_INET;
628
629 free(str);
630 return &sa;
631}
632
633/*
634 * This function tries to send a syslog message to the syslog server at
635 * address <sa>. It doesn't care about errors nor does it report them.
636 * WARNING! no check is made on the prog+hostname+date length, so the
637 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
638 * the message will be truncated to fit the maximum length.
639 */
640void send_syslog(struct sockaddr_in *sa,
641 int facility, int level, char *message)
642{
643
644 static int logfd = -1; /* syslog UDP socket */
645 struct timeval tv;
646 struct tm *tm;
647 static char logmsg[MAX_SYSLOG_LEN];
648 char *p;
649
650 if (logfd < 0) {
651 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
652 return;
653 }
654
655 if (facility < 0 || level < 0
656 || sa == NULL || progname == NULL || message == NULL)
657 return;
658
659 gettimeofday(&tv, NULL);
660 tm = localtime(&tv.tv_sec);
661
662 p = logmsg;
663 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
664 // facility * 8 + level,
665 // monthname[tm->tm_mon],
666 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
667 // hostname, progname, pid);
668 /* 20011216/WT : other progs don't set the hostname, and syslogd
669 * systematically repeats it which is contrary to RFC3164.
670 */
671 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
672 facility * 8 + level,
673 monthname[tm->tm_mon],
674 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
675 progname, pid);
676
677 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
678 int len = strlen(message);
679 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
680 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
681 memcpy(p, message, len);
682 p += len;
683 }
willy tarreau3242e862005-12-17 12:27:53 +0100684#ifndef MSG_NOSIGNAL
685 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
686 (struct sockaddr *)sa, sizeof(*sa));
687#else
willy tarreau0f7af912005-12-17 12:21:26 +0100688 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
689 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100690#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100691}
692
693
694/* sets <tv> to the current time */
695static inline struct timeval *tv_now(struct timeval *tv) {
696 if (tv)
697 gettimeofday(tv, NULL);
698 return tv;
699}
700
701/*
702 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
703 */
704static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
705 if (!tv || !from)
706 return NULL;
707 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
708 tv->tv_sec = from->tv_sec + (ms/1000);
709 while (tv->tv_usec >= 1000000) {
710 tv->tv_usec -= 1000000;
711 tv->tv_sec++;
712 }
713 return tv;
714}
715
716/*
717 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
718 */
719static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
720 if (tv1->tv_sec > tv2->tv_sec)
721 return 1;
722 else if (tv1->tv_sec < tv2->tv_sec)
723 return -1;
724 else if (tv1->tv_usec > tv2->tv_usec)
725 return 1;
726 else if (tv1->tv_usec < tv2->tv_usec)
727 return -1;
728 else
729 return 0;
730}
731
732/*
733 * returns the absolute difference, in ms, between tv1 and tv2
734 */
735unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
736 int cmp;
737 unsigned long ret;
738
739
willy tarreauef900ab2005-12-17 12:52:52 +0100740 cmp = tv_cmp(tv1, tv2);
willy tarreau0f7af912005-12-17 12:21:26 +0100741 if (!cmp)
742 return 0; /* same dates, null diff */
743 else if (cmp<0) {
willy tarreauef900ab2005-12-17 12:52:52 +0100744 struct timeval *tmp = tv1;
745 tv1 = tv2;
746 tv2 = tmp;
willy tarreau0f7af912005-12-17 12:21:26 +0100747 }
willy tarreauef900ab2005-12-17 12:52:52 +0100748 ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100749 if (tv1->tv_usec > tv2->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100750 ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100751 else
willy tarreauef900ab2005-12-17 12:52:52 +0100752 ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100753 return (unsigned long) ret;
754}
755
756/*
757 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
758 */
759static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
willy tarreauefae1842005-12-17 12:51:03 +0100760 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100761 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100762 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100763 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100764 return -1;
765 else
766 return 0;
767 }
768 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100769 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100770 return 1;
771 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100772 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100773 return -1;
774 else
775 return 0;
776}
777
778/*
779 * returns the remaining time between tv1=now and event=tv2
780 * if tv2 is passed, 0 is returned.
781 */
782static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
783 unsigned long ret;
784
willy tarreau0f7af912005-12-17 12:21:26 +0100785 if (tv_cmp_ms(tv1, tv2) >= 0)
786 return 0; /* event elapsed */
787
willy tarreauef900ab2005-12-17 12:52:52 +0100788 ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100789 if (tv2->tv_usec > tv1->tv_usec)
willy tarreauef900ab2005-12-17 12:52:52 +0100790 ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100791 else
willy tarreauef900ab2005-12-17 12:52:52 +0100792 ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
willy tarreau0f7af912005-12-17 12:21:26 +0100793 return (unsigned long) ret;
794}
795
796
797/*
798 * zeroes a struct timeval
799 */
800
801static inline struct timeval *tv_eternity(struct timeval *tv) {
802 tv->tv_sec = tv->tv_usec = 0;
803 return tv;
804}
805
806/*
807 * returns 1 if tv is null, else 0
808 */
809static inline int tv_iseternity(struct timeval *tv) {
810 if (tv->tv_sec == 0 && tv->tv_usec == 0)
811 return 1;
812 else
813 return 0;
814}
815
816/*
817 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
818 * considering that 0 is the eternity.
819 */
820static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
821 if (tv_iseternity(tv1))
822 if (tv_iseternity(tv2))
823 return 0; /* same */
824 else
825 return 1; /* tv1 later than tv2 */
826 else if (tv_iseternity(tv2))
827 return -1; /* tv2 later than tv1 */
828
829 if (tv1->tv_sec > tv2->tv_sec)
830 return 1;
831 else if (tv1->tv_sec < tv2->tv_sec)
832 return -1;
833 else if (tv1->tv_usec > tv2->tv_usec)
834 return 1;
835 else if (tv1->tv_usec < tv2->tv_usec)
836 return -1;
837 else
838 return 0;
839}
840
841/*
842 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
843 * considering that 0 is the eternity.
844 */
845static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
846 if (tv_iseternity(tv1))
847 if (tv_iseternity(tv2))
848 return 0; /* same */
849 else
850 return 1; /* tv1 later than tv2 */
851 else if (tv_iseternity(tv2))
852 return -1; /* tv2 later than tv1 */
853
willy tarreauefae1842005-12-17 12:51:03 +0100854 if (tv1->tv_sec == tv2->tv_sec) {
willy tarreauef900ab2005-12-17 12:52:52 +0100855 if (tv1->tv_usec > tv2->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100856 return 1;
willy tarreauef900ab2005-12-17 12:52:52 +0100857 else if (tv2->tv_usec > tv1->tv_usec + 1000)
willy tarreauefae1842005-12-17 12:51:03 +0100858 return -1;
859 else
860 return 0;
861 }
862 else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100863 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100864 return 1;
865 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
willy tarreauef900ab2005-12-17 12:52:52 +0100866 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
willy tarreau0f7af912005-12-17 12:21:26 +0100867 return -1;
868 else
869 return 0;
870}
871
872/*
873 * returns the first event between tv1 and tv2 into tvmin.
874 * a zero tv is ignored. tvmin is returned.
875 */
876static inline struct timeval *tv_min(struct timeval *tvmin,
877 struct timeval *tv1, struct timeval *tv2) {
878
879 if (tv_cmp2(tv1, tv2) <= 0)
880 *tvmin = *tv1;
881 else
882 *tvmin = *tv2;
883
884 return tvmin;
885}
886
887
888
889/***********************************************************/
890/* fd management ***************************************/
891/***********************************************************/
892
893
894
willy tarreau5cbea6f2005-12-17 12:48:26 +0100895/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
896 * The file descriptor is also closed.
897 */
willy tarreau0f7af912005-12-17 12:21:26 +0100898static inline void fd_delete(int fd) {
willy tarreau0f7af912005-12-17 12:21:26 +0100899 FD_CLR(fd, StaticReadEvent);
900 FD_CLR(fd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +0100901 close(fd);
902 fdtab[fd].state = FD_STCLOSE;
willy tarreau0f7af912005-12-17 12:21:26 +0100903
904 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
905 maxfd--;
906}
907
908/* recomputes the maxfd limit from the fd */
909static inline void fd_insert(int fd) {
910 if (fd+1 > maxfd)
911 maxfd = fd+1;
912}
913
914/*************************************************************/
915/* task management ***************************************/
916/*************************************************************/
917
willy tarreau5cbea6f2005-12-17 12:48:26 +0100918/* puts the task <t> in run queue <q>, and returns <t> */
919static inline struct task *task_wakeup(struct task **q, struct task *t) {
920 if (t->state == TASK_RUNNING)
921 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100922 else {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100923 t->rqnext = *q;
924 t->state = TASK_RUNNING;
925 return *q = t;
willy tarreau0f7af912005-12-17 12:21:26 +0100926 }
927}
928
willy tarreau5cbea6f2005-12-17 12:48:26 +0100929/* removes the task <t> from the queue <q>
930 * <s> MUST be <q>'s first task.
willy tarreau0f7af912005-12-17 12:21:26 +0100931 * set the run queue to point to the next one, and return it
932 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100933static inline struct task *task_sleep(struct task **q, struct task *t) {
934 if (t->state == TASK_RUNNING) {
935 *q = t->rqnext;
936 t->state = TASK_IDLE; /* tell that s has left the run queue */
willy tarreau0f7af912005-12-17 12:21:26 +0100937 }
willy tarreau5cbea6f2005-12-17 12:48:26 +0100938 return *q; /* return next running task */
willy tarreau0f7af912005-12-17 12:21:26 +0100939}
940
941/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100942 * removes the task <t> from its wait queue. It must have already been removed
willy tarreau0f7af912005-12-17 12:21:26 +0100943 * from the run queue. A pointer to the task itself is returned.
944 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100945static inline struct task *task_delete(struct task *t) {
946 t->prev->next = t->next;
947 t->next->prev = t->prev;
948 return t;
willy tarreau0f7af912005-12-17 12:21:26 +0100949}
950
951/*
willy tarreau5cbea6f2005-12-17 12:48:26 +0100952 * frees a task. Its context must have been freed since it will be lost.
willy tarreau0f7af912005-12-17 12:21:26 +0100953 */
954static inline void task_free(struct task *t) {
willy tarreau5cbea6f2005-12-17 12:48:26 +0100955 pool_free(task, t);
willy tarreau0f7af912005-12-17 12:21:26 +0100956}
957
willy tarreau5cbea6f2005-12-17 12:48:26 +0100958/* inserts <task> into its assigned wait queue, where it may already be. In this case, it
willy tarreau0f7af912005-12-17 12:21:26 +0100959 * may be only moved or left where it was, depending on its timing requirements.
960 * <task> is returned.
961 */
willy tarreau5cbea6f2005-12-17 12:48:26 +0100962struct task *task_queue(struct task *task) {
963 struct task *list = task->wq;
willy tarreau0f7af912005-12-17 12:21:26 +0100964 struct task *start_from;
965
966 /* first, test if the task was already in a list */
967 if (task->prev == NULL) {
968 // start_from = list;
969 start_from = list->prev;
970 stats_tsk_new++;
971
972 /* insert the unlinked <task> into the list, searching back from the last entry */
973 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
974 start_from = start_from->prev;
975 stats_tsk_nsrch++;
976 }
977
978 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
979 // start_from = start_from->next;
980 // stats_tsk_nsrch++;
981 // }
982 }
983 else if (task->prev == list ||
984 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
985 start_from = task->next;
986 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
987 stats_tsk_good++;
988 return task; /* it's already in the right place */
989 }
990
991 stats_tsk_right++;
992 /* insert the unlinked <task> into the list, searching after position <start_from> */
993 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
994 start_from = start_from->next;
995 stats_tsk_rsrch++;
996 }
997 /* we need to unlink it now */
998 task_delete(task);
999 }
1000 else { /* walk left. */
1001 stats_tsk_left++;
1002#ifdef LEFT_TO_TOP /* not very good */
1003 start_from = list;
1004 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
1005 start_from = start_from->next;
1006 stats_tsk_lsrch++;
1007 }
1008#else
1009 start_from = task->prev->prev; /* valid because of the previous test above */
1010 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
1011 start_from = start_from->prev;
1012 stats_tsk_lsrch++;
1013 }
1014#endif
1015 /* we need to unlink it now */
1016 task_delete(task);
1017 }
1018 task->prev = start_from;
1019 task->next = start_from->next;
1020 task->next->prev = task;
1021 start_from->next = task;
1022 return task;
1023}
1024
1025
1026/*********************************************************************/
1027/* more specific functions ***************************************/
1028/*********************************************************************/
1029
1030/* some prototypes */
1031static int maintain_proxies(void);
1032
willy tarreau5cbea6f2005-12-17 12:48:26 +01001033/* this either returns the sockname or the original destination address. Code
1034 * inspired from Patrick Schaaf's example of nf_getsockname() implementation.
1035 */
1036static int get_original_dst(int fd, struct sockaddr_in *sa, int *salen) {
1037#if defined(TRANSPARENT) && defined(SO_ORIGINAL_DST)
1038 return getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, (void *)sa, salen);
1039#else
1040#if defined(TRANSPARENT) && defined(USE_GETSOCKNAME)
1041 return getsockname(fd, (struct sockaddr *)sa, salen);
1042#else
1043 return -1;
1044#endif
1045#endif
1046}
1047
1048/*
1049 * frees the context associated to a session. It must have been removed first.
1050 */
1051static inline void session_free(struct session *s) {
1052 if (s->req)
1053 pool_free(buffer, s->req);
1054 if (s->rep)
1055 pool_free(buffer, s->rep);
1056 pool_free(session, s);
1057}
1058
willy tarreau0f7af912005-12-17 12:21:26 +01001059
1060/*
willy tarreau5cbea6f2005-12-17 12:48:26 +01001061 * This function initiates a connection to the current server (s->srv) if (s->direct)
1062 * is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
willy tarreau0f7af912005-12-17 12:21:26 +01001063 * it's OK, -1 if it's impossible.
1064 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001065int connect_server(struct session *s) {
willy tarreau0f7af912005-12-17 12:21:26 +01001066 int one = 1;
1067 int fd;
1068
1069 // fprintf(stderr,"connect_server : s=%p\n",s);
1070
willy tarreau5cbea6f2005-12-17 12:48:26 +01001071 if (s->flags & TF_DIRECT) { /* srv cannot be null */
1072 s->srv_addr = s->srv->addr;
1073 }
1074 else if (s->proxy->options & PR_O_BALANCE) {
1075 if (s->proxy->options & PR_O_BALANCE_RR) {
1076 int retry = s->proxy->nbservers;
willy tarreauefae1842005-12-17 12:51:03 +01001077 while (retry) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001078 if (s->proxy->cursrv == NULL)
1079 s->proxy->cursrv = s->proxy->srv;
1080 if (s->proxy->cursrv->state & SRV_RUNNING)
1081 break;
1082 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreauefae1842005-12-17 12:51:03 +01001083 retry--;
1084 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001085
1086 if (retry == 0) /* no server left */
1087 return -1;
1088
1089 s->srv = s->proxy->cursrv;
1090 s->srv_addr = s->srv->addr;
1091 s->proxy->cursrv = s->proxy->cursrv->next;
willy tarreau0f7af912005-12-17 12:21:26 +01001092 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001093 else /* unknown balancing algorithm */
1094 return -1;
willy tarreau0f7af912005-12-17 12:21:26 +01001095 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001096 else if (*(int *)&s->proxy->dispatch_addr) {
1097 /* connect to the defined dispatch addr */
willy tarreau0f7af912005-12-17 12:21:26 +01001098 s->srv_addr = s->proxy->dispatch_addr;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001099 }
1100 else if (s->proxy->options & PR_O_TRANSP) {
1101 /* in transparent mode, use the original dest addr if no dispatch specified */
1102 int salen = sizeof(struct sockaddr_in);
1103 if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
1104 qfprintf(stderr, "Cannot get original server address.\n");
1105 return -1;
1106 }
1107 }
willy tarreau0f7af912005-12-17 12:21:26 +01001108
1109 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001110 qfprintf(stderr, "Cannot get a server socket.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001111 return -1;
1112 }
1113
willy tarreau5cbea6f2005-12-17 12:48:26 +01001114 if (fd >= cfg_maxsock) {
1115 Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
1116 close(fd);
1117 return -1;
1118 }
1119
willy tarreau0f7af912005-12-17 12:21:26 +01001120 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
1121 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001122 qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001123 close(fd);
1124 return -1;
1125 }
1126
1127 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
1128 if (errno == EAGAIN) { /* no free ports left, try again later */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001129 qfprintf(stderr,"Cannot connect, no free ports.\n");
willy tarreau0f7af912005-12-17 12:21:26 +01001130 close(fd);
1131 return -1;
1132 }
1133 else if (errno != EALREADY && errno != EISCONN) {
1134 close(fd);
1135 return -1;
1136 }
1137 }
1138
willy tarreau5cbea6f2005-12-17 12:48:26 +01001139 fdtab[fd].owner = s->task;
willy tarreau0f7af912005-12-17 12:21:26 +01001140 fdtab[fd].read = &event_srv_read;
1141 fdtab[fd].write = &event_srv_write;
1142 fdtab[fd].state = FD_STCONN; /* connection in progress */
1143
1144 FD_SET(fd, StaticWriteEvent); /* for connect status */
1145
1146 fd_insert(fd);
1147
1148 if (s->proxy->contimeout)
1149 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
1150 else
1151 tv_eternity(&s->cnexpire);
1152 return 0;
1153}
1154
1155/*
1156 * this function is called on a read event from a client socket.
1157 * It returns 0.
1158 */
1159int event_cli_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001160 struct task *t = fdtab[fd].owner;
1161 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001162 struct buffer *b = s->req;
1163 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001164
1165 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
1166
willy tarreau0f7af912005-12-17 12:21:26 +01001167 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001168 while (1) {
1169 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1170 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001171 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001172 }
1173 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001174 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001175 }
1176 else {
1177 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001178 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1179 * since it means that the rewrite protection has been removed. This
1180 * implies that the if statement can be removed.
1181 */
1182 if (max > b->rlim - b->data)
1183 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001184 }
1185
1186 if (max == 0) { /* not anymore room to store data */
1187 FD_CLR(fd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001188 break;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001189 }
1190
willy tarreau3242e862005-12-17 12:27:53 +01001191#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001192 {
1193 int skerr, lskerr;
1194
1195 lskerr = sizeof(skerr);
1196 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1197 if (skerr)
1198 ret = -1;
1199 else
1200 ret = recv(fd, b->r, max, 0);
1201 }
willy tarreau3242e862005-12-17 12:27:53 +01001202#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001203 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001204#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001205 if (ret > 0) {
1206 b->r += ret;
1207 b->l += ret;
1208 s->res_cr = RES_DATA;
1209
1210 if (b->r == b->data + BUFSIZE) {
1211 b->r = b->data; /* wrap around the buffer */
1212 }
1213 /* we hope to read more data or to get a close on next round */
1214 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001215 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001216 else if (ret == 0) {
1217 s->res_cr = RES_NULL;
1218 break;
1219 }
1220 else if (errno == EAGAIN) {/* ignore EAGAIN */
1221 break;
1222 }
1223 else {
1224 s->res_cr = RES_ERROR;
1225 fdtab[fd].state = FD_STERROR;
1226 break;
1227 }
1228 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001229 }
1230 else {
1231 s->res_cr = RES_ERROR;
1232 fdtab[fd].state = FD_STERROR;
1233 }
1234
willy tarreau5cbea6f2005-12-17 12:48:26 +01001235 if (s->res_cr != RES_SILENT) {
1236 if (s->proxy->clitimeout)
1237 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1238 else
1239 tv_eternity(&s->crexpire);
1240
1241 task_wakeup(&rq, t);
1242 }
willy tarreau0f7af912005-12-17 12:21:26 +01001243
willy tarreau0f7af912005-12-17 12:21:26 +01001244 return 0;
1245}
1246
1247
1248/*
1249 * this function is called on a read event from a server socket.
1250 * It returns 0.
1251 */
1252int event_srv_read(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001253 struct task *t = fdtab[fd].owner;
1254 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001255 struct buffer *b = s->rep;
1256 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001257
1258 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1259
willy tarreau0f7af912005-12-17 12:21:26 +01001260 if (fdtab[fd].state != FD_STERROR) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001261 while (1) {
1262 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
1263 b->r = b->w = b->h = b->lr = b->data;
willy tarreauef900ab2005-12-17 12:52:52 +01001264 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001265 }
1266 else if (b->r > b->w) {
willy tarreauef900ab2005-12-17 12:52:52 +01001267 max = b->rlim - b->r;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001268 }
1269 else {
1270 max = b->w - b->r;
willy tarreauef900ab2005-12-17 12:52:52 +01001271 /* FIXME: theorically, if w>0, we shouldn't have rlim < data+size anymore
1272 * since it means that the rewrite protection has been removed. This
1273 * implies that the if statement can be removed.
1274 */
1275 if (max > b->rlim - b->data)
1276 max = b->rlim - b->data;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001277 }
1278
1279 if (max == 0) { /* not anymore room to store data */
1280 FD_CLR(fd, StaticReadEvent);
1281 break;
1282 }
1283
willy tarreau3242e862005-12-17 12:27:53 +01001284#ifndef MSG_NOSIGNAL
willy tarreau5cbea6f2005-12-17 12:48:26 +01001285 {
1286 int skerr, lskerr;
1287
1288 lskerr = sizeof(skerr);
1289 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1290 if (skerr)
1291 ret = -1;
1292 else
1293 ret = recv(fd, b->r, max, 0);
1294 }
willy tarreau3242e862005-12-17 12:27:53 +01001295#else
willy tarreau5cbea6f2005-12-17 12:48:26 +01001296 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001297#endif
willy tarreau5cbea6f2005-12-17 12:48:26 +01001298 if (ret > 0) {
1299 b->r += ret;
1300 b->l += ret;
1301 s->res_sr = RES_DATA;
willy tarreau0f7af912005-12-17 12:21:26 +01001302
willy tarreau5cbea6f2005-12-17 12:48:26 +01001303 if (b->r == b->data + BUFSIZE) {
1304 b->r = b->data; /* wrap around the buffer */
1305 }
1306 /* we hope to read more data or to get a close on next round */
1307 continue;
willy tarreau0f7af912005-12-17 12:21:26 +01001308 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001309 else if (ret == 0) {
1310 s->res_sr = RES_NULL;
1311 break;
1312 }
1313 else if (errno == EAGAIN) {/* ignore EAGAIN */
1314 break;
1315 }
1316 else {
1317 s->res_sr = RES_ERROR;
1318 fdtab[fd].state = FD_STERROR;
1319 break;
1320 }
1321 } /* while(1) */
willy tarreau0f7af912005-12-17 12:21:26 +01001322 }
1323 else {
1324 s->res_sr = RES_ERROR;
1325 fdtab[fd].state = FD_STERROR;
1326 }
1327
willy tarreau5cbea6f2005-12-17 12:48:26 +01001328 if (s->res_sr != RES_SILENT) {
1329 if (s->proxy->srvtimeout)
1330 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1331 else
1332 tv_eternity(&s->srexpire);
1333
1334 task_wakeup(&rq, t);
1335 }
willy tarreau0f7af912005-12-17 12:21:26 +01001336
willy tarreau0f7af912005-12-17 12:21:26 +01001337 return 0;
1338}
1339
1340/*
1341 * this function is called on a write event from a client socket.
1342 * It returns 0.
1343 */
1344int event_cli_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001345 struct task *t = fdtab[fd].owner;
1346 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001347 struct buffer *b = s->rep;
1348 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001349
1350 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1351
1352 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001353 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001354 // max = BUFSIZE; BUG !!!!
1355 max = 0;
1356 }
1357 else if (b->r > b->w) {
1358 max = b->r - b->w;
1359 }
1360 else
1361 max = b->data + BUFSIZE - b->w;
1362
willy tarreau0f7af912005-12-17 12:21:26 +01001363 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001364#ifndef MSG_NOSIGNAL
1365 int skerr, lskerr;
1366#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001367
1368 if (max == 0) {
1369 s->res_cw = RES_NULL;
1370 task_wakeup(&rq, t);
1371 return 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001372 }
1373
willy tarreau3242e862005-12-17 12:27:53 +01001374#ifndef MSG_NOSIGNAL
1375 lskerr=sizeof(skerr);
1376 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1377 if (skerr)
1378 ret = -1;
1379 else
1380 ret = send(fd, b->w, max, MSG_DONTWAIT);
1381#else
willy tarreau0f7af912005-12-17 12:21:26 +01001382 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001383#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001384
1385 if (ret > 0) {
1386 b->l -= ret;
1387 b->w += ret;
1388
1389 s->res_cw = RES_DATA;
1390
1391 if (b->w == b->data + BUFSIZE) {
1392 b->w = b->data; /* wrap around the buffer */
1393 }
1394 }
1395 else if (ret == 0) {
1396 /* nothing written, just make as if we were never called */
1397// s->res_cw = RES_NULL;
1398 return 0;
1399 }
1400 else if (errno == EAGAIN) /* ignore EAGAIN */
1401 return 0;
1402 else {
1403 s->res_cw = RES_ERROR;
1404 fdtab[fd].state = FD_STERROR;
1405 }
1406 }
1407 else {
1408 s->res_cw = RES_ERROR;
1409 fdtab[fd].state = FD_STERROR;
1410 }
1411
1412 if (s->proxy->clitimeout)
1413 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1414 else
1415 tv_eternity(&s->cwexpire);
1416
willy tarreau5cbea6f2005-12-17 12:48:26 +01001417 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001418 return 0;
1419}
1420
1421
1422/*
1423 * this function is called on a write event from a server socket.
1424 * It returns 0.
1425 */
1426int event_srv_write(int fd) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001427 struct task *t = fdtab[fd].owner;
1428 struct session *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001429 struct buffer *b = s->req;
1430 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001431
1432 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1433
1434 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001435 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001436 // max = BUFSIZE; BUG !!!!
1437 max = 0;
1438 }
1439 else if (b->r > b->w) {
1440 max = b->r - b->w;
1441 }
1442 else
1443 max = b->data + BUFSIZE - b->w;
1444
willy tarreau0f7af912005-12-17 12:21:26 +01001445 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001446#ifndef MSG_NOSIGNAL
1447 int skerr, lskerr;
1448#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001449 if (max == 0) {
1450 /* may be we have received a connection acknowledgement in TCP mode without data */
willy tarreau0f7af912005-12-17 12:21:26 +01001451 s->res_sw = RES_NULL;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001452 task_wakeup(&rq, t);
willy tarreauef900ab2005-12-17 12:52:52 +01001453 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001454 return 0;
1455 }
1456
willy tarreauef900ab2005-12-17 12:52:52 +01001457
willy tarreau3242e862005-12-17 12:27:53 +01001458#ifndef MSG_NOSIGNAL
1459 lskerr=sizeof(skerr);
1460 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1461 if (skerr)
1462 ret = -1;
1463 else
1464 ret = send(fd, b->w, max, MSG_DONTWAIT);
1465#else
willy tarreau0f7af912005-12-17 12:21:26 +01001466 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001467#endif
willy tarreauef900ab2005-12-17 12:52:52 +01001468 fdtab[fd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001469 if (ret > 0) {
1470 b->l -= ret;
1471 b->w += ret;
1472
1473 s->res_sw = RES_DATA;
1474
1475 if (b->w == b->data + BUFSIZE) {
1476 b->w = b->data; /* wrap around the buffer */
1477 }
1478 }
1479 else if (ret == 0) {
1480 /* nothing written, just make as if we were never called */
1481 // s->res_sw = RES_NULL;
1482 return 0;
1483 }
1484 else if (errno == EAGAIN) /* ignore EAGAIN */
1485 return 0;
1486 else {
1487 s->res_sw = RES_ERROR;
1488 fdtab[fd].state = FD_STERROR;
1489 }
1490 }
1491 else {
1492 s->res_sw = RES_ERROR;
1493 fdtab[fd].state = FD_STERROR;
1494 }
1495
1496 if (s->proxy->srvtimeout)
1497 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1498 else
1499 tv_eternity(&s->swexpire);
1500
willy tarreau5cbea6f2005-12-17 12:48:26 +01001501 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001502 return 0;
1503}
1504
1505
1506/*
1507 * this function is called on a read event from a listen socket, corresponding
willy tarreau5cbea6f2005-12-17 12:48:26 +01001508 * to an accept. It tries to accept as many connections as possible.
1509 * It returns 0.
willy tarreau0f7af912005-12-17 12:21:26 +01001510 */
1511int event_accept(int fd) {
1512 struct proxy *p = (struct proxy *)fdtab[fd].owner;
willy tarreau5cbea6f2005-12-17 12:48:26 +01001513 struct session *s;
1514 struct task *t;
willy tarreau0f7af912005-12-17 12:21:26 +01001515 int cfd;
1516 int one = 1;
1517
willy tarreau5cbea6f2005-12-17 12:48:26 +01001518 while (p->nbconn < p->maxconn) {
1519 struct sockaddr_in addr;
1520 int laddr = sizeof(addr);
1521 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
1522 return 0; /* nothing more to accept */
willy tarreau0f7af912005-12-17 12:21:26 +01001523
willy tarreau5cbea6f2005-12-17 12:48:26 +01001524 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1525 Alert("out of memory in event_accept().\n");
1526 FD_CLR(fd, StaticReadEvent);
1527 p->state = PR_STIDLE;
1528 close(cfd);
1529 return 0;
1530 }
willy tarreau0f7af912005-12-17 12:21:26 +01001531
willy tarreau5cbea6f2005-12-17 12:48:26 +01001532 if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
1533 Alert("out of memory in event_accept().\n");
1534 FD_CLR(fd, StaticReadEvent);
1535 p->state = PR_STIDLE;
1536 close(cfd);
1537 pool_free(session, s);
1538 return 0;
1539 }
willy tarreau0f7af912005-12-17 12:21:26 +01001540
willy tarreau5cbea6f2005-12-17 12:48:26 +01001541 s->cli_addr = addr;
1542 if (cfd >= cfg_maxsock) {
1543 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
1544 close(cfd);
1545 pool_free(task, t);
1546 pool_free(session, s);
1547 return 0;
1548 }
willy tarreau0f7af912005-12-17 12:21:26 +01001549
willy tarreau5cbea6f2005-12-17 12:48:26 +01001550 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1551 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1552 (char *) &one, sizeof(one)) == -1)) {
1553 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1554 close(cfd);
1555 pool_free(task, t);
1556 pool_free(session, s);
1557 return 0;
1558 }
willy tarreau0f7af912005-12-17 12:21:26 +01001559
willy tarreau5cbea6f2005-12-17 12:48:26 +01001560 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1561 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1562 struct sockaddr_in peername, sockname;
1563 unsigned char *pn, *sn;
1564 int namelen;
1565 char message[256];
willy tarreau0f7af912005-12-17 12:21:26 +01001566
willy tarreau5cbea6f2005-12-17 12:48:26 +01001567 //namelen = sizeof(peername);
1568 //getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1569 //pn = (unsigned char *)&peername.sin_addr;
1570 pn = (unsigned char *)&s->cli_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001571
willy tarreau5cbea6f2005-12-17 12:48:26 +01001572 namelen = sizeof(sockname);
1573 if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
1574 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1575 sn = (unsigned char *)&sockname.sin_addr;
willy tarreau0f7af912005-12-17 12:21:26 +01001576
willy tarreau5cbea6f2005-12-17 12:48:26 +01001577 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1578 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1579 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1580 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
willy tarreau0f7af912005-12-17 12:21:26 +01001581
willy tarreau5cbea6f2005-12-17 12:48:26 +01001582 if (p->logfac1 >= 0)
1583 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1584 if (p->logfac2 >= 0)
1585 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1586 }
willy tarreau0f7af912005-12-17 12:21:26 +01001587
willy tarreauef900ab2005-12-17 12:52:52 +01001588 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1589 int len;
1590 len = sprintf(trash, "accept(%04x)=%04x\n", (unsigned short)fd, (unsigned short)cfd);
1591 write(1, trash, len);
1592 }
willy tarreau0f7af912005-12-17 12:21:26 +01001593
willy tarreau5cbea6f2005-12-17 12:48:26 +01001594 t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
1595 t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
1596 t->state = TASK_IDLE;
1597 t->process = process_session;
1598 t->context = s;
willy tarreau0f7af912005-12-17 12:21:26 +01001599
willy tarreau5cbea6f2005-12-17 12:48:26 +01001600 s->task = t;
1601 s->proxy = p;
1602 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1603 s->srv_state = SV_STIDLE;
1604 s->req = s->rep = NULL; /* will be allocated later */
1605 s->flags = 0;
1606 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1607 s->cli_fd = cfd;
1608 s->srv_fd = -1;
1609 s->conn_retries = p->conn_retries;
1610
1611 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1612 close(cfd); /* nothing can be done for this fd without memory */
1613 pool_free(task, t);
1614 pool_free(session, s);
1615 return 0;
1616 }
1617 s->req->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001618 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1619 s->req->rlim = s->req->data + BUFSIZE;
1620 if (s->cli_state == CL_STHEADERS) /* reserver some space for header rewriting */
1621 s->req->rlim -= MAXREWRITE;
willy tarreau0f7af912005-12-17 12:21:26 +01001622
willy tarreau5cbea6f2005-12-17 12:48:26 +01001623 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1624 pool_free(buffer, s->req);
1625 close(cfd); /* nothing can be done for this fd without memory */
1626 pool_free(task, t);
1627 pool_free(session, s);
1628 return 0;
1629 }
1630 s->rep->l = 0;
willy tarreauef900ab2005-12-17 12:52:52 +01001631 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->rlim = s->rep->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001632
willy tarreau5cbea6f2005-12-17 12:48:26 +01001633 fdtab[cfd].read = &event_cli_read;
1634 fdtab[cfd].write = &event_cli_write;
1635 fdtab[cfd].owner = t;
1636 fdtab[cfd].state = FD_STREADY;
willy tarreau0f7af912005-12-17 12:21:26 +01001637
willy tarreau5cbea6f2005-12-17 12:48:26 +01001638 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1639 FD_CLR(cfd, StaticReadEvent);
willy tarreauef900ab2005-12-17 12:52:52 +01001640 FD_SET(cfd, StaticWriteEvent);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001641 tv_eternity(&s->crexpire);
1642 shutdown(s->cli_fd, SHUT_RD);
1643 s->cli_state = CL_STSHUTR;
willy tarreau0f7af912005-12-17 12:21:26 +01001644
willy tarreau5cbea6f2005-12-17 12:48:26 +01001645 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1646 s->rep->l = 3;
1647 s->rep->r += 3;
1648 }
1649 else {
1650 FD_SET(cfd, StaticReadEvent);
1651 }
1652
1653 fd_insert(cfd);
1654
1655 tv_eternity(&s->cnexpire);
1656 tv_eternity(&s->srexpire);
1657 tv_eternity(&s->swexpire);
1658 tv_eternity(&s->cwexpire);
1659
1660 if (s->proxy->clitimeout)
1661 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1662 else
1663 tv_eternity(&s->crexpire);
1664
1665 t->expire = s->crexpire;
1666
1667 task_queue(t);
willy tarreauef900ab2005-12-17 12:52:52 +01001668
1669 if (p->mode != PR_MODE_HEALTH)
1670 task_wakeup(&rq, t);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001671
1672 p->nbconn++;
1673 actconn++;
1674 totalconn++;
1675
1676 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1677 } /* end of while (p->nbconn < p->maxconn) */
1678 return 0;
1679}
willy tarreau0f7af912005-12-17 12:21:26 +01001680
willy tarreau0f7af912005-12-17 12:21:26 +01001681
willy tarreau5cbea6f2005-12-17 12:48:26 +01001682/*
1683 * This function is used only for server health-checks. It handles
1684 * the connection acknowledgement and returns 1 if the socket is OK,
1685 * or -1 if an error occured.
1686 */
1687int event_srv_hck(int fd) {
1688 struct task *t = fdtab[fd].owner;
1689 struct server *s = t->context;
willy tarreau0f7af912005-12-17 12:21:26 +01001690
willy tarreau5cbea6f2005-12-17 12:48:26 +01001691 int skerr, lskerr;
willy tarreauef900ab2005-12-17 12:52:52 +01001692 lskerr = sizeof(skerr);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001693 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1694 if (skerr)
1695 s->result = -1;
1696 else
1697 s->result = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001698
willy tarreau5cbea6f2005-12-17 12:48:26 +01001699 task_wakeup(&rq, t);
willy tarreau0f7af912005-12-17 12:21:26 +01001700 return 0;
1701}
1702
1703
1704/*
1705 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1706 * and moves <end> just after the end of <str>.
1707 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1708 * the shift value (positive or negative) is returned.
1709 * If there's no space left, the move is not done.
1710 *
1711 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001712int buffer_replace(struct buffer *b, char *pos, char *end, char *str) {
willy tarreau0f7af912005-12-17 12:21:26 +01001713 int delta;
1714 int len;
1715
1716 len = strlen(str);
1717 delta = len - (end - pos);
1718
1719 if (delta + b->r >= b->data + BUFSIZE)
1720 return 0; /* no space left */
1721
1722 /* first, protect the end of the buffer */
1723 memmove(end + delta, end, b->data + b->l - end);
1724
1725 /* now, copy str over pos */
1726 memcpy(pos, str,len);
1727
willy tarreau5cbea6f2005-12-17 12:48:26 +01001728 /* we only move data after the displaced zone */
1729 if (b->r > pos) b->r += delta;
1730 if (b->w > pos) b->w += delta;
1731 if (b->h > pos) b->h += delta;
1732 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001733 b->l += delta;
1734
1735 return delta;
1736}
1737
1738/* same except that the string len is given */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001739int buffer_replace2(struct buffer *b, char *pos, char *end, char *str, int len) {
willy tarreau0f7af912005-12-17 12:21:26 +01001740 int delta;
1741
1742 delta = len - (end - pos);
1743
1744 if (delta + b->r >= b->data + BUFSIZE)
1745 return 0; /* no space left */
1746
1747 /* first, protect the end of the buffer */
1748 memmove(end + delta, end, b->data + b->l - end);
1749
1750 /* now, copy str over pos */
1751 memcpy(pos, str,len);
1752
willy tarreau5cbea6f2005-12-17 12:48:26 +01001753 /* we only move data after the displaced zone */
1754 if (b->r > pos) b->r += delta;
1755 if (b->w > pos) b->w += delta;
1756 if (b->h > pos) b->h += delta;
1757 if (b->lr > pos) b->lr += delta;
willy tarreau0f7af912005-12-17 12:21:26 +01001758 b->l += delta;
1759
1760 return delta;
1761}
1762
1763
1764int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1765 char *old_dst = dst;
1766
1767 while (*str) {
1768 if (*str == '\\') {
1769 str++;
1770 if (isdigit(*str)) {
1771 int len, num;
1772
1773 num = *str - '0';
1774 str++;
1775
1776 if (matches[num].rm_so > -1) {
1777 len = matches[num].rm_eo - matches[num].rm_so;
1778 memcpy(dst, src + matches[num].rm_so, len);
1779 dst += len;
1780 }
1781
1782 }
1783 else if (*str == 'x') {
1784 unsigned char hex1, hex2;
1785 str++;
1786
1787 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1788
1789 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1790 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1791 *dst++ = (hex1<<4) + hex2;
1792 }
1793 else
1794 *dst++ = *str++;
1795 }
1796 else
1797 *dst++ = *str++;
1798 }
1799 *dst = 0;
1800 return dst - old_dst;
1801}
1802
1803/*
1804 * manages the client FSM and its socket. BTW, it also tries to handle the
1805 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1806 * 0 else.
1807 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001808int process_cli(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01001809 int s = t->srv_state;
1810 int c = t->cli_state;
1811 struct buffer *req = t->req;
1812 struct buffer *rep = t->rep;
1813
1814 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1815 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1816 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1817 //);
1818 if (c == CL_STHEADERS) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01001819 /* now parse the partial (or complete) headers */
1820 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
1821 char *ptr;
1822 int delete_header;
willy tarreau0f7af912005-12-17 12:21:26 +01001823
willy tarreau5cbea6f2005-12-17 12:48:26 +01001824 ptr = req->lr;
willy tarreau0f7af912005-12-17 12:21:26 +01001825
willy tarreau0f7af912005-12-17 12:21:26 +01001826 /* look for the end of the current header */
1827 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1828 ptr++;
1829
willy tarreau5cbea6f2005-12-17 12:48:26 +01001830 if (ptr == req->h) { /* empty line, end of headers */
1831 char newhdr[MAXREWRITE + 1];
1832 int line, len;
1833 /* we can only get here after an end of headers */
1834 /* we'll have something else to do here : add new headers ... */
willy tarreau0f7af912005-12-17 12:21:26 +01001835
willy tarreau5cbea6f2005-12-17 12:48:26 +01001836 for (line = 0; line < t->proxy->nb_reqadd; line++) {
1837 len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
1838 buffer_replace2(req, req->h, req->h, newhdr, len);
1839 }
willy tarreau0f7af912005-12-17 12:21:26 +01001840
willy tarreau5cbea6f2005-12-17 12:48:26 +01001841 t->cli_state = CL_STDATA;
willy tarreauef900ab2005-12-17 12:52:52 +01001842 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
willy tarreau0f7af912005-12-17 12:21:26 +01001843
willy tarreau5cbea6f2005-12-17 12:48:26 +01001844 /* FIXME: we'll set the client in a wait state while we try to
1845 * connect to the server. Is this really needed ? wouldn't it be
1846 * better to release the maximum of system buffers instead ? */
willy tarreauef900ab2005-12-17 12:52:52 +01001847 //FD_CLR(t->cli_fd, StaticReadEvent);
1848 //tv_eternity(&t->crexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01001849 break;
1850 }
willy tarreau0f7af912005-12-17 12:21:26 +01001851
willy tarreau5cbea6f2005-12-17 12:48:26 +01001852 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1853 if (ptr > req->r - 2) {
1854 /* this is a partial header, let's wait for more to come */
1855 req->lr = ptr;
1856 break;
1857 }
willy tarreau0f7af912005-12-17 12:21:26 +01001858
willy tarreau5cbea6f2005-12-17 12:48:26 +01001859 /* now we know that *ptr is either \r or \n,
1860 * and that there are at least 1 char after it.
1861 */
1862 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1863 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1864 else
1865 req->lr = ptr + 2; /* \r\n or \n\r */
willy tarreau0f7af912005-12-17 12:21:26 +01001866
willy tarreau5cbea6f2005-12-17 12:48:26 +01001867 /*
1868 * now we know that we have a full header ; we can do whatever
1869 * we want with these pointers :
1870 * req->h = beginning of header
1871 * ptr = end of header (first \r or \n)
1872 * req->lr = beginning of next line (next rep->h)
1873 * req->r = end of data (not used at this stage)
1874 */
willy tarreau0f7af912005-12-17 12:21:26 +01001875
willy tarreau5cbea6f2005-12-17 12:48:26 +01001876 delete_header = 0;
willy tarreau0f7af912005-12-17 12:21:26 +01001877
willy tarreau5cbea6f2005-12-17 12:48:26 +01001878 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
1879 int len, max;
1880 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1881 max = ptr - req->h;
1882 UBOUND(max, sizeof(trash) - len - 1);
1883 len += strlcpy(trash + len, req->h, max + 1);
1884 trash[len++] = '\n';
1885 write(1, trash, len);
1886 }
willy tarreau0f7af912005-12-17 12:21:26 +01001887
willy tarreau5cbea6f2005-12-17 12:48:26 +01001888 /* try headers regexps */
1889 if (t->proxy->nb_reqexp) {
1890 struct proxy *p = t->proxy;
1891 int exp;
1892 char term;
1893
1894 term = *ptr;
1895 *ptr = '\0';
1896 for (exp=0; exp < p->nb_reqexp; exp++) {
1897 if (regexec(p->req_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1898 if (p->req_exp[exp].replace != NULL) {
1899 int len = exp_replace(trash, req->h, p->req_exp[exp].replace, pmatch);
1900 ptr += buffer_replace2(req, req->h, ptr, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01001901 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001902 else {
1903 delete_header = 1;
willy tarreau0f7af912005-12-17 12:21:26 +01001904 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001905 break;
willy tarreau0f7af912005-12-17 12:21:26 +01001906 }
1907 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001908 *ptr = term; /* restore the string terminator */
willy tarreau0f7af912005-12-17 12:21:26 +01001909 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001910
1911 /* now look for cookies */
1912 if (!delete_header && (req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1913 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1914 char *p1, *p2, *p3, *p4;
1915
1916 p1 = req->h + 8; /* first char after 'Cookie: ' */
1917
1918 while (p1 < ptr) {
1919 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1920 p1++;
1921
1922 if (p1 == ptr)
1923 break;
1924 else if (*p1 == ';') { /* next cookie */
1925 ++p1;
1926 continue;
1927 }
1928
1929 /* p1 is at the beginning of the cookie name */
1930 p2 = p1;
1931
1932 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1933 p2++;
1934
1935 if (p2 == ptr)
1936 break;
1937 else if (*p2 == ';') { /* next cookie */
1938 p1=++p2;
1939 continue;
1940 }
1941
1942 p3 = p2 + 1; /* skips the '=' sign */
1943 if (p3 == ptr)
1944 break;
1945
1946 p4=p3;
1947 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1948 p4++;
1949
1950 /* here, we have the cookie name between p1 and p2,
1951 * and its value between p3 and p4.
1952 * we can process it.
1953 */
1954
1955 if ((p2 - p1 == strlen(t->proxy->cookie_name)) &&
1956 (strncmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1957 /* Cool... it's the right one */
1958 struct server *srv = t->proxy->srv;
1959
1960 while (srv &&
1961 ((srv->cklen != p4 - p3) || memcmp(p3, srv->cookie, p4 - p3))) {
1962 srv = srv->next;
1963 }
1964
1965 if (srv) { /* we found the server */
1966 t->flags |= TF_DIRECT;
1967 t->srv = srv;
1968 }
1969
1970 break;
1971 }
1972 else {
1973 // fprintf(stderr,"Ignoring unknown cookie : ");
1974 // write(2, p1, p2-p1);
1975 // fprintf(stderr," = ");
1976 // write(2, p3, p4-p3);
1977 // fprintf(stderr,"\n");
1978 }
1979 /* we'll have to look for another cookie ... */
1980 p1 = p4;
1981 } /* while (p1 < ptr) */
1982 } /* end of cookie processing */
1983
1984 /* let's look if we have to delete this header */
1985 if (delete_header) {
1986 buffer_replace2(req, req->h, req->lr, "", 0);
willy tarreau0f7af912005-12-17 12:21:26 +01001987 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01001988 req->h = req->lr;
1989 } /* while (req->lr < req->r) */
1990
1991 /* end of header processing (even if incomplete) */
1992
willy tarreauef900ab2005-12-17 12:52:52 +01001993
1994 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1995 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1996 * full. We cannot loop here since event_cli_read will disable it only if
1997 * req->l == rlim-data
1998 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01001999 FD_SET(t->cli_fd, StaticReadEvent);
2000 if (t->proxy->clitimeout)
2001 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2002 else
2003 tv_eternity(&t->crexpire);
2004 }
2005
willy tarreauef900ab2005-12-17 12:52:52 +01002006 /* read timeout, read error, or last read : give up.
2007 * since we are in header mode, if there's no space left for headers, we
2008 * won't be able to free more later, so the session will never terminate.
2009 */
2010 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
2011 || req->l >= req->rlim - req->data || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002012 tv_eternity(&t->crexpire);
2013 fd_delete(t->cli_fd);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002014 t->cli_state = CL_STCLOSE;
2015 return 1;
willy tarreau0f7af912005-12-17 12:21:26 +01002016 }
willy tarreau5cbea6f2005-12-17 12:48:26 +01002017
2018 return t->cli_state != CL_STHEADERS;
willy tarreau0f7af912005-12-17 12:21:26 +01002019 }
2020 else if (c == CL_STDATA) {
2021 /* read or write error */
2022 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
willy tarreau0f7af912005-12-17 12:21:26 +01002023 tv_eternity(&t->crexpire);
2024 tv_eternity(&t->cwexpire);
willy tarreau5cbea6f2005-12-17 12:48:26 +01002025 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002026 t->cli_state = CL_STCLOSE;
2027 return 1;
2028 }
2029 /* read timeout, last read, or end of server write */
2030 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
2031 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002032 FD_CLR(t->cli_fd, StaticReadEvent);
2033 // if (req->l == 0) /* nothing to write on the server side */
2034 // FD_CLR(t->srv_fd, StaticWriteEvent);
2035 tv_eternity(&t->crexpire);
2036 shutdown(t->cli_fd, SHUT_RD);
2037 t->cli_state = CL_STSHUTR;
2038 return 1;
2039 }
2040 /* write timeout, or last server read and buffer empty */
2041 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
2042 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002043 FD_CLR(t->cli_fd, StaticWriteEvent);
2044 tv_eternity(&t->cwexpire);
2045 shutdown(t->cli_fd, SHUT_WR);
2046 t->cli_state = CL_STSHUTW;
2047 return 1;
2048 }
2049
willy tarreauef900ab2005-12-17 12:52:52 +01002050 if (req->l >= req->rlim - req->data) {
2051 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002052 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002053 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002054 FD_CLR(t->cli_fd, StaticReadEvent);
2055 tv_eternity(&t->crexpire);
2056 }
2057 }
2058 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002059 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002060 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2061 FD_SET(t->cli_fd, StaticReadEvent);
2062 if (t->proxy->clitimeout)
2063 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2064 else
2065 tv_eternity(&t->crexpire);
2066 }
2067 }
2068
2069 if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002070 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002071 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2072 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2073 tv_eternity(&t->cwexpire);
2074 }
2075 }
2076 else { /* buffer not empty */
2077 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2078 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2079 if (t->proxy->clitimeout)
2080 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2081 else
2082 tv_eternity(&t->cwexpire);
2083 }
2084 }
2085 return 0; /* other cases change nothing */
2086 }
2087 else if (c == CL_STSHUTR) {
2088 if ((t->res_cw == RES_ERROR) ||
2089 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
willy tarreaub719f002005-12-17 12:55:07 +01002090 || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002091 tv_eternity(&t->cwexpire);
2092 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002093 t->cli_state = CL_STCLOSE;
2094 return 1;
2095 }
2096 else if ((rep->l == 0) ||
willy tarreau5cbea6f2005-12-17 12:48:26 +01002097 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002098 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2099 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
2100 tv_eternity(&t->cwexpire);
2101 }
2102 }
2103 else { /* buffer not empty */
2104 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
2105 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
2106 if (t->proxy->clitimeout)
2107 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
2108 else
2109 tv_eternity(&t->cwexpire);
2110 }
2111 }
2112 return 0;
2113 }
2114 else if (c == CL_STSHUTW) {
2115 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
willy tarreaub719f002005-12-17 12:55:07 +01002116 s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002117 tv_eternity(&t->crexpire);
2118 fd_delete(t->cli_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002119 t->cli_state = CL_STCLOSE;
2120 return 1;
2121 }
willy tarreauef900ab2005-12-17 12:52:52 +01002122 else if (req->l >= req->rlim - req->data) {
2123 /* no room to read more data */
willy tarreau0f7af912005-12-17 12:21:26 +01002124 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
willy tarreauef900ab2005-12-17 12:52:52 +01002125 /* stop reading until we get some space */
willy tarreau0f7af912005-12-17 12:21:26 +01002126 FD_CLR(t->cli_fd, StaticReadEvent);
2127 tv_eternity(&t->crexpire);
2128 }
2129 }
2130 else {
willy tarreauef900ab2005-12-17 12:52:52 +01002131 /* there's still some space in the buffer */
willy tarreau0f7af912005-12-17 12:21:26 +01002132 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
2133 FD_SET(t->cli_fd, StaticReadEvent);
2134 if (t->proxy->clitimeout)
2135 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
2136 else
2137 tv_eternity(&t->crexpire);
2138 }
2139 }
2140 return 0;
2141 }
2142 else { /* CL_STCLOSE: nothing to do */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002143 if ((mode & MODE_DEBUG) && !(mode & MODE_QUIET)) {
willy tarreau0f7af912005-12-17 12:21:26 +01002144 int len;
willy tarreau5cbea6f2005-12-17 12:48:26 +01002145 len = sprintf(trash, "clicls[%04x:%04x]\n", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
willy tarreau0f7af912005-12-17 12:21:26 +01002146 write(1, trash, len);
2147 }
2148 return 0;
2149 }
2150 return 0;
2151}
2152
2153
2154/*
2155 * manages the server FSM and its socket. It returns 1 if a state has changed
2156 * (and a resync may be needed), 0 else.
2157 */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002158int process_srv(struct session *t) {
willy tarreau0f7af912005-12-17 12:21:26 +01002159 int s = t->srv_state;
2160 int c = t->cli_state;
2161 struct buffer *req = t->req;
2162 struct buffer *rep = t->rep;
2163
willy tarreau5cbea6f2005-12-17 12:48:26 +01002164 //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
2165 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
2166 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
2167 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
2168 //);
willy tarreau0f7af912005-12-17 12:21:26 +01002169 if (s == SV_STIDLE) {
2170 if (c == CL_STHEADERS)
2171 return 0; /* stay in idle, waiting for data to reach the client side */
2172 else if (c == CL_STCLOSE ||
2173 c == CL_STSHUTW ||
2174 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
2175 tv_eternity(&t->cnexpire);
2176 t->srv_state = SV_STCLOSE;
2177 return 1;
2178 }
2179 else { /* go to SV_STCONN */
willy tarreau5cbea6f2005-12-17 12:48:26 +01002180 if (connect_server(t) == 0) { /* initiate a connection to the server */
willy tarreau0f7af912005-12-17 12:21:26 +01002181 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
2182 t->srv_state = SV_STCONN;
2183 }
2184 else { /* try again */
2185 while (t->conn_retries-- > 0) {
willy tarreau5cbea6f2005-12-17 12:48:26 +01002186 if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
2187 t->flags &= ~TF_DIRECT; /* ignore cookie and force to use the dispatcher */
2188 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2189 }
2190
2191 if (connect_server(t) == 0) {
willy tarreau0f7af912005-12-17 12:21:26 +01002192 t->srv_state = SV_STCONN;
2193 break;
2194 }
2195 }
2196 if (t->conn_retries < 0) {
2197 /* if conn_retries < 0 or other error, let's abort */
2198 tv_eternity(&t->cnexpire);
2199 t