haproxy/include/haproxy/stconn-t.h
Willy Tarreau 7aff64518c MINOR: stconn: report that a buffer allocation succeeded
We used to have two states for the channel's input buffer used by the SC,
NEED_BUFF or not, flipped by sc_need_buff() and sc_have_buff(). We want to
have a 3rd state, indicating that we've just got a desired buffer. Let's
add an HAVE_BUFF flag that is set by sc_have_buff() and that is cleared by
sc_used_buff(). This way by looking at HAVE_BUFF we know that we're coming
back from the allocation callback and that the offered buffer has not yet
been used.
2024-05-10 17:18:13 +02:00

362 lines
17 KiB
C

/*
* include/haproxy/stconn-t.h
* This file describes the stream connector struct and associated constants.
*
* Copyright 2021 Christopher Faulet <cfaulet@haproxy.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_STCONN_T_H
#define _HAPROXY_STCONN_T_H
#include <haproxy/obj_type-t.h>
#include <haproxy/connection-t.h>
#include <haproxy/pipe-t.h>
#include <haproxy/show_flags-t.h>
#include <haproxy/task-t.h>
#include <haproxy/xref-t.h>
enum iobuf_flags {
IOBUF_FL_NONE = 0x00000000, /* For initialization purposes */
IOBUF_FL_NO_FF = 0x00000001, /* Fast-forwarding is not supported */
IOBUF_FL_NO_SPLICING = 0x00000002, /* Splicing is not supported or unusable for this stream */
IOBUF_FL_FF_BLOCKED = 0x00000004, /* Fast-forwarding is blocked (buffer allocation/full) */
IOBUF_FL_INTERIM_FF = 0x00000008, /* Producer side warn it will immediately retry a fast-forward.
* .done_fastfwd() on consumer side must take care of this flag
*/
IOBUF_FL_EOI = 0x00000010, /* A EOI was encountered on producer side */
};
/* Flags used */
enum nego_ff_flags {
NEGO_FF_FL_NONE = 0x00000000, /* For initialization purposes */
NEGO_FF_FL_MAY_SPLICE = 0x00000001, /* Consumer may choose to use kernel splicing if it supports it */
NEGO_FF_FL_EXACT_SIZE = 0x00000002, /* Size passed for the nego is the expected exact size to forwarded */
};
struct iobuf {
struct pipe *pipe; /* non-NULL only when data present */
struct buffer *buf;
size_t offset;
size_t data;
unsigned int flags;
};
/* Stream Endpoint Flags.
* Please also update the se_show_flags() function below in case of changes.
*/
enum se_flags {
SE_FL_NONE = 0x00000000, /* For initialization purposes */
/* Endpoint types */
SE_FL_T_MUX = 0x00000001, /* The endpoint is a mux (the target may be NULL before the mux init) */
SE_FL_T_APPLET = 0x00000002, /* The endpoint is an applet */
/* unused: 0x00000004 .. 0x00000008 */
/* Endpoint states: none == attached to a mux with a stream connector */
SE_FL_DETACHED = 0x00000010, /* The endpoint is detached (no mux/no applet) */
SE_FL_ORPHAN = 0x00000020, /* The endpoint is orphan (no stream connector) */
/* unused: 0x00000040 .. 0x00000080 */
SE_FL_SHRD = 0x00000100, /* read shut, draining extra data */
SE_FL_SHRR = 0x00000200, /* read shut, resetting extra data */
SE_FL_SHR = SE_FL_SHRD | SE_FL_SHRR, /* read shut status */
SE_FL_SHWN = 0x00000400, /* write shut, verbose mode */
SE_FL_SHWS = 0x00000800, /* write shut, silent mode */
SE_FL_SHW = SE_FL_SHWN | SE_FL_SHWS, /* write shut status */
/* following flags are supposed to be set by the endpoint and read by
* the app layer :
*/
/* Permanent flags */
SE_FL_NOT_FIRST = 0x00001000, /* This stream connector is not the first one for the endpoint */
SE_FL_WEBSOCKET = 0x00002000, /* The endpoint uses the websocket proto */
SE_FL_EOI = 0x00004000, /* end-of-input reached */
SE_FL_EOS = 0x00008000, /* End of stream delivered to data layer */
SE_FL_ERROR = 0x00010000, /* a fatal error was reported */
/* Transient flags */
SE_FL_ERR_PENDING= 0x00020000, /* An error is pending, but there's still data to be read */
SE_FL_RCV_MORE = 0x00040000, /* Endpoint may have more bytes to transfer */
SE_FL_WANT_ROOM = 0x00080000, /* More bytes to transfer, but not enough room */
SE_FL_EXP_NO_DATA= 0x00100000, /* No data expected by the endpoint */
SE_FL_MAY_FASTFWD_PROD = 0x00200000, /* The endpoint may produce data via zero-copy forwarding */
SE_FL_MAY_FASTFWD_CONS = 0x00400000, /* The endpoint may consume data via zero-copy forwarding */
SE_FL_ENDP_MASK = 0x004ff000, /* Mask for flags set by the endpoint */
/* following flags are supposed to be set by the app layer and read by
* the endpoint :
*/
/* unused 0x00800000,*/
/* unused 0x01000000,*/
/* unused 0x02000000,*/
SE_FL_WAIT_FOR_HS = 0x04000000, /* This stream is waiting for handhskae */
SE_FL_KILL_CONN = 0x08000000, /* must kill the connection when the SC closes */
SE_FL_WAIT_DATA = 0x10000000, /* stream endpoint cannot work without more data from the stream's output */
SE_FL_WONT_CONSUME = 0x20000000, /* stream endpoint will not consume more data */
SE_FL_HAVE_NO_DATA = 0x40000000, /* the endpoint has no more data to deliver to the stream */
SE_FL_APPLET_NEED_CONN = 0x80000000, /* applet is waiting for the other side to (fail to) connect */
};
/* Shutdown modes */
enum se_shut_mode {
SE_SHR_DRAIN = 0x00000001, /* read shutdown, drain any extra stuff */
SE_SHR_RESET = 0x00000002, /* read shutdown, reset any extra stuff */
SE_SHW_NORMAL = 0x00000004, /* regular write shutdown */
SE_SHW_SILENT = 0x00000008, /* imminent close, don't notify peer */
};
/* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the
* __APPEND_FLAG macro. The new end of the buffer is returned.
*/
static forceinline char *se_show_flags(char *buf, size_t len, const char *delim, uint flg)
{
#define _(f, ...) __APPEND_FLAG(buf, len, delim, flg, f, #f, __VA_ARGS__)
/* prologue */
_(0);
/* flags */
_(SE_FL_T_MUX, _(SE_FL_T_APPLET, _(SE_FL_DETACHED, _(SE_FL_ORPHAN,
_(SE_FL_SHRD, _(SE_FL_SHRR, _(SE_FL_SHWN, _(SE_FL_SHWS,
_(SE_FL_NOT_FIRST, _(SE_FL_WEBSOCKET, _(SE_FL_EOI, _(SE_FL_EOS,
_(SE_FL_ERROR, _(SE_FL_ERR_PENDING, _(SE_FL_RCV_MORE,
_(SE_FL_WANT_ROOM, _(SE_FL_EXP_NO_DATA, _(SE_FL_MAY_FASTFWD_PROD, _(SE_FL_MAY_FASTFWD_CONS,
_(SE_FL_WAIT_FOR_HS, _(SE_FL_KILL_CONN, _(SE_FL_WAIT_DATA,
_(SE_FL_WONT_CONSUME, _(SE_FL_HAVE_NO_DATA, _(SE_FL_APPLET_NEED_CONN)))))))))))))))))))))))));
/* epilogue */
_(~0U);
return buf;
#undef _
}
/* stconn flags.
* Please also update the sc_show_flags() function below in case of changes.
*
* When SC_FL_ABRT_WANTED/SC_FL_EOS is set, it is strictly forbidden for the
* producer to alter the buffer contents. In this case, the consumer is free to
* perform a shutdown when it has consumed the last contents, otherwise the
* session processor will do it anyway. SC_FL_ABRT* are set at the upper layer
* level (the stream) while SC_FL_EOS is set at the SE layer.
*
* The SC_FL_SHUT_WANTED flaga should be set by the session processor when
* SC_FLABRT_DONE/SC_FL_EOS and CF_AUTO_CLOSE are both set. And it may also be
* set by the producer when it detects SC_FL_EOS while directly forwarding data to the
* consumer.
*
* The SHUT/ABRT flags work like this :
*
* ABRT_WANTED ABRT_DONE meaning
* 0 0 normal case, connection still open and data is being read
* 1 0 closing : the producer cannot feed data anymore but can close
* 0/1 1 closed: the producer has closed its input channel.
*
* SHUT_WANTED SHUT_DONE meaning
* 0 0 normal case, connection still open and data is being written
* 1 0 closing: the consumer can send last data and may then close
* 0/1 1 closed: the consumer has closed its output channel.
*
*
* The ABRT_WANTED flag is mostly used to force the producer to abort when an error is
* detected on the consumer side.
*
*/
enum sc_flags {
SC_FL_NONE = 0x00000000, /* Just for initialization purposes */
SC_FL_ISBACK = 0x00000001, /* Set for SC on back-side */
SC_FL_EOI = 0x00000002, /* End of input was reached. no more data will be received from the endpoint */
SC_FL_ERROR = 0x00000004, /* A fatal error was reported */
SC_FL_NOLINGER = 0x00000008, /* may close without lingering. One-shot. */
SC_FL_NOHALF = 0x00000010, /* no half close, close both sides at once */
SC_FL_DONT_WAKE = 0x00000020, /* resync in progress, don't wake up */
SC_FL_INDEP_STR = 0x00000040, /* independent streams = don't update rex on write */
SC_FL_WONT_READ = 0x00000080, /* SC doesn't want to read data */
SC_FL_NEED_BUFF = 0x00000100, /* SC waits for an rx buffer allocation to complete */
SC_FL_NEED_ROOM = 0x00000200, /* SC needs more room in the rx buffer to store incoming data */
SC_FL_RCV_ONCE = 0x00000400, /* Don't loop to receive data. cleared after a successful receive */
SC_FL_SND_ASAP = 0x00000800, /* Don't wait for sending. cleared when all data were sent */
SC_FL_SND_NEVERWAIT = 0x00001000, /* Never wait for sending (permanent) */
SC_FL_SND_EXP_MORE = 0x00002000, /* More data expected to be sent very soon. cleared when all data were sent */
SC_FL_ABRT_WANTED = 0x00004000, /* An abort was requested and must be performed ASAP (up side to down side) */
SC_FL_SHUT_WANTED = 0x00008000, /* A shutdown was requested and mux be performed ASAP (up side to down side) */
SC_FL_ABRT_DONE = 0x00010000, /* An abort was performed for the SC */
SC_FL_SHUT_DONE = 0x00020000, /* A shutdown was performed for the SC */
SC_FL_EOS = 0x00040000, /* End of stream was reached (from down side to up side) */
SC_FL_HAVE_BUFF = 0x00080000, /* A buffer is ready, flag will be cleared once allocated */
};
/* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the
* __APPEND_FLAG macro. The new end of the buffer is returned.
*/
static forceinline char *sc_show_flags(char *buf, size_t len, const char *delim, uint flg)
{
#define _(f, ...) __APPEND_FLAG(buf, len, delim, flg, f, #f, __VA_ARGS__)
/* prologue */
_(0);
/* flags */
_(SC_FL_ISBACK, _(SC_FL_EOI, _(SC_FL_ERROR, _(SC_FL_NOLINGER, _(SC_FL_NOHALF,
_(SC_FL_DONT_WAKE, _(SC_FL_INDEP_STR, _(SC_FL_WONT_READ,
_(SC_FL_NEED_BUFF, _(SC_FL_NEED_ROOM,
_(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE,
_(SC_FL_ABRT_WANTED, _(SC_FL_SHUT_WANTED, _(SC_FL_ABRT_DONE, _(SC_FL_SHUT_DONE,
_(SC_FL_EOS, _(SC_FL_HAVE_BUFF))))))))))))))))))));
/* epilogue */
_(~0U);
return buf;
#undef _
}
/* A conn stream must have its own errors independently of the buffer's, so that
* applications can rely on what the buffer reports while the conn stream is
* performing some retries (eg: connection error). Some states are transient and
* do not last beyond process_session().
*/
enum sc_state {
SC_ST_INI = 0, /* SC not sollicitated yet */
SC_ST_REQ, /* [transient] connection initiation desired and not started yet */
SC_ST_QUE, /* SC waiting in queue */
SC_ST_TAR, /* SC in turn-around state after failed connect attempt */
SC_ST_ASS, /* server just assigned to this SC */
SC_ST_CON, /* initiated connection request (resource exists) */
SC_ST_CER, /* [transient] previous connection attempt failed (resource released) */
SC_ST_RDY, /* [transient] ready proven after I/O success during SC_ST_CON */
SC_ST_EST, /* connection established (resource exists) */
SC_ST_DIS, /* [transient] disconnected from other side, but cleanup not done yet */
SC_ST_CLO, /* SC closed, might not existing anymore. Buffers shut. */
} __attribute__((packed));
/* state bits for use with lists of states */
enum sc_state_bit {
SC_SB_NONE = 0,
SC_SB_INI = 1U << SC_ST_INI,
SC_SB_REQ = 1U << SC_ST_REQ,
SC_SB_QUE = 1U << SC_ST_QUE,
SC_SB_TAR = 1U << SC_ST_TAR,
SC_SB_ASS = 1U << SC_ST_ASS,
SC_SB_CON = 1U << SC_ST_CON,
SC_SB_CER = 1U << SC_ST_CER,
SC_SB_RDY = 1U << SC_ST_RDY,
SC_SB_EST = 1U << SC_ST_EST,
SC_SB_DIS = 1U << SC_ST_DIS,
SC_SB_CLO = 1U << SC_ST_CLO,
SC_SB_ALL = SC_SB_INI|SC_SB_REQ|SC_SB_QUE|SC_SB_TAR|SC_SB_ASS|SC_SB_CON|SC_SB_CER|SC_SB_RDY|SC_SB_EST|SC_SB_DIS|SC_SB_CLO,
};
struct stconn;
/* represent the abort code, enriched with contextual info:
* - First 5 bits are used for the source (31 possible sources)
* - other bits are reserved for now
*/
#define SE_ABRT_SRC_SHIFT 0
#define SE_ABRT_SRC_MASK 0x0000001f
#define SE_ABRT_SRC_MUX_PT 0x01 /* Code set by the PT mux */
#define SE_ABRT_SRC_MUX_H1 0x02 /* Code set bu the H1 mux */
#define SE_ABRT_SRC_MUX_H2 0x03 /* Code set bu the H2 mux */
#define SE_ABRT_SRC_MUX_QUIC 0x04 /* Code set bu the QUIC/H3 mux */
#define SE_ABRT_SRC_MUX_FCGI 0x05 /* Code set bu the FCGI mux */
struct se_abort_info {
uint32_t info;
uint64_t code;
};
/* A Stream Endpoint Descriptor (sedesc) is the link between the stream
* connector (ex. stconn) and the Stream Endpoint (mux or appctx).
* It always exists for either of them, and binds them together. It also
* contains some shared information relative to the endpoint. It is created by
* the first one which needs it and is shared by the other one, i.e. on the
* client side, it's created the mux or applet and shared with the connector.
* An sedesc without stconn is called an ORPHANED descriptor. An sedesc with
* no mux/applet is called a DETACHED descriptor. Upon detach, the connector
* transfers the whole responsibility of the endpoint descriptor to the
* endpoint itself (mux/applet) and eventually creates a new sedesc (for
* instance on connection retries).
*
* <lra> should be updated when a read activity at the endpoint level is
* detected. It can be a successful receive or when a EOS/EOI is reported.
* A read activity is also reported when receives are unblocked.
* <fsb> should be updated when the first send of a series is blocked and reset
* when a successful send is reported.
*
*
* NOTE: <lra> and <fsb> must only be used via the SC api to compute read/write
* expiration date.
*
*/
struct sedesc {
void *se; /* the stream endpoint, i.e. the mux stream or the appctx */
struct connection *conn; /* the connection for connection-based streams */
struct stconn *sc; /* the stream connector we're attached to, or NULL */
struct iobuf iobuf; /* contains data forwarded by the other side and that must be sent by the stream endpoint */
unsigned int flags; /* SE_FL_* */
struct se_abort_info abort_info; /* Info about abort, as reported by the endpoint and eventually enriched by the app level */
unsigned int lra; /* the last read activity */
unsigned int fsb; /* the first send blocked */
/* 4 bytes hole here */
struct xref xref; /* cross reference with the opposite SC */
};
/* sc_app_ops describes the application layer's operations and notification
* callbacks when I/O activity is reported and to use to perform shutr/shutw.
* There are very few combinations in practice (strm/chk <-> none/mux/applet).
*/
struct sc_app_ops {
void (*chk_rcv)(struct stconn *); /* chk_rcv function, may not be null */
void (*chk_snd)(struct stconn *); /* chk_snd function, may not be null */
void (*abort)(struct stconn *); /* abort function, may not be null */
void (*shutdown)(struct stconn *); /* shutdown function, may not be null */
int (*wake)(struct stconn *); /* data-layer callback to report activity */
char name[8]; /* data layer name, zero-terminated */
};
/*
* This structure describes the elements of a connection relevant to a stream
*/
struct stconn {
enum obj_type obj_type; /* differentiates connection from applet context */
enum sc_state state; /* SC_ST* */
/* 2 bytes hole here */
unsigned int flags; /* SC_FL_* */
unsigned int ioto; /* I/O activity timeout */
ssize_t room_needed; /* free space in the input buffer required to receive more data.
* -1 : the SC is waiting for room but not on a specific amount of data
* >= 0 : min free space required to progress. 0 means SC must be unblocked ASAP
*/
struct wait_event wait_event; /* We're in a wait list */
struct sedesc *sedesc; /* points to the stream endpoint descriptor */
enum obj_type *app; /* points to the applicative point (stream or check) */
const struct sc_app_ops *app_ops; /* general operations used at the app layer */
struct sockaddr_storage *src; /* source address (pool), when known, otherwise NULL */
struct sockaddr_storage *dst; /* destination address (pool), when known, otherwise NULL */
};
#endif /* _HAPROXY_STCONN_T_H */