2006-06-26 00:48:02 +00:00
|
|
|
/*
|
|
|
|
* Client-side variables and functions.
|
|
|
|
*
|
2008-06-22 15:18:02 +00:00
|
|
|
* Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
|
2006-06-26 00:48:02 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2006-06-29 15:53:05 +00:00
|
|
|
#include <string.h>
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2006-06-29 15:53:05 +00:00
|
|
|
#include <common/compat.h>
|
2006-06-29 16:54:54 +00:00
|
|
|
#include <common/config.h>
|
2006-06-29 15:53:05 +00:00
|
|
|
#include <common/time.h>
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
#include <types/global.h>
|
|
|
|
|
2007-05-06 22:55:35 +00:00
|
|
|
#include <proto/acl.h>
|
2006-07-29 14:59:06 +00:00
|
|
|
#include <proto/buffers.h>
|
2006-06-26 00:48:02 +00:00
|
|
|
#include <proto/client.h>
|
|
|
|
#include <proto/fd.h>
|
|
|
|
#include <proto/log.h>
|
2006-12-03 14:21:35 +00:00
|
|
|
#include <proto/hdr_idx.h>
|
2006-06-26 00:48:02 +00:00
|
|
|
#include <proto/proto_http.h>
|
2009-03-05 17:43:00 +00:00
|
|
|
#include <proto/proxy.h>
|
2007-05-13 17:43:47 +00:00
|
|
|
#include <proto/session.h>
|
2008-11-30 18:48:07 +00:00
|
|
|
#include <proto/stream_interface.h>
|
2006-06-26 00:48:02 +00:00
|
|
|
#include <proto/stream_sock.h>
|
|
|
|
#include <proto/task.h>
|
|
|
|
|
|
|
|
|
2007-05-08 17:46:30 +00:00
|
|
|
/* Retrieves the original destination address used by the client, and sets the
|
|
|
|
* SN_FRT_ADDR_SET flag.
|
|
|
|
*/
|
|
|
|
void get_frt_addr(struct session *s)
|
|
|
|
{
|
|
|
|
socklen_t namelen = sizeof(s->frt_addr);
|
|
|
|
|
2008-12-07 15:27:56 +00:00
|
|
|
if (get_original_dst(s->si[0].fd, (struct sockaddr_in *)&s->frt_addr, &namelen) == -1)
|
|
|
|
getsockname(s->si[0].fd, (struct sockaddr *)&s->frt_addr, &namelen);
|
2007-05-08 17:46:30 +00:00
|
|
|
s->flags |= SN_FRT_ADDR_SET;
|
|
|
|
}
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: This should move to the STREAM_SOCK code then split into TCP and HTTP.
|
|
|
|
*/
|
2008-11-23 18:53:55 +00:00
|
|
|
|
2006-06-26 00:48:02 +00:00
|
|
|
/*
|
|
|
|
* this function is called on a read event from a listen socket, corresponding
|
|
|
|
* to an accept. It tries to accept as many connections as possible.
|
|
|
|
* It returns 0.
|
|
|
|
*/
|
|
|
|
int event_accept(int fd) {
|
2008-08-29 21:36:51 +00:00
|
|
|
struct listener *l = fdtab[fd].owner;
|
2007-10-29 00:09:36 +00:00
|
|
|
struct proxy *p = (struct proxy *)l->private; /* attached frontend */
|
2006-06-26 00:48:02 +00:00
|
|
|
struct session *s;
|
2007-03-03 19:51:44 +00:00
|
|
|
struct http_txn *txn;
|
2006-06-26 00:48:02 +00:00
|
|
|
struct task *t;
|
|
|
|
int cfd;
|
2008-01-06 10:22:57 +00:00
|
|
|
int max_accept = global.tune.maxaccept;
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2009-05-10 16:52:49 +00:00
|
|
|
if (p->fe_sps_lim) {
|
|
|
|
int max = freq_ctr_remain(&p->fe_sess_per_sec, p->fe_sps_lim, 0);
|
2009-03-06 08:18:27 +00:00
|
|
|
if (max_accept > max)
|
|
|
|
max_accept = max;
|
|
|
|
}
|
|
|
|
|
2009-03-21 21:43:12 +00:00
|
|
|
while (p->feconn < p->maxconn && actconn < global.maxconn && max_accept--) {
|
2006-06-26 00:48:02 +00:00
|
|
|
struct sockaddr_storage addr;
|
|
|
|
socklen_t laddr = sizeof(addr);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-13 17:43:47 +00:00
|
|
|
if ((s = pool_alloc2(pool2_session)) == NULL) { /* disable this proxy for a while */
|
2006-06-26 00:48:02 +00:00
|
|
|
Alert("out of memory in event_accept().\n");
|
2007-04-08 14:59:42 +00:00
|
|
|
EV_FD_CLR(fd, DIR_RD);
|
2006-06-26 00:48:02 +00:00
|
|
|
p->state = PR_STIDLE;
|
2007-11-04 16:51:50 +00:00
|
|
|
goto out_close;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
2008-11-23 18:53:55 +00:00
|
|
|
LIST_ADDQ(&sessions, &s->list);
|
2008-12-07 19:16:23 +00:00
|
|
|
LIST_INIT(&s->back_refs);
|
2008-11-23 18:53:55 +00:00
|
|
|
|
2008-08-10 20:55:22 +00:00
|
|
|
s->flags = 0;
|
2008-08-16 12:55:08 +00:00
|
|
|
s->term_trace = 0;
|
2008-08-10 20:55:22 +00:00
|
|
|
|
2006-06-26 00:48:02 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
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);
|
2007-05-13 17:43:47 +00:00
|
|
|
pool_free2(pool2_session, s);
|
2006-06-26 00:48:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
s->flags |= SN_MONITOR;
|
|
|
|
}
|
|
|
|
|
2009-03-21 17:13:21 +00:00
|
|
|
if ((t = task_new()) == NULL) { /* disable this proxy for a while */
|
2006-06-26 00:48:02 +00:00
|
|
|
Alert("out of memory in event_accept().\n");
|
2007-04-08 14:59:42 +00:00
|
|
|
EV_FD_CLR(fd, DIR_RD);
|
2006-06-26 00:48:02 +00:00
|
|
|
p->state = PR_STIDLE;
|
2007-11-04 16:51:50 +00:00
|
|
|
goto out_free_session;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s->cli_addr = addr;
|
|
|
|
if (cfd >= global.maxsock) {
|
|
|
|
Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
|
2007-11-04 16:51:50 +00:00
|
|
|
goto out_free_task;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) ||
|
|
|
|
(setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY,
|
|
|
|
(char *) &one, sizeof(one)) == -1)) {
|
|
|
|
Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
|
2007-11-04 16:51:50 +00:00
|
|
|
goto out_free_task;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p->options & PR_O_TCP_CLI_KA)
|
|
|
|
setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));
|
|
|
|
|
2007-10-11 18:48:58 +00:00
|
|
|
if (p->options & PR_O_TCP_NOLING)
|
|
|
|
setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
|
|
|
|
|
2008-12-07 10:50:35 +00:00
|
|
|
t->process = l->handler;
|
2006-06-26 00:48:02 +00:00
|
|
|
t->context = s;
|
|
|
|
|
|
|
|
s->task = t;
|
2008-12-07 15:45:10 +00:00
|
|
|
s->listener = l;
|
2006-11-30 10:40:23 +00:00
|
|
|
|
2009-07-07 13:10:31 +00:00
|
|
|
/* Note: initially, the session's backend points to the frontend.
|
|
|
|
* This changes later when switching rules are executed or
|
|
|
|
* when the default backend is assigned.
|
2007-11-03 13:28:39 +00:00
|
|
|
*/
|
2009-07-07 13:10:31 +00:00
|
|
|
s->be = s->fe = p;
|
2007-11-03 13:28:39 +00:00
|
|
|
|
2008-12-07 13:37:09 +00:00
|
|
|
s->ana_state = 0; /* analysers may change it but must reset it upon exit */
|
2006-06-26 00:48:02 +00:00
|
|
|
s->req = s->rep = NULL; /* will be allocated later */
|
|
|
|
|
2008-09-03 16:11:02 +00:00
|
|
|
s->si[0].state = s->si[0].prev_state = SI_ST_EST;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->si[0].err_type = SI_ET_NONE;
|
|
|
|
s->si[0].err_loc = NULL;
|
2008-08-30 01:17:31 +00:00
|
|
|
s->si[0].owner = t;
|
2008-09-04 09:19:41 +00:00
|
|
|
s->si[0].shutr = stream_sock_shutr;
|
2008-08-30 02:58:38 +00:00
|
|
|
s->si[0].shutw = stream_sock_shutw;
|
2008-12-14 13:42:35 +00:00
|
|
|
s->si[0].chk_rcv = stream_sock_chk_rcv;
|
|
|
|
s->si[0].chk_snd = stream_sock_chk_snd;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->si[0].fd = cfd;
|
2009-06-28 21:10:19 +00:00
|
|
|
s->si[0].flags = SI_FL_NONE | SI_FL_CAP_SPLTCP; /* TCP splicing capable */
|
2008-09-03 16:11:02 +00:00
|
|
|
s->si[0].exp = TICK_ETERNITY;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
|
2008-09-03 16:11:02 +00:00
|
|
|
s->si[1].state = s->si[1].prev_state = SI_ST_INI;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->si[1].err_type = SI_ET_NONE;
|
|
|
|
s->si[1].err_loc = NULL;
|
2008-08-30 01:17:31 +00:00
|
|
|
s->si[1].owner = t;
|
2008-09-04 09:19:41 +00:00
|
|
|
s->si[1].shutr = stream_sock_shutr;
|
2008-08-30 02:58:38 +00:00
|
|
|
s->si[1].shutw = stream_sock_shutw;
|
2008-12-14 13:42:35 +00:00
|
|
|
s->si[1].chk_rcv = stream_sock_chk_rcv;
|
|
|
|
s->si[1].chk_snd = stream_sock_chk_snd;
|
2008-09-03 16:11:02 +00:00
|
|
|
s->si[1].exp = TICK_ETERNITY;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->si[1].fd = -1; /* just to help with debugging */
|
2008-09-04 09:51:16 +00:00
|
|
|
s->si[1].flags = SI_FL_NONE;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
|
[BUG] fix the dequeuing logic to ensure that all requests get served
The dequeuing logic was completely wrong. First, a task was assigned
to all servers to process the queue, but this task was never scheduled
and was only woken up on session free. Second, there was no reservation
of server entries when a task was assigned a server. This means that
as long as the task was not connected to the server, its presence was
not accounted for. This was causing trouble when detecting whether or
not a server had reached maxconn. Third, during a redispatch, a session
could lose its place at the server's and get blocked because another
session at the same moment would have stolen the entry. Fourth, the
redispatch option did not work when maxqueue was reached for a server,
and it was not possible to do so without indefinitely hanging a session.
The root cause of all those problems was the lack of pre-reservation of
connections at the server's, and the lack of tracking of servers during
a redispatch. Everything relied on combinations of flags which could
appear similarly in quite distinct situations.
This patch is a major rework but there was no other solution, as the
internal logic was deeply flawed. The resulting code is cleaner, more
understandable, uses less magics and is overall more robust.
As an added bonus, "option redispatch" now works when maxqueue has
been reached on a server.
2008-06-20 13:04:11 +00:00
|
|
|
s->srv = s->prev_srv = s->srv_conn = NULL;
|
2006-06-26 00:48:02 +00:00
|
|
|
s->pend_pos = NULL;
|
2007-11-03 13:28:39 +00:00
|
|
|
s->conn_retries = s->be->conn_retries;
|
2006-12-17 21:55:52 +00:00
|
|
|
|
|
|
|
/* FIXME: the logs are horribly complicated now, because they are
|
2007-03-31 22:01:37 +00:00
|
|
|
* defined in <p>, <p>, and later <be> and <be>.
|
2006-12-17 21:55:52 +00:00
|
|
|
*/
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
if (s->flags & SN_MONITOR)
|
|
|
|
s->logs.logwait = 0;
|
|
|
|
else
|
|
|
|
s->logs.logwait = p->to_log;
|
|
|
|
|
2008-11-30 18:02:32 +00:00
|
|
|
if (s->logs.logwait & LW_REQ)
|
|
|
|
s->do_log = http_sess_log;
|
|
|
|
else
|
|
|
|
s->do_log = tcp_sess_log;
|
|
|
|
|
2008-11-30 19:44:17 +00:00
|
|
|
if (p->mode == PR_MODE_HTTP)
|
|
|
|
s->srv_error = http_return_srv_error;
|
|
|
|
else
|
2009-03-15 21:34:05 +00:00
|
|
|
s->srv_error = default_srv_error;
|
2008-11-30 19:44:17 +00:00
|
|
|
|
2008-06-22 15:18:02 +00:00
|
|
|
s->logs.accept_date = date; /* user-visible date for logging */
|
|
|
|
s->logs.tv_accept = now; /* corrected date for internal use */
|
2008-06-13 19:12:51 +00:00
|
|
|
tv_zero(&s->logs.tv_request);
|
2006-06-26 00:48:02 +00:00
|
|
|
s->logs.t_queue = -1;
|
|
|
|
s->logs.t_connect = -1;
|
|
|
|
s->logs.t_data = -1;
|
|
|
|
s->logs.t_close = 0;
|
2007-01-01 23:28:21 +00:00
|
|
|
s->logs.bytes_in = s->logs.bytes_out = 0;
|
2006-06-26 00:48:02 +00:00
|
|
|
s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
|
|
|
|
s->logs.srv_queue_size = 0; /* we will get this number soon */
|
|
|
|
|
|
|
|
s->data_source = DATA_SRC_NONE;
|
|
|
|
|
|
|
|
s->uniq_id = totalconn;
|
2009-03-05 17:43:00 +00:00
|
|
|
proxy_inc_fe_ctr(p); /* note: cum_beconn will be increased once assigned */
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2007-03-03 19:51:44 +00:00
|
|
|
txn = &s->txn;
|
2007-03-18 17:34:41 +00:00
|
|
|
txn->flags = 0;
|
2007-03-19 15:20:06 +00:00
|
|
|
/* Those variables will be checked and freed if non-NULL in
|
|
|
|
* session.c:session_free(). It is important that they are
|
|
|
|
* properly initialized.
|
|
|
|
*/
|
|
|
|
txn->srv_cookie = NULL;
|
|
|
|
txn->cli_cookie = NULL;
|
|
|
|
txn->uri = NULL;
|
2007-03-03 19:51:44 +00:00
|
|
|
txn->req.cap = NULL;
|
|
|
|
txn->rsp.cap = NULL;
|
|
|
|
txn->hdr_idx.v = NULL;
|
|
|
|
txn->hdr_idx.size = txn->hdr_idx.used = 0;
|
2006-12-16 23:05:15 +00:00
|
|
|
|
|
|
|
if (p->mode == PR_MODE_HTTP) {
|
2007-03-18 16:31:28 +00:00
|
|
|
txn->status = -1;
|
2008-04-14 18:47:37 +00:00
|
|
|
txn->req.hdr_content_len = 0LL;
|
|
|
|
txn->rsp.hdr_content_len = 0LL;
|
2007-03-03 19:51:44 +00:00
|
|
|
txn->req.msg_state = HTTP_MSG_RQBEFORE; /* at the very beginning of the request */
|
2007-06-17 14:58:38 +00:00
|
|
|
txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
|
2007-03-03 19:51:44 +00:00
|
|
|
txn->req.sol = txn->req.eol = NULL;
|
|
|
|
txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
|
2009-04-27 06:11:33 +00:00
|
|
|
txn->rsp.sol = txn->rsp.eol = NULL;
|
|
|
|
txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */
|
2009-04-02 09:35:18 +00:00
|
|
|
txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
|
|
|
|
if (p->options2 & PR_O2_REQBUG_OK)
|
|
|
|
txn->req.err_pos = -1; /* let buggy requests pass */
|
2007-03-03 19:51:44 +00:00
|
|
|
txn->auth_hdr.len = -1;
|
2006-12-16 23:05:15 +00:00
|
|
|
|
2007-03-31 22:01:37 +00:00
|
|
|
if (p->nb_req_cap > 0) {
|
2007-11-04 16:51:50 +00:00
|
|
|
if ((txn->req.cap = pool_alloc2(p->req_cap_pool)) == NULL)
|
|
|
|
goto out_fail_reqcap; /* no memory */
|
|
|
|
|
2007-03-31 22:01:37 +00:00
|
|
|
memset(txn->req.cap, 0, p->nb_req_cap*sizeof(char *));
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
2006-12-16 23:05:15 +00:00
|
|
|
|
2007-03-31 22:01:37 +00:00
|
|
|
if (p->nb_rsp_cap > 0) {
|
2007-11-04 16:51:50 +00:00
|
|
|
if ((txn->rsp.cap = pool_alloc2(p->rsp_cap_pool)) == NULL)
|
|
|
|
goto out_fail_rspcap; /* no memory */
|
|
|
|
|
2007-03-31 22:01:37 +00:00
|
|
|
memset(txn->rsp.cap, 0, p->nb_rsp_cap*sizeof(char *));
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
2006-12-16 23:05:15 +00:00
|
|
|
|
2007-05-13 20:57:02 +00:00
|
|
|
txn->hdr_idx.size = MAX_HTTP_HDR;
|
|
|
|
|
2007-11-04 16:51:50 +00:00
|
|
|
if ((txn->hdr_idx.v = pool_alloc2(p->hdr_idx_pool)) == NULL)
|
|
|
|
goto out_fail_idx; /* no memory */
|
|
|
|
|
2007-03-03 19:51:44 +00:00
|
|
|
hdr_idx_init(&txn->hdr_idx);
|
2006-12-03 14:21:35 +00:00
|
|
|
}
|
|
|
|
|
2006-06-26 00:48:02 +00:00
|
|
|
if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
|
|
|
|
&& (p->logfac1 >= 0 || p->logfac2 >= 0)) {
|
|
|
|
if (p->to_log) {
|
|
|
|
/* we have the client ip */
|
|
|
|
if (s->logs.logwait & LW_CLIP)
|
|
|
|
if (!(s->logs.logwait &= ~LW_CLIP))
|
2008-11-30 18:02:32 +00:00
|
|
|
s->do_log(s);
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
else if (s->cli_addr.ss_family == AF_INET) {
|
|
|
|
char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
|
2007-05-08 17:46:30 +00:00
|
|
|
|
|
|
|
if (!(s->flags & SN_FRT_ADDR_SET))
|
|
|
|
get_frt_addr(s);
|
|
|
|
|
|
|
|
if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->frt_addr)->sin_addr,
|
2006-06-26 00:48:02 +00:00
|
|
|
sn, sizeof(sn)) &&
|
|
|
|
inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
|
|
|
|
pn, sizeof(pn))) {
|
|
|
|
send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
|
|
|
|
pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
|
2007-05-08 17:46:30 +00:00
|
|
|
sn, ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port),
|
2006-06-26 00:48:02 +00:00
|
|
|
p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
|
2007-05-08 17:46:30 +00:00
|
|
|
|
|
|
|
if (!(s->flags & SN_FRT_ADDR_SET))
|
|
|
|
get_frt_addr(s);
|
|
|
|
|
|
|
|
if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->frt_addr)->sin6_addr,
|
2006-06-26 00:48:02 +00:00
|
|
|
sn, sizeof(sn)) &&
|
|
|
|
inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
|
|
|
|
pn, sizeof(pn))) {
|
|
|
|
send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
|
|
|
|
pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
|
2007-05-08 17:46:30 +00:00
|
|
|
sn, ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port),
|
2006-06-26 00:48:02 +00:00
|
|
|
p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
|
|
|
|
int len;
|
2007-05-08 17:46:30 +00:00
|
|
|
|
|
|
|
if (!(s->flags & SN_FRT_ADDR_SET))
|
|
|
|
get_frt_addr(s);
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
if (s->cli_addr.ss_family == AF_INET) {
|
|
|
|
char pn[INET_ADDRSTRLEN];
|
|
|
|
inet_ntop(AF_INET,
|
|
|
|
(const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
|
|
|
|
pn, sizeof(pn));
|
|
|
|
|
|
|
|
len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
|
|
|
|
s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
|
|
|
|
pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char pn[INET6_ADDRSTRLEN];
|
|
|
|
inet_ntop(AF_INET6,
|
|
|
|
(const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
|
|
|
|
pn, sizeof(pn));
|
|
|
|
|
|
|
|
len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
|
|
|
|
s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
|
|
|
|
pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
|
|
|
|
}
|
|
|
|
|
|
|
|
write(1, trash, len);
|
|
|
|
}
|
|
|
|
|
2007-11-04 16:51:50 +00:00
|
|
|
if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
|
|
|
|
goto out_fail_req; /* no memory */
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2006-07-29 14:59:06 +00:00
|
|
|
buffer_init(s->req);
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->req->prod = &s->si[0];
|
|
|
|
s->req->cons = &s->si[1];
|
2008-08-30 02:58:38 +00:00
|
|
|
s->si[0].ib = s->si[1].ob = s->req;
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
|
2008-08-30 10:31:07 +00:00
|
|
|
s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
|
|
|
|
|
2009-03-21 20:10:04 +00:00
|
|
|
if (p->mode == PR_MODE_HTTP) { /* reserve some space for header rewriting */
|
2009-01-09 10:13:00 +00:00
|
|
|
s->req->max_len -= MAXREWRITE;
|
2009-03-21 20:10:04 +00:00
|
|
|
s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */
|
|
|
|
}
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2008-12-07 10:50:35 +00:00
|
|
|
/* activate default analysers enabled for this listener */
|
|
|
|
s->req->analysers = l->analysers;
|
2008-08-17 13:20:19 +00:00
|
|
|
|
|
|
|
if (!s->req->analysers)
|
2008-08-29 07:58:42 +00:00
|
|
|
buffer_write_ena(s->req); /* don't wait to establish connection */
|
2008-08-03 18:38:13 +00:00
|
|
|
|
2007-12-03 00:38:36 +00:00
|
|
|
s->req->rto = s->fe->timeout.client;
|
|
|
|
s->req->wto = s->be->timeout.server;
|
|
|
|
s->req->cto = s->be->timeout.connect;
|
2006-07-29 16:36:34 +00:00
|
|
|
|
2007-11-04 16:51:50 +00:00
|
|
|
if ((s->rep = pool_alloc2(pool2_buffer)) == NULL)
|
|
|
|
goto out_fail_rep; /* no memory */
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2006-07-29 14:59:06 +00:00
|
|
|
buffer_init(s->rep);
|
[MAJOR] rework of the server FSM
srv_state has been removed from HTTP state machines, and states
have been split in either TCP states or analyzers. For instance,
the TARPIT state has just become a simple analyzer.
New flags have been added to the struct buffer to compensate this.
The high-level stream processors sometimes need to force a disconnection
without touching a file-descriptor (eg: report an error). But if
they touched BF_SHUTW or BF_SHUTR, the file descriptor would not
be closed. Thus, the two SHUT?_NOW flags have been added so that
an application can request a forced close which the stream interface
will be forced to obey.
During this change, a new BF_HIJACK flag was added. It will
be used for data generation, eg during a stats dump. It
prevents the producer on a buffer from sending data into it.
BF_SHUTR_NOW /* the producer must shut down for reads ASAP */
BF_SHUTW_NOW /* the consumer must shut down for writes ASAP */
BF_HIJACK /* the producer is temporarily replaced */
BF_SHUTW_NOW has precedence over BF_HIJACK. BF_HIJACK has
precedence over BF_MAY_FORWARD (so that it does not need it).
New functions buffer_shutr_now(), buffer_shutw_now(), buffer_abort()
are provided to manipulate BF_SHUT* flags.
A new type "stream_interface" has been added to describe both
sides of a buffer. A stream interface has states and error
reporting. The session now has two stream interfaces (one per
side). Each buffer has stream_interface pointers to both
consumer and producer sides.
The server-side file descriptor has moved to its stream interface,
so that even the buffer has access to it.
process_srv() has been split into three parts :
- tcp_get_connection() obtains a connection to the server
- tcp_connection_failed() tests if a previously attempted
connection has succeeded or not.
- process_srv_data() only manages the data phase, and in
this sense should be roughly equivalent to process_cli.
Little code has been removed, and a lot of old code has been
left in comments for now.
2008-10-19 05:30:41 +00:00
|
|
|
s->rep->prod = &s->si[1];
|
|
|
|
s->rep->cons = &s->si[0];
|
2008-08-30 02:58:38 +00:00
|
|
|
s->si[0].ob = s->si[1].ib = s->rep;
|
2006-07-29 14:59:06 +00:00
|
|
|
|
2007-12-03 00:38:36 +00:00
|
|
|
s->rep->rto = s->be->timeout.server;
|
|
|
|
s->rep->wto = s->fe->timeout.client;
|
2008-07-06 22:09:58 +00:00
|
|
|
s->rep->cto = TICK_ETERNITY;
|
2006-07-29 16:36:34 +00:00
|
|
|
|
2008-08-11 21:42:50 +00:00
|
|
|
s->req->rex = TICK_ETERNITY;
|
|
|
|
s->req->wex = TICK_ETERNITY;
|
2008-08-17 16:03:28 +00:00
|
|
|
s->req->analyse_exp = TICK_ETERNITY;
|
2008-08-11 21:42:50 +00:00
|
|
|
s->rep->rex = TICK_ETERNITY;
|
|
|
|
s->rep->wex = TICK_ETERNITY;
|
2008-08-17 16:03:28 +00:00
|
|
|
s->rep->analyse_exp = TICK_ETERNITY;
|
2008-08-11 21:42:50 +00:00
|
|
|
t->expire = TICK_ETERNITY;
|
|
|
|
|
2007-04-15 08:58:02 +00:00
|
|
|
fd_insert(cfd);
|
2008-08-30 01:17:31 +00:00
|
|
|
fdtab[cfd].owner = &s->si[0];
|
2006-06-26 00:48:02 +00:00
|
|
|
fdtab[cfd].state = FD_STREADY;
|
2009-06-14 13:24:37 +00:00
|
|
|
fdtab[cfd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
|
2009-06-28 09:09:07 +00:00
|
|
|
if (p->options & PR_O_TCP_NOLING)
|
|
|
|
fdtab[cfd].flags |= FD_FL_TCP_NOLING;
|
|
|
|
|
2007-10-29 00:09:36 +00:00
|
|
|
fdtab[cfd].cb[DIR_RD].f = l->proto->read;
|
2006-07-29 14:59:06 +00:00
|
|
|
fdtab[cfd].cb[DIR_RD].b = s->req;
|
2007-10-29 00:09:36 +00:00
|
|
|
fdtab[cfd].cb[DIR_WR].f = l->proto->write;
|
2006-07-29 14:59:06 +00:00
|
|
|
fdtab[cfd].cb[DIR_WR].b = s->rep;
|
2007-10-09 15:14:37 +00:00
|
|
|
fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
|
|
|
|
fdtab[cfd].peerlen = sizeof(s->cli_addr);
|
2006-06-26 00:48:02 +00:00
|
|
|
|
|
|
|
if ((p->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
|
2006-12-23 19:51:41 +00:00
|
|
|
(p->mode == PR_MODE_HEALTH && (p->options & PR_O_HTTP_CHK))) {
|
2006-06-26 00:48:02 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2006-12-23 19:51:41 +00:00
|
|
|
struct chunk msg = { .str = "HTTP/1.0 200 OK\r\n\r\n", .len = 19 };
|
2008-11-30 18:48:07 +00:00
|
|
|
stream_int_retnclose(&s->si[0], &msg); /* forge a 200 response */
|
2009-03-06 18:16:39 +00:00
|
|
|
s->req->analysers = 0;
|
2008-08-11 21:42:50 +00:00
|
|
|
t->expire = s->rep->wex;
|
2006-12-23 19:51:41 +00:00
|
|
|
}
|
2006-06-26 00:48:02 +00:00
|
|
|
else if (p->mode == PR_MODE_HEALTH) { /* health check mode, no client reading */
|
2006-12-23 19:51:41 +00:00
|
|
|
struct chunk msg = { .str = "OK\n", .len = 3 };
|
2008-11-30 18:48:07 +00:00
|
|
|
stream_int_retnclose(&s->si[0], &msg); /* forge an "OK" response */
|
2009-03-06 18:16:39 +00:00
|
|
|
s->req->analysers = 0;
|
2008-08-11 21:42:50 +00:00
|
|
|
t->expire = s->rep->wex;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2007-04-08 14:59:42 +00:00
|
|
|
EV_FD_SET(cfd, DIR_RD);
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
2008-08-11 21:42:50 +00:00
|
|
|
/* it is important not to call the wakeup function directly but to
|
|
|
|
* pass through task_wakeup(), because this one knows how to apply
|
|
|
|
* priorities to tasks.
|
|
|
|
*/
|
2009-03-08 11:25:07 +00:00
|
|
|
task_wakeup(t, TASK_WOKEN_INIT);
|
2006-06-26 00:48:02 +00:00
|
|
|
|
2006-12-17 21:14:12 +00:00
|
|
|
p->feconn++; /* beconn will be increased later */
|
|
|
|
if (p->feconn > p->feconn_max)
|
|
|
|
p->feconn_max = p->feconn;
|
2007-11-03 13:28:39 +00:00
|
|
|
|
2006-06-26 00:48:02 +00:00
|
|
|
actconn++;
|
|
|
|
totalconn++;
|
|
|
|
|
|
|
|
// fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p\n", p, actconn, totalconn, t);
|
2006-12-17 21:14:12 +00:00
|
|
|
} /* end of while (p->feconn < p->maxconn) */
|
2006-06-26 00:48:02 +00:00
|
|
|
return 0;
|
2007-11-04 16:51:50 +00:00
|
|
|
|
|
|
|
/* Error unrolling */
|
|
|
|
out_fail_rep:
|
2008-08-03 15:41:33 +00:00
|
|
|
pool_free2(pool2_buffer, s->req);
|
2007-11-04 16:51:50 +00:00
|
|
|
out_fail_req:
|
2008-08-03 15:41:33 +00:00
|
|
|
pool_free2(p->hdr_idx_pool, txn->hdr_idx.v);
|
2007-11-04 16:51:50 +00:00
|
|
|
out_fail_idx:
|
2008-08-03 15:41:33 +00:00
|
|
|
pool_free2(p->rsp_cap_pool, txn->rsp.cap);
|
2007-11-04 16:51:50 +00:00
|
|
|
out_fail_rspcap:
|
2008-08-03 15:41:33 +00:00
|
|
|
pool_free2(p->req_cap_pool, txn->req.cap);
|
2007-11-04 16:51:50 +00:00
|
|
|
out_fail_reqcap:
|
|
|
|
out_free_task:
|
2009-03-21 17:13:21 +00:00
|
|
|
task_free(t);
|
2007-11-04 16:51:50 +00:00
|
|
|
out_free_session:
|
2008-11-23 18:53:55 +00:00
|
|
|
LIST_DEL(&s->list);
|
2007-11-04 16:51:50 +00:00
|
|
|
pool_free2(pool2_session, s);
|
|
|
|
out_close:
|
|
|
|
close(cfd);
|
|
|
|
return 0;
|
2006-06-26 00:48:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-05-06 22:55:35 +00:00
|
|
|
/************************************************************************/
|
|
|
|
/* All supported keywords must be declared here. */
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
/* set test->ptr to point to the source IPv4/IPv6 address and test->i to the family */
|
2007-06-10 08:06:18 +00:00
|
|
|
static int
|
2007-06-10 09:47:14 +00:00
|
|
|
acl_fetch_src(struct proxy *px, struct session *l4, void *l7, int dir,
|
|
|
|
struct acl_expr *expr, struct acl_test *test)
|
2007-05-06 22:55:35 +00:00
|
|
|
{
|
|
|
|
test->i = l4->cli_addr.ss_family;
|
|
|
|
if (test->i == AF_INET)
|
|
|
|
test->ptr = (void *)&((struct sockaddr_in *)&l4->cli_addr)->sin_addr;
|
|
|
|
else
|
|
|
|
test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->cli_addr))->sin6_addr;
|
|
|
|
test->flags = ACL_TEST_F_READ_ONLY;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* set test->i to the connexion's source port */
|
2007-06-10 08:06:18 +00:00
|
|
|
static int
|
2007-06-10 09:47:14 +00:00
|
|
|
acl_fetch_sport(struct proxy *px, struct session *l4, void *l7, int dir,
|
|
|
|
struct acl_expr *expr, struct acl_test *test)
|
2007-05-06 22:55:35 +00:00
|
|
|
{
|
|
|
|
if (l4->cli_addr.ss_family == AF_INET)
|
|
|
|
test->i = ntohs(((struct sockaddr_in *)&l4->cli_addr)->sin_port);
|
|
|
|
else
|
|
|
|
test->i = ntohs(((struct sockaddr_in6 *)(&l4->cli_addr))->sin6_port);
|
|
|
|
test->flags = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-05-08 17:56:15 +00:00
|
|
|
|
|
|
|
/* set test->ptr to point to the frontend's IPv4/IPv6 address and test->i to the family */
|
2007-06-10 08:06:18 +00:00
|
|
|
static int
|
2007-06-10 09:47:14 +00:00
|
|
|
acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
|
|
|
|
struct acl_expr *expr, struct acl_test *test)
|
2007-05-08 17:56:15 +00:00
|
|
|
{
|
|
|
|
if (!(l4->flags & SN_FRT_ADDR_SET))
|
|
|
|
get_frt_addr(l4);
|
|
|
|
|
|
|
|
test->i = l4->frt_addr.ss_family;
|
|
|
|
if (test->i == AF_INET)
|
|
|
|
test->ptr = (void *)&((struct sockaddr_in *)&l4->frt_addr)->sin_addr;
|
|
|
|
else
|
|
|
|
test->ptr = (void *)&((struct sockaddr_in6 *)(&l4->frt_addr))->sin6_addr;
|
|
|
|
test->flags = ACL_TEST_F_READ_ONLY;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* set test->i to the frontend connexion's destination port */
|
2007-06-10 08:06:18 +00:00
|
|
|
static int
|
2007-06-10 09:47:14 +00:00
|
|
|
acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
|
|
|
|
struct acl_expr *expr, struct acl_test *test)
|
2007-05-08 17:56:15 +00:00
|
|
|
{
|
|
|
|
if (!(l4->flags & SN_FRT_ADDR_SET))
|
|
|
|
get_frt_addr(l4);
|
|
|
|
|
|
|
|
if (l4->frt_addr.ss_family == AF_INET)
|
|
|
|
test->i = ntohs(((struct sockaddr_in *)&l4->frt_addr)->sin_port);
|
|
|
|
else
|
|
|
|
test->i = ntohs(((struct sockaddr_in6 *)(&l4->frt_addr))->sin6_port);
|
|
|
|
test->flags = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-11-29 14:43:32 +00:00
|
|
|
|
2007-05-06 22:55:35 +00:00
|
|
|
/* set test->i to the number of connexions to the proxy */
|
2007-06-10 08:06:18 +00:00
|
|
|
static int
|
2007-06-10 09:47:14 +00:00
|
|
|
acl_fetch_dconn(struct proxy *px, struct session *l4, void *l7, int dir,
|
|
|
|
struct acl_expr *expr, struct acl_test *test)
|
2007-05-06 22:55:35 +00:00
|
|
|
{
|
|
|
|
test->i = px->feconn;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Note: must not be declared <const> as its list will be overwritten */
|
|
|
|
static struct acl_kw_list acl_kws = {{ },{
|
2008-07-25 17:31:03 +00:00
|
|
|
{ "src_port", acl_parse_int, acl_fetch_sport, acl_match_int, ACL_USE_TCP_PERMANENT },
|
|
|
|
{ "src", acl_parse_ip, acl_fetch_src, acl_match_ip, ACL_USE_TCP4_PERMANENT },
|
|
|
|
{ "dst", acl_parse_ip, acl_fetch_dst, acl_match_ip, ACL_USE_TCP4_PERMANENT },
|
|
|
|
{ "dst_port", acl_parse_int, acl_fetch_dport, acl_match_int, ACL_USE_TCP_PERMANENT },
|
2007-05-08 17:56:15 +00:00
|
|
|
#if 0
|
2007-11-29 14:43:32 +00:00
|
|
|
{ "src_limit", acl_parse_int, acl_fetch_sconn, acl_match_int },
|
2007-05-06 22:55:35 +00:00
|
|
|
#endif
|
2008-07-25 17:31:03 +00:00
|
|
|
{ "dst_conn", acl_parse_int, acl_fetch_dconn, acl_match_int, ACL_USE_NOTHING },
|
2007-05-06 22:55:35 +00:00
|
|
|
{ NULL, NULL, NULL, NULL },
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((constructor))
|
|
|
|
static void __client_init(void)
|
|
|
|
{
|
|
|
|
acl_register_keywords(&acl_kws);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-06-26 00:48:02 +00:00
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* c-indent-level: 8
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* End:
|
|
|
|
*/
|