* released 1.2.6-pre4

* the time-out fix introduced in 1.1.25 caused a corner case where it was
  possible for a client to keep a connection maintained regardless of the
  timeout if the server closed the connection during the HEADER phase,
  while the client ignored the close request while doing nothing in the
  other direction. This has been fixed now by ensuring that read timeouts
  are re-armed when switching to any SHUTW state.
* enhanced error reporting in the logs. Now the proxy will precisely detect
  various error conditions related to the system and/or process limits, and
  generate LOG_EMERG logs indicating that a resource has been exhausted.
* logs will contain two new characters for the error cause : 'R' indicates
  a resource exhausted, and 'I' indicates an internal error, though this
  one should never happen.
* server connection timeouts can now be reported in the logs (sC), as well
  as connections refused because of maxconn limitations (PC).
* new global configuration keyword "ulimit-n" may be used to raise the FD
  limit to usable values.
* a warning is now displayed on startup if the FD limit is lower than the
  configured maximum number of sockets.
* new configuration keyword "monitor-net" makes it possible to be monitored
  by external devices which connect to the proxy without being logged nor
  forwarded to any server. Particularly useful on generic TCPv4 relays.
This commit is contained in:
willy tarreau 2005-12-18 01:20:14 +01:00
parent 5dffb607d6
commit b1285d5ce0
3 changed files with 325 additions and 43 deletions

View File

@ -1,6 +1,35 @@
ChangeLog :
===========
2005/07/06 : 1.2.6 (1.1.32)
- the time-out fix introduced in 1.1.25 caused a corner case where it was
possible for a client to keep a connection maintained regardless of the
timeout if the server closed the connection during the HEADER phase,
while the client ignored the close request while doing nothing in the
other direction. This has been fixed now by ensuring that read timeouts
are re-armed when switching to any SHUTW state.
2005/07/05 : 1.2.6-pre3 (1.1.32-pre3)
- enhanced error reporting in the logs. Now the proxy will precisely detect
various error conditions related to the system and/or process limits, and
generate LOG_EMERG logs indicating that a resource has been exhausted.
- logs will contain two new characters for the error cause : 'R' indicates
a resource exhausted, and 'I' indicates an internal error, though this
one should never happen.
- server connection timeouts can now be reported in the logs (sC), as well
as connections refused because of maxconn limitations (PC).
2005/07/05 : 1.2.6-pre2 (1.1.32-pre2)
- new global configuration keyword "ulimit-n" may be used to raise the FD
limit to usable values.
- a warning is now displayed on startup if the FD limit is lower than the
configured maximum number of sockets.
2005/07/05 : 1.2.6-pre1 (1.1.32-pre1)
- new configuration keyword "monitor-net" makes it possible to be monitored
by external devices which connect to the proxy without being logged nor
forwarded to any server. Particularly useful on generic TCPv4 relays.
2005/06/21 : 1.2.5.2
- fixed build on PPC where chars are unsigned by default

View File

@ -1,7 +1,8 @@
global
# log 127.0.0.1 local0
log 127.0.0.1 local0
# log 127.0.0.1 local1
maxconn 4000
ulimit-n 8000
uid 0
gid 0
# chroot /tmp
@ -15,7 +16,7 @@ listen proxy1 0.0.0.0:8000
# source 127.0.0.2:0
# log 127.0.0.1 local0
# log 127.0.0.1 local1
# log global
log global
#mode tcp
cookie SERVERID insert indirect
balance roundrobin
@ -112,6 +113,7 @@ listen proxy1 0.0.0.0:3128
retries 3
grace 3000
rspdel ^Via:.*
monitor-net 192.168.12.252/30
listen proxy2 0.0.0.0:3129

333
haproxy.c
View File

@ -76,8 +76,8 @@
#include "include/appsession.h"
#define HAPROXY_VERSION "1.2.5.2"
#define HAPROXY_DATE "2005/06/21"
#define HAPROXY_VERSION "1.2.6"
#define HAPROXY_DATE "2005/07/06"
/* this is for libc5 for example */
#ifndef TCP_NODELAY
@ -321,6 +321,7 @@ int strlcpy2(char *dst, const char *src, int size) {
#define SN_SVDENY 0x00000008 /* a server header matches a deny regex */
#define SN_SVALLOW 0x00000010 /* a server header matches an allow regex */
#define SN_POST 0x00000020 /* the request was an HTTP POST */
#define SN_MONITOR 0x00000040 /* this session comes from a monitoring system */
#define SN_CK_NONE 0x00000000 /* this session had no cookie */
#define SN_CK_INVALID 0x00000040 /* this session had a cookie which matches no server */
@ -329,11 +330,14 @@ int strlcpy2(char *dst, const char *src, int size) {
#define SN_CK_MASK 0x000000C0 /* mask to get this session's cookie flags */
#define SN_CK_SHIFT 6 /* bit shift */
#define SN_ERR_NONE 0x00000000
#define SN_ERR_CLITO 0x00000100 /* client time-out */
#define SN_ERR_CLICL 0x00000200 /* client closed (read/write error) */
#define SN_ERR_SRVTO 0x00000300 /* server time-out, connect time-out */
#define SN_ERR_SRVCL 0x00000400 /* server closed (connect/read/write error) */
#define SN_ERR_PRXCOND 0x00000500 /* the proxy decided to close (deny...) */
#define SN_ERR_RESOURCE 0x00000600 /* the proxy encountered a lack of a local resources (fd, mem, ...) */
#define SN_ERR_INTERNAL 0x00000700 /* the proxy encountered an internal error */
#define SN_ERR_MASK 0x00000700 /* mask to get only session error flags */
#define SN_ERR_SHIFT 8 /* bit shift */
@ -527,6 +531,7 @@ struct listener {
struct proxy {
struct listener *listen; /* the listen addresses and sockets */
struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */
int state; /* proxy state */
struct sockaddr_in dispatch_addr; /* the default address to connect to */
struct server *srv, *cursrv; /* known servers, current server */
@ -608,6 +613,7 @@ static struct {
int nbproc;
int maxconn;
int maxsock; /* max # of sockets */
int rlimit_nofile; /* default ulimit-n value : 0=unset */
int mode;
char *chroot;
char *pidfile;
@ -697,7 +703,7 @@ const char *log_levels[NB_LOG_LEVELS] = {
const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
const char sess_term_cond[8] = "-cCsSP67"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
const char sess_fin_state[8] = "-RCHDL67"; /* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
@ -945,6 +951,54 @@ struct sockaddr_in *str2sa(char *str) {
return &sa;
}
/*
* converts <str> to a two struct in_addr* which are locally allocated.
* The format is "addr[/mask]", where "addr" cannot be empty, and mask
* is optionnal and either in the dotted or CIDR notation.
* Note: "addr" can also be a hostname. Returns 1 if OK, 0 if error.
*/
int str2net(char *str, struct in_addr *addr, struct in_addr *mask) {
char *c;
unsigned long len;
memset(mask, 0, sizeof(*mask));
memset(addr, 0, sizeof(*addr));
str=strdup(str);
if ((c = strrchr(str, '/')) != NULL) {
*c++ = 0;
/* c points to the mask */
if (strchr(c, '.') != NULL) { /* dotted notation */
if (!inet_pton(AF_INET, c, mask))
return 0;
}
else { /* mask length */
char *err;
len = strtol(c, &err, 10);
if (!*c || (err && *err) || (unsigned)len > 32)
return 0;
if (len)
mask->s_addr = htonl(0xFFFFFFFFUL << (32 - len));
else
mask->s_addr = 0;
}
}
else {
mask->s_addr = 0xFFFFFFFF;
}
if (!inet_pton(AF_INET, str, addr)) {
struct hostent *he;
if ((he = gethostbyname(str)) == NULL) {
return 0;
}
else
*addr = *(struct in_addr *) *(he->h_addr_list);
}
free(str);
return 1;
}
/*
* converts <str> to a list of listeners which are dynamically allocated.
@ -1671,8 +1725,15 @@ static inline struct server *find_server(struct proxy *px) {
/*
* This function initiates a connection to the current server (s->srv) if (s->direct)
* is set, or to the dispatch server if (s->direct) is 0. It returns 0 if
* it's OK, -1 if it's impossible.
* is set, or to the dispatch server if (s->direct) is 0.
* It can return one of :
* - SN_ERR_NONE if everything's OK
* - SN_ERR_SRVTO if there are no more servers
* - SN_ERR_SRVCL if the connection was refused by the server
* - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
* - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
* - SN_ERR_INTERNAL for any other purely internal errors
* Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
*/
int connect_server(struct session *s) {
int fd;
@ -1691,14 +1752,14 @@ int connect_server(struct session *s) {
srv = find_server(s->proxy);
if (srv == NULL) /* no server left */
return -1;
return SN_ERR_SRVTO;
s->srv_addr = srv->addr;
s->srv = srv;
s->proxy->cursrv = srv->next;
}
else /* unknown balancing algorithm */
return -1;
return SN_ERR_INTERNAL;
}
else if (*(int *)&s->proxy->dispatch_addr.sin_addr) {
/* connect to the defined dispatch addr */
@ -1709,7 +1770,7 @@ int connect_server(struct session *s) {
int salen = sizeof(struct sockaddr_in);
if (get_original_dst(s->cli_fd, &s->srv_addr, &salen) == -1) {
qfprintf(stderr, "Cannot get original server address.\n");
return -1;
return SN_ERR_INTERNAL;
}
}
@ -1727,20 +1788,37 @@ int connect_server(struct session *s) {
if ((fd = s->srv_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
qfprintf(stderr, "Cannot get a server socket.\n");
return -1;
if (errno == ENFILE)
send_log(s->proxy, LOG_EMERG,
"Proxy %s reached system FD limit at %d. Please check system tunables.\n",
s->proxy->id, maxfd);
else if (errno == EMFILE)
send_log(s->proxy, LOG_EMERG,
"Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
s->proxy->id, maxfd);
else if (errno == ENOBUFS || errno == ENOMEM)
send_log(s->proxy, LOG_EMERG,
"Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
s->proxy->id, maxfd);
/* this is a resource error */
return SN_ERR_RESOURCE;
}
if (fd >= global.maxsock) {
/* do not log anything there, it's a normal condition when this option
* is used to serialize connections to a server !
*/
Alert("socket(): not enough free sockets. Raise -n argument. Giving up.\n");
close(fd);
return -1;
return SN_ERR_PRXCOND; /* it is a configuration limit */
}
if ((fcntl(fd, F_SETFL, O_NONBLOCK)==-1) ||
(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)) {
qfprintf(stderr,"Cannot set client socket to non blocking mode.\n");
close(fd);
return -1;
return SN_ERR_INTERNAL;
}
/* allow specific binding :
@ -1753,7 +1831,10 @@ int connect_server(struct session *s) {
Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
s->proxy->id, s->srv->id);
close(fd);
return -1;
send_log(s->proxy, LOG_EMERG,
"Cannot bind to source address before connect() for server %s/%s.\n",
s->proxy->id, s->srv->id);
return SN_ERR_RESOURCE;
}
}
else if (s->proxy->options & PR_O_BIND_SRC) {
@ -1761,19 +1842,36 @@ int connect_server(struct session *s) {
if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
close(fd);
return -1;
send_log(s->proxy, LOG_EMERG,
"Cannot bind to source address before connect() for server %s/%s.\n",
s->proxy->id, s->srv->id);
return SN_ERR_RESOURCE;
}
}
if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) {
if (errno == EAGAIN) { /* no free ports left, try again later */
qfprintf(stderr,"Cannot connect, no free ports.\n");
if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) &&
(errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
if (errno == EAGAIN || errno == EADDRINUSE) {
char *msg;
if (errno == EAGAIN) /* no free ports left, try again later */
msg = "no free ports";
else
msg = "local address already in use";
qfprintf(stderr,"Cannot connect: %s.\n",msg);
close(fd);
return -1;
}
else if (errno != EALREADY && errno != EISCONN) {
send_log(s->proxy, LOG_EMERG,
"Connect() failed for server %s/%s: %s.\n",
s->proxy->id, s->srv->id, msg);
return SN_ERR_RESOURCE;
} else if (errno == ETIMEDOUT) {
close(fd);
return -1;
return SN_ERR_SRVTO;
} else {
// (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EACCES || errno == EPERM)
close(fd);
return SN_ERR_SRVCL;
}
}
@ -1790,7 +1888,7 @@ int connect_server(struct session *s) {
tv_delayfrom(&s->cnexpire, &now, s->proxy->contimeout);
else
tv_eternity(&s->cnexpire);
return 0;
return SN_ERR_NONE; /* connection is OK */
}
/*
@ -2193,6 +2291,7 @@ void client_retnclose(struct session *s, int len, const char *msg) {
FD_CLR(s->cli_fd, StaticReadEvent);
FD_SET(s->cli_fd, StaticWriteEvent);
tv_eternity(&s->crexpire);
tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
shutdown(s->cli_fd, SHUT_RD);
s->cli_state = CL_STSHUTR;
strcpy(s->rep->data, msg);
@ -2342,8 +2441,32 @@ int event_accept(int fd) {
while (p->nbconn < p->maxconn) {
struct sockaddr_storage addr;
int laddr = sizeof(addr);
if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
return 0; /* nothing more to accept */
if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
switch (errno) {
case EAGAIN:
case EINTR:
case ECONNABORTED:
return 0; /* nothing more to accept */
case ENFILE:
send_log(p, LOG_EMERG,
"Proxy %s reached system FD limit at %d. Please check system tunables.\n",
p->id, maxfd);
return 0;
case EMFILE:
send_log(p, LOG_EMERG,
"Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
p->id, maxfd);
return 0;
case ENOBUFS:
case ENOMEM:
send_log(p, LOG_EMERG,
"Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
p->id, maxfd);
return 0;
default:
return 0;
}
}
if ((s = pool_alloc(session)) == NULL) { /* disable this proxy for a while */
Alert("out of memory in event_accept().\n");
@ -2353,6 +2476,21 @@ int event_accept(int fd) {
return 0;
}
/* if this session comes from a known monitoring system, we want to ignore
* it as soon as possible, which means closing it immediately for TCP.
*/
s->flags = 0;
if (addr.ss_family == AF_INET &&
p->mon_mask.s_addr &&
(((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr) {
if (p->mode == PR_MODE_TCP) {
close(cfd);
pool_free(session, s);
continue;
}
s->flags |= SN_MONITOR;
}
if ((t = pool_alloc(task)) == NULL) { /* disable this proxy for a while */
Alert("out of memory in event_accept().\n");
FD_CLR(fd, StaticReadEvent);
@ -2392,7 +2530,6 @@ int event_accept(int fd) {
s->cli_state = (p->mode == PR_MODE_HTTP) ? CL_STHEADERS : CL_STDATA; /* no HTTP headers for non-HTTP proxies */
s->srv_state = SV_STIDLE;
s->req = s->rep = NULL; /* will be allocated later */
s->flags = 0;
s->res_cr = s->res_cw = s->res_sr = s->res_sw = RES_SILENT;
s->cli_fd = cfd;
@ -2400,7 +2537,11 @@ int event_accept(int fd) {
s->srv = NULL;
s->conn_retries = p->conn_retries;
s->logs.logwait = p->to_log;
if (s->flags & SN_MONITOR)
s->logs.logwait = 0;
else
s->logs.logwait = p->to_log;
s->logs.tv_accept = now;
s->logs.t_request = -1;
s->logs.t_connect = -1;
@ -2557,11 +2698,15 @@ int event_accept(int fd) {
fdtab[cfd].owner = t;
fdtab[cfd].state = FD_STREADY;
if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
if (p->options & PR_O_HTTP_CHK) /* "option httpchk" will make it speak HTTP */
client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
else
client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
(p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK)))
/* Either we got a request from a monitoring system on an HTTP instance,
* or we're in health check mode with the 'httpchk' option enabled. In
* both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
*/
client_retnclose(s, 19, "HTTP/1.0 200 OK\r\n\r\n"); /* forge a 200 response */
else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
client_retnclose(s, 3, "OK\n"); /* forge an "OK" response */
}
else {
FD_SET(cfd, StaticReadEvent);
@ -2574,12 +2719,14 @@ int event_accept(int fd) {
tv_eternity(&s->swexpire);
tv_eternity(&s->cwexpire);
if (s->proxy->clitimeout)
tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
else
tv_eternity(&s->crexpire);
if (s->proxy->clitimeout) {
if (FD_ISSET(cfd, StaticReadEvent))
tv_delayfrom(&s->crexpire, &now, s->proxy->clitimeout);
if (FD_ISSET(cfd, StaticWriteEvent))
tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
}
t->expire = s->crexpire;
tv_min(&t->expire, &s->crexpire, &s->cwexpire);
task_queue(t);
@ -2835,7 +2982,11 @@ int process_cli(struct session *t) {
appsess local_asession;
#ifdef DEBUG_FULL
fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
cli_stnames[c], srv_stnames[s],
FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
t->crexpire.tv_sec, t->crexpire.tv_usec,
t->cwexpire.tv_sec, t->cwexpire.tv_usec);
#endif
//fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
//FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
@ -2925,6 +3076,10 @@ int process_cli(struct session *t) {
* and we know for sure that it can expire, then it's cleaner to
* disable the timeout on the client side so that too low values
* cannot make the sessions abort too early.
*
* FIXME-20050705: the server needs a way to re-enable this time-out
* when it switches its state, otherwise a client can stay connected
* indefinitely. This now seems to be OK.
*/
tv_eternity(&t->crexpire);
@ -3502,6 +3657,11 @@ int process_cli(struct session *t) {
FD_CLR(t->cli_fd, StaticWriteEvent);
tv_eternity(&t->cwexpire);
shutdown(t->cli_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->cli_fd, StaticReadEvent);
if (t->proxy->clitimeout)
tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
t->cli_state = CL_STSHUTW;
return 1;
}
@ -3522,6 +3682,12 @@ int process_cli(struct session *t) {
FD_CLR(t->cli_fd, StaticWriteEvent);
tv_eternity(&t->cwexpire);
shutdown(t->cli_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->cli_fd, StaticReadEvent);
if (t->proxy->clitimeout)
tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
t->cli_state = CL_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLITO;
@ -3653,6 +3819,11 @@ int process_cli(struct session *t) {
}
else if (req->l >= req->rlim - req->data) {
/* no room to read more data */
/* FIXME-20050705: is it possible for a client to maintain a session
* after the timeout by sending more data after it receives a close ?
*/
if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
/* stop reading until we get some space */
FD_CLR(t->cli_fd, StaticReadEvent);
@ -3694,6 +3865,7 @@ int process_srv(struct session *t) {
struct buffer *rep = t->rep;
appsess *asession_temp = NULL;
appsess local_asession;
int conn_err;
#ifdef DEBUG_FULL
fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
@ -3717,7 +3889,9 @@ int process_srv(struct session *t) {
return 1;
}
else { /* go to SV_STCONN */
if (connect_server(t) == 0) { /* initiate a connection to the server */
/* initiate a connection to the server */
conn_err = connect_server(t);
if (conn_err == SN_ERR_NONE) {
//fprintf(stderr,"0: c=%d, s=%d\n", c, s);
t->srv_state = SV_STCONN;
}
@ -3732,7 +3906,8 @@ int process_srv(struct session *t) {
}
}
if (connect_server(t) == 0) {
conn_err = connect_server(t);
if (conn_err == SN_ERR_NONE) {
t->srv_state = SV_STCONN;
break;
}
@ -3745,7 +3920,7 @@ int process_srv(struct session *t) {
if (t->proxy->mode == PR_MODE_HTTP)
client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVCL;
t->flags |= conn_err; /* report the precise connect() error */
if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_C;
}
@ -3774,9 +3949,15 @@ int process_srv(struct session *t) {
t->flags |= SN_CK_DOWN;
}
}
if (connect_server(t) == 0)
conn_err = connect_server(t);
if (conn_err == SN_ERR_NONE)
return 0; /* no state changed */
}
else if (t->res_sw == RES_SILENT)
conn_err = SN_ERR_SRVTO; // it was a connect timeout.
else
conn_err = SN_ERR_SRVCL; // it was a connect error.
/* if conn_retries < 0 or other error, let's abort */
tv_eternity(&t->cnexpire);
t->srv_state = SV_STCLOSE;
@ -3784,7 +3965,7 @@ int process_srv(struct session *t) {
if (t->proxy->mode == PR_MODE_HTTP)
client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVCL;
t->flags |= conn_err;
if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_C;
return 1;
@ -4339,6 +4520,13 @@ int process_srv(struct session *t) {
else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
FD_CLR(t->srv_fd, StaticWriteEvent);
tv_eternity(&t->swexpire);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->srv_fd, StaticReadEvent);
if (t->proxy->srvtimeout)
tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
shutdown(t->srv_fd, SHUT_WR);
t->srv_state = SV_STSHUTW;
return 1;
@ -4352,6 +4540,18 @@ int process_srv(struct session *t) {
FD_CLR(t->srv_fd, StaticWriteEvent);
tv_eternity(&t->swexpire);
shutdown(t->srv_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->srv_fd, StaticReadEvent);
if (t->proxy->srvtimeout)
tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->srv_fd, StaticReadEvent);
if (t->proxy->srvtimeout)
tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVTO;
@ -4413,6 +4613,12 @@ int process_srv(struct session *t) {
FD_CLR(t->srv_fd, StaticWriteEvent);
tv_eternity(&t->swexpire);
shutdown(t->srv_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->srv_fd, StaticReadEvent);
if (t->proxy->srvtimeout)
tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
t->srv_state = SV_STSHUTW;
return 1;
}
@ -4433,6 +4639,11 @@ int process_srv(struct session *t) {
FD_CLR(t->srv_fd, StaticWriteEvent);
tv_eternity(&t->swexpire);
shutdown(t->srv_fd, SHUT_WR);
/* We must ensure that the read part is still alive when switching
* to shutw */
FD_SET(t->srv_fd, StaticReadEvent);
if (t->proxy->srvtimeout)
tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
t->srv_state = SV_STSHUTW;
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVTO;
@ -5611,6 +5822,17 @@ int cfg_parse_global(char *file, int linenum, char **args) {
}
global.maxconn = atol(args[1]);
}
else if (!strcmp(args[0], "ulimit-n")) {
if (global.rlimit_nofile != 0) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
return 0;
}
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
return -1;
}
global.rlimit_nofile = atol(args[1]);
}
else if (!strcmp(args[0], "chroot")) {
if (global.chroot != NULL) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
@ -5785,6 +6007,8 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
curproxy->to_log = defproxy.to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
curproxy->grace = defproxy.grace;
curproxy->source_addr = defproxy.source_addr;
curproxy->mon_net = defproxy.mon_net;
curproxy->mon_mask = defproxy.mon_mask;
return 0;
}
else if (!strcmp(args[0], "defaults")) { /* use this one to assign default values */
@ -5823,6 +6047,16 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
curproxy->listen = str2listener(args[1], curproxy->listen);
return 0;
}
else if (!strcmp(args[0], "monitor-net")) { /* set the range of IPs to ignore */
if (!*args[1] || !str2net(args[1], &curproxy->mon_net, &curproxy->mon_mask)) {
Alert("parsing [%s:%d] : '%s' expects address[/mask].\n",
file, linenum, args[0]);
return -1;
}
/* flush useless bits */
curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
return 0;
}
else if (!strcmp(args[0], "mode")) { /* sets the proxy mode */
if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
@ -7523,6 +7757,7 @@ void deinit(void){
} /* end deinit() */
int main(int argc, char **argv) {
struct rlimit limit;
FILE *pidfile = NULL;
init(argc, argv);
@ -7571,6 +7806,14 @@ int main(int argc, char **argv) {
chdir("/");
}
/* ulimits */
if (global.rlimit_nofile) {
limit.rlim_cur = limit.rlim_max = global.rlimit_nofile;
if (setrlimit(RLIMIT_NOFILE, &limit) == -1) {
Warning("[%s.main()] Cannot raise FD limit to %d.\n", argv[0], global.rlimit_nofile);
}
}
/* setgid / setuid */
if (global.gid && setgid(global.gid) == -1) {
Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
@ -7582,6 +7825,14 @@ int main(int argc, char **argv) {
exit(1);
}
/* check ulimits */
limit.rlim_cur = limit.rlim_max = 0;
getrlimit(RLIMIT_NOFILE, &limit);
if (limit.rlim_cur < global.maxsock) {
Warning("[%s.main()] FD limit (%d) too low for maxconn=%d/maxsock=%d. Please raise 'ulimit-n' to %d or more to avoid any trouble.\n",
argv[0], limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
}
if (global.mode & MODE_DAEMON) {
int ret = 0;
int proc;