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