haproxy/include/proto/stream_interface.h
Willy Tarreau 87b09668be REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.

In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.

The files stream.{c,h} were added and session.{c,h} removed.

The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.

Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.

Once all changes are completed, we should see approximately this :

   L7 - http_txn
   L6 - stream
   L5 - session
   L4 - connection | applet

There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.

Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-06 11:23:56 +02:00

433 lines
12 KiB
C

/*
* include/proto/stream_interface.h
* This file contains stream_interface function prototypes
*
* Copyright (C) 2000-2014 Willy Tarreau - w@1wt.eu
*
* 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 _PROTO_STREAM_INTERFACE_H
#define _PROTO_STREAM_INTERFACE_H
#include <stdlib.h>
#include <common/config.h>
#include <types/stream.h>
#include <types/stream_interface.h>
#include <proto/channel.h>
#include <proto/connection.h>
/* main event functions used to move data between sockets and buffers */
int stream_int_check_timeouts(struct stream_interface *si);
void stream_int_report_error(struct stream_interface *si);
void stream_int_retnclose(struct stream_interface *si, const struct chunk *msg);
int conn_si_send_proxy(struct connection *conn, unsigned int flag);
void stream_sock_read0(struct stream_interface *si);
extern struct si_ops si_embedded_ops;
extern struct si_ops si_conn_ops;
extern struct data_cb si_conn_cb;
extern struct data_cb si_idle_conn_cb;
struct appctx *stream_int_register_handler(struct stream_interface *si, struct si_applet *app);
void stream_int_unregister_handler(struct stream_interface *si);
/* returns the channel which receives data from this stream interface (input channel) */
static inline struct channel *si_ic(struct stream_interface *si)
{
if (si->flags & SI_FL_ISBACK)
return &LIST_ELEM(si, struct stream *, si[1])->res;
else
return &LIST_ELEM(si, struct stream *, si[0])->req;
}
/* returns the channel which feeds data to this stream interface (output channel) */
static inline struct channel *si_oc(struct stream_interface *si)
{
if (si->flags & SI_FL_ISBACK)
return &LIST_ELEM(si, struct stream *, si[1])->req;
else
return &LIST_ELEM(si, struct stream *, si[0])->res;
}
/* returns the buffer which receives data from this stream interface (input channel's buffer) */
static inline struct buffer *si_ib(struct stream_interface *si)
{
return si_ic(si)->buf;
}
/* returns the buffer which feeds data to this stream interface (output channel's buffer) */
static inline struct buffer *si_ob(struct stream_interface *si)
{
return si_oc(si)->buf;
}
/* returns the stream associated to a stream interface */
static inline struct stream *si_strm(struct stream_interface *si)
{
if (si->flags & SI_FL_ISBACK)
return LIST_ELEM(si, struct stream *, si[1]);
else
return LIST_ELEM(si, struct stream *, si[0]);
}
/* returns the task associated to this stream interface */
static inline struct task *si_task(struct stream_interface *si)
{
if (si->flags & SI_FL_ISBACK)
return LIST_ELEM(si, struct stream *, si[1])->task;
else
return LIST_ELEM(si, struct stream *, si[0])->task;
}
/* returns the stream interface on the other side. Used during forwarding. */
static inline struct stream_interface *si_opposite(struct stream_interface *si)
{
if (si->flags & SI_FL_ISBACK)
return &LIST_ELEM(si, struct stream *, si[1])->si[0];
else
return &LIST_ELEM(si, struct stream *, si[0])->si[1];
}
/* Initializes all required fields for a new appctx. Note that it does the
* minimum acceptable initialization for an appctx. This means only the
* 3 integer states st0, st1, st2 are zeroed.
*/
static inline void appctx_init(struct appctx *appctx)
{
appctx->st0 = appctx->st1 = appctx->st2 = 0;
}
/* sets <appctx>'s applet to point to <applet> */
static inline void appctx_set_applet(struct appctx *appctx, struct si_applet *applet)
{
appctx->applet = applet;
}
/* Tries to allocate a new appctx and initialize its main fields. The
* appctx is returned on success, NULL on failure. The appctx must be
* released using pool_free2(connection) or appctx_free(), since it's
* allocated from the connection pool.
*/
static inline struct appctx *appctx_new()
{
struct appctx *appctx;
appctx = pool_alloc2(pool2_connection);
if (likely(appctx != NULL)) {
appctx->obj_type = OBJ_TYPE_APPCTX;
appctx->applet = NULL;
appctx_init(appctx);
}
return appctx;
}
/* Releases an appctx previously allocated by appctx_new(). Note that
* we share the connection pool.
*/
static inline void appctx_free(struct appctx *appctx)
{
pool_free2(pool2_connection, appctx);
}
/* initializes a stream interface in the SI_ST_INI state. It's detached from
* any endpoint and only keeps its side which is expected to have already been
* set.
*/
static inline void si_reset(struct stream_interface *si)
{
si->err_type = SI_ET_NONE;
si->conn_retries = 0; /* used for logging too */
si->exp = TICK_ETERNITY;
si->flags &= SI_FL_ISBACK;
si->end = NULL;
si->state = si->prev_state = SI_ST_INI;
}
/* sets the current and previous state of a stream interface to <state>. This
* is mainly used to create one in the established state on incoming
* conncetions.
*/
static inline void si_set_state(struct stream_interface *si, int state)
{
si->state = si->prev_state = state;
}
/* Release the endpoint if it's a connection or an applet, then nullify it.
* Note: released connections are closed then freed.
*/
static inline void si_release_endpoint(struct stream_interface *si)
{
struct connection *conn;
struct appctx *appctx;
if (!si->end)
return;
if ((conn = objt_conn(si->end))) {
conn_force_close(conn);
conn_free(conn);
}
else if ((appctx = objt_appctx(si->end))) {
if (appctx->applet->release)
appctx->applet->release(si);
appctx_free(appctx); /* we share the connection pool */
}
si->end = NULL;
}
static inline void si_detach(struct stream_interface *si)
{
si_release_endpoint(si);
si->ops = &si_embedded_ops;
}
/* Turn a possibly existing connection endpoint of stream interface <si> to
* idle mode, which means that the connection will be polled for incoming events
* and might be killed by the underlying I/O handler.
*/
static inline void si_idle_conn(struct stream_interface *si)
{
struct connection *conn = objt_conn(si->end);
if (!conn)
return;
conn_attach(conn, si, &si_idle_conn_cb);
conn_data_want_recv(conn);
}
/* Attach connection <conn> to the stream interface <si>. The stream interface
* is configured to work with a connection and the connection it configured
* with a stream interface data layer.
*/
static inline void si_attach_conn(struct stream_interface *si, struct connection *conn)
{
si->ops = &si_conn_ops;
si->end = &conn->obj_type;
conn_attach(conn, si, &si_conn_cb);
}
/* Returns true if a connection is attached to the stream interface <si> and
* if this connection is ready.
*/
static inline int si_conn_ready(struct stream_interface *si)
{
struct connection *conn = objt_conn(si->end);
return conn && conn_ctrl_ready(conn) && conn_xprt_ready(conn);
}
/* Attach appctx <appctx> to the stream interface <si>. The stream interface
* is configured to work with an applet context. It is left to the caller to
* call appctx_set_applet() to assign an applet to this context.
*/
static inline void si_attach_appctx(struct stream_interface *si, struct appctx *appctx)
{
si->ops = &si_embedded_ops;
appctx->obj_type = OBJ_TYPE_APPCTX;
si->end = &appctx->obj_type;
}
/* returns a pointer to the appctx being run in the SI or NULL if none */
static inline struct appctx *si_appctx(struct stream_interface *si)
{
return objt_appctx(si->end);
}
/* returns a pointer to the applet being run in the SI or NULL if none */
static inline const struct si_applet *si_applet(struct stream_interface *si)
{
const struct appctx *appctx;
appctx = si_appctx(si);
if (appctx)
return appctx->applet;
return NULL;
}
/* Call the applet's main function when an appctx is attached to the stream
* interface. Returns zero if no call was made, or non-zero if a call was made.
*/
static inline int si_applet_call(struct stream_interface *si)
{
const struct si_applet *applet;
applet = si_applet(si);
if (applet) {
applet->fct(si);
return 1;
}
return 0;
}
/* call the applet's release function if any. Needs to be called upon close() */
static inline void si_applet_release(struct stream_interface *si)
{
const struct si_applet *applet;
applet = si_applet(si);
if (applet && applet->release)
applet->release(si);
}
/* Try to allocate a new connection and assign it to the interface. If
* a connection was previously allocated and the <reuse> flag is set,
* it is returned unmodified. Otherwise it is reset.
*/
/* Returns the stream interface's existing connection if one such already
* exists, or tries to allocate and initialize a new one which is then
* assigned to the stream interface.
*/
static inline struct connection *si_alloc_conn(struct stream_interface *si, int reuse)
{
struct connection *conn;
/* If we find a connection, we return it, otherwise it's an applet
* and we start by releasing it.
*/
if (si->end) {
conn = objt_conn(si->end);
if (conn) {
if (!reuse) {
conn_force_close(conn);
conn_init(conn);
}
return conn;
}
/* it was an applet then */
si_release_endpoint(si);
}
conn = conn_new();
if (conn)
si_attach_conn(si, conn);
return conn;
}
/* Release the interface's existing endpoint (connection or appctx) and
* allocate then initialize a new appctx which is assigned to the interface
* and returned. NULL may be returned upon memory shortage. It is left to the
* caller to call appctx_set_applet() to assign an applet to this context.
*/
static inline struct appctx *si_alloc_appctx(struct stream_interface *si)
{
struct appctx *appctx;
si_release_endpoint(si);
appctx = appctx_new();
if (appctx)
si_attach_appctx(si, appctx);
return appctx;
}
/* Sends a shutr to the connection using the data layer */
static inline void si_shutr(struct stream_interface *si)
{
si->ops->shutr(si);
}
/* Sends a shutw to the connection using the data layer */
static inline void si_shutw(struct stream_interface *si)
{
si->ops->shutw(si);
}
/* Calls the data state update on the stream interfaace */
static inline void si_update(struct stream_interface *si)
{
si->ops->update(si);
}
/* Calls chk_rcv on the connection using the data layer */
static inline void si_chk_rcv(struct stream_interface *si)
{
si->ops->chk_rcv(si);
}
/* Calls chk_snd on the connection using the data layer */
static inline void si_chk_snd(struct stream_interface *si)
{
si->ops->chk_snd(si);
}
/* Calls chk_snd on the connection using the ctrl layer */
static inline int si_connect(struct stream_interface *si)
{
struct connection *conn = objt_conn(si->end);
int ret = SN_ERR_NONE;
if (unlikely(!conn || !conn->ctrl || !conn->ctrl->connect))
return SN_ERR_INTERNAL;
if (!conn_ctrl_ready(conn) || !conn_xprt_ready(conn)) {
ret = conn->ctrl->connect(conn, !channel_is_empty(si_oc(si)), 0);
if (ret != SN_ERR_NONE)
return ret;
/* we need to be notified about connection establishment */
conn->flags |= CO_FL_WAKE_DATA;
/* we're in the process of establishing a connection */
si->state = SI_ST_CON;
}
else if (!channel_is_empty(si_oc(si))) {
/* reuse the existing connection, we'll have to send a
* request there.
*/
conn_data_want_send(conn);
/* the connection is established */
si->state = SI_ST_EST;
}
/* needs src ip/port for logging */
if (si->flags & SI_FL_SRC_ADDR)
conn_get_from_addr(conn);
return ret;
}
/* for debugging, reports the stream interface state name */
static inline const char *si_state_str(int state)
{
switch (state) {
case SI_ST_INI: return "INI";
case SI_ST_REQ: return "REQ";
case SI_ST_QUE: return "QUE";
case SI_ST_TAR: return "TAR";
case SI_ST_ASS: return "ASS";
case SI_ST_CON: return "CON";
case SI_ST_CER: return "CER";
case SI_ST_EST: return "EST";
case SI_ST_DIS: return "DIS";
case SI_ST_CLO: return "CLO";
default: return "???";
}
}
#endif /* _PROTO_STREAM_INTERFACE_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/