blob: dbbef4326284b840b96c3e9428fdd99bc139e9a6 [file] [log] [blame]
willy tarreau0f7af912005-12-17 12:21:26 +01001/*
2 * HA-Proxy : High Availability-enabled HTTP/TCP proxy - Willy Tarreau
3 * willy AT meta-x DOT org.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * ChangeLog :
11 *
willy tarreau9da061b2005-12-17 12:29:56 +010012 * 2001/12/30 : release of version 1.0.2 : no fixed a bug in header processing
willy tarreau3242e862005-12-17 12:27:53 +010013 * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
willy tarreau0f7af912005-12-17 12:21:26 +010014 * 2001/12/16 : release of version 1.0.0.
15 * 2001/12/16 : added syslog capability for each accepted connection.
16 * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
17 * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
18 * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
19 * with or without cookies (use keyword http for this).
20 * 2001/09/01 : added client/server header replacing with regexps.
21 * eg:
22 * cliexp ^(Host:\ [^:]*).* Host:\ \1:80
23 * srvexp ^Server:\ .* Server:\ Apache
24 * 2000/11/29 : first fully working release with complete FSMs and timeouts.
25 * 2000/11/28 : major rewrite
26 * 2000/11/26 : first write
27 *
28 * TODO: handle properly intermediate incomplete server headers.
29 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36#include <ctype.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <netinet/tcp.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <sys/resource.h>
49#include <time.h>
50#include <regex.h>
51#include <syslog.h>
52
willy tarreau9da061b2005-12-17 12:29:56 +010053#define HAPROXY_VERSION "1.0.2"
54#define HAPROXY_DATE "2001/12/30"
willy tarreau0f7af912005-12-17 12:21:26 +010055
56/* this is for libc5 for example */
57#ifndef TCP_NODELAY
58#define TCP_NODELAY 1
59#endif
60
61#ifndef SHUT_RD
62#define SHUT_RD 0
63#endif
64
65#ifndef SHUT_WR
66#define SHUT_WR 1
67#endif
68
69#define BUFSIZE 4096
70
71// reserved buffer space for header rewriting
72#define MAXREWRITE 256
73
74// max # of regexps per proxy
75#define MAX_REGEXP 10
76
77// max # of matches per regexp
78#define MAX_MATCH 10
79
80#define COOKIENAME_LEN 16
81#define SERVERID_LEN 16
82#define CONN_RETRIES 3
83
84/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
85#define INTBITS 5
86
87/* show stats this every millisecond, 0 to disable */
88#ifndef STATTIME
89#define STATTIME 2000
90#endif
91
92#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
93#define SETNOW(a) (*a=now)
94
willy tarreau9da061b2005-12-17 12:29:56 +010095/****** string-specific macros and functions ******/
96/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
97#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
98
99/* if a < min, then bound <a> to <min>. The macro returns the new <a> */
100#define LBOUND(a, min) ({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
101
102
103#ifndef HAVE_STRLCPY
104/*
105 * copies at most <size-1> chars from <src> to <dst>. Last char is always
106 * set to 0, unless <size> is 0. The number of chars copied is returned
107 * (excluding the terminating zero).
108 * This code has been optimized for size and speed : on x86, it's 45 bytes
109 * long, uses only registers, and consumes only 4 cycles per char.
110 */
111int strlcpy(char *dst, const char *src, int size) {
112 char *orig = dst;
113 if (size) {
114 while (--size && (*dst = *src)) {
115 src++; dst++;
116 }
117 *dst = 0;
118 }
119 return dst - orig;
120}
121#endif
122
123
willy tarreau0f7af912005-12-17 12:21:26 +0100124#define MEM_OPTIM
125#ifdef MEM_OPTIM
126/*
127 * Returns a pointer to type <type> taken from the
128 * pool <pool_type> or dynamically allocated. In the
129 * first case, <pool_type> is updated to point to the
130 * next element in the list.
131 */
132#define pool_alloc(type) ({ \
133 void *p; \
134 if ((p = pool_##type) == NULL) \
135 p = malloc(sizeof_##type); \
136 else { \
137 pool_##type = *(void **)pool_##type; \
138 } \
139 p; \
140})
141
142/*
143 * Puts a memory area back to the corresponding pool.
144 * Items are chained directly through a pointer that
145 * is written in the beginning of the memory area, so
willy tarreau9da061b2005-12-17 12:29:56 +0100146 * there's no need for any carrier cell. This implies
willy tarreau0f7af912005-12-17 12:21:26 +0100147 * that each memory area is at least as big as one
148 * pointer.
149 */
150#define pool_free(type, ptr) ({ \
151 *(void **)ptr = (void *)pool_##type; \
152 pool_##type = (void *)ptr; \
153})
154
155#else
156#define pool_alloc(type) (calloc(1,sizeof_##type));
157#define pool_free(type, ptr) (free(ptr));
158#endif /* MEM_OPTIM */
159
160#define sizeof_session sizeof(struct task)
161#define sizeof_buffer sizeof(struct buffer)
162#define sizeof_fdtab sizeof(struct fdtab)
163#define sizeof_str256 256
164
165
166/*
167 * different possible states for the sockets
168 */
169#define FD_STCLOSE 0
170#define FD_STLISTEN 1
171#define FD_STCONN 2
172#define FD_STREADY 3
173#define FD_STERROR 4
174
175#define TASK_IDLE 0
176#define TASK_RUNNING 1
177
178#define PR_STNEW 0
179#define PR_STIDLE 1
180#define PR_STRUN 2
181#define PR_STDISABLED 3
182
183#define PR_MODE_TCP 0
184#define PR_MODE_HTTP 1
185#define PR_MODE_HEALTH 2
186
187#define CL_STHEADERS 0
188#define CL_STDATA 1
189#define CL_STSHUTR 2
190#define CL_STSHUTW 3
191#define CL_STCLOSE 4
192
193#define SV_STIDLE 0
194#define SV_STCONN 1
195#define SV_STHEADERS 2
196#define SV_STDATA 3
197#define SV_STSHUTR 4
198#define SV_STSHUTW 5
199#define SV_STCLOSE 6
200
201/* result of an I/O event */
202#define RES_SILENT 0 /* didn't happen */
203#define RES_DATA 1 /* data were sent or received */
204#define RES_NULL 2 /* result is 0 (read == 0), or connect without need for writing */
205#define RES_ERROR 3 /* result -1 or error on the socket (eg: connect()) */
206
207/* modes of operation */
208#define MODE_DEBUG 1
209#define MODE_STATS 2
210#define MODE_LOG 4
211#define MODE_DAEMON 8
212
213/*********************************************************************/
214
215#define LIST_HEAD(a) ((void *)(&(a)))
216
217/*********************************************************************/
218
219struct hdr_exp {
220 regex_t *preg; /* expression to look for */
221 char *replace; /* expression to set instead */
222};
223
224struct buffer {
225 unsigned int l; /* data length */
226 char *r, *w, *h, *lr; /* read ptr, write ptr, last header ptr, last read */
227 char data[BUFSIZE];
228};
229
230struct server {
231 struct server *next;
232 char *id; /* the id found in the cookie */
233 struct sockaddr_in addr; /* the address to connect to */
234};
235
236struct task {
237 struct task *next, *prev; /* chaining ... */
238 struct task *rqnext; /* chaining in run queue ... */
239 int state; /* task state : IDLE or RUNNING */
240 struct timeval expire; /* next expiration time for this task, use only for fast sorting */
241 /* application specific below */
242 struct timeval crexpire; /* expiration date for a client read */
243 struct timeval cwexpire; /* expiration date for a client write */
244 struct timeval srexpire; /* expiration date for a server read */
245 struct timeval swexpire; /* expiration date for a server write */
246 struct timeval cnexpire; /* expiration date for a connect */
247 char res_cr, res_cw, res_sr, res_sw;/* results of some events */
248 struct proxy *proxy; /* the proxy this socket belongs to */
249 int cli_fd; /* the client side fd */
250 int srv_fd; /* the server side fd */
251 int cli_state; /* state of the client side */
252 int srv_state; /* state of the server side */
253 int conn_retries; /* number of connect retries left */
254 int conn_redisp; /* allow reconnection to dispatch in case of errors */
255 struct buffer *req; /* request buffer */
256 struct buffer *rep; /* response buffer */
257 struct sockaddr_in cli_addr; /* the client address */
258 struct sockaddr_in srv_addr; /* the address to connect to */
259 char cookie_val[SERVERID_LEN+1]; /* the cookie value, if present */
260};
261
262struct proxy {
263 int listen_fd; /* the listen socket */
264 int state; /* proxy state */
265 struct sockaddr_in listen_addr; /* the address we listen to */
266 struct sockaddr_in dispatch_addr; /* the default address to connect to */
267 struct server *srv; /* known servers */
268 char *cookie_name; /* name of the cookie to look for */
269 int clitimeout; /* client I/O timeout (in milliseconds) */
270 int srvtimeout; /* server I/O timeout (in milliseconds) */
271 int contimeout; /* connect timeout (in milliseconds) */
272 char *id; /* proxy id */
273 int nbconn; /* # of active sessions */
274 int maxconn; /* max # of active sessions */
275 int conn_retries; /* number of connect retries left */
276 int conn_redisp; /* allow to reconnect to dispatch in case of errors */
277 int mode; /* mode = PR_MODE_TCP or PR_MODE_HTTP */
278 struct task task; /* active sessions (bi-dir chaining) */
279 struct task *rq; /* sessions in the run queue (unidir chaining) */
280 struct proxy *next;
281 struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
282 char logfac1, logfac2; /* log facility for both servers. -1 = disabled */
283 struct timeval stop_time; /* date to stop listening, when stopping != 0 */
284 int nb_cliexp, nb_srvexp;
285 struct hdr_exp cli_exp[MAX_REGEXP]; /* regular expressions for client headers */
286 struct hdr_exp srv_exp[MAX_REGEXP]; /* regular expressions for server headers */
287 int grace; /* grace time after stop request */
288};
289
290/* info about one given fd */
291struct fdtab {
292 int (*read)(int fd); /* read function */
293 int (*write)(int fd); /* write function */
294 struct task *owner; /* the session (or proxy) associated with this fd */
295 int state; /* the state of this fd */
296};
297
298/*********************************************************************/
299
300int cfg_maxconn = 2000; /* # of simultaneous connections, (-n) */
301int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
302int cfg_maxsock = 0; /* max # of sockets */
303char *cfg_cfgfile = NULL; /* configuration file */
304char *progname = NULL; /* program name */
305int pid; /* current process id */
306/*********************************************************************/
307
308fd_set *ReadEvent,
309 *WriteEvent,
310 *StaticReadEvent,
311 *StaticWriteEvent;
312
313void **pool_session = NULL,
314 **pool_buffer = NULL,
315 **pool_fdtab = NULL,
316 **pool_str256 = NULL;
317
318struct proxy *proxy = NULL; /* list of all existing proxies */
319struct fdtab *fdtab = NULL; /* array of all the file descriptors */
320
321static int mode = 0; /* MODE_DEBUG, ... */
322static int totalconn = 0; /* total # of terminated sessions */
323static int actconn = 0; /* # of active sessions */
324static int maxfd = 0; /* # of the highest fd + 1 */
325static int listeners = 0; /* # of listeners */
326static int stopping = 0; /* non zero means stopping in progress */
327static struct timeval now = {0,0}; /* the current date at any moment */
328
329static regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
330static char trash[BUFSIZE];
331
332/*
333 * Syslog facilities and levels
334 */
335
336#define MAX_SYSLOG_LEN 1024
337#define NB_LOG_FACILITIES 24
338const char *log_facilities[NB_LOG_FACILITIES] = {
339 "kern", "user", "mail", "daemon",
340 "auth", "syslog", "lpr", "news",
341 "uucp", "cron", "auth2", "ftp",
342 "ntp", "audit", "alert", "cron2",
343 "local0", "local1", "local2", "local3",
344 "local4", "local5", "local6", "local7"
345};
346
347
348#define NB_LOG_LEVELS 8
349const char *log_levels[NB_LOG_LEVELS] = {
350 "emerg", "alert", "crit", "err",
351 "warning", "notice", "info", "debug"
352};
353
354#define SYSLOG_PORT 514
355
356const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
357 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
358#define MAX_HOSTNAME_LEN 32
359static char hostname[MAX_HOSTNAME_LEN] = "";
360
361/*********************************************************************/
362/* statistics ******************************************************/
363/*********************************************************************/
364
365static int stats_tsk_lsrch, stats_tsk_rsrch,
366 stats_tsk_good, stats_tsk_right, stats_tsk_left,
367 stats_tsk_new, stats_tsk_nsrch;
368
369
370/*********************************************************************/
371/* function prototypes *********************************************/
372/*********************************************************************/
373
374int event_accept(int fd);
375int event_cli_read(int fd);
376int event_cli_write(int fd);
377int event_srv_read(int fd);
378int event_srv_write(int fd);
379
380/*********************************************************************/
381/* general purpose functions ***************************************/
382/*********************************************************************/
383
384void display_version() {
385 printf("HA-Proxy version " HAPROXY_VERSION " " HAPROXY_DATE"\n");
386 printf("Copyright 2000-2001 Willy Tarreau <willy AT meta-x DOT org>\n\n");
387}
388
389/*
390 * This function prints the command line usage and exits
391 */
392void usage(char *name) {
393 display_version();
394 fprintf(stderr,
395 "Usage : %s -f <cfgfile> [ -vd"
396#if STATTIME > 0
397 "sl"
398#endif
399 "D ] [ -n <maxconn> ] [ -N <maxpconn> ]\n"
400 " -v displays version\n"
401 " -d enters debug mode\n"
402#if STATTIME > 0
403 " -s enables statistics output\n"
404 " -l enables long statistics format\n"
405#endif
406 " -D goes daemon\n"
407 " -n sets the maximum total # of connections (%d)\n"
408 " -N sets the default, per-proxy maximum # of connections (%d)\n\n",
409 name, cfg_maxconn, cfg_maxpconn);
410 exit(1);
411}
412
413
414/*
415 * Displays the message on stderr with the date and pid.
416 */
417void Alert(char *fmt, ...) {
418 va_list argp;
419 struct timeval tv;
420 struct tm *tm;
421
422 va_start(argp, fmt);
423
424 gettimeofday(&tv, NULL);
425 tm=localtime(&tv.tv_sec);
426 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
427 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
428 vfprintf(stderr, fmt, argp);
429 fflush(stderr);
430 va_end(argp);
431}
432
433
434/*
435 * Displays the message on stderr with the date and pid.
436 */
437void Warning(char *fmt, ...) {
438 va_list argp;
439 struct timeval tv;
440 struct tm *tm;
441
442 va_start(argp, fmt);
443
444 gettimeofday(&tv, NULL);
445 tm=localtime(&tv.tv_sec);
446 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
447 tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid());
448 vfprintf(stderr, fmt, argp);
449 fflush(stderr);
450 va_end(argp);
451}
452
453
454/*
455 * converts <str> to a struct sockaddr_in* which is locally allocated.
456 * The format is "addr:port", where "addr" can be empty or "*" to indicate
457 * INADDR_ANY.
458 */
459struct sockaddr_in *str2sa(char *str) {
460 static struct sockaddr_in sa;
461 char *c;
462 int port;
463
464 bzero(&sa, sizeof(sa));
465 str=strdup(str);
466
467 if ((c=strrchr(str,':')) != NULL) {
468 *c++=0;
469 port=atol(c);
470 }
471 else
472 port=0;
473
474 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
475 sa.sin_addr.s_addr = INADDR_ANY;
476 }
477 else if (
478#ifndef SOLARIS
479 !inet_aton(str, &sa.sin_addr)
480#else
481 !inet_pton(AF_INET, str, &sa.sin_addr)
482#endif
483 ) {
484 struct hostent *he;
485
486 if ((he = gethostbyname(str)) == NULL) {
487 Alert("Invalid server name: <%s>\n",str);
488 }
489 else
490 sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
491 }
492 sa.sin_port=htons(port);
493 sa.sin_family=AF_INET;
494
495 free(str);
496 return &sa;
497}
498
499/*
500 * This function tries to send a syslog message to the syslog server at
501 * address <sa>. It doesn't care about errors nor does it report them.
502 * WARNING! no check is made on the prog+hostname+date length, so the
503 * local hostname + the prog name must be shorter than MAX_SYSLOG_LEN-19.
504 * the message will be truncated to fit the maximum length.
505 */
506void send_syslog(struct sockaddr_in *sa,
507 int facility, int level, char *message)
508{
509
510 static int logfd = -1; /* syslog UDP socket */
511 struct timeval tv;
512 struct tm *tm;
513 static char logmsg[MAX_SYSLOG_LEN];
514 char *p;
515
516 if (logfd < 0) {
517 if ((logfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
518 return;
519 }
520
521 if (facility < 0 || level < 0
522 || sa == NULL || progname == NULL || message == NULL)
523 return;
524
525 gettimeofday(&tv, NULL);
526 tm = localtime(&tv.tv_sec);
527
528 p = logmsg;
529 //p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s %s[%d]: ",
530 // facility * 8 + level,
531 // monthname[tm->tm_mon],
532 // tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
533 // hostname, progname, pid);
534 /* 20011216/WT : other progs don't set the hostname, and syslogd
535 * systematically repeats it which is contrary to RFC3164.
536 */
537 p += sprintf(p, "<%d>%s %2d %02d:%02d:%02d %s[%d]: ",
538 facility * 8 + level,
539 monthname[tm->tm_mon],
540 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
541 progname, pid);
542
543 if (((char *)&logmsg - p + MAX_SYSLOG_LEN) > 0) {
544 int len = strlen(message);
545 if (len > ((char *)&logmsg + MAX_SYSLOG_LEN - p))
546 len = ((char *)&logmsg + MAX_SYSLOG_LEN - p);
547 memcpy(p, message, len);
548 p += len;
549 }
willy tarreau3242e862005-12-17 12:27:53 +0100550#ifndef MSG_NOSIGNAL
551 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT,
552 (struct sockaddr *)sa, sizeof(*sa));
553#else
willy tarreau0f7af912005-12-17 12:21:26 +0100554 sendto(logfd, logmsg, p - logmsg, MSG_DONTWAIT | MSG_NOSIGNAL,
555 (struct sockaddr *)sa, sizeof(*sa));
willy tarreau3242e862005-12-17 12:27:53 +0100556#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100557}
558
559
560/* sets <tv> to the current time */
561static inline struct timeval *tv_now(struct timeval *tv) {
562 if (tv)
563 gettimeofday(tv, NULL);
564 return tv;
565}
566
567/*
568 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
569 */
570static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *from, int ms) {
571 if (!tv || !from)
572 return NULL;
573 tv->tv_usec = from->tv_usec + (ms%1000)*1000;
574 tv->tv_sec = from->tv_sec + (ms/1000);
575 while (tv->tv_usec >= 1000000) {
576 tv->tv_usec -= 1000000;
577 tv->tv_sec++;
578 }
579 return tv;
580}
581
582/*
583 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
584 */
585static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
586 if (tv1->tv_sec > tv2->tv_sec)
587 return 1;
588 else if (tv1->tv_sec < tv2->tv_sec)
589 return -1;
590 else if (tv1->tv_usec > tv2->tv_usec)
591 return 1;
592 else if (tv1->tv_usec < tv2->tv_usec)
593 return -1;
594 else
595 return 0;
596}
597
598/*
599 * returns the absolute difference, in ms, between tv1 and tv2
600 */
601unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
602 int cmp;
603 unsigned long ret;
604
605
606 cmp=tv_cmp(tv1, tv2);
607 if (!cmp)
608 return 0; /* same dates, null diff */
609 else if (cmp<0) {
610 struct timeval *tmp=tv1;
611 tv1=tv2;
612 tv2=tmp;
613 }
614 ret=(tv1->tv_sec - tv2->tv_sec)*1000;
615 if (tv1->tv_usec > tv2->tv_usec)
616 ret+=(tv1->tv_usec - tv2->tv_usec)/1000;
617 else
618 ret-=(tv2->tv_usec - tv1->tv_usec)/1000;
619 return (unsigned long) ret;
620}
621
622/*
623 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
624 */
625static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
626 if ((tv1->tv_sec > tv2->tv_sec + 1) ||
627 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
628 return 1;
629 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
630 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
631 return -1;
632 else
633 return 0;
634}
635
636/*
637 * returns the remaining time between tv1=now and event=tv2
638 * if tv2 is passed, 0 is returned.
639 */
640static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
641 unsigned long ret;
642
643
644 if (tv_cmp_ms(tv1, tv2) >= 0)
645 return 0; /* event elapsed */
646
647 ret=(tv2->tv_sec - tv1->tv_sec)*1000;
648 if (tv2->tv_usec > tv1->tv_usec)
649 ret+=(tv2->tv_usec - tv1->tv_usec)/1000;
650 else
651 ret-=(tv1->tv_usec - tv2->tv_usec)/1000;
652 return (unsigned long) ret;
653}
654
655
656/*
657 * zeroes a struct timeval
658 */
659
660static inline struct timeval *tv_eternity(struct timeval *tv) {
661 tv->tv_sec = tv->tv_usec = 0;
662 return tv;
663}
664
665/*
666 * returns 1 if tv is null, else 0
667 */
668static inline int tv_iseternity(struct timeval *tv) {
669 if (tv->tv_sec == 0 && tv->tv_usec == 0)
670 return 1;
671 else
672 return 0;
673}
674
675/*
676 * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
677 * considering that 0 is the eternity.
678 */
679static inline int tv_cmp2(struct timeval *tv1, struct timeval *tv2) {
680 if (tv_iseternity(tv1))
681 if (tv_iseternity(tv2))
682 return 0; /* same */
683 else
684 return 1; /* tv1 later than tv2 */
685 else if (tv_iseternity(tv2))
686 return -1; /* tv2 later than tv1 */
687
688 if (tv1->tv_sec > tv2->tv_sec)
689 return 1;
690 else if (tv1->tv_sec < tv2->tv_sec)
691 return -1;
692 else if (tv1->tv_usec > tv2->tv_usec)
693 return 1;
694 else if (tv1->tv_usec < tv2->tv_usec)
695 return -1;
696 else
697 return 0;
698}
699
700/*
701 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
702 * considering that 0 is the eternity.
703 */
704static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
705 if (tv_iseternity(tv1))
706 if (tv_iseternity(tv2))
707 return 0; /* same */
708 else
709 return 1; /* tv1 later than tv2 */
710 else if (tv_iseternity(tv2))
711 return -1; /* tv2 later than tv1 */
712
713 if ((tv1->tv_sec > tv2->tv_sec + 1) ||
714 ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 >= tv2->tv_usec + 1000)))
715 return 1;
716 else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
717 ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 >= tv1->tv_usec + 1000)))
718 return -1;
719 else
720 return 0;
721}
722
723/*
724 * returns the first event between tv1 and tv2 into tvmin.
725 * a zero tv is ignored. tvmin is returned.
726 */
727static inline struct timeval *tv_min(struct timeval *tvmin,
728 struct timeval *tv1, struct timeval *tv2) {
729
730 if (tv_cmp2(tv1, tv2) <= 0)
731 *tvmin = *tv1;
732 else
733 *tvmin = *tv2;
734
735 return tvmin;
736}
737
738
739
740/***********************************************************/
741/* fd management ***************************************/
742/***********************************************************/
743
744
745
746/* deletes an FD from the fdsets, and recomputes the maxfd limit */
747static inline void fd_delete(int fd) {
748 fdtab[fd].state = FD_STCLOSE;
749 FD_CLR(fd, StaticReadEvent);
750 FD_CLR(fd, StaticWriteEvent);
751
752 while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
753 maxfd--;
754}
755
756/* recomputes the maxfd limit from the fd */
757static inline void fd_insert(int fd) {
758 if (fd+1 > maxfd)
759 maxfd = fd+1;
760}
761
762/*************************************************************/
763/* task management ***************************************/
764/*************************************************************/
765
766/* puts the task <s> in <p>'s run queue, and returns <s> */
767static inline struct task *task_wakeup(struct proxy *p, struct task *s) {
768 // fprintf(stderr,"task_wakeup: proxy %p, task %p\n", p, s);
769
770 if (s->state == TASK_RUNNING)
771 return s;
772 else {
773 s->rqnext = p->rq;
774 s->state = TASK_RUNNING;
775 return p->rq = s;
776 }
777}
778
779/* removes the task <s> from <p>'s run queue.
780 * <s> MUST be <p>'s first task in the queue.
781 * set the run queue to point to the next one, and return it
782 */
783static inline struct task *task_sleep(struct proxy *p, struct task *s) {
784 if (s->state == TASK_RUNNING) {
785 p->rq = s->rqnext;
786 s->state = TASK_IDLE; /* tell that s has left the run queue */
787 }
788 return p->rq; /* return next running task */
789}
790
791/*
792 * removes the task <s> from its wait queue. It must have already been removed
793 * from the run queue. A pointer to the task itself is returned.
794 */
795static inline struct task *task_delete(struct task *s) {
796 s->prev->next = s->next;
797 s->next->prev = s->prev;
798 return s;
799}
800
801/*
802 * frees the context associated to a task. It must have been removed first.
803 */
804static inline void task_free(struct task *t) {
805 if (t->req)
806 pool_free(buffer, t->req);
807 if (t->rep)
808 pool_free(buffer, t->rep);
809 pool_free(session, t);
810}
811
812/* inserts <task> into the list <list>, where it may already be. In this case, it
813 * may be only moved or left where it was, depending on its timing requirements.
814 * <task> is returned.
815 */
816
817struct task *task_queue(struct task *list, struct task *task) {
818 struct task *start_from;
819
820 /* first, test if the task was already in a list */
821 if (task->prev == NULL) {
822 // start_from = list;
823 start_from = list->prev;
824 stats_tsk_new++;
825
826 /* insert the unlinked <task> into the list, searching back from the last entry */
827 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
828 start_from = start_from->prev;
829 stats_tsk_nsrch++;
830 }
831
832 // while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
833 // start_from = start_from->next;
834 // stats_tsk_nsrch++;
835 // }
836 }
837 else if (task->prev == list ||
838 tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
839 start_from = task->next;
840 if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
841 stats_tsk_good++;
842 return task; /* it's already in the right place */
843 }
844
845 stats_tsk_right++;
846 /* insert the unlinked <task> into the list, searching after position <start_from> */
847 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
848 start_from = start_from->next;
849 stats_tsk_rsrch++;
850 }
851 /* we need to unlink it now */
852 task_delete(task);
853 }
854 else { /* walk left. */
855 stats_tsk_left++;
856#ifdef LEFT_TO_TOP /* not very good */
857 start_from = list;
858 while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
859 start_from = start_from->next;
860 stats_tsk_lsrch++;
861 }
862#else
863 start_from = task->prev->prev; /* valid because of the previous test above */
864 while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
865 start_from = start_from->prev;
866 stats_tsk_lsrch++;
867 }
868#endif
869 /* we need to unlink it now */
870 task_delete(task);
871 }
872 task->prev = start_from;
873 task->next = start_from->next;
874 task->next->prev = task;
875 start_from->next = task;
876 return task;
877}
878
879
880/*********************************************************************/
881/* more specific functions ***************************************/
882/*********************************************************************/
883
884/* some prototypes */
885static int maintain_proxies(void);
886
887
888/*
889 * This function initiates a connection to the server whose name is in <s->proxy->src->id>,
890 * or the dispatch server if <id> not found. It returns 0 if
891 * it's OK, -1 if it's impossible.
892 */
893int connect_server(struct task *s, int usecookie) {
894 struct server *srv = s->proxy->srv;
895 char *sn = s->cookie_val;
896 int one = 1;
897 int fd;
898
899 // fprintf(stderr,"connect_server : s=%p\n",s);
900
901 if (usecookie) {
902 while (*sn && srv && strcmp(sn, srv->id)) {
903 srv = srv->next;
904 }
905 if (!srv || !*sn) { /* server not found, let's use the dispatcher */
906 s->srv_addr = s->proxy->dispatch_addr;
907 }
908 else {
909 s->srv_addr = srv->addr;
910 }
911 }
912 else
913 s->srv_addr = s->proxy->dispatch_addr;
914
915 if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
916 fprintf(stderr,"Cannot get a server socket.\n");
917 return -1;
918 }
919
920 if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
921 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
922 fprintf(stderr,"Cannot set client socket to non blocking mode.\n");
923 close(fd);
924 return -1;
925 }
926
927 if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
928 if (errno == EAGAIN) { /* no free ports left, try again later */
929 fprintf(stderr,"Cannot connect, no free ports.\n");
930 close(fd);
931 return -1;
932 }
933 else if (errno != EALREADY && errno != EISCONN) {
934 close(fd);
935 return -1;
936 }
937 }
938
939 fdtab[fd].owner = s;
940 fdtab[fd].read = &event_srv_read;
941 fdtab[fd].write = &event_srv_write;
942 fdtab[fd].state = FD_STCONN; /* connection in progress */
943
944 FD_SET(fd, StaticWriteEvent); /* for connect status */
945
946 fd_insert(fd);
947
948 if (s->proxy->contimeout)
949 tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
950 else
951 tv_eternity(&s->cnexpire);
952 return 0;
953}
954
955/*
956 * this function is called on a read event from a client socket.
957 * It returns 0.
958 */
959int event_cli_read(int fd) {
960 struct task *s = fdtab[fd].owner;
961 struct buffer *b = s->req;
962 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +0100963
964 // fprintf(stderr,"event_cli_read : fd=%d, s=%p\n", fd, s);
965
966 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +0100967 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +0100968 max = BUFSIZE - MAXREWRITE;
969 }
970 else if (b->r > b->w) {
971 max = b->data + BUFSIZE - MAXREWRITE - b->r;
972 }
973 else {
974 max = b->w - b->r;
975 if (max > BUFSIZE - MAXREWRITE)
976 max = BUFSIZE - MAXREWRITE;
977 }
978
979 if (max == 0) {
980 FD_CLR(fd, StaticReadEvent);
981 //fprintf(stderr, "cli_read(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
982 //fd, max, b->data, b->r, b->w, b->l);
983 return 0;
984 }
985
willy tarreau0f7af912005-12-17 12:21:26 +0100986 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +0100987#ifndef MSG_NOSIGNAL
988 int skerr, lskerr;
989 lskerr=sizeof(skerr);
990 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
991 if (skerr)
992 ret = -1;
993 else
994 ret = recv(fd, b->r, max, 0);
995#else
willy tarreau0f7af912005-12-17 12:21:26 +0100996 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +0100997#endif
willy tarreau0f7af912005-12-17 12:21:26 +0100998
999 if (ret > 0) {
1000 b->r += ret;
1001 b->l += ret;
1002 s->res_cr = RES_DATA;
1003
1004 if (b->r == b->data + BUFSIZE) {
1005 b->r = b->data; /* wrap around the buffer */
1006 }
1007 }
1008 else if (ret == 0)
1009 s->res_cr = RES_NULL;
1010 else if (errno == EAGAIN) /* ignore EAGAIN */
1011 return 0;
1012 else {
1013 s->res_cr = RES_ERROR;
1014 fdtab[fd].state = FD_STERROR;
1015 }
1016 }
1017 else {
1018 s->res_cr = RES_ERROR;
1019 fdtab[fd].state = FD_STERROR;
1020 }
1021
1022 if (s->proxy->clitimeout)
1023 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1024 else
1025 tv_eternity(&s->crexpire);
1026
1027 task_wakeup(s->proxy, s);
1028 return 0;
1029}
1030
1031
1032/*
1033 * this function is called on a read event from a server socket.
1034 * It returns 0.
1035 */
1036int event_srv_read(int fd) {
1037 struct task *s = fdtab[fd].owner;
1038 struct buffer *b = s->rep;
1039 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001040
1041 // fprintf(stderr,"event_srv_read : fd=%d, s=%p\n", fd, s);
1042
1043 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001044 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001045 max = BUFSIZE - MAXREWRITE;
1046 }
1047 else if (b->r > b->w) {
1048 max = b->data + BUFSIZE - MAXREWRITE - b->r;
1049 }
1050 else {
1051 max = b->w - b->r;
1052 if (max > BUFSIZE - MAXREWRITE)
1053 max = BUFSIZE - MAXREWRITE;
1054 }
1055
1056 if (max == 0) {
1057 FD_CLR(fd, StaticReadEvent);
1058 //fprintf(stderr, "srv_read(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1059 //fd, max, b->data, b->r, b->w, b->l);
1060 return 0;
1061 }
1062
willy tarreau0f7af912005-12-17 12:21:26 +01001063 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001064#ifndef MSG_NOSIGNAL
1065 int skerr, lskerr;
1066 lskerr=sizeof(skerr);
1067 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1068 if (skerr)
1069 ret = -1;
1070 else
1071 ret = recv(fd, b->r, max, 0);
1072#else
willy tarreau0f7af912005-12-17 12:21:26 +01001073 ret = recv(fd, b->r, max, MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001074#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001075 if (ret > 0) {
1076 b->r += ret;
1077 b->l += ret;
1078 s->res_sr = RES_DATA;
1079
1080 if (b->r == b->data + BUFSIZE) {
1081 b->r = b->data; /* wrap around the buffer */
1082 }
1083 }
1084 else if (ret == 0)
1085 s->res_sr = RES_NULL;
1086 else if (errno != EAGAIN) /* ignore EAGAIN */
1087 return 0;
1088 else {
1089 s->res_sr = RES_ERROR;
1090 fdtab[fd].state = FD_STERROR;
1091 }
1092 }
1093 else {
1094 s->res_sr = RES_ERROR;
1095 fdtab[fd].state = FD_STERROR;
1096 }
1097
1098
1099 if (s->proxy->srvtimeout)
1100 tv_delayfrom(&s->srexpire, &now, s->proxy->srvtimeout);
1101 else
1102 tv_eternity(&s->srexpire);
1103
1104 task_wakeup(s->proxy, s);
1105 return 0;
1106}
1107
1108/*
1109 * this function is called on a write event from a client socket.
1110 * It returns 0.
1111 */
1112int event_cli_write(int fd) {
1113 struct task *s = fdtab[fd].owner;
1114 struct buffer *b = s->rep;
1115 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001116
1117 // fprintf(stderr,"event_cli_write : fd=%d, s=%p\n", fd, s);
1118
1119 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001120 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001121 // max = BUFSIZE; BUG !!!!
1122 max = 0;
1123 }
1124 else if (b->r > b->w) {
1125 max = b->r - b->w;
1126 }
1127 else
1128 max = b->data + BUFSIZE - b->w;
1129
1130 if (max == 0) {
1131 FD_CLR(fd, StaticWriteEvent);
1132 //fprintf(stderr, "cli_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1133 //fd, max, b->data, b->r, b->w, b->l);
1134 s->res_cw = RES_NULL;
1135 return 0;
1136 }
1137
willy tarreau0f7af912005-12-17 12:21:26 +01001138 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001139#ifndef MSG_NOSIGNAL
1140 int skerr, lskerr;
1141#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001142 if (max == 0) { /* nothing to write, just make as if we were never called */
1143 s->res_cw = RES_NULL;
1144 task_wakeup(s->proxy, s);
1145 return 0;
1146 }
1147
willy tarreau3242e862005-12-17 12:27:53 +01001148#ifndef MSG_NOSIGNAL
1149 lskerr=sizeof(skerr);
1150 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1151 if (skerr)
1152 ret = -1;
1153 else
1154 ret = send(fd, b->w, max, MSG_DONTWAIT);
1155#else
willy tarreau0f7af912005-12-17 12:21:26 +01001156 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001157#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001158
1159 if (ret > 0) {
1160 b->l -= ret;
1161 b->w += ret;
1162
1163 s->res_cw = RES_DATA;
1164
1165 if (b->w == b->data + BUFSIZE) {
1166 b->w = b->data; /* wrap around the buffer */
1167 }
1168 }
1169 else if (ret == 0) {
1170 /* nothing written, just make as if we were never called */
1171// s->res_cw = RES_NULL;
1172 return 0;
1173 }
1174 else if (errno == EAGAIN) /* ignore EAGAIN */
1175 return 0;
1176 else {
1177 s->res_cw = RES_ERROR;
1178 fdtab[fd].state = FD_STERROR;
1179 }
1180 }
1181 else {
1182 s->res_cw = RES_ERROR;
1183 fdtab[fd].state = FD_STERROR;
1184 }
1185
1186 if (s->proxy->clitimeout)
1187 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
1188 else
1189 tv_eternity(&s->cwexpire);
1190
1191 task_wakeup(s->proxy, s);
1192 return 0;
1193}
1194
1195
1196/*
1197 * this function is called on a write event from a server socket.
1198 * It returns 0.
1199 */
1200int event_srv_write(int fd) {
1201 struct task *s = fdtab[fd].owner;
1202 struct buffer *b = s->req;
1203 int ret, max;
willy tarreau0f7af912005-12-17 12:21:26 +01001204
1205 //fprintf(stderr,"event_srv_write : fd=%d, s=%p\n", fd, s);
1206
1207 if (b->l == 0) { /* let's realign the buffer to optimize I/O */
willy tarreau9da061b2005-12-17 12:29:56 +01001208 b->r = b->w = b->h = b->lr = b->data;
willy tarreau0f7af912005-12-17 12:21:26 +01001209 // max = BUFSIZE; BUG !!!!
1210 max = 0;
1211 }
1212 else if (b->r > b->w) {
1213 max = b->r - b->w;
1214 }
1215 else
1216 max = b->data + BUFSIZE - b->w;
1217
1218 if (max == 0) {
1219 FD_CLR(fd, StaticWriteEvent);
1220 //fprintf(stderr, "srv_write(%d) : max=%d, d=%p, r=%p, w=%p, l=%d\n",
1221 //fd, max, b->data, b->r, b->w, b->l);
1222 s->res_sw = RES_NULL;
1223 return 0;
1224 }
1225
willy tarreau0f7af912005-12-17 12:21:26 +01001226 if (fdtab[fd].state != FD_STERROR) {
willy tarreau3242e862005-12-17 12:27:53 +01001227#ifndef MSG_NOSIGNAL
1228 int skerr, lskerr;
1229#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001230 fdtab[fd].state = FD_STREADY;
1231 if (max == 0) { /* nothing to write, just make as if we were never called, except to finish a connect() */
1232 s->res_sw = RES_NULL;
1233 task_wakeup(s->proxy, s);
1234 return 0;
1235 }
1236
willy tarreau3242e862005-12-17 12:27:53 +01001237#ifndef MSG_NOSIGNAL
1238 lskerr=sizeof(skerr);
1239 getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
1240 if (skerr)
1241 ret = -1;
1242 else
1243 ret = send(fd, b->w, max, MSG_DONTWAIT);
1244#else
willy tarreau0f7af912005-12-17 12:21:26 +01001245 ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
willy tarreau3242e862005-12-17 12:27:53 +01001246#endif
willy tarreau0f7af912005-12-17 12:21:26 +01001247 if (ret > 0) {
1248 b->l -= ret;
1249 b->w += ret;
1250
1251 s->res_sw = RES_DATA;
1252
1253 if (b->w == b->data + BUFSIZE) {
1254 b->w = b->data; /* wrap around the buffer */
1255 }
1256 }
1257 else if (ret == 0) {
1258 /* nothing written, just make as if we were never called */
1259 // s->res_sw = RES_NULL;
1260 return 0;
1261 }
1262 else if (errno == EAGAIN) /* ignore EAGAIN */
1263 return 0;
1264 else {
1265 s->res_sw = RES_ERROR;
1266 fdtab[fd].state = FD_STERROR;
1267 }
1268 }
1269 else {
1270 s->res_sw = RES_ERROR;
1271 fdtab[fd].state = FD_STERROR;
1272 }
1273
1274 if (s->proxy->srvtimeout)
1275 tv_delayfrom(&s->swexpire, &now, s->proxy->srvtimeout);
1276 else
1277 tv_eternity(&s->swexpire);
1278
1279 task_wakeup(s->proxy, s);
1280 return 0;
1281}
1282
1283
1284/*
1285 * this function is called on a read event from a listen socket, corresponding
1286 * to an accept. It returns 0.
1287 */
1288int event_accept(int fd) {
1289 struct proxy *p = (struct proxy *)fdtab[fd].owner;
1290 struct task *s;
1291 int laddr;
1292 int cfd;
1293 int one = 1;
1294
1295 if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
1296 Alert("out of memory in event_accept().\n");
1297 FD_CLR(fd, StaticReadEvent);
1298 p->state = PR_STIDLE;
1299 return 0;
1300 }
1301
1302 laddr = sizeof(s->cli_addr);
1303 if ((cfd = accept(fd, (struct sockaddr *)&s->cli_addr, &laddr)) == -1) {
1304 pool_free(session, s);
1305 return 0;
1306 }
1307
1308 if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
1309 (setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
1310 (char *) &one, sizeof(one)) == -1)) {
1311 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
1312 close(cfd);
1313 pool_free(session, s);
1314 return 0;
1315 }
1316
1317 if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
1318 && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
1319 struct sockaddr_in peername, sockname;
1320 unsigned char *pn, *sn;
1321 int namelen;
1322 char message[256];
1323
1324 namelen = sizeof(peername);
1325 getpeername(cfd, (struct sockaddr *)&peername, &namelen);
1326 pn = (unsigned char *)&peername.sin_addr;
1327
1328 namelen = sizeof(sockname);
1329 getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
1330 sn = (unsigned char *)&sockname.sin_addr;
1331
1332 sprintf(message, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
1333 pn[0], pn[1], pn[2], pn[3], ntohs(peername.sin_port),
1334 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
1335 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
1336
1337 if (p->logfac1 >= 0)
1338 send_syslog(&p->logsrv1, p->logfac1, LOG_INFO, message);
1339 if (p->logfac2 >= 0)
1340 send_syslog(&p->logsrv2, p->logfac2, LOG_INFO, message);
1341 }
1342
1343 s->proxy = p;
1344 s->state = TASK_IDLE;
1345 s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
1346 s->srv_state = SV_STIDLE;
1347 s->req = s->rep = NULL; /* will be allocated later */
1348 s->cookie_val[0] = 0;
1349 s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
1350 s->rqnext = NULL; /* task not in run queue */
1351 s->next = s->prev = NULL;
1352 s->cli_fd = cfd;
1353 s->conn_retries = p->conn_retries;
1354 s->conn_redisp = p->conn_redisp;
1355
1356 if ((s->req = pool_alloc(buffer)) == NULL) { /* no memory */
1357 close(cfd); /* nothing can be done for this fd without memory */
1358 pool_free(session, s);
1359 return 0;
1360 }
1361 s->req->l = 0;
1362 s->req->h = s->req->r = s->req->lr = s->req->w = s->req->data; /* r and w will be reset further */
1363
1364 if ((s->rep = pool_alloc(buffer)) == NULL) { /* no memory */
1365 pool_free(buffer, s->req);
1366 close(cfd); /* nothing can be done for this fd without memory */
1367 pool_free(session, s);
1368 return 0;
1369 }
1370 s->rep->l = 0;
1371 s->rep->h = s->rep->r = s->rep->lr = s->rep->w = s->rep->data;
1372
1373 fdtab[cfd].read = &event_cli_read;
1374 fdtab[cfd].write = &event_cli_write;
1375 fdtab[cfd].owner = s;
1376 fdtab[cfd].state = FD_STREADY;
1377
1378 if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
1379 FD_CLR(cfd, StaticReadEvent);
1380 tv_eternity(&s->crexpire);
1381 shutdown(s->cli_fd, SHUT_RD);
1382 s->cli_state = CL_STSHUTR;
1383
1384 strcpy(s->rep->data, "OK\n"); /* forge an "OK" response */
1385 s->rep->l = 3;
1386 s->rep->r += 3;
1387 }
1388 else {
1389 FD_SET(cfd, StaticReadEvent);
1390 }
1391
1392 fd_insert(cfd);
1393
1394 tv_eternity(&s->cnexpire);
1395 tv_eternity(&s->srexpire);
1396 tv_eternity(&s->swexpire);
1397 tv_eternity(&s->cwexpire);
1398
1399 if (s->proxy->clitimeout)
1400 tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
1401 else
1402 tv_eternity(&s->crexpire);
1403
1404 s->expire = s->crexpire;
1405
1406 task_queue(LIST_HEAD(p->task), s);
1407 task_wakeup(p, s);
1408
1409 p->nbconn++;
1410 actconn++;
1411 totalconn++;
1412
1413 // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
1414
1415 return 0;
1416}
1417
1418
1419/*
1420 * this function writes the string <str> at position <pos> which must be in buffer <b>,
1421 * and moves <end> just after the end of <str>.
1422 * <b>'s parameters (l, r, w, h, lr) are recomputed to be valid after the shift.
1423 * the shift value (positive or negative) is returned.
1424 * If there's no space left, the move is not done.
1425 *
1426 */
1427int buffer_replace(struct buffer *b, char *pos, char *str, char *end) {
1428 int delta;
1429 int len;
1430
1431 len = strlen(str);
1432 delta = len - (end - pos);
1433
1434 if (delta + b->r >= b->data + BUFSIZE)
1435 return 0; /* no space left */
1436
1437 /* first, protect the end of the buffer */
1438 memmove(end + delta, end, b->data + b->l - end);
1439
1440 /* now, copy str over pos */
1441 memcpy(pos, str,len);
1442
1443 if (b->r >= end) b->r += delta;
1444 if (b->w >= end) b->w += delta;
1445 if (b->h >= end) b->h += delta;
1446 if (b->lr >= end) b->lr += delta;
1447 b->l += delta;
1448
1449 return delta;
1450}
1451
1452/* same except that the string len is given */
1453int buffer_replace2(struct buffer *b, char *pos, char *str, int len, char *end) {
1454 int delta;
1455
1456 delta = len - (end - pos);
1457
1458 if (delta + b->r >= b->data + BUFSIZE)
1459 return 0; /* no space left */
1460
1461 /* first, protect the end of the buffer */
1462 memmove(end + delta, end, b->data + b->l - end);
1463
1464 /* now, copy str over pos */
1465 memcpy(pos, str,len);
1466
1467 if (b->r >= end) b->r += delta;
1468 if (b->w >= end) b->w += delta;
1469 if (b->h >= end) b->h += delta;
1470 if (b->lr >= end) b->lr += delta;
1471 b->l += delta;
1472
1473 return delta;
1474}
1475
1476
1477int exp_replace(char *dst, char *src, char *str, regmatch_t *matches) {
1478 char *old_dst = dst;
1479
1480 while (*str) {
1481 if (*str == '\\') {
1482 str++;
1483 if (isdigit(*str)) {
1484 int len, num;
1485
1486 num = *str - '0';
1487 str++;
1488
1489 if (matches[num].rm_so > -1) {
1490 len = matches[num].rm_eo - matches[num].rm_so;
1491 memcpy(dst, src + matches[num].rm_so, len);
1492 dst += len;
1493 }
1494
1495 }
1496 else if (*str == 'x') {
1497 unsigned char hex1, hex2;
1498 str++;
1499
1500 hex1=toupper(*str++) - '0'; hex2=toupper(*str++) - '0';
1501
1502 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
1503 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
1504 *dst++ = (hex1<<4) + hex2;
1505 }
1506 else
1507 *dst++ = *str++;
1508 }
1509 else
1510 *dst++ = *str++;
1511 }
1512 *dst = 0;
1513 return dst - old_dst;
1514}
1515
1516/*
1517 * manages the client FSM and its socket. BTW, it also tries to handle the
1518 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1519 * 0 else.
1520 */
1521int process_cli(struct task *t) {
1522 int s = t->srv_state;
1523 int c = t->cli_state;
1524 struct buffer *req = t->req;
1525 struct buffer *rep = t->rep;
1526
1527 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1528 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1529 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1530 //);
1531 if (c == CL_STHEADERS) {
1532 char *ptr;
1533
1534 /* read timeout, read error, or last read : give up */
1535 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL ||
1536 tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1537 FD_CLR(t->cli_fd, StaticReadEvent);
1538 FD_CLR(t->cli_fd, StaticWriteEvent);
1539 fd_delete(t->cli_fd);
1540 close(t->cli_fd);
1541 tv_eternity(&t->crexpire);
1542 t->cli_state = CL_STCLOSE;
1543 return 1;
1544 }
1545 else if (t->res_cr == RES_SILENT) {
1546 return 0;
1547 }
1548 /* now we know that there are headers to process */
1549
1550 if (req->l >= BUFSIZE - MAXREWRITE) {
1551 /* buffer full : stop reading till we free some space */
1552 FD_CLR(t->cli_fd, StaticReadEvent);
1553 tv_eternity(&t->crexpire);
1554 }
1555
1556 ptr = req->lr;
1557 req->lr = req->r; /* tell that bytes up to <lr> have been read and processes */
1558 while (ptr < req->r) {
1559 /* look for the end of the current header */
1560 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
1561 ptr++;
1562
1563 if (ptr < req->r) {
1564 /* now we have one complete client header between req->h and ptr */
1565 if (ptr == req->h) { /* empty line, end of headers */
1566 t->cli_state = CL_STDATA;
1567 //req->lr = ptr; /* tell that bytes up to <lr> have been read and processes */
1568 return 1;
1569 }
1570 else {
1571 /* we have one standard header */
1572 if (mode & MODE_DEBUG) {
1573 int len, max;
1574 len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1575 max = ptr - req->h;
willy tarreau9da061b2005-12-17 12:29:56 +01001576 UBOUND(max, sizeof(trash) - len - 1);
1577 len += strlcpy(trash + len, req->h, max + 1);
willy tarreau0f7af912005-12-17 12:21:26 +01001578 trash[len++] = '\n';
willy tarreau0f7af912005-12-17 12:21:26 +01001579 write(1, trash, len);
1580 }
1581
1582 if ((req->r >= req->h + 8) && (t->proxy->cookie_name != NULL)
1583 && (strncmp(req->h, "Cookie: ", 8) == 0)) {
1584 char *p1, *p2, *p3, *p4;
1585
1586 p1 = req->h + 8; /* first char after 'Cookie: ' */
1587
1588 while (p1 < ptr) {
1589 while (p1 < ptr && (isspace(*p1) || *p1 == ';'))
1590 p1++;
1591
1592 if (p1 == ptr)
1593 break;
1594 else if (*p1 == ';') { /* next cookie */
1595 ++p1;
1596 continue;
1597 }
1598
1599 /* p1 is at the beginning of the cookie name */
1600 p2 = p1;
1601
1602 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1603 p2++;
1604
1605 if (p2 == ptr)
1606 break;
1607 else if (*p2 == ';') { /* next cookie */
1608 p1=++p2;
1609 continue;
1610 }
1611
1612 p3 = p2 + 1; /* skips the '=' sign */
1613 if (p3 == ptr)
1614 break;
1615
1616 p4=p3;
1617 while (p4 < ptr && !isspace(*p4) && *p4 != ';')
1618 p4++;
1619
1620 /* here, we have the cookie name between p1 and p2,
1621 * and its value between p3 and p4.
1622 * we can process it.
1623 */
1624
1625 if ((p2-p1 == strlen(t->proxy->cookie_name)) &&
1626 (strncmp(p1, t->proxy->cookie_name, p2-p1) == 0)) {
1627 /* Cool... it's the right one */
1628 int l;
1629 l = (p4 - p3) < SERVERID_LEN ?
1630 (p4 - p3) : SERVERID_LEN;
willy tarreau9da061b2005-12-17 12:29:56 +01001631 strlcpy(t->cookie_val, p3, l + 1);
willy tarreau0f7af912005-12-17 12:21:26 +01001632 break;
1633 }
1634 else {
1635// fprintf(stderr,"Ignoring unknown cookie : ");
1636// write(2, p1, p2-p1);
1637// fprintf(stderr," = ");
1638// write(2, p3, p4-p3);
1639// fprintf(stderr,"\n");
1640 }
1641 /* we'll have to look for another cookie ... */
1642 p1 = p4;
1643 }
1644 /* FIXME */
1645// fprintf(stderr,"Cookie is now: <%s>\n", s->cookie_val);
1646 }
1647 else if (t->proxy->nb_cliexp) { /* try headers regexps */
1648 struct proxy *p = t->proxy;
1649 int exp;
1650 char term;
1651
1652 term = *ptr;
1653 *ptr = '\0';
1654 for (exp=0; exp < p->nb_cliexp; exp++) {
1655 if (regexec(p->cli_exp[exp].preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
1656 int len = exp_replace(trash, req->h, p->cli_exp[exp].replace, pmatch);
1657 ptr += buffer_replace2(req, req->h, trash, len, ptr);
1658 break;
1659 }
1660 }
1661 *ptr = term; /* restore the string terminator */
1662 }
1663
1664 /* look for the beginning of the next header */
1665 if (ptr < req->r) {
1666 if (*ptr == '\n') {
1667 if ((++ptr < req->r) && (*ptr == '\r'))
1668 ptr++;
1669 }
1670 else if (*ptr == '\r') {
1671 if ((++ptr < req->r) && (*ptr == '\n'))
1672 ptr++;
1673 }
1674 req->h = ptr;
1675 }
1676 }
1677 }
1678 else if (ptr >= req->data + BUFSIZE - MAXREWRITE) { /* no more headers */
1679 t->cli_state = CL_STDATA;
1680 FD_CLR(t->cli_fd, StaticReadEvent);
1681 tv_eternity(&t->crexpire);
1682 //req->lr = ptr; /* tell that bytes up to <lr> have been read and processes */
1683 return 1;
1684 }
1685 }
1686 //req->lr = ptr; /* tell that bytes up to <lr> have been read and processes */
1687 }
1688 else if (c == CL_STDATA) {
1689 /* read or write error */
1690 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
1691 FD_CLR(t->cli_fd, StaticReadEvent);
1692 FD_CLR(t->cli_fd, StaticWriteEvent);
1693 tv_eternity(&t->crexpire);
1694 tv_eternity(&t->cwexpire);
1695 close(t->cli_fd);
1696 t->cli_state = CL_STCLOSE;
1697 return 1;
1698 }
1699 /* read timeout, last read, or end of server write */
1700 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
1701 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1702
1703 FD_CLR(t->cli_fd, StaticReadEvent);
1704 // if (req->l == 0) /* nothing to write on the server side */
1705 // FD_CLR(t->srv_fd, StaticWriteEvent);
1706 tv_eternity(&t->crexpire);
1707 shutdown(t->cli_fd, SHUT_RD);
1708 t->cli_state = CL_STSHUTR;
1709 return 1;
1710 }
1711 /* write timeout, or last server read and buffer empty */
1712 else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
1713 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
1714
1715 FD_CLR(t->cli_fd, StaticWriteEvent);
1716 tv_eternity(&t->cwexpire);
1717 shutdown(t->cli_fd, SHUT_WR);
1718 t->cli_state = CL_STSHUTW;
1719 return 1;
1720 }
1721
1722 if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
1723 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
1724 FD_CLR(t->cli_fd, StaticReadEvent);
1725 tv_eternity(&t->crexpire);
1726 }
1727 }
1728 else {
1729 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1730 FD_SET(t->cli_fd, StaticReadEvent);
1731 if (t->proxy->clitimeout)
1732 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1733 else
1734 tv_eternity(&t->crexpire);
1735 }
1736 }
1737
1738 if ((rep->l == 0) ||
1739 ((s == SV_STHEADERS) && (rep->w == rep->h))) {
1740 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1741 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
1742 tv_eternity(&t->cwexpire);
1743 }
1744 }
1745 else { /* buffer not empty */
1746 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1747 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
1748 if (t->proxy->clitimeout)
1749 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
1750 else
1751 tv_eternity(&t->cwexpire);
1752 }
1753 }
1754 return 0; /* other cases change nothing */
1755 }
1756 else if (c == CL_STSHUTR) {
1757 if ((t->res_cw == RES_ERROR) ||
1758 ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
1759 || (tv_cmp2_ms(&t->crexpire, &now) <= 0)) {
1760
1761 FD_CLR(t->cli_fd, StaticWriteEvent);
1762 tv_eternity(&t->cwexpire);
1763 fd_delete(t->cli_fd);
1764 close(t->cli_fd);
1765 t->cli_state = CL_STCLOSE;
1766 return 1;
1767 }
1768 else if ((rep->l == 0) ||
1769 ((s == SV_STHEADERS) && (rep->w == rep->h))) {
1770 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1771 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
1772 tv_eternity(&t->cwexpire);
1773 }
1774 }
1775 else { /* buffer not empty */
1776 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1777 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
1778 if (t->proxy->clitimeout)
1779 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
1780 else
1781 tv_eternity(&t->cwexpire);
1782 }
1783 }
1784 return 0;
1785 }
1786 else if (c == CL_STSHUTW) {
1787 if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
1788 s == SV_STCLOSE || tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
1789 FD_CLR(t->cli_fd, StaticReadEvent);
1790 tv_eternity(&t->crexpire);
1791 fd_delete(t->cli_fd);
1792 close(t->cli_fd);
1793 t->cli_state = CL_STCLOSE;
1794 return 1;
1795 }
1796 else if (req->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
1797 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
1798 FD_CLR(t->cli_fd, StaticReadEvent);
1799 tv_eternity(&t->crexpire);
1800 }
1801 }
1802 else {
1803 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1804 FD_SET(t->cli_fd, StaticReadEvent);
1805 if (t->proxy->clitimeout)
1806 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1807 else
1808 tv_eternity(&t->crexpire);
1809 }
1810 }
1811 return 0;
1812 }
1813 else { /* CL_STCLOSE: nothing to do */
1814 if (mode & MODE_DEBUG) {
1815 int len;
1816 len = sprintf(trash, "clicls[%04x:%04x]\n", t->cli_fd, t->srv_fd);
1817 write(1, trash, len);
1818 }
1819 return 0;
1820 }
1821 return 0;
1822}
1823
1824
1825/*
1826 * manages the server FSM and its socket. It returns 1 if a state has changed
1827 * (and a resync may be needed), 0 else.
1828 */
1829int process_srv(struct task *t) {
1830 int s = t->srv_state;
1831 int c = t->cli_state;
1832 struct buffer *req = t->req;
1833 struct buffer *rep = t->rep;
1834
willy tarreau9da061b2005-12-17 12:29:56 +01001835 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1836 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1837 // FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1838 //);
willy tarreau0f7af912005-12-17 12:21:26 +01001839 if (s == SV_STIDLE) {
1840 if (c == CL_STHEADERS)
1841 return 0; /* stay in idle, waiting for data to reach the client side */
1842 else if (c == CL_STCLOSE ||
1843 c == CL_STSHUTW ||
1844 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
1845 tv_eternity(&t->cnexpire);
1846 t->srv_state = SV_STCLOSE;
1847 return 1;
1848 }
1849 else { /* go to SV_STCONN */
1850 if (connect_server(t, 1) == 0) { /* initiate a connection to the server */
1851 //fprintf(stderr,"0: c=%d, s=%d\n", c, s);
1852 t->srv_state = SV_STCONN;
1853 }
1854 else { /* try again */
1855 while (t->conn_retries-- > 0) {
1856 if (connect_server(t, !t->conn_redisp || (t->conn_retries > 0)) == 0) {
1857 t->srv_state = SV_STCONN;
1858 break;
1859 }
1860 }
1861 if (t->conn_retries < 0) {
1862 /* if conn_retries < 0 or other error, let's abort */
1863 tv_eternity(&t->cnexpire);
1864 t->srv_state = SV_STCLOSE;
1865 }
1866 }
1867 return 1;
1868 }
1869 }
1870 else if (s == SV_STCONN) { /* connection in progress */
1871 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
1872 //fprintf(stderr,"1: c=%d, s=%d\n", c, s);
1873 return 0; /* nothing changed */
1874 }
1875 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
1876 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1877 /* timeout, connect error or first write error */
1878 FD_CLR(t->srv_fd, StaticWriteEvent);
1879 fd_delete(t->srv_fd);
1880 close(t->srv_fd);
1881 t->conn_retries--;
1882 if (t->conn_retries >= 0 &&
1883 connect_server(t, !t->conn_redisp || (t->conn_retries > 0)) == 0) {
1884 return 0; /* no state changed */
1885 }
1886 /* if conn_retries < 0 or other error, let's abort */
1887 tv_eternity(&t->cnexpire);
1888 t->srv_state = SV_STCLOSE;
1889 return 1;
1890 }
1891 else { /* no error or write 0 */
1892 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1893 if (req->l == 0) /* nothing to write */
1894 FD_CLR(t->srv_fd, StaticWriteEvent);
1895 else /* need the right to write */
1896 FD_SET(t->srv_fd, StaticWriteEvent);
1897
1898 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
1899 FD_SET(t->srv_fd, StaticReadEvent);
1900 if (t->proxy->srvtimeout)
1901 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
1902 else
1903 tv_eternity(&t->srexpire);
1904
1905 t->srv_state = SV_STDATA;
1906 }
1907 else
1908 t->srv_state = SV_STHEADERS;
1909 return 1;
1910 }
1911 }
1912 else if (s == SV_STHEADERS) { /* receiving server headers */
1913 char *ptr;
1914 int header_processed = 0;
1915
1916 /* read or write error */
1917 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
1918 FD_CLR(t->srv_fd, StaticReadEvent);
1919 FD_CLR(t->srv_fd, StaticWriteEvent);
1920 tv_eternity(&t->srexpire);
1921 tv_eternity(&t->swexpire);
1922 close(t->srv_fd);
1923 t->srv_state = SV_STCLOSE;
1924 return 1;
1925 }
1926 /* read timeout, last read, or end of client write */
1927 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
1928 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
1929 FD_CLR(t->srv_fd, StaticReadEvent);
1930 tv_eternity(&t->srexpire);
1931 shutdown(t->srv_fd, SHUT_RD);
1932 t->srv_state = SV_STSHUTR;
1933 return 1;
1934
1935 }
1936 /* write timeout, or last client read and buffer empty */
1937 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
1938 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
1939 FD_CLR(t->srv_fd, StaticWriteEvent);
1940 tv_eternity(&t->swexpire);
1941 shutdown(t->srv_fd, SHUT_WR);
1942 t->srv_state = SV_STSHUTW;
1943 return 1;
1944 }
1945
1946 if (req->l == 0) {
1947 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
1948 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
1949 tv_eternity(&t->swexpire);
1950 }
1951 }
1952 else { /* client buffer not empty */
1953 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
1954 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
1955 if (t->proxy->srvtimeout)
1956 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
1957 else
1958 tv_eternity(&t->swexpire);
1959 }
1960 }
1961
1962 if (rep->l >= BUFSIZE - MAXREWRITE) { /* no room to read more data */
1963 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
1964 FD_CLR(t->srv_fd, StaticReadEvent);
1965 tv_eternity(&t->srexpire);
1966 }
1967 }
1968
1969 /* now parse the partial (or complete) headers */
1970
1971 //fprintf(stderr,"rep->data=%p, rep->lr=%p, rep->r=%p, rep->l=%d\n", rep->data, rep->lr, rep->r, rep->l);
1972 ptr = rep->lr;
1973 rep->lr = rep->r;
1974
1975 //write(1,"rep=",4); write(1, ptr, 4); write(1,"\n",1);
1976 //write(1,"hdr=",4); write(1, rep->h, 4); write(1,"\n",1);
1977 while (ptr < rep->r) {
1978 /* look for the end of the current header */
1979 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1980 ptr++;
1981
1982 if (ptr < rep->r) {
1983 //write(1,"ptr=",4); write(1, ptr, 4); write(1,"\n",1);
1984 /* now we have one complete header between rep->h and ptr */
1985 header_processed = 1;
1986 if (ptr == rep->h) { /* empty line, end of headers */
1987 t->srv_state = SV_STDATA;
1988 //rep->lr = ptr; /* tell that bytes up to <lr> have been read and processes */
1989 return 1;
1990 }
1991 else {
1992 /* we have one standard header */
1993 if (mode & MODE_DEBUG) {
1994 int len, max;
1995 len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1996 max = ptr - rep->h;
willy tarreau9da061b2005-12-17 12:29:56 +01001997 UBOUND(max, sizeof(trash) - len - 1);
1998 len += strlcpy(trash + len, rep->h, max + 1);
willy tarreau0f7af912005-12-17 12:21:26 +01001999 trash[len++] = '\n';
willy tarreau0f7af912005-12-17 12:21:26 +01002000 write(1, trash, len);
willy tarreau0f7af912005-12-17 12:21:26 +01002001 }
2002
2003 if (t->proxy->nb_srvexp) { /* try headers regexps */
2004 struct proxy *p = t->proxy;
2005 int exp;
2006 char term;
2007
2008 term = *ptr;
2009 *ptr = '\0';
2010 for (exp=0; exp < p->nb_srvexp; exp++) {
2011 if (regexec(p->srv_exp[exp].preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2012 int len = exp_replace(trash, rep->h, p->srv_exp[exp].replace, pmatch);
2013 ptr += buffer_replace2(rep, rep->h, trash, len, ptr);
2014 break;
2015 }
2016 }
2017 *ptr = term; /* restore the string terminator */
2018 }
2019
2020 /* look for the beginning of the next header */
2021 if (ptr < rep->r) {
2022 if (*ptr == '\n') {
2023 if ((++ptr < rep->r) && (*ptr == '\r'))
2024 ptr++;
2025 }
2026 else if (*ptr == '\r') {
2027 if ((++ptr < rep->r) && (*ptr == '\n'))
2028 ptr++;
2029 }
2030 rep->h = ptr;
2031 }
2032 }
2033 //// rep->lr = ptr;
2034 //rep->lr = rep->h;
2035 }
2036 }
2037
2038 if ((rep->l < BUFSIZE - MAXREWRITE) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2039 FD_SET(t->srv_fd, StaticReadEvent);
2040 if (t->proxy->srvtimeout)
2041 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2042 else
2043 tv_eternity(&t->srexpire);
2044 }
2045
2046 /* be nice with the client side which would like to send a complete header */
2047 return header_processed;
2048 //return 0;
2049 }
2050 else if (s == SV_STDATA) {
2051 /* read or write error */
2052 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
2053 FD_CLR(t->srv_fd, StaticReadEvent);
2054 FD_CLR(t->srv_fd, StaticWriteEvent);
2055 tv_eternity(&t->srexpire);
2056 tv_eternity(&t->swexpire);
2057 close(t->srv_fd);
2058 t->srv_state = SV_STCLOSE;
2059 return 1;
2060 }
2061 /* read timeout, last read, or end of client write */
2062 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE ||
2063 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2064
2065 FD_CLR(t->srv_fd, StaticReadEvent);
2066 tv_eternity(&t->srexpire);
2067 shutdown(t->srv_fd, SHUT_RD);
2068 t->srv_state = SV_STSHUTR;
2069 return 1;
2070
2071 }
2072 /* write timeout, or last client read and buffer empty */
2073 else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2074 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2075 FD_CLR(t->srv_fd, StaticWriteEvent);
2076 tv_eternity(&t->swexpire);
2077 shutdown(t->srv_fd, SHUT_WR);
2078 t->srv_state = SV_STSHUTW;
2079 return 1;
2080 }
2081 else if (req->l == 0) {
2082 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2083 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2084 tv_eternity(&t->swexpire);
2085 }
2086 }
2087 else { /* buffer not empty */
2088 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2089 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2090 if (t->proxy->srvtimeout)
2091 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2092 else
2093 tv_eternity(&t->swexpire);
2094 }
2095 }
2096
2097 if (rep->l == BUFSIZE) { /* no room to read more data */
2098 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2099 FD_CLR(t->srv_fd, StaticReadEvent);
2100 tv_eternity(&t->srexpire);
2101 }
2102 }
2103 else {
2104 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2105 FD_SET(t->srv_fd, StaticReadEvent);
2106 if (t->proxy->srvtimeout)
2107 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2108 else
2109 tv_eternity(&t->srexpire);
2110 }
2111 }
2112
2113 return 0; /* other cases change nothing */
2114 }
2115 else if (s == SV_STSHUTR) {
2116 if ((t->res_sw == RES_ERROR) ||
2117 ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
2118 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
2119
2120 FD_CLR(t->srv_fd, StaticWriteEvent);
2121 tv_eternity(&t->swexpire);
2122 fd_delete(t->srv_fd);
2123 close(t->srv_fd);
2124 t->srv_state = SV_STCLOSE;
2125 return 1;
2126 }
2127 else if (req->l == 0) {
2128 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2129 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2130 tv_eternity(&t->swexpire);
2131 }
2132 }
2133 else { /* buffer not empty */
2134 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2135 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2136 if (t->proxy->srvtimeout)
2137 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2138 else
2139 tv_eternity(&t->swexpire);
2140 }
2141 }
2142 return 0;
2143 }
2144 else if (s == SV_STSHUTW) {
2145 if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
2146 c == CL_STSHUTW || c == CL_STCLOSE ||
2147 tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2148
2149 FD_CLR(t->srv_fd, StaticReadEvent);
2150 tv_eternity(&t->srexpire);
2151 fd_delete(t->srv_fd);
2152 close(t->srv_fd);
2153 t->srv_state = SV_STCLOSE;
2154 return 1;
2155 }
2156 else if (rep->l == BUFSIZE) { /* no room to read more data */
2157 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2158 FD_CLR(t->srv_fd, StaticReadEvent);
2159 tv_eternity(&t->srexpire);
2160 }
2161 }
2162 else {
2163 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2164 FD_SET(t->srv_fd, StaticReadEvent);
2165 if (t->proxy->srvtimeout)
2166 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2167 else
2168 tv_eternity(&t->srexpire);
2169 }
2170 }
2171 return 0;
2172 }
2173 else { /* SV_STCLOSE : nothing to do */
2174 if (mode & MODE_DEBUG) {
2175 int len;
2176 len = sprintf(trash, "srvcls[%04x:%04x]\n", t->cli_fd, t->srv_fd);
2177 write(1, trash, len);
2178 }
2179 return 0;
2180 }
2181 return 0;
2182}
2183
2184
2185/*
2186 * puts a task back to the wait queue in a clean state, or
2187 * cleans up its resources if it must be deleted.
2188 */
2189void process_task(struct task *t) {
2190
2191 if (t->cli_state != CL_STCLOSE || t->srv_state != SV_STCLOSE) {
2192 struct timeval min1, min2;
2193 t->res_cw = t->res_cr = t->res_sw = t->res_sr = RES_SILENT;
2194
2195 tv_min(&min1, &t->crexpire, &t->cwexpire);
2196 tv_min(&min2, &t->srexpire, &t->swexpire);
2197 tv_min(&min1, &min1, &t->cnexpire);
2198 tv_min(&t->expire, &min1, &min2);
2199
2200 /* restore t to its place in the task list */
2201 task_queue(LIST_HEAD(t->proxy->task), t);
2202
2203 return; /* nothing more to do */
2204 }
2205
2206 t->proxy->nbconn--;
2207 actconn--;
2208
2209 if (mode & MODE_DEBUG) {
2210 int len;
2211 len = sprintf(trash, "closed[%04x:%04x]\n", t->cli_fd, t->srv_fd);
2212 write(1, trash, len);
2213 }
2214
2215 /* the task MUST not be in the run queue anymore */
2216 task_delete(t);
2217 task_free(t);
2218}
2219
2220
2221#if STATTIME > 0
2222int stats(void);
2223#endif
2224
2225/*
2226 * Main select() loop.
2227 */
2228
2229void select_loop() {
2230 int next_time;
2231#if STATTIME > 0
2232 int time2;
2233#endif
2234 int status;
2235 int fd,i;
2236 struct timeval delta;
2237 int readnotnull, writenotnull;
2238 struct proxy *p;
2239
2240 /* stop when there's no connection left and we don't allow them anymore */
2241 while (actconn || listeners > 0) {
2242 next_time = -1;
2243 tv_now(&now);
2244
2245 maintain_proxies();
2246
2247#if STATTIME > 0
2248 time2 = stats();
2249 // fprintf(stderr," stats = %d\n", time2);
2250 next_time = MINTIME(time2, next_time);
2251#endif
2252
2253 if (next_time >= 0) {
2254 /* Convert to timeval */
2255 delta.tv_sec=next_time/1000;
2256 delta.tv_usec=(next_time%1000)*1000;
2257 }
2258
2259
2260 /* let's restore fdset state */
2261
2262 readnotnull = 0; writenotnull = 0;
2263 for (i = 0; i < (cfg_maxsock + 3 + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
2264 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
2265 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
2266 }
2267
2268// /* just a verification code, needs to be removed for performance */
2269// for (i=0; i<maxfd; i++) {
2270// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
2271// abort();
2272// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
2273// abort();
2274//
2275// }
2276
2277 status=select(maxfd,
2278 readnotnull ? ReadEvent : NULL,
2279 writenotnull ? WriteEvent : NULL,
2280 NULL,
2281 (next_time >= 0) ? &delta : NULL);
2282
2283 tv_now(&now);
2284 if (status > 0) { /* must proceed with events */
2285
2286 int fds;
2287 char count;
2288
2289 for (fds = 0; (fds << INTBITS) < maxfd; fds++)
2290 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) != 0)
2291 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
2292
2293 if (fdtab[fd].state == FD_STCLOSE)
2294 continue;
2295
2296 if (FD_ISSET(fd, WriteEvent))
2297 fdtab[fd].write(fd);
2298
2299 if (FD_ISSET(fd, ReadEvent))
2300 fdtab[fd].read(fd);
2301 }
2302 }
2303 else {
2304 // fprintf(stderr,"select returned %d, maxfd=%d\n", status, maxfd);
2305 }
2306
2307 for (p = proxy; p; p = p->next) {
2308 struct task *t, *tnext;
2309 tnext = ((struct task *)LIST_HEAD(p->task))->next;
2310 while ((t = tnext) != LIST_HEAD(p->task)) { /* we haven't looped ? */
2311 tnext = t->next;
2312
2313 /* wakeup expired entries. It doesn't matter if they are
2314 * already running because of a previous event
2315 */
2316 if (tv_cmp2_ms(&t->expire, &now) <= 0) {
2317 // fprintf(stderr,"WQ: expiring task %p : rq=%p\n", t, p->rq);
2318 task_wakeup(p, t);
2319 }
2320 else {
2321 // fprintf(stderr,"WQ: ignoring task %p : rq=%p\n", t, p->rq);
2322 break;
2323 }
2324 }
2325
2326 /* process each task in the run queue now. Each task may be deleted
2327 * since we only use tnext.
2328 */
2329 tnext = p->rq;
2330 while ((t = tnext) != NULL) {
2331 int fsm_resync = 0;
2332
2333 tnext = t->rqnext;
2334 task_sleep(p, t);
2335
2336 do {
2337 fsm_resync = 0;
2338 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2339 fsm_resync |= process_cli(t);
2340 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2341 fsm_resync |= process_srv(t);
2342 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", t->cli_state, t->srv_state);
2343 } while (fsm_resync);
2344
2345 // task_queue(LIST_HEAD(p->task), t); /* restore t to its place in the task list */
2346 // it has been moved to process_task which was more logical.
2347 process_task(t);
2348 }
2349 }
2350 }
2351}
2352
2353
2354#if STATTIME > 0
2355/*
2356 * Display proxy statistics regularly. It is designed to be called from the
2357 * select_loop().
2358 */
2359int stats(void) {
2360 static int lines;
2361 static struct timeval nextevt;
2362 static struct timeval lastevt;
2363 static struct timeval starttime = {0,0};
2364 unsigned long totaltime, deltatime;
2365 int ret;
2366
2367 if (tv_remain(&now, &nextevt) == 0) {
2368 deltatime = (tv_delta(&now, &lastevt)?:1);
2369 totaltime = (tv_delta(&now, &starttime)?:1);
2370
2371 if (mode & MODE_STATS) {
2372 if ((lines++ % 16 == 0) && !(mode & MODE_LOG))
2373 fprintf(stderr,
2374 "\n active total tsknew tskgood tskleft tskrght tsknsch tsklsch tskrsch\n");
2375 if (lines>1) {
2376 fprintf(stderr,"%07d %07d %07d %07d %07d %07d %07d %07d %07d\n",
2377 actconn, totalconn,
2378 stats_tsk_new, stats_tsk_good,
2379 stats_tsk_left, stats_tsk_right,
2380 stats_tsk_nsrch, stats_tsk_lsrch, stats_tsk_rsrch);
2381 }
2382 }
2383
2384 tv_delayfrom(&nextevt, &now, STATTIME);
2385
2386 lastevt=now;
2387 }
2388 ret = tv_remain(&now, &nextevt);
2389 return ret;
2390}
2391#endif
2392
2393
2394/*
2395 * this function enables proxies when there are enough free sessions,
2396 * or stops them when the table is full. It is designed to be called from the
2397 * select_loop().
2398 */
2399static int maintain_proxies(void) {
2400 struct proxy *p;
2401
2402 p = proxy;
2403
2404 if (stopping) {
2405 while (p) {
2406 if (p->state != PR_STDISABLED) {
2407 if (stopping && (tv_remain(&now, &p->stop_time) == 0)) {
2408 FD_CLR(p->listen_fd, StaticReadEvent);
2409 close(p->listen_fd);
2410 p->state = PR_STDISABLED;
2411 listeners--;
2412 }
2413 }
2414 p = p->next;
2415 }
2416 return -1;
2417 }
2418
2419 /* if there are enough free sessions, we'll activate proxies */
2420 if (actconn < cfg_maxconn) {
2421 while (p) {
2422 if (p->nbconn < p->maxconn) {
2423 if (p->state == PR_STIDLE) {
2424 FD_SET(p->listen_fd, StaticReadEvent);
2425 p->state = PR_STRUN;
2426 }
2427 }
2428 else {
2429 if (p->state == PR_STRUN) {
2430 FD_CLR(p->listen_fd, StaticReadEvent);
2431 p->state = PR_STIDLE;
2432 }
2433 }
2434 p = p->next;
2435 }
2436 }
2437 else { /* block all proxies */
2438 while (p) {
2439 if (p->state == PR_STRUN) {
2440 FD_CLR(p->listen_fd, StaticReadEvent);
2441 p->state = PR_STIDLE;
2442 }
2443 p = p->next;
2444 }
2445 }
2446
2447 return -1;
2448}
2449
2450/*
2451 * this function disables health-check servers so that the process will quickly be ignored
2452 * by load balancers.
2453 */
2454static void soft_stop(void) {
2455 struct proxy *p;
2456
2457 stopping = 1;
2458 p = proxy;
2459 while (p) {
2460 if (p->state != PR_STDISABLED)
2461 tv_delayfrom(&p->stop_time, &now, p->grace);
2462 p = p->next;
2463 }
2464}
2465
2466/*
2467 * upon SIGUSR1, let's have a soft stop.
2468 */
2469void sig_soft_stop(int sig) {
2470 soft_stop();
2471 signal(sig, SIG_IGN);
2472}
2473
2474
2475void dump(int sig) {
2476 struct proxy *p;
2477
2478 for (p = proxy; p; p = p->next) {
2479 struct task *t, *tnext;
2480 tnext = ((struct task *)LIST_HEAD(p->task))->next;
2481 while ((t = tnext) != LIST_HEAD(p->task)) { /* we haven't looped ? */
2482 tnext = t->next;
2483 fprintf(stderr,"[dump] wq: task %p, still %ld ms, "
2484 "cli=%d, srv=%d, cr=%d, cw=%d, sr=%d, sw=%d, "
2485 "req=%d, rep=%d, clifd=%d\n",
2486 t, tv_remain(&now, &t->expire),
2487 t->cli_state,
2488 t->srv_state,
2489 FD_ISSET(t->cli_fd, StaticReadEvent),
2490 FD_ISSET(t->cli_fd, StaticWriteEvent),
2491 FD_ISSET(t->srv_fd, StaticReadEvent),
2492 FD_ISSET(t->srv_fd, StaticWriteEvent),
2493 t->req->l, t->rep?t->rep->l:0, t->cli_fd
2494 );
2495 }
2496 }
2497}
2498
2499/*
2500 * This function reads and parses the configuration file given in the argument.
2501 * returns 0 if OK, -1 if error.
2502 */
2503int readcfgfile(char *file) {
2504 char thisline[256];
2505 char *line;
2506 FILE *f;
2507 int linenum = 0;
2508 char *cmd;
2509 char *args[10];
2510 int arg;
2511 int cfgerr = 0;
2512
2513 struct proxy *curproxy = NULL;
2514 struct server *newsrv = NULL;
2515
2516 if ((f=fopen(file,"r")) == NULL)
2517 return -1;
2518
2519 while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
2520 linenum++;
2521 /* skips leading spaces */
2522 while (isspace(*line))
2523 line++;
2524
2525 /* cleans up line contents */
2526 cmd = line;
2527 while (*cmd) {
2528 if (*cmd == '#' || *cmd == ';' || *cmd == '\n' || *cmd == '\r')
2529 *cmd = 0; /* end of string, end of loop */
2530 else
2531 cmd++;
2532 }
2533
2534 if (*line == 0)
2535 continue;
2536
2537 /* fills args[0..9] with the line contents */
2538 for (arg=0; arg<9; arg++) {
2539 int escaped = 0;
2540
2541 args[arg] = line;
2542 while (*line && (escaped || !isspace(*line))) {
2543 if (!escaped) {
2544 if (*line == '\\')
2545 escaped = 1;
2546 }
2547 else
2548 escaped = 0;
2549 line++;
2550 }
2551
2552 if (*line) {
2553 *(line++) = 0;
2554 while (isspace(*line))
2555 line++;
2556 }
2557 }
2558
2559 if (!strcmp(args[0], "listen")) { /* new proxy */
2560 if (strchr(args[2], ':') == NULL) {
2561 Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
2562 file, linenum);
2563 return -1;
2564 }
2565
2566 if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy)))
2567 == NULL) {
2568 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
2569 exit(1);
2570 }
2571 curproxy->next = proxy;
2572 proxy = curproxy;
2573 curproxy->id = strdup(args[1]);
2574 curproxy->listen_addr = *str2sa(args[2]);
2575 curproxy->state = PR_STNEW;
2576 curproxy->task.prev = curproxy->task.next = LIST_HEAD(curproxy->task);
2577 curproxy->rq = NULL;
2578 /* set default values */
2579 curproxy->maxconn = cfg_maxpconn;
2580 curproxy->conn_retries = CONN_RETRIES;
2581 curproxy->conn_redisp = 0;
2582 curproxy->clitimeout = curproxy->contimeout = curproxy->srvtimeout = 0;
2583 curproxy->mode = PR_MODE_TCP;
2584 curproxy->logfac1 = curproxy->logfac2 = -1; /* log disabled */
2585 continue;
2586 }
2587 else if (curproxy == NULL) {
2588 Alert("parsing [%s:%d] : <listen> expected.\n",
2589 file, linenum);
2590 return -1;
2591 }
2592
2593 if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
2594 if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
2595 else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
2596 else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
2597 else {
2598 Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
2599 return -1;
2600 }
2601 }
2602 else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
2603 curproxy->state = PR_STDISABLED;
2604 }
2605 else if (!strcmp(args[0], "cookie")) { /* cookie name */
2606 if (curproxy->cookie_name != NULL) {
2607 Alert("parsing [%s:%d] : cookie name already specified. Continuing.\n",
2608 file, linenum);
2609 continue;
2610 }
2611
2612 if (*(args[1]) == 0) {
2613 Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
2614 file, linenum);
2615 return -1;
2616 }
2617 curproxy->cookie_name = strdup(args[1]);
2618 }
2619 else if (!strcmp(args[0], "contimeout")) { /* connect timeout */
2620 if (curproxy->contimeout != 0) {
2621 Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n",
2622 file, linenum);
2623 continue;
2624 }
2625 if (*(args[1]) == 0) {
2626 Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
2627 file, linenum);
2628 return -1;
2629 }
2630 curproxy->contimeout = atol(args[1]);
2631 }
2632 else if (!strcmp(args[0], "clitimeout")) { /* client timeout */
2633 if (curproxy->clitimeout != 0) {
2634 Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
2635 file, linenum);
2636 continue;
2637 }
2638 if (*(args[1]) == 0) {
2639 Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
2640 file, linenum);
2641 return -1;
2642 }
2643 curproxy->clitimeout = atol(args[1]);
2644 }
2645 else if (!strcmp(args[0], "srvtimeout")) { /* server timeout */
2646 if (curproxy->srvtimeout != 0) {
2647 Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n",
2648 file, linenum);
2649 continue;
2650 }
2651 if (*(args[1]) == 0) {
2652 Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
2653 file, linenum);
2654 return -1;
2655 }
2656 curproxy->srvtimeout = atol(args[1]);
2657 }
2658 else if (!strcmp(args[0], "retries")) { /* connection retries */
2659 if (*(args[1]) == 0) {
2660 Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
2661 file, linenum);
2662 return -1;
2663 }
2664 curproxy->conn_retries = atol(args[1]);
2665 }
2666 else if (!strcmp(args[0], "redisp")) { /* enable reconnections to dispatch */
2667 curproxy->conn_redisp = 1;
2668 }
2669 else if (!strcmp(args[0], "maxconn")) { /* maxconn */
2670 if (*(args[1]) == 0) {
2671 Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n",
2672 file, linenum);
2673 return -1;
2674 }
2675 curproxy->maxconn = atol(args[1]);
2676 }
2677 else if (!strcmp(args[0], "grace")) { /* grace time (ms) */
2678 if (*(args[1]) == 0) {
2679 Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n",
2680 file, linenum);
2681 return -1;
2682 }
2683 curproxy->grace = atol(args[1]);
2684 }
2685 else if (!strcmp(args[0], "dispatch")) { /* dispatch address */
2686 if (strchr(args[1], ':') == NULL) {
2687 Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n",
2688 file, linenum);
2689 return -1;
2690 }
2691 curproxy->dispatch_addr = *str2sa(args[1]);
2692 }
2693 else if (!strcmp(args[0], "server")) { /* server address */
2694 if (strchr(args[2], ':') == NULL) {
2695 Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
2696 file, linenum);
2697 return -1;
2698 }
2699 if ((newsrv = (struct server *)calloc(1, sizeof(struct server)))
2700 == NULL) {
2701 Alert("parsing [%s:%d] : out of memory\n", file, linenum);
2702 exit(1);
2703 }
2704 newsrv->next = curproxy->srv;
2705 curproxy->srv = newsrv;
2706 newsrv->id = strdup(args[1]);
2707 newsrv->addr = *str2sa(args[2]);
2708 }
2709 else if (!strcmp(args[0], "log")) { /* syslog server address */
2710 struct sockaddr_in *sa;
2711 int facility;
2712
2713 if (*(args[1]) == 0 || *(args[2]) == 0) {
2714 Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n",
2715 file, linenum);
2716 return -1;
2717 }
2718
2719 for (facility = 0; facility < NB_LOG_FACILITIES; facility++)
2720 if (!strcmp(log_facilities[facility], args[2]))
2721 break;
2722
2723 if (facility >= NB_LOG_FACILITIES) {
2724 Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
2725 exit(1);
2726 }
2727
2728 sa = str2sa(args[1]);
2729 if (!sa->sin_port)
2730 sa->sin_port = htons(SYSLOG_PORT);
2731
2732 if (curproxy->logfac1 == -1) {
2733 curproxy->logsrv1 = *sa;
2734 curproxy->logfac1 = facility;
2735 }
2736 else if (curproxy->logfac2 == -1) {
2737 curproxy->logsrv2 = *sa;
2738 curproxy->logfac2 = facility;
2739 }
2740 else {
2741 Alert("parsing [%s:%d] : too many syslog servers\n", file, linenum);
2742 exit(1);
2743 }
2744
2745 }
2746 else if (!strcmp(args[0], "cliexp")) { /* client regex */
2747 regex_t *preg;
2748 if (curproxy->nb_cliexp >= MAX_REGEXP) {
2749 Alert("parsing [%s:%d] : too many client expressions. Continuing.\n",
2750 file, linenum);
2751 continue;
2752 }
2753
2754 if (*(args[1]) == 0 || *(args[2]) == 0) {
2755 Alert("parsing [%s:%d] : <cliexp> expects <search> and <replace> as arguments.\n",
2756 file, linenum);
2757 return -1;
2758 }
2759
2760 preg = calloc(1, sizeof(regex_t));
2761 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2762 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
2763 return -1;
2764 }
2765 curproxy->cli_exp[curproxy->nb_cliexp].preg = preg;
2766 curproxy->cli_exp[curproxy->nb_cliexp].replace = strdup(args[2]);
2767 curproxy->nb_cliexp++;
2768 }
2769 else if (!strcmp(args[0], "srvexp")) { /* server regex */
2770 regex_t *preg;
2771 if (curproxy->nb_srvexp >= MAX_REGEXP) {
2772 Alert("parsing [%s:%d] : too many server expressions. Continuing.\n",
2773 file, linenum);
2774 continue;
2775 }
2776
2777 if (*(args[1]) == 0 || *(args[2]) == 0) {
2778 Alert("parsing [%s:%d] : <srvexp> expects <search> and <replace> as arguments.\n",
2779 file, linenum);
2780 return -1;
2781 }
2782
2783 preg = calloc(1, sizeof(regex_t));
2784 if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
2785 Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
2786 return -1;
2787 }
2788 // fprintf(stderr,"before=<%s> after=<%s>\n", args[1], args[2]);
2789 curproxy->srv_exp[curproxy->nb_srvexp].preg = preg;
2790 curproxy->srv_exp[curproxy->nb_srvexp].replace = strdup(args[2]);
2791 curproxy->nb_srvexp++;
2792 }
2793 else {
2794 Alert("parsing [%s:%d] : unknown keyword <%s>\n", file, linenum, args[0]);
2795 exit(1);
2796 }
2797 }
2798 fclose(f);
2799
2800 /*
2801 * Now, check for the integrity of all that we have collected.
2802 */
2803
2804 if ((curproxy = proxy) == NULL) {
2805 Alert("parsing %s : no <listen> line. Nothing to do !\n",
2806 file);
2807 return -1;
2808 }
2809
2810 while (curproxy != NULL) {
2811 if (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HEALTH) { /* TCP PROXY or HEALTH CHECK */
2812 if (curproxy->cookie_name != NULL) {
2813 Warning("parsing %s : cookie will be ignored for listener %s.\n",
2814 file, curproxy->id);
2815 }
2816 if ((newsrv = curproxy->srv) != NULL) {
2817 Warning("parsing %s : servers will be ignored for listener %s.\n",
2818 file, curproxy->id);
2819 }
2820 if (curproxy->nb_srvexp) {
2821 Warning("parsing %s : server regular expressions will be ignored for listener %s.\n",
2822 file, curproxy->id);
2823 }
2824 if (curproxy->nb_cliexp) {
2825 Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
2826 file, curproxy->id);
2827 }
2828 }
2829 else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
2830 if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
2831 Alert("parsing %s : HTTP proxy %s has a cookie but no server list !\n",
2832 file, curproxy->id);
2833 cfgerr++;
2834 }
2835 else {
2836 while (newsrv != NULL) {
2837 /* nothing to check for now */
2838 newsrv = newsrv->next;
2839 }
2840 }
2841 }
2842 curproxy = curproxy->next;
2843 }
2844 if (cfgerr > 0) {
2845 Alert("Errors found in configuration file, aborting.\n");
2846 return -1;
2847 }
2848 else
2849 return 0;
2850}
2851
2852
2853/*
2854 * This function initializes all the necessary variables. It only returns
2855 * if everything is OK. If something fails, it exits.
2856 */
2857void init(int argc, char **argv) {
2858 int i;
2859 char *old_argv = *argv;
2860 char *tmp;
2861
2862 if (1<<INTBITS != sizeof(int)*8) {
2863 fprintf(stderr,
2864 "Error: wrong architecture. Recompile so that sizeof(int)=%d\n",
2865 sizeof(int)*8);
2866 exit(1);
2867 }
2868
2869 pid = getpid();
2870 progname = *argv;
2871 while ((tmp = strchr(progname, '/')) != NULL)
2872 progname = tmp + 1;
2873
2874 argc--; argv++;
2875 while (argc > 0) {
2876 char *flag;
2877
2878 if (**argv == '-') {
2879 flag = *argv+1;
2880
2881 /* 1 arg */
2882 if (*flag == 'v') {
2883 display_version();
2884 exit(0);
2885 }
2886 else if (*flag == 'd')
2887 mode |= MODE_DEBUG;
2888 else if (*flag == 'D')
2889 mode |= MODE_DAEMON;
2890#if STATTIME > 0
2891 else if (*flag == 's')
2892 mode |= MODE_STATS;
2893 else if (*flag == 'l')
2894 mode |= MODE_LOG;
2895#endif
2896 else { /* >=2 args */
2897 argv++; argc--;
2898 if (argc == 0)
2899 usage(old_argv);
2900
2901 switch (*flag) {
2902 case 'n' : cfg_maxconn = atol(*argv); break;
2903 case 'N' : cfg_maxpconn = atol(*argv); break;
2904 case 'f' : cfg_cfgfile = *argv; break;
2905 default: usage(old_argv);
2906 }
2907 }
2908 }
2909 else
2910 usage(old_argv);
2911 argv++; argc--;
2912 }
2913
2914 cfg_maxsock = cfg_maxconn * 2; /* each connection needs two sockets */
2915
2916 if (!cfg_cfgfile)
2917 usage(old_argv);
2918
2919 gethostname(hostname, MAX_HOSTNAME_LEN);
2920
2921 if (readcfgfile(cfg_cfgfile) < 0) {
2922 Alert("Error reading configuration file : %s\n", cfg_cfgfile);
2923 exit(1);
2924 }
2925
2926 ReadEvent = (fd_set *)calloc(1,
2927 sizeof(fd_set) *
2928 (cfg_maxsock + 3 + FD_SETSIZE - 1) / FD_SETSIZE);
2929 WriteEvent = (fd_set *)calloc(1,
2930 sizeof(fd_set) *
2931 (cfg_maxsock + 3 + FD_SETSIZE - 1) / FD_SETSIZE);
2932 StaticReadEvent = (fd_set *)calloc(1,
2933 sizeof(fd_set) *
2934 (cfg_maxsock + 3 + FD_SETSIZE - 1) / FD_SETSIZE);
2935 StaticWriteEvent = (fd_set *)calloc(1,
2936 sizeof(fd_set) *
2937 (cfg_maxsock + 3 + FD_SETSIZE - 1) / FD_SETSIZE);
2938
2939 fdtab = (struct fdtab *)calloc(1,
2940 sizeof(struct fdtab) * (cfg_maxsock + 3));
2941 for (i = 0; i < cfg_maxsock + 3; i++) {
2942 fdtab[i].state = FD_STCLOSE;
2943 }
2944}
2945
2946/*
2947 * this function starts all the proxies. It returns 0 if OK, -1 if not.
2948 */
2949int start_proxies() {
2950 struct proxy *curproxy;
2951 int one = 1;
2952 int fd;
2953
2954 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
2955
2956 if (curproxy->state == PR_STDISABLED)
2957 continue;
2958
2959 if ((fd = curproxy->listen_fd =
2960 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
2961 Alert("cannot create listening socket for proxy %s. Aborting.\n",
2962 curproxy->id);
2963 return -1;
2964 }
2965
2966 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
2967 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
2968 (char *) &one, sizeof(one)) == -1)) {
2969 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
2970 curproxy->id);
2971 close(fd);
2972 return -1;
2973 }
2974
2975 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
2976 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
2977 curproxy->id);
2978 }
2979
2980 if (bind(fd,
2981 (struct sockaddr *)&curproxy->listen_addr,
2982 sizeof(curproxy->listen_addr)) == -1) {
2983 Alert("cannot bind socket for proxy %s. Aborting.\n",
2984 curproxy->id);
2985 close(fd);
2986 return -1;
2987 }
2988
2989 if (listen(fd, curproxy->maxconn) == -1) {
2990 Alert("cannot listen to socket for proxy %s. Aborting.\n",
2991 curproxy->id);
2992 close(fd);
2993 return -1;
2994 }
2995
2996 /* the function for the accept() event */
2997 fdtab[fd].read = &event_accept;
2998 fdtab[fd].write = NULL; /* never called */
2999 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy */
3000 curproxy->state = PR_STRUN;
3001 fdtab[fd].state = FD_STLISTEN;
3002 FD_SET(fd, StaticReadEvent);
3003 fd_insert(fd);
3004 listeners++;
3005// fprintf(stderr,"Proxy %s : socket bound.\n", curproxy->id);
3006 }
3007 return 0;
3008}
3009
3010
3011int main(int argc, char **argv) {
3012 init(argc, argv);
3013
3014 if (mode & MODE_DAEMON) {
3015 int ret;
3016
3017 ret = fork();
3018
3019 if (ret > 0)
3020 exit(0); /* parent must leave */
3021 else if (ret < 0) {
3022 Alert("[%s.main()] Cannot fork\n", argv[0]);
3023 exit(1); /* there has been an error */
3024 }
3025
3026 /* detach from the tty */
3027 close(0); close(1); close(2);
3028 setpgid(1, 0);
3029 }
3030
3031 signal(SIGQUIT, dump);
3032 signal(SIGUSR1, sig_soft_stop);
3033
3034 /* on very high loads, a sigpipe sometimes happen just between the
3035 * getsockopt() which tells "it's OK to write", and the following write :-(
3036 */
willy tarreau3242e862005-12-17 12:27:53 +01003037#ifndef MSG_NOSIGNAL
3038 signal(SIGPIPE, SIG_IGN);
3039#endif
willy tarreau0f7af912005-12-17 12:21:26 +01003040
3041 if (start_proxies() < 0)
3042 exit(1);
3043
3044 select_loop();
3045
3046 exit(0);
3047}