[MAJOR] add a connection error state to the stream_interface
Tracking connection status changes was hard, and some code was
redundant. A new SI_ST_CER state was added to the stream interface
to indicate a past connection error, and an SI_FL_ERR flag was
added to report past I/O error. The stream_sock code does not set
the connection to SI_ST_CLO anymore in case of I/O error, it's
the upper layer which does it. This makes it possible to know
exactly when the file descriptors are allocated.
The new SI_ST_CER state permitted to split tcp_connection_status()
in two parts, one processing SI_ST_CON and the other one SI_ST_CER.
Synchronous connection errors now make use of this last state, hence
eliminating duplicate code.
Some ib<->ob copy paste errors were found and fixed, and all entities
setting SI_ST_CLO also shut the buffers down.
Some of these stream_interface specific functions and structures
have migrated to a new stream_interface.c file.
Some types of errors are still not detected by the buffers. For
instance, let's assume the following scenario in one single pass
of process_session: a connection sits in SI_ST_TAR state during
a retry. At TAR expiration, a new connection attempt is made, the
connection is obtained and srv->cur_sess is increased. Then the
buffer timeout is fires and everything is cleared, the new state
becomes SI_ST_CLO. The cleaning code checks that previous state
was either SI_ST_CON or SI_ST_EST to release the connection. But
that's wrong because last state is still SI_ST_TAR. So the
server's connection count does not get decreased.
This means that prev_state must not be used, and must be replaced
by some transition detection instead of level detection.
The following debugging line was useful to track state changes :
fprintf(stderr, "%s:%d: cs=%d ss=%d(%d) rqf=0x%08x rpf=0x%08x\n", __FUNCTION__, __LINE__,
s->si[0].state, s->si[1].state, s->si[1].err_type, s->req->flags, s-> rep->flags);
2008-11-03 05:26:53 +00:00
|
|
|
/*
|
|
|
|
* Functions managing stream_interface structures
|
|
|
|
*
|
|
|
|
* Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
|
|
|
|
*
|
|
|
|
* 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>
|
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <common/compat.h>
|
|
|
|
#include <common/config.h>
|
|
|
|
#include <common/debug.h>
|
|
|
|
#include <common/standard.h>
|
|
|
|
#include <common/ticks.h>
|
|
|
|
#include <common/time.h>
|
|
|
|
|
|
|
|
#include <proto/buffers.h>
|
|
|
|
#include <proto/client.h>
|
|
|
|
#include <proto/fd.h>
|
|
|
|
#include <proto/stream_sock.h>
|
|
|
|
#include <proto/task.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function only has to be called once after a wakeup event in case of
|
|
|
|
* suspected timeout. It controls the stream interface timeouts and sets
|
|
|
|
* si->flags accordingly. It does NOT close anything, as this timeout may
|
|
|
|
* be used for any purpose. It returns 1 if the timeout fired, otherwise
|
|
|
|
* zero.
|
|
|
|
*/
|
|
|
|
int stream_int_check_timeouts(struct stream_interface *si)
|
|
|
|
{
|
|
|
|
if (tick_is_expired(si->exp, now_ms)) {
|
|
|
|
si->flags |= SI_FL_EXP;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-30 17:14:12 +00:00
|
|
|
/* to be called only when in SI_ST_DIS with SI_FL_ERR */
|
[MAJOR] add a connection error state to the stream_interface
Tracking connection status changes was hard, and some code was
redundant. A new SI_ST_CER state was added to the stream interface
to indicate a past connection error, and an SI_FL_ERR flag was
added to report past I/O error. The stream_sock code does not set
the connection to SI_ST_CLO anymore in case of I/O error, it's
the upper layer which does it. This makes it possible to know
exactly when the file descriptors are allocated.
The new SI_ST_CER state permitted to split tcp_connection_status()
in two parts, one processing SI_ST_CON and the other one SI_ST_CER.
Synchronous connection errors now make use of this last state, hence
eliminating duplicate code.
Some ib<->ob copy paste errors were found and fixed, and all entities
setting SI_ST_CLO also shut the buffers down.
Some of these stream_interface specific functions and structures
have migrated to a new stream_interface.c file.
Some types of errors are still not detected by the buffers. For
instance, let's assume the following scenario in one single pass
of process_session: a connection sits in SI_ST_TAR state during
a retry. At TAR expiration, a new connection attempt is made, the
connection is obtained and srv->cur_sess is increased. Then the
buffer timeout is fires and everything is cleared, the new state
becomes SI_ST_CLO. The cleaning code checks that previous state
was either SI_ST_CON or SI_ST_EST to release the connection. But
that's wrong because last state is still SI_ST_TAR. So the
server's connection count does not get decreased.
This means that prev_state must not be used, and must be replaced
by some transition detection instead of level detection.
The following debugging line was useful to track state changes :
fprintf(stderr, "%s:%d: cs=%d ss=%d(%d) rqf=0x%08x rpf=0x%08x\n", __FUNCTION__, __LINE__,
s->si[0].state, s->si[1].state, s->si[1].err_type, s->req->flags, s-> rep->flags);
2008-11-03 05:26:53 +00:00
|
|
|
void stream_int_report_error(struct stream_interface *si)
|
|
|
|
{
|
|
|
|
if (!si->err_type)
|
|
|
|
si->err_type = SI_ET_DATA_ERR;
|
|
|
|
|
|
|
|
si->ob->flags |= BF_WRITE_ERROR;
|
|
|
|
si->ib->flags |= BF_READ_ERROR;
|
|
|
|
}
|
|
|
|
|
2008-11-30 18:22:53 +00:00
|
|
|
/*
|
|
|
|
* Returns a message into the output buffer, and flushes the input buffer. The
|
|
|
|
* output buffer doesn't need to be empty before this. The message is contained
|
|
|
|
* in a "chunk". If it is null, then an empty message is used.
|
|
|
|
*/
|
|
|
|
void stream_int_return(struct stream_interface *si, const struct chunk *msg)
|
|
|
|
{
|
|
|
|
buffer_flush(si->ib);
|
|
|
|
buffer_flush(si->ob);
|
|
|
|
if (msg && msg->len)
|
|
|
|
buffer_write(si->ob, msg->str, msg->len);
|
|
|
|
}
|
|
|
|
|
2008-11-30 18:48:07 +00:00
|
|
|
/*
|
|
|
|
* Returns a message to the client ; the connection is shut down for read,
|
|
|
|
* and the request is cleared so that no server connection can be initiated.
|
|
|
|
* The buffer is marked for read shutdown on the other side to protect the
|
|
|
|
* message, and the buffer write is enabled. The message is contained in a
|
|
|
|
* "chunk". If it is null, then an empty message is used. The reply buffer
|
|
|
|
* doesn't need to be empty before this. The goal of this function is to
|
|
|
|
* return error messages to a client.
|
|
|
|
*/
|
|
|
|
void stream_int_retnclose(struct stream_interface *si, const struct chunk *msg)
|
|
|
|
{
|
|
|
|
buffer_abort(si->ib);
|
|
|
|
buffer_flush(si->ob);
|
|
|
|
buffer_shutr_now(si->ob);
|
|
|
|
if (msg && msg->len)
|
|
|
|
buffer_write(si->ob, msg->str, msg->len);
|
|
|
|
|
|
|
|
si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
|
|
|
|
buffer_write_ena(si->ob);
|
|
|
|
}
|
|
|
|
|
[MAJOR] add a connection error state to the stream_interface
Tracking connection status changes was hard, and some code was
redundant. A new SI_ST_CER state was added to the stream interface
to indicate a past connection error, and an SI_FL_ERR flag was
added to report past I/O error. The stream_sock code does not set
the connection to SI_ST_CLO anymore in case of I/O error, it's
the upper layer which does it. This makes it possible to know
exactly when the file descriptors are allocated.
The new SI_ST_CER state permitted to split tcp_connection_status()
in two parts, one processing SI_ST_CON and the other one SI_ST_CER.
Synchronous connection errors now make use of this last state, hence
eliminating duplicate code.
Some ib<->ob copy paste errors were found and fixed, and all entities
setting SI_ST_CLO also shut the buffers down.
Some of these stream_interface specific functions and structures
have migrated to a new stream_interface.c file.
Some types of errors are still not detected by the buffers. For
instance, let's assume the following scenario in one single pass
of process_session: a connection sits in SI_ST_TAR state during
a retry. At TAR expiration, a new connection attempt is made, the
connection is obtained and srv->cur_sess is increased. Then the
buffer timeout is fires and everything is cleared, the new state
becomes SI_ST_CLO. The cleaning code checks that previous state
was either SI_ST_CON or SI_ST_EST to release the connection. But
that's wrong because last state is still SI_ST_TAR. So the
server's connection count does not get decreased.
This means that prev_state must not be used, and must be replaced
by some transition detection instead of level detection.
The following debugging line was useful to track state changes :
fprintf(stderr, "%s:%d: cs=%d ss=%d(%d) rqf=0x%08x rpf=0x%08x\n", __FUNCTION__, __LINE__,
s->si[0].state, s->si[1].state, s->si[1].err_type, s->req->flags, s-> rep->flags);
2008-11-03 05:26:53 +00:00
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* c-indent-level: 8
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* End:
|
|
|
|
*/
|