mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
[MAJOR] buffers: split BF_WRITE_ENA into BF_AUTO_CONNECT and BF_AUTO_CLOSE
The BF_WRITE_ENA buffer flag became very complex to deal with, because it was used to : - enable automatic connection - enable close forwarding - enable data forwarding The last point was not very true anymore since we introduced ->send_max, but still the test remained everywhere. This was causing issues such as impossibility to connect without forwarding data, impossibility to prevent closing when data was forwarded, etc... This patch clarifies the situation by getting rid of this multi-purpose flag and replacing it with : - data forwarding based only on ->send_max || ->pipe ; - a new BF_AUTO_CONNECT flag to allow automatic connection and only that ; - ability to perform an automatic connection when ->send_max or ->pipe indicate that data is waiting to leave the buffer ; - a new BF_AUTO_CLOSE flag to let the producer automatically set the BF_SHUTW_NOW flag when it gets a BF_SHUTR. During this cleanup, it was discovered that some tests were performed twice, or that the BF_HIJACK flag was still tested, which is not needed anymore since ->send_max replcaed it. These places have been fixed too. These cleanups have also revealed a few areas where the other flags such as BF_EMPTY are not cleanly used. This will be an opportunity for a second patch.
This commit is contained in:
parent
c77e761968
commit
520d95e42b
@ -211,54 +211,30 @@ static inline void buffer_stop_hijack(struct buffer *buf)
|
|||||||
buf->flags &= ~BF_HIJACK;
|
buf->flags &= ~BF_HIJACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allows the consumer to send the buffer contents */
|
/* allow the consumer to try to establish a new connection. */
|
||||||
static inline void buffer_write_ena(struct buffer *buf)
|
static inline void buffer_auto_connect(struct buffer *buf)
|
||||||
{
|
{
|
||||||
buf->flags |= BF_WRITE_ENA;
|
buf->flags |= BF_AUTO_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prevents the consumer from sending the buffer contents */
|
/* prevent the consumer from trying to establish a new connection, and also
|
||||||
static inline void buffer_write_dis(struct buffer *buf)
|
* disable auto shutdown forwarding.
|
||||||
|
*/
|
||||||
|
static inline void buffer_dont_connect(struct buffer *buf)
|
||||||
{
|
{
|
||||||
buf->flags &= ~BF_WRITE_ENA;
|
buf->flags &= ~(BF_AUTO_CONNECT|BF_AUTO_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the buffer needs to be shut down for read, and perform the shutdown
|
/* allow the producer to forward shutdown requests */
|
||||||
* at the stream_interface level if needed. This must not be used with a buffer
|
static inline void buffer_auto_close(struct buffer *buf)
|
||||||
* for which a connection is currently in queue or turn-around.
|
|
||||||
*/
|
|
||||||
static inline void buffer_check_shutr(struct buffer *b)
|
|
||||||
{
|
{
|
||||||
if (b->flags & BF_SHUTR)
|
buf->flags |= BF_AUTO_CLOSE;
|
||||||
return;
|
|
||||||
|
|
||||||
if (!(b->flags & (BF_SHUTR_NOW|BF_SHUTW)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Last read, forced read-shutdown, or other end closed. We have to
|
|
||||||
* close our read side and inform the stream_interface.
|
|
||||||
*/
|
|
||||||
b->prod->shutr(b->prod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the buffer needs to be shut down for write, and perform the shutdown
|
/* prevent the producer from forwarding shutdown requests */
|
||||||
* at the stream_interface level if needed. This must not be used with a buffer
|
static inline void buffer_dont_close(struct buffer *buf)
|
||||||
* for which a connection is currently in queue or turn-around.
|
|
||||||
*/
|
|
||||||
static inline void buffer_check_shutw(struct buffer *b)
|
|
||||||
{
|
{
|
||||||
if (b->flags & BF_SHUTW)
|
buf->flags &= ~BF_AUTO_CLOSE;
|
||||||
return;
|
|
||||||
|
|
||||||
if ((b->flags & BF_SHUTW_NOW) ||
|
|
||||||
(b->flags & (BF_EMPTY|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR)) ==
|
|
||||||
(BF_EMPTY|BF_WRITE_ENA|BF_SHUTR)) {
|
|
||||||
/* Application requested write-shutdown, or other end closed
|
|
||||||
* with empty buffer. We have to close our write side and
|
|
||||||
* inform the stream_interface.
|
|
||||||
*/
|
|
||||||
b->cons->shutw(b->cons);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the maximum number of bytes writable at once in this buffer */
|
/* returns the maximum number of bytes writable at once in this buffer */
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
#define BF_EMPTY 0x001000 /* buffer is empty */
|
#define BF_EMPTY 0x001000 /* buffer is empty */
|
||||||
#define BF_SHUTW 0x002000 /* consumer has already shut down */
|
#define BF_SHUTW 0x002000 /* consumer has already shut down */
|
||||||
#define BF_SHUTW_NOW 0x004000 /* the consumer must shut down for writes ASAP */
|
#define BF_SHUTW_NOW 0x004000 /* the consumer must shut down for writes ASAP */
|
||||||
#define BF_WRITE_ENA 0x008000 /* consumer is allowed to forward all buffer contents */
|
#define BF_AUTO_CLOSE 0x008000 /* producer can forward shutdown to other side */
|
||||||
|
|
||||||
/* When either BF_SHUTR_NOW or BF_HIJACK is set, it is strictly forbidden for
|
/* When either BF_SHUTR_NOW or BF_HIJACK is set, it is strictly forbidden for
|
||||||
* the producer to alter the buffer contents. When BF_SHUTW_NOW is set, the
|
* the producer to alter the buffer contents. When BF_SHUTW_NOW is set, the
|
||||||
@ -92,7 +92,7 @@
|
|||||||
* 1 0 closed: the consumer has closed its output channel.
|
* 1 0 closed: the consumer has closed its output channel.
|
||||||
* 1 1 impossible
|
* 1 1 impossible
|
||||||
*
|
*
|
||||||
* The SHUTW_NOW flag should be set by the session processor when SHUTR and WRITE_ENA
|
* The SHUTW_NOW flag should be set by the session processor when SHUTR and AUTO_CLOSE
|
||||||
* are both set. It may also be set by a hijacker at the end of data. And it may also
|
* are both set. It may also be set by a hijacker at the end of data. And it may also
|
||||||
* be set by the producer when it detects SHUTR while directly forwarding data to the
|
* be set by the producer when it detects SHUTR while directly forwarding data to the
|
||||||
* consumer.
|
* consumer.
|
||||||
@ -109,6 +109,7 @@
|
|||||||
#define BF_READ_ATTACHED 0x100000 /* the read side is attached for the first time */
|
#define BF_READ_ATTACHED 0x100000 /* the read side is attached for the first time */
|
||||||
#define BF_KERN_SPLICING 0x200000 /* kernel splicing desired for this buffer */
|
#define BF_KERN_SPLICING 0x200000 /* kernel splicing desired for this buffer */
|
||||||
#define BF_READ_DONTWAIT 0x400000 /* wake the task up after every read (eg: HTTP request) */
|
#define BF_READ_DONTWAIT 0x400000 /* wake the task up after every read (eg: HTTP request) */
|
||||||
|
#define BF_AUTO_CONNECT 0x800000 /* consumer may attempt to establish a new connection */
|
||||||
|
|
||||||
/* Use these masks to clear the flags before going back to lower layers */
|
/* Use these masks to clear the flags before going back to lower layers */
|
||||||
#define BF_CLEAR_READ (~(BF_READ_NULL|BF_READ_PARTIAL|BF_READ_ERROR|BF_READ_ATTACHED))
|
#define BF_CLEAR_READ (~(BF_READ_NULL|BF_READ_PARTIAL|BF_READ_ERROR|BF_READ_ATTACHED))
|
||||||
@ -119,7 +120,7 @@
|
|||||||
#define BF_MASK_ANALYSER (BF_READ_ATTACHED|BF_READ_ACTIVITY|BF_READ_TIMEOUT|BF_ANA_TIMEOUT|BF_WRITE_ACTIVITY)
|
#define BF_MASK_ANALYSER (BF_READ_ATTACHED|BF_READ_ACTIVITY|BF_READ_TIMEOUT|BF_ANA_TIMEOUT|BF_WRITE_ACTIVITY)
|
||||||
|
|
||||||
/* Mask for static flags which are not events, but might change during processing */
|
/* Mask for static flags which are not events, but might change during processing */
|
||||||
#define BF_MASK_STATIC (BF_EMPTY|BF_FULL|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR|BF_SHUTW|BF_SHUTR_NOW|BF_SHUTW_NOW)
|
#define BF_MASK_STATIC (BF_EMPTY|BF_FULL|BF_HIJACK|BF_AUTO_CLOSE|BF_AUTO_CONNECT|BF_SHUTR|BF_SHUTW|BF_SHUTR_NOW|BF_SHUTW_NOW)
|
||||||
|
|
||||||
|
|
||||||
/* Analysers (buffer->analysers).
|
/* Analysers (buffer->analysers).
|
||||||
|
@ -403,8 +403,10 @@ int event_accept(int fd) {
|
|||||||
s->req->analysers = l->analysers;
|
s->req->analysers = l->analysers;
|
||||||
|
|
||||||
/* note: this should not happen anymore since there's always at least the switching rules */
|
/* note: this should not happen anymore since there's always at least the switching rules */
|
||||||
if (!s->req->analysers)
|
if (!s->req->analysers) {
|
||||||
buffer_write_ena(s->req); /* don't wait to establish connection */
|
buffer_auto_connect(s->req); /* don't wait to establish connection */
|
||||||
|
buffer_auto_close(s->req); /* let the producer forward close requests */
|
||||||
|
}
|
||||||
|
|
||||||
s->req->rto = s->fe->timeout.client;
|
s->req->rto = s->fe->timeout.client;
|
||||||
s->req->wto = s->be->timeout.server;
|
s->req->wto = s->be->timeout.server;
|
||||||
|
@ -316,7 +316,7 @@ int stats_sock_req_analyser(struct session *s, struct buffer *req, int an_bit)
|
|||||||
memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
|
memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
|
||||||
s->data_source = DATA_SRC_STATS;
|
s->data_source = DATA_SRC_STATS;
|
||||||
s->ana_state = STATS_ST_REQ;
|
s->ana_state = STATS_ST_REQ;
|
||||||
buffer_write_dis(s->req);
|
buffer_dont_connect(s->req);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case STATS_ST_REQ:
|
case STATS_ST_REQ:
|
||||||
|
@ -526,7 +526,7 @@ static void http_server_error(struct session *t, struct stream_interface *si,
|
|||||||
{
|
{
|
||||||
buffer_erase(si->ob);
|
buffer_erase(si->ob);
|
||||||
buffer_erase(si->ib);
|
buffer_erase(si->ib);
|
||||||
buffer_write_ena(si->ib);
|
buffer_auto_close(si->ib);
|
||||||
if (status > 0 && msg) {
|
if (status > 0 && msg) {
|
||||||
t->txn.status = status;
|
t->txn.status = status;
|
||||||
buffer_write(si->ib, msg->str, msg->len);
|
buffer_write(si->ib, msg->str, msg->len);
|
||||||
@ -1885,7 +1885,7 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
|
req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
|
||||||
|
|
||||||
/* just set the request timeout once at the beginning of the request */
|
/* just set the request timeout once at the beginning of the request */
|
||||||
@ -2036,7 +2036,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
|
|||||||
|
|
||||||
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
||||||
/* we need more data */
|
/* we need more data */
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2094,7 +2094,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
|
|||||||
/* wipe the request out so that we can drop the connection early
|
/* wipe the request out so that we can drop the connection early
|
||||||
* if the client closes first.
|
* if the client closes first.
|
||||||
*/
|
*/
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
req->analysers = 0; /* remove switching rules etc... */
|
req->analysers = 0; /* remove switching rules etc... */
|
||||||
req->analysers |= AN_REQ_HTTP_TARPIT;
|
req->analysers |= AN_REQ_HTTP_TARPIT;
|
||||||
req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.tarpit);
|
req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.tarpit);
|
||||||
@ -2321,7 +2321,7 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
|
|
||||||
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
||||||
/* we need more data */
|
/* we need more data */
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2549,7 +2549,7 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
ctx.idx = 0;
|
ctx.idx = 0;
|
||||||
http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
|
http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
|
||||||
if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
|
if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
req->analysers |= AN_REQ_HTTP_BODY;
|
req->analysers |= AN_REQ_HTTP_BODY;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2572,7 +2572,7 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
hint = s->be->url_param_post_limit;
|
hint = s->be->url_param_post_limit;
|
||||||
/* now do we really need to buffer more data? */
|
/* now do we really need to buffer more data? */
|
||||||
if (len < hint) {
|
if (len < hint) {
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
req->analysers |= AN_REQ_HTTP_BODY;
|
req->analysers |= AN_REQ_HTTP_BODY;
|
||||||
}
|
}
|
||||||
/* else... There are no body bytes to wait for */
|
/* else... There are no body bytes to wait for */
|
||||||
@ -2626,7 +2626,7 @@ int http_process_tarpit(struct session *s, struct buffer *req, int an_bit)
|
|||||||
* timeout. We just have to check that the client is still
|
* timeout. We just have to check that the client is still
|
||||||
* there and that the timeout has not expired.
|
* there and that the timeout has not expired.
|
||||||
*/
|
*/
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
if ((req->flags & (BF_SHUTR|BF_READ_ERROR)) == 0 &&
|
if ((req->flags & (BF_SHUTR|BF_READ_ERROR)) == 0 &&
|
||||||
!tick_is_expired(req->analyse_exp, now_ms))
|
!tick_is_expired(req->analyse_exp, now_ms))
|
||||||
return 0;
|
return 0;
|
||||||
@ -2669,7 +2669,7 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit)
|
|||||||
|
|
||||||
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
|
||||||
/* we need more data */
|
/* we need more data */
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2738,7 +2738,7 @@ int http_process_request_body(struct session *s, struct buffer *req, int an_bit)
|
|||||||
* request timeout once at the beginning of the
|
* request timeout once at the beginning of the
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
if (!tick_isset(req->analyse_exp))
|
if (!tick_isset(req->analyse_exp))
|
||||||
req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
|
req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
|
||||||
return 0;
|
return 0;
|
||||||
@ -2921,14 +2921,7 @@ int process_response(struct session *t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We disable sending only if we have nothing to send.
|
buffer_dont_close(rep);
|
||||||
* Note that we should not need to do this since the
|
|
||||||
* buffer is protected by the fact that at least one
|
|
||||||
* analyser remains. But close events could still be
|
|
||||||
* forwarded if we don't disable the BF_WRITE_ENA flag.
|
|
||||||
*/
|
|
||||||
if (!rep->send_max)
|
|
||||||
buffer_write_dis(rep);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4635,7 +4628,7 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend)
|
|||||||
/* The request is valid, the user is authenticated. Let's start sending
|
/* The request is valid, the user is authenticated. Let's start sending
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
buffer_write_dis(t->req);
|
buffer_dont_connect(t->req);
|
||||||
buffer_shutw_now(t->req);
|
buffer_shutw_now(t->req);
|
||||||
buffer_shutr_now(t->rep);
|
buffer_shutr_now(t->rep);
|
||||||
t->logs.tv_request = now;
|
t->logs.tv_request = now;
|
||||||
|
@ -668,7 +668,7 @@ int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit)
|
|||||||
if (rule->cond) {
|
if (rule->cond) {
|
||||||
ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ | partial);
|
ret = acl_exec_cond(rule->cond, s->fe, s, &s->txn, ACL_DIR_REQ | partial);
|
||||||
if (ret == ACL_PAT_MISS) {
|
if (ret == ACL_PAT_MISS) {
|
||||||
buffer_write_dis(req);
|
buffer_dont_connect(req);
|
||||||
/* just set the request timeout once at the beginning of the request */
|
/* just set the request timeout once at the beginning of the request */
|
||||||
if (!tick_isset(req->analyse_exp) && s->fe->tcp_req.inspect_delay)
|
if (!tick_isset(req->analyse_exp) && s->fe->tcp_req.inspect_delay)
|
||||||
req->analyse_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
|
req->analyse_exp = tick_add_ifset(now_ms, s->fe->tcp_req.inspect_delay);
|
||||||
|
@ -769,8 +769,9 @@ resync_stream_interface:
|
|||||||
if (s->req->prod->state >= SI_ST_EST) {
|
if (s->req->prod->state >= SI_ST_EST) {
|
||||||
unsigned int last_ana = 0;
|
unsigned int last_ana = 0;
|
||||||
|
|
||||||
/* it's up to the analysers to reset write_ena */
|
/* it's up to the analysers to stop new connections */
|
||||||
buffer_write_ena(s->req);
|
buffer_auto_connect(s->req);
|
||||||
|
buffer_auto_close(s->req);
|
||||||
|
|
||||||
/* We will call all analysers for which a bit is set in
|
/* We will call all analysers for which a bit is set in
|
||||||
* s->req->analysers, following the bit order from LSB
|
* s->req->analysers, following the bit order from LSB
|
||||||
@ -884,8 +885,8 @@ resync_stream_interface:
|
|||||||
unsigned int flags = s->rep->flags;
|
unsigned int flags = s->rep->flags;
|
||||||
|
|
||||||
if (s->rep->prod->state >= SI_ST_EST) {
|
if (s->rep->prod->state >= SI_ST_EST) {
|
||||||
/* it's up to the analysers to reset write_ena */
|
/* it's up to the analysers to reset auto_close */
|
||||||
buffer_write_ena(s->rep);
|
buffer_auto_close(s->rep);
|
||||||
if (s->rep->analysers)
|
if (s->rep->analysers)
|
||||||
process_response(s);
|
process_response(s);
|
||||||
}
|
}
|
||||||
@ -950,6 +951,8 @@ resync_stream_interface:
|
|||||||
* attached to it. If any data are left in, we'll permit them to
|
* attached to it. If any data are left in, we'll permit them to
|
||||||
* move.
|
* move.
|
||||||
*/
|
*/
|
||||||
|
buffer_auto_connect(s->req);
|
||||||
|
buffer_auto_close(s->req);
|
||||||
buffer_flush(s->req);
|
buffer_flush(s->req);
|
||||||
|
|
||||||
/* If the producer is still connected, we'll schedule large blocks
|
/* If the producer is still connected, we'll schedule large blocks
|
||||||
@ -980,18 +983,15 @@ resync_stream_interface:
|
|||||||
* Now forward all shutdown requests between both sides of the buffer
|
* Now forward all shutdown requests between both sides of the buffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* first, let's check if the request buffer needs to shutdown(write) */
|
/* first, let's check if the request buffer needs to shutdown(write), which may
|
||||||
if (unlikely((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR)) ==
|
* happen either because the input is closed or because we want to force a close
|
||||||
(BF_WRITE_ENA|BF_SHUTR)))
|
* once the server has begun to respond.
|
||||||
buffer_shutw_now(s->req);
|
|
||||||
else if ((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_WRITE_ENA)) == (BF_WRITE_ENA) &&
|
|
||||||
(s->req->cons->state == SI_ST_EST) &&
|
|
||||||
s->be->options & PR_O_FORCE_CLO &&
|
|
||||||
s->rep->flags & BF_READ_ACTIVITY) {
|
|
||||||
/* We want to force the connection to the server to close,
|
|
||||||
* and the server has begun to respond. That's the right
|
|
||||||
* time.
|
|
||||||
*/
|
*/
|
||||||
|
if ((s->req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE)) == BF_AUTO_CLOSE) {
|
||||||
|
if (unlikely((s->req->flags & BF_SHUTR) ||
|
||||||
|
((s->req->cons->state == SI_ST_EST) &&
|
||||||
|
(s->be->options & PR_O_FORCE_CLO) &&
|
||||||
|
(s->rep->flags & BF_READ_ACTIVITY))))
|
||||||
buffer_shutw_now(s->req);
|
buffer_shutw_now(s->req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,10 +1008,15 @@ resync_stream_interface:
|
|||||||
if (unlikely((s->req->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
|
if (unlikely((s->req->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
|
||||||
s->req->prod->shutr(s->req->prod);
|
s->req->prod->shutr(s->req->prod);
|
||||||
|
|
||||||
/* it's possible that an upper layer has requested a connection setup or abort */
|
/* it's possible that an upper layer has requested a connection setup or abort.
|
||||||
if (s->req->cons->state == SI_ST_INI &&
|
* There are 2 situations where we decide to establish a new connection :
|
||||||
(s->req->flags & (BF_WRITE_ENA|BF_SHUTW|BF_SHUTW_NOW))) {
|
* - there are data scheduled for emission in the buffer
|
||||||
if ((s->req->flags & (BF_WRITE_ENA|BF_SHUTW|BF_SHUTW_NOW)) == BF_WRITE_ENA) {
|
* - the BF_AUTO_CONNECT flag is set (active connection)
|
||||||
|
*/
|
||||||
|
if (s->req->cons->state == SI_ST_INI) {
|
||||||
|
if (!(s->req->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
|
||||||
|
if ((s->req->flags & BF_AUTO_CONNECT) ||
|
||||||
|
(s->req->send_max || s->req->pipe)) {
|
||||||
/* If we have a ->connect method, we need to perform a connection request,
|
/* If we have a ->connect method, we need to perform a connection request,
|
||||||
* otherwise we immediately switch to the connected state.
|
* otherwise we immediately switch to the connected state.
|
||||||
*/
|
*/
|
||||||
@ -1020,6 +1025,7 @@ resync_stream_interface:
|
|||||||
else
|
else
|
||||||
s->req->cons->state = SI_ST_EST; /* connection established */
|
s->req->cons->state = SI_ST_EST; /* connection established */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
s->req->cons->state = SI_ST_CLO; /* shutw+ini = abort */
|
s->req->cons->state = SI_ST_CLO; /* shutw+ini = abort */
|
||||||
}
|
}
|
||||||
@ -1065,6 +1071,7 @@ resync_stream_interface:
|
|||||||
* attached to it. If any data are left in, we'll permit them to
|
* attached to it. If any data are left in, we'll permit them to
|
||||||
* move.
|
* move.
|
||||||
*/
|
*/
|
||||||
|
buffer_auto_close(s->rep);
|
||||||
buffer_flush(s->rep);
|
buffer_flush(s->rep);
|
||||||
|
|
||||||
/* If the producer is still connected, we'll schedule large blocks
|
/* If the producer is still connected, we'll schedule large blocks
|
||||||
@ -1100,8 +1107,8 @@ resync_stream_interface:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* first, let's check if the response buffer needs to shutdown(write) */
|
/* first, let's check if the response buffer needs to shutdown(write) */
|
||||||
if (unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR)) ==
|
if (unlikely((s->rep->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTR)) ==
|
||||||
(BF_WRITE_ENA|BF_SHUTR)))
|
(BF_AUTO_CLOSE|BF_SHUTR)))
|
||||||
buffer_shutw_now(s->rep);
|
buffer_shutw_now(s->rep);
|
||||||
|
|
||||||
/* shutdown(write) pending */
|
/* shutdown(write) pending */
|
||||||
@ -1182,7 +1189,7 @@ resync_stream_interface:
|
|||||||
* request timeout is set and the server has not yet sent a response.
|
* request timeout is set and the server has not yet sent a response.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((s->rep->flags & (BF_WRITE_ENA|BF_SHUTR)) == 0 &&
|
if ((s->rep->flags & (BF_AUTO_CLOSE|BF_SHUTR)) == 0 &&
|
||||||
(tick_isset(s->req->wex) || tick_isset(s->rep->rex))) {
|
(tick_isset(s->req->wex) || tick_isset(s->rep->rex))) {
|
||||||
s->req->flags |= BF_READ_NOEXP;
|
s->req->flags |= BF_READ_NOEXP;
|
||||||
s->req->rex = TICK_ETERNITY;
|
s->req->rex = TICK_ETERNITY;
|
||||||
|
@ -89,7 +89,7 @@ void stream_int_retnclose(struct stream_interface *si, const struct chunk *msg)
|
|||||||
buffer_write(si->ob, msg->str, msg->len);
|
buffer_write(si->ob, msg->str, msg->len);
|
||||||
|
|
||||||
si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
|
si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
|
||||||
buffer_write_ena(si->ob);
|
buffer_auto_close(si->ob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -502,7 +502,7 @@ int stream_sock_read(int fd) {
|
|||||||
/* we received a shutdown */
|
/* we received a shutdown */
|
||||||
fdtab[fd].ev &= ~FD_POLL_HUP;
|
fdtab[fd].ev &= ~FD_POLL_HUP;
|
||||||
b->flags |= BF_READ_NULL;
|
b->flags |= BF_READ_NULL;
|
||||||
if (b->flags & BF_WRITE_ENA)
|
if (b->flags & BF_AUTO_CLOSE)
|
||||||
buffer_shutw_now(b);
|
buffer_shutw_now(b);
|
||||||
stream_sock_shutr(si);
|
stream_sock_shutr(si);
|
||||||
goto out_wakeup;
|
goto out_wakeup;
|
||||||
@ -601,7 +601,7 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
|
|||||||
unsigned int send_flag = MSG_DONTWAIT | MSG_NOSIGNAL;
|
unsigned int send_flag = MSG_DONTWAIT | MSG_NOSIGNAL;
|
||||||
|
|
||||||
if (MSG_MORE &&
|
if (MSG_MORE &&
|
||||||
(((b->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_WRITE_ENA)) == (BF_WRITE_ENA|BF_SHUTW_NOW) &&
|
(((b->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK)) == BF_SHUTW_NOW &&
|
||||||
(max == b->l)) ||
|
(max == b->l)) ||
|
||||||
(max != b->l && max != b->send_max))
|
(max != b->l && max != b->send_max))
|
||||||
&& (fdtab[si->fd].flags & FD_FL_TCP)) {
|
&& (fdtab[si->fd].flags & FD_FL_TCP)) {
|
||||||
@ -741,8 +741,7 @@ int stream_sock_write(int fd)
|
|||||||
* send_max limit was reached. Maybe we just wrote the last
|
* send_max limit was reached. Maybe we just wrote the last
|
||||||
* chunk and need to close.
|
* chunk and need to close.
|
||||||
*/
|
*/
|
||||||
if (((b->flags & (BF_SHUTW|BF_HIJACK|BF_WRITE_ENA|BF_SHUTW_NOW)) ==
|
if (((b->flags & (BF_SHUTW|BF_HIJACK|BF_SHUTW_NOW)) == BF_SHUTW_NOW) &&
|
||||||
(BF_WRITE_ENA|BF_SHUTW_NOW)) &&
|
|
||||||
(si->state == SI_ST_EST)) {
|
(si->state == SI_ST_EST)) {
|
||||||
stream_sock_shutw(si);
|
stream_sock_shutw(si);
|
||||||
goto out_wakeup;
|
goto out_wakeup;
|
||||||
@ -926,11 +925,9 @@ void stream_sock_data_finish(struct stream_interface *si)
|
|||||||
/* Check if we need to close the write side */
|
/* Check if we need to close the write side */
|
||||||
if (!(ob->flags & BF_SHUTW)) {
|
if (!(ob->flags & BF_SHUTW)) {
|
||||||
/* Write not closed, update FD status and timeout for writes */
|
/* Write not closed, update FD status and timeout for writes */
|
||||||
if ((ob->send_max == 0 && !ob->pipe) ||
|
if ((ob->send_max == 0 && !ob->pipe) || (ob->flags & BF_EMPTY)) {
|
||||||
(ob->flags & BF_EMPTY) ||
|
|
||||||
(ob->flags & (BF_HIJACK|BF_WRITE_ENA)) == 0) {
|
|
||||||
/* stop writing */
|
/* stop writing */
|
||||||
if ((ob->flags & (BF_EMPTY|BF_HIJACK|BF_WRITE_ENA)) == (BF_EMPTY|BF_WRITE_ENA))
|
if ((ob->flags & (BF_EMPTY|BF_HIJACK)) == BF_EMPTY)
|
||||||
si->flags |= SI_FL_WAIT_DATA;
|
si->flags |= SI_FL_WAIT_DATA;
|
||||||
EV_FD_COND_C(fd, DIR_WR);
|
EV_FD_COND_C(fd, DIR_WR);
|
||||||
ob->wex = TICK_ETERNITY;
|
ob->wex = TICK_ETERNITY;
|
||||||
@ -1014,8 +1011,7 @@ void stream_sock_chk_snd(struct stream_interface *si)
|
|||||||
|
|
||||||
if (!(si->flags & SI_FL_WAIT_DATA) || /* not waiting for data */
|
if (!(si->flags & SI_FL_WAIT_DATA) || /* not waiting for data */
|
||||||
(fdtab[si->fd].ev & FD_POLL_OUT) || /* we'll be called anyway */
|
(fdtab[si->fd].ev & FD_POLL_OUT) || /* we'll be called anyway */
|
||||||
!(ob->send_max || ob->pipe) || /* called with nothing to send ! */
|
!(ob->send_max || ob->pipe)) /* called with nothing to send ! */
|
||||||
!(ob->flags & (BF_HIJACK|BF_WRITE_ENA))) /* we may not write */
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
retval = stream_sock_write_loop(si, ob);
|
retval = stream_sock_write_loop(si, ob);
|
||||||
@ -1045,14 +1041,14 @@ void stream_sock_chk_snd(struct stream_interface *si)
|
|||||||
* send_max limit was reached. Maybe we just wrote the last
|
* send_max limit was reached. Maybe we just wrote the last
|
||||||
* chunk and need to close.
|
* chunk and need to close.
|
||||||
*/
|
*/
|
||||||
if (((ob->flags & (BF_SHUTW|BF_HIJACK|BF_WRITE_ENA|BF_SHUTW_NOW)) ==
|
if (((ob->flags & (BF_SHUTW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTW_NOW)) ==
|
||||||
(BF_WRITE_ENA|BF_SHUTW_NOW)) &&
|
(BF_AUTO_CLOSE|BF_SHUTW_NOW)) &&
|
||||||
(si->state == SI_ST_EST)) {
|
(si->state == SI_ST_EST)) {
|
||||||
stream_sock_shutw(si);
|
stream_sock_shutw(si);
|
||||||
goto out_wakeup;
|
goto out_wakeup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ob->flags & (BF_SHUTW|BF_EMPTY|BF_HIJACK|BF_WRITE_ENA)) == (BF_EMPTY|BF_WRITE_ENA))
|
if ((ob->flags & (BF_SHUTW|BF_EMPTY|BF_HIJACK)) == BF_EMPTY)
|
||||||
si->flags |= SI_FL_WAIT_DATA;
|
si->flags |= SI_FL_WAIT_DATA;
|
||||||
ob->wex = TICK_ETERNITY;
|
ob->wex = TICK_ETERNITY;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user