mirror of
https://github.com/haproxy/haproxy.git
synced 2026-02-03 20:39:41 -05:00
* 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.
This commit is contained in:
parent
c5f73ed21c
commit
b952e1db84
5 changed files with 220 additions and 86 deletions
13
CHANGELOG
13
CHANGELOG
|
|
@ -1,6 +1,19 @@
|
|||
ChangeLog :
|
||||
===========
|
||||
|
||||
2005/10/09 : 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.
|
||||
|
||||
2005/08/07 : 1.2.6
|
||||
- clean-up patch from Alexander Lazic fixes build on Debian 3.1 (socklen_t).
|
||||
|
||||
|
|
|
|||
5
Makefile
5
Makefile
|
|
@ -33,7 +33,10 @@ PCREDIR := $(shell pcre-config --prefix 2>/dev/null || :)
|
|||
COPTS.linux26 = -DNETFILTER -DENABLE_POLL -DENABLE_EPOLL
|
||||
LIBS.linux26 =
|
||||
|
||||
# This is for enhanced Linux 2.4 with netfilter and epoll() patch
|
||||
# This is for enhanced Linux 2.4 with netfilter and epoll() patch.
|
||||
# Warning! If kernel is 2.4 with epoll-lt <= 0.21, then you must add
|
||||
# -DEPOLL_CTL_MOD_WORKAROUND to workaround a very rare bug.
|
||||
#COPTS.linux24e = -DNETFILTER -DENABLE_POLL -DENABLE_EPOLL -DUSE_MY_EPOLL -DEPOLL_CTL_MOD_WORKAROUND
|
||||
COPTS.linux24e = -DNETFILTER -DENABLE_POLL -DENABLE_EPOLL -DUSE_MY_EPOLL
|
||||
LIBS.linux24e =
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
H A - P r o x y
|
||||
Reference Manual
|
||||
-------------------
|
||||
version 1.2.6
|
||||
version 1.2.7
|
||||
willy tarreau
|
||||
2005/08/07
|
||||
2005/10/09
|
||||
|
||||
============
|
||||
| Abstract |
|
||||
|
|
@ -1093,6 +1093,20 @@ Example :
|
|||
server srv1 192.168.1.1:80 source 192.168.2.1:20
|
||||
server srv2 192.168.1.2:80 source 192.168.2.1:20
|
||||
|
||||
4.1.3) TCP keep-alive
|
||||
---------------------
|
||||
With version 1.2.7, it becomes possible to enable TCP keep-alives on both the
|
||||
client and server sides. This makes it possible to prevent long sessions from
|
||||
expiring on external layer 4 components such as firewalls and load-balancers.
|
||||
It also allows the system to terminate dead sessions when no timeout has been
|
||||
set (not recommanded). The proxy cannot set the keep-alive probes intervals nor
|
||||
maximal count, consult your operating system manual for this. There are 3
|
||||
options to enable TCP keep-alive :
|
||||
|
||||
option tcpka # enables keep-alive both on client and server side
|
||||
option clitcpka # enables keep-alive only on client side
|
||||
option srvtcpka # enables keep-alive only on server side
|
||||
|
||||
|
||||
4.2) Event logging
|
||||
------------------
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
H A - P r o x y
|
||||
Manuel de référence
|
||||
-------------------
|
||||
version 1.2.6
|
||||
version 1.2.7
|
||||
willy tarreau
|
||||
2005/08/07
|
||||
2005/10/09
|
||||
|
||||
================
|
||||
| Introduction |
|
||||
|
|
@ -1102,6 +1102,22 @@ Exemple :
|
|||
server srv1 192.168.1.1:80 source 192.168.2.1:20
|
||||
server srv2 192.168.1.2:80 source 192.168.2.1:20
|
||||
|
||||
4.1.3) Maintien de session TCP (keep-alive)
|
||||
-------------------------------------------
|
||||
Avec la version 1.2.7, il devient possible d'activer le maintien de session
|
||||
TCP (TCP keep-alive) à la fois côté client et côté serveur. Cela permet
|
||||
d'empêcher des sessions longues d'expirer sur des équipements de niveau 4
|
||||
externes tels que des firewalls ou des répartiteurs de charge. Cela permet
|
||||
aussi au système de détecter et terminer des sessions figées lorsqu'aucun
|
||||
time-out n'a été positionné (fortement déconseillé). Le proxy ne peut pas
|
||||
positionner l'intervalle entre les annonces ni le nombre maximal, veuillez
|
||||
vous référer au manuel du système d'exploitation pour cela. Il existe 3 options
|
||||
pour activer le maintien de session TCP :
|
||||
|
||||
option tcpka # active le keep-alive côté client et côté serveur
|
||||
option clitcpka # active le keep-alive côté client
|
||||
option srvtcpka # active le keep-alive côté serveur
|
||||
|
||||
|
||||
4.2) Journalisation des connexions
|
||||
----------------------------------
|
||||
|
|
|
|||
250
haproxy.c
250
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 @@ int strlcpy2(char *dst, const char *src, int size) {
|
|||
#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 @@ struct proxy {
|
|||
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 @@ struct fdtab {
|
|||
|
||||
/*********************************************************************/
|
||||
|
||||
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 @@ static inline struct timeval *tv_delayfrom(struct timeval *tv, struct timeval *f
|
|||
|
||||
/*
|
||||
* 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 @@ static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
|
|||
|
||||
/*
|
||||
* 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 @@ unsigned long tv_delta(struct timeval *tv1, struct timeval *tv2) {
|
|||
|
||||
/*
|
||||
* 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 @@ static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
|
|||
|
||||
/*
|
||||
* 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 @@ static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
|
|||
/*
|
||||
* 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;
|
||||
|
|
@ -1448,6 +1457,28 @@ static inline int tv_cmp2_ms(struct timeval *tv1, struct timeval *tv2) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ struct task *task_queue(struct task *task) {
|
|||
/* 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 @@ int connect_server(struct session *s) {
|
|||
}
|
||||
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 @@ int connect_server(struct session *s) {
|
|||
* 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 @@ int connect_server(struct session *s) {
|
|||
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 @@ int connect_server(struct session *s) {
|
|||
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 @@ int event_cli_read(int fd) {
|
|||
|
||||
#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 @@ int event_srv_read(int fd) {
|
|||
|
||||
#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 @@ int event_cli_write(int fd) {
|
|||
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 @@ int event_cli_write(int fd) {
|
|||
}
|
||||
|
||||
#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 @@ int event_srv_write(int fd) {
|
|||
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 @@ int event_srv_write(int fd) {
|
|||
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 @@ int event_accept(int fd) {
|
|||
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 @@ int event_accept(int fd) {
|
|||
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 @@ int event_accept(int fd) {
|
|||
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 @@ int event_accept(int fd) {
|
|||
|
||||
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 @@ int event_accept(int fd) {
|
|||
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 @@ int event_accept(int fd) {
|
|||
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 @@ int event_srv_chk_w(int fd) {
|
|||
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 @@ int event_srv_chk_r(int fd) {
|
|||
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 @@ int process_cli(struct session *t) {
|
|||
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 @@ int process_cli(struct session *t) {
|
|||
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 @@ int process_cli(struct session *t) {
|
|||
} 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 @@ int process_cli(struct session *t) {
|
|||
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 @@ int process_cli(struct session *t) {
|
|||
/* 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 @@ int process_cli(struct session *t) {
|
|||
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 @@ int process_srv(struct session *t) {
|
|||
|
||||
/* 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 @@ int process_srv(struct session *t) {
|
|||
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 @@ int process_srv(struct session *t) {
|
|||
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 @@ int process_srv(struct session *t) {
|
|||
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 @@ int process_srv(struct session *t) {
|
|||
/* 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 @@ int process_session(struct task *t) {
|
|||
/* 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 @@ int process_session(struct task *t) {
|
|||
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 @@ int process_chk(struct task *t) {
|
|||
//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 @@ int process_chk(struct task *t) {
|
|||
//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 process_runnable_tasks() {
|
|||
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 @@ int process_runnable_tasks() {
|
|||
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 @@ int epoll_loop(int action) {
|
|||
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 @@ int epoll_loop(int action) {
|
|||
// exit(1);
|
||||
}
|
||||
}
|
||||
#endif // EPOLL_CTL_MOD_WORKAROUND
|
||||
}
|
||||
((int*)PrevReadEvent)[fds] = rn;
|
||||
((int*)PrevWriteEvent)[fds] = wn;
|
||||
|
|
@ -5538,7 +5614,7 @@ int stats(void) {
|
|||
* 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 @@ static int maintain_proxies(void) {
|
|||
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 @@ static int maintain_proxies(void) {
|
|||
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 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
|
|||
/* 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 @@ int start_proxies() {
|
|||
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 @@ int match_str(const void *key1, const void *key2){
|
|||
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 @@ void pool_destroy(void **pool)
|
|||
}
|
||||
}/* 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 @@ void deinit(void){
|
|||
|
||||
/* 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 @@ void deinit(void){
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue