* released 1.2.7rc (1.1.33rc)
* second batch of socklen_t changes.
* clean-ups from Cameron Simpson.
* because tv_remain() does not know about eternity, using no timeout can
make select() spin around a null time-out. Bug reported by Cameron Simpson.
* client read timeout was not properly set to eternity initialized after an
accept() if it was not set in the config. It remained undetected so long
because eternity is 0 and newly allocated pages are zeroed by the system.
* do not call get_original_dst() when not in transparent mode.
* implemented a workaround for a bug in certain epoll() implementations on
linux-2.4 kernels (epoll-lt <= 0.21).
* implemented TCP keepalive with new options : tcpka, clitcpka, srvtcpka.
diff --git a/haproxy.c b/haproxy.c
index 34d9b40..e362df5 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -76,8 +76,8 @@
#include "include/appsession.h"
-#define HAPROXY_VERSION "1.2.6"
-#define HAPROXY_DATE "2005/08/07"
+#define HAPROXY_VERSION "1.2.7rc"
+#define HAPROXY_DATE "2005/10/09"
/* this is for libc5 for example */
#ifndef TCP_NODELAY
@@ -155,6 +155,8 @@
*/
#define SCHEDULER_RESOLUTION 9
+#define TIME_ETERNITY -1
+/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
#define SETNOW(a) (*a=now)
@@ -313,6 +315,8 @@
#define PR_O_LOGASAP 0x00008000 /* log as soon as possible, without waiting for the session to complete */
#define PR_O_HTTP_CLOSE 0x00010000 /* force 'connection: close' in both directions */
#define PR_O_CHK_CACHE 0x00020000 /* require examination of cacheability of the 'set-cookie' field */
+#define PR_O_TCP_CLI_KA 0x00040000 /* enable TCP keep-alive on client-side sessions */
+#define PR_O_TCP_SRV_KA 0x00080000 /* enable TCP keep-alive on server-side sessions */
/* various session flags */
#define SN_DIRECT 0x00000001 /* connection made on the server matching the client cookie */
@@ -553,7 +557,7 @@
int nbconn; /* # of active sessions */
int maxconn; /* max # of active sessions */
int conn_retries; /* maximum number of connect retries */
- int options; /* PR_O_REDISP, PR_O_TRANSP */
+ int options; /* PR_O_REDISP, PR_O_TRANSP, ... */
int mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
struct proxy *next;
@@ -601,7 +605,7 @@
/*********************************************************************/
-int cfg_maxpconn = 2000; /* # of simultaneous connections per proxy (-N) */
+int cfg_maxpconn = DEFAULT_MAXCONN; /* # of simultaneous connections per proxy (-N) */
char *cfg_cfgfile = NULL; /* configuration file */
char *progname = NULL; /* program name */
int pid; /* current process id */
@@ -1280,6 +1284,7 @@
/*
* compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
+ * Must not be used when either argument is eternity. Use tv_cmp2() for that.
*/
static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
if (tv1->tv_sec < tv2->tv_sec)
@@ -1296,6 +1301,7 @@
/*
* returns the absolute difference, in ms, between tv1 and tv2
+ * Must not be used when either argument is eternity.
*/
unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
int cmp;
@@ -1320,6 +1326,7 @@
/*
* returns the difference, in ms, between tv1 and tv2
+ * Must not be used when either argument is eternity.
*/
static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
unsigned long ret;
@@ -1334,6 +1341,7 @@
/*
* compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
+ * Must not be used when either argument is eternity. Use tv_cmp2_ms() for that.
*/
static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
if (tv1->tv_sec == tv2->tv_sec) {
@@ -1357,6 +1365,7 @@
/*
* returns the remaining time between tv1=now and event=tv2
* if tv2 is passed, 0 is returned.
+ * Must not be used when either argument is eternity.
*/
static inline unsigned long tv_remain(struct timeval *tv1, struct timeval *tv2) {
unsigned long ret;
@@ -1449,6 +1458,28 @@
}
/*
+ * returns the remaining time between tv1=now and event=tv2
+ * if tv2 is passed, 0 is returned.
+ * Returns TIME_ETERNITY if tv2 is eternity.
+ */
+static inline unsigned long tv_remain2(struct timeval *tv1, struct timeval *tv2) {
+ unsigned long ret;
+
+ if (tv_iseternity(tv2))
+ return TIME_ETERNITY;
+
+ if (tv_cmp_ms(tv1, tv2) >= 0)
+ return 0; /* event elapsed */
+
+ ret = (tv2->tv_sec - tv1->tv_sec) * 1000;
+ if (tv2->tv_usec > tv1->tv_usec)
+ ret += (tv2->tv_usec - tv1->tv_usec) / 1000;
+ else
+ ret -= (tv1->tv_usec - tv2->tv_usec) / 1000;
+ return (unsigned long) ret;
+}
+
+/*
* returns the first event between tv1 and tv2 into tvmin.
* a zero tv is ignored. tvmin is returned.
*/
@@ -1648,7 +1679,7 @@
/* some prototypes */
static int maintain_proxies(void);
-/* this either returns the sockname or the original destination address. Code
+/* This either returns the sockname or the original destination address. Code
* inspired from Patrick Schaaf's example of nf_getsockname() implementation.
*/
static int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *salen) {
@@ -1767,7 +1798,8 @@
}
else if (s->proxy->options & PR_O_TRANSP) {
/* in transparent mode, use the original dest addr if no dispatch specified */
- socklen_t salen = sizeof(struct sockaddr_in);
+ socklen_t salen = sizeof(s->srv_addr);
+
if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
qfprintf(stderr, "Cannot get original server address.\n");
return SN_ERR_INTERNAL;
@@ -1778,10 +1810,10 @@
* the port the client connected to with an offset. */
if (s->srv != NULL && s->srv->state & SRV_MAPPORTS) {
struct sockaddr_in sockname;
- socklen_t namelen;
+ socklen_t namelen = sizeof(sockname);
- namelen = sizeof(sockname);
- if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
+ if (!(s->proxy->options & PR_O_TRANSP) ||
+ get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1)
getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen);
s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port));
}
@@ -1821,6 +1853,9 @@
return SN_ERR_INTERNAL;
}
+ if (s->proxy->options & PR_O_TCP_SRV_KA)
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
+
/* allow specific binding :
* - server-specific at first
* - proxy-specific next
@@ -1866,10 +1901,12 @@
s->proxy->id, s->srv->id, msg);
return SN_ERR_RESOURCE;
} else if (errno == ETIMEDOUT) {
+ //qfprintf(stderr,"Connect(): ETIMEDOUT");
close(fd);
return SN_ERR_SRVTO;
} else {
// (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
+ //qfprintf(stderr,"Connect(): %d", errno);
close(fd);
return SN_ERR_SRVCL;
}
@@ -1936,9 +1973,9 @@
#ifndef MSG_NOSIGNAL
{
- int skerr, lskerr;
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
- lskerr = sizeof(skerr);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
if (skerr)
ret = -1;
@@ -2041,9 +2078,9 @@
#ifndef MSG_NOSIGNAL
{
- int skerr, lskerr;
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
- lskerr = sizeof(skerr);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
if (skerr)
ret = -1;
@@ -2126,10 +2163,6 @@
max = b->data + BUFSIZE - b->w;
if (fdtab[fd].state != FD_STERROR) {
-#ifndef MSG_NOSIGNAL
- int skerr, lskerr;
-#endif
-
if (max == 0) {
s->res_cw = RES_NULL;
task_wakeup(&rq, t);
@@ -2139,12 +2172,16 @@
}
#ifndef MSG_NOSIGNAL
- lskerr=sizeof(skerr);
- getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
- if (skerr)
+ {
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
+
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
+ if (skerr)
ret = -1;
- else
+ else
ret = send(fd, b->w, max, MSG_DONTWAIT);
+ }
#else
ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
#endif
@@ -2215,9 +2252,6 @@
max = b->data + BUFSIZE - b->w;
if (fdtab[fd].state != FD_STERROR) {
-#ifndef MSG_NOSIGNAL
- int skerr, lskerr;
-#endif
if (max == 0) {
/* may be we have received a connection acknowledgement in TCP mode without data */
s->res_sw = RES_NULL;
@@ -2228,14 +2262,16 @@
return 0;
}
-
#ifndef MSG_NOSIGNAL
- lskerr=sizeof(skerr);
- getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
- if (skerr)
+ {
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
+ if (skerr)
ret = -1;
- else
+ else
ret = send(fd, b->w, max, MSG_DONTWAIT);
+ }
#else
ret = send(fd, b->w, max, MSG_DONTWAIT | MSG_NOSIGNAL);
#endif
@@ -2442,6 +2478,7 @@
while (p->nbconn < p->maxconn) {
struct sockaddr_storage addr;
socklen_t laddr = sizeof(addr);
+
if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
switch (errno) {
case EAGAIN:
@@ -2520,6 +2557,9 @@
return 0;
}
+ if (p->options & PR_O_TCP_CLI_KA)
+ setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
+
t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */
t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */
t->state = TASK_IDLE;
@@ -2589,10 +2629,10 @@
if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
&& (p->logfac1 >= 0 || p->logfac2 >= 0)) {
struct sockaddr_storage sockname;
- socklen_t namelen;
+ socklen_t namelen = sizeof(sockname);
- namelen = sizeof(sockname);
if (addr.ss_family != AF_INET ||
+ !(s->proxy->options & PR_O_TRANSP) ||
get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
@@ -2630,10 +2670,10 @@
if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
struct sockaddr_in sockname;
- socklen_t namelen;
+ socklen_t namelen = sizeof(sockname);
int len;
- namelen = sizeof(sockname);
if (addr.ss_family != AF_INET ||
+ !(s->proxy->options & PR_O_TRANSP) ||
get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
@@ -2713,11 +2753,18 @@
FD_SET(cfd, StaticReadEvent);
}
+#if defined(DEBUG_FULL) && defined(ENABLE_EPOLL)
+ if (PrevReadEvent) {
+ assert(!(FD_ISSET(cfd, PrevReadEvent)));
+ assert(!(FD_ISSET(cfd, PrevWriteEvent)));
+ }
+#endif
fd_insert(cfd);
tv_eternity(&s->cnexpire);
tv_eternity(&s->srexpire);
tv_eternity(&s->swexpire);
+ tv_eternity(&s->crexpire);
tv_eternity(&s->cwexpire);
if (s->proxy->clitimeout) {
@@ -2738,7 +2785,7 @@
actconn++;
totalconn++;
- // fprintf(stderr, "accepting from %p => %d conn, %d total\n", p, actconn, totalconn);
+ // fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
} /* end of while (p->nbconn < p->maxconn) */
return 0;
}
@@ -2755,8 +2802,8 @@
struct server *s = t->context;
int skerr;
- socklen_t lskerr;
- lskerr = sizeof(skerr);
+ socklen_t lskerr = sizeof(skerr);
+
getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
/* in case of TCP only, this tells us if the connection succeeded */
if (skerr)
@@ -2802,14 +2849,16 @@
struct task *t = fdtab[fd].owner;
struct server *s = t->context;
- int skerr, lskerr;
- lskerr = sizeof(skerr);
-
s->result = len = -1;
#ifndef MSG_NOSIGNAL
- getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
- if (!skerr)
- len = recv(fd, reply, sizeof(reply), 0);
+ {
+ int skerr;
+ socklen_t lskerr = sizeof(skerr);
+
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
+ if (!skerr)
+ len = recv(fd, reply, sizeof(reply), 0);
+ }
#else
/* Warning! Linux returns EAGAIN on SO_ERROR if data are still available
* but the connection was closed on the remote end. Fortunately, recv still
@@ -3150,8 +3199,8 @@
asession_temp->sessid = local_asession.sessid;
asession_temp->serverid = local_asession.serverid;
chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
- } /* end if(chtbl_lookup()) */
- else{
+ } /* end if (chtbl_lookup()) */
+ else {
/*free wasted memory;*/
pool_free_to(apools.sessid, local_asession.sessid);
}
@@ -3175,20 +3224,20 @@
t->flags |= SN_CK_VALID | SN_DIRECT;
t->srv = srv;
break;
- }else {
+ } else {
t->flags &= ~SN_CK_MASK;
t->flags |= SN_CK_DOWN;
}
- }/* end if(strcmp()) */
+ } /* end if (strcmp()) */
srv = srv->next;
}/* end while(srv) */
}/* end else of if (asession_temp->serverid == NULL) */
- }/* end if(strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
+ }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
else {
//fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
}
method_checked = 1;
- }/* end if(!method_checked ...) */
+ } /* end if (!method_checked ...) */
else{
//printf("No Methode-Header with Session-String\n");
}
@@ -3520,7 +3569,7 @@
} else {
struct server *srv = t->proxy->srv;
while (srv) {
- if(strcmp(srv->id, asession_temp->serverid) == 0) {
+ if (strcmp(srv->id, asession_temp->serverid) == 0) {
if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
/* we found the server and it's usable */
t->flags &= ~SN_CK_MASK;
@@ -3665,6 +3714,7 @@
if (t->proxy->clitimeout)
tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
t->cli_state = CL_STSHUTW;
+ //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
return 1;
}
/* read timeout */
@@ -3830,6 +3880,7 @@
/* stop reading until we get some space */
FD_CLR(t->cli_fd, StaticReadEvent);
tv_eternity(&t->crexpire);
+ //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
}
}
else {
@@ -3840,6 +3891,7 @@
tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
else
tv_eternity(&t->crexpire);
+ //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
}
}
return 0;
@@ -4386,10 +4438,10 @@
/* Cool... it's the right one */
- size_t server_id_len = strlen(t->srv->id)+1;
+ size_t server_id_len = strlen(t->srv->id) + 1;
asession_temp = &local_asession;
- if((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL){
+ if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
}
@@ -4407,22 +4459,22 @@
asession_temp->sessid = local_asession.sessid;
asession_temp->serverid = local_asession.serverid;
chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
- }/* end if(chtbl_lookup()) */
- else
- {
+ }/* end if (chtbl_lookup()) */
+ else {
/* free wasted memory */
pool_free_to(apools.sessid, local_asession.sessid);
- } /* end else from if(chtbl_lookup()) */
+ } /* end else from if (chtbl_lookup()) */
- if(asession_temp->serverid == NULL){
- if((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL){
+ if (asession_temp->serverid == NULL) {
+ if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
}
asession_temp->serverid[0] = '\0';
}
- if(asession_temp->serverid[0] == '\0') memcpy(asession_temp->serverid,t->srv->id,server_id_len);
+ if (asession_temp->serverid[0] == '\0')
+ memcpy(asession_temp->serverid,t->srv->id,server_id_len);
tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
@@ -4493,6 +4545,7 @@
tv_eternity(&t->srexpire);
shutdown(t->srv_fd, SHUT_RD);
t->srv_state = SV_STSHUTR;
+ //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
return 1;
}
/* read timeout : return a 504 to the client.
@@ -4608,6 +4661,7 @@
tv_eternity(&t->srexpire);
shutdown(t->srv_fd, SHUT_RD);
t->srv_state = SV_STSHUTR;
+ //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
return 1;
}
/* end of client read and no more data to send */
@@ -4811,7 +4865,8 @@
/* Processes the client and server jobs of a session task, then
* puts it back to the wait queue in a clean state, or
* cleans up its resources if it must be deleted. Returns
- * the time the task accepts to wait, or -1 for infinity
+ * the time the task accepts to wait, or TIME_ETERNITY for
+ * infinity.
*/
int process_session(struct task *t) {
struct session *s = t->context;
@@ -4838,7 +4893,7 @@
/* restore t to its place in the task list */
task_queue(t);
- return tv_remain(&now, &t->expire); /* nothing more to do */
+ return tv_remain2(&now, &t->expire); /* nothing more to do */
}
s->proxy->nbconn--;
@@ -4862,14 +4917,14 @@
task_delete(t);
session_free(s);
task_free(t);
- return -1; /* rest in peace for eternity */
+ return TIME_ETERNITY; /* rest in peace for eternity */
}
/*
* manages a server health-check. Returns
- * the time the task accepts to wait, or -1 for infinity.
+ * the time the task accepts to wait, or TIME_ETERNITY for infinity.
*/
int process_chk(struct task *t) {
struct server *s = t->context;
@@ -4882,7 +4937,7 @@
//fprintf(stderr, "process_chk: 2\n");
if (tv_cmp2_ms(&t->expire, &now) > 0) { /* not good time yet */
task_queue(t); /* restore t to its place in the task list */
- return tv_remain(&now, &t->expire);
+ return tv_remain2(&now, &t->expire);
}
/* we'll initiate a new check */
@@ -5022,7 +5077,7 @@
//fprintf(stderr, "process_chk: 11\n");
s->result = 0;
task_queue(t); /* restore t to its place in the task list */
- return tv_remain(&now, &t->expire);
+ return tv_remain2(&now, &t->expire);
}
@@ -5046,7 +5101,7 @@
int time2;
struct task *t, *tnext;
- next_time = -1; /* set the timer to wait eternally first */
+ next_time = TIME_ETERNITY; /* set the timer to wait eternally first */
/* look for expired tasks and add them to the run queue.
*/
@@ -5056,10 +5111,13 @@
if (t->state & TASK_RUNNING)
continue;
+ if (tv_iseternity(&t->expire))
+ continue;
+
/* wakeup expired entries. It doesn't matter if they are
* already running because of a previous event
*/
- if (tv_cmp2_ms(&t->expire, &now) <= 0) {
+ if (tv_cmp_ms(&t->expire, &now) <= 0) {
task_wakeup(&rq, t);
}
else {
@@ -5194,6 +5252,23 @@
ev.events = (sr ? EPOLLIN : 0) | (sw ? EPOLLOUT : 0);
ev.data.fd = fd;
+#ifdef EPOLL_CTL_MOD_WORKAROUND
+ /* I encountered a rarely reproducible problem with
+ * EPOLL_CTL_MOD where a modified FD (systematically
+ * the one in epoll_events[0], fd#7) would sometimes
+ * be set EPOLL_OUT while asked for a read ! This is
+ * with the 2.4 epoll patch. The workaround is to
+ * delete then recreate in case of modification.
+ * This is in 2.4 up to epoll-lt-0.21 but not in 2.6
+ * nor RHEL kernels.
+ */
+
+ if ((pr | pw) && fdtab[fd].state != FD_STCLOSE)
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
+
+ if ((sr | sw))
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
+#else
if ((pr | pw)) {
/* the file-descriptor already exists... */
if ((sr | sw)) {
@@ -5217,6 +5292,7 @@
// exit(1);
}
}
+#endif // EPOLL_CTL_MOD_WORKAROUND
}
((int*)PrevReadEvent)[fds] = rn;
((int*)PrevWriteEvent)[fds] = wn;
@@ -5538,7 +5614,7 @@
* this function enables proxies when there are enough free sessions,
* or stops them when the table is full. It is designed to be called from the
* select_loop(). It returns the time left before next expiration event
- * during stop time, -1 otherwise.
+ * during stop time, TIME_ETERNITY otherwise.
*/
static int maintain_proxies(void) {
struct proxy *p;
@@ -5546,7 +5622,7 @@
int tleft; /* time left */
p = proxy;
- tleft = -1; /* infinite time */
+ tleft = TIME_ETERNITY; /* infinite time */
/* if there are enough free sessions, we'll activate proxies */
if (actconn < global.maxconn) {
@@ -5587,7 +5663,7 @@
while (p) {
if (p->state != PR_STDISABLED) {
int t;
- t = tv_remain(&now, &p->stop_time);
+ t = tv_remain2(&now, &p->stop_time);
if (t == 0) {
Warning("Proxy %s stopped.\n", p->id);
send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
@@ -6327,6 +6403,18 @@
/* don't log empty requests */
curproxy->options |= PR_O_NULLNOLOG;
}
+ else if (!strcmp(args[1], "tcpka")) {
+ /* enable TCP keep-alives on client and server sessions */
+ curproxy->options |= PR_O_TCP_CLI_KA | PR_O_TCP_SRV_KA;
+ }
+ else if (!strcmp(args[1], "clitcpka")) {
+ /* enable TCP keep-alives on client sessions */
+ curproxy->options |= PR_O_TCP_CLI_KA;
+ }
+ else if (!strcmp(args[1], "srvtcpka")) {
+ /* enable TCP keep-alives on server sessions */
+ curproxy->options |= PR_O_TCP_SRV_KA;
+ }
else if (!strcmp(args[1], "httpchk")) {
/* use HTTP request to check servers' health */
if (curproxy->check_req != NULL) {
@@ -7611,7 +7699,7 @@
return 0;
}
-int match_str(const void *key1, const void *key2){
+int match_str(const void *key1, const void *key2) {
appsess *temp1,*temp2;
temp1 = (appsess *)key1;
@@ -7623,7 +7711,7 @@
return (strcmp(temp1->sessid,temp2->sessid) == 0);
}/* end match_str */
-void destroy(void *data){
+void destroy(void *data) {
appsess *temp1;
//printf("destroy called\n");
@@ -7659,7 +7747,7 @@
}
}/* end pool_destroy() */
-void deinit(void){
+void deinit(void) {
struct proxy *p = proxy;
struct cap_hdr *h,*h_next;
struct server *s,*s_next;
@@ -7680,13 +7768,13 @@
/* only strup if the user have set in config.
When should we free it?!
- if(p->errmsg.msg400) free(p->errmsg.msg400);
- if(p->errmsg.msg403) free(p->errmsg.msg403);
- if(p->errmsg.msg408) free(p->errmsg.msg408);
- if(p->errmsg.msg500) free(p->errmsg.msg500);
- if(p->errmsg.msg502) free(p->errmsg.msg502);
- if(p->errmsg.msg503) free(p->errmsg.msg503);
- if(p->errmsg.msg504) free(p->errmsg.msg504);
+ if (p->errmsg.msg400) free(p->errmsg.msg400);
+ if (p->errmsg.msg403) free(p->errmsg.msg403);
+ if (p->errmsg.msg408) free(p->errmsg.msg408);
+ if (p->errmsg.msg500) free(p->errmsg.msg500);
+ if (p->errmsg.msg502) free(p->errmsg.msg502);
+ if (p->errmsg.msg503) free(p->errmsg.msg503);
+ if (p->errmsg.msg504) free(p->errmsg.msg504);
*/
if (p->appsession_name)
free(p->appsession_name);
@@ -7715,10 +7803,10 @@
s = p->srv;
while (s) {
s_next = s->next;
- if(s->id)
+ if (s->id)
free(s->id);
- if(s->cookie)
+ if (s->cookie)
free(s->cookie);
free(s);