blob: 48a676f8be33e4b5f57c2a7a1e088725977a482e [file] [log] [blame]
Willy Tarreau53a47662017-08-28 10:53:00 +02001/*
2 * Pass-through mux-demux for connections
3 *
4 * Copyright 2017 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <common/config.h>
14#include <proto/connection.h>
15#include <proto/stream.h>
16
17/* Initialize the mux once it's attached. If conn->mux_ctx is NULL, it is
18 * assumed that no data layer has yet been instanciated so the mux is
19 * attached to an incoming connection and will instanciate a new stream. If
20 * conn->mux_ctx exists, it is assumed that it is an outgoing connection
21 * requested for this context. Returns < 0 on error.
22 */
23static int mux_pt_init(struct connection *conn)
24{
25 if (!conn->mux_ctx)
26 return stream_create_from_conn(conn);
27 return 0;
28}
29
30/* callback to be used by default for the pass-through mux. It calls the data
31 * layer wake() callback if it is set otherwise returns 0.
32 */
33static int mux_pt_wake(struct connection *conn)
34{
35 return conn->data->wake ? conn->data->wake(conn) : 0;
36}
37
Olivier Houchard7a3f0df2017-09-13 18:30:23 +020038/* callback used to update the mux's polling flags after changing a cs' status.
39 * The caller (cs_mux_update_poll) will take care of propagating any changes to
40 * the transport layer.
41 */
42static void mux_pt_update_poll(struct conn_stream *cs)
43{
44 struct connection *conn = cs->conn;
45 int flags = 0;
46
47 conn_refresh_polling_flags(conn);
48
49 if (cs->flags & CS_FL_DATA_RD_ENA)
50 flags |= CO_FL_XPRT_RD_ENA;
51 if (cs->flags & CS_FL_DATA_WR_ENA)
52 flags |= CO_FL_XPRT_WR_ENA;
53
54 conn->flags = (conn->flags & ~(CO_FL_XPRT_RD_ENA | CO_FL_XPRT_WR_ENA)) | flags;
55 conn_cond_update_xprt_polling(conn);
56}
57
Willy Tarreau53a47662017-08-28 10:53:00 +020058/* callback to be used by default for the pass-through mux. It simply calls the
59 * data layer recv() callback much must be set.
60 */
61static void mux_pt_recv(struct connection *conn)
62{
63 conn->data->recv(conn);
64}
65
66/* callback to be used by default for the pass-through mux. It simply calls the
67 * data layer send() callback which must be set.
68 */
69static void mux_pt_send(struct connection *conn)
70{
71 conn->data->send(conn);
72}
73
Olivier Houchard7a3f0df2017-09-13 18:30:23 +020074/*
75 * Attach a new stream to a connection
76 * (Used for outgoing connections)
77 */
78static struct conn_stream *mux_pt_attach(struct connection *conn)
79{
80 return NULL;
81}
82
83/*
84 * Detach the stream from the connection
85 * (Used for outgoing connections)
86 */
87static void mux_pt_detach(struct conn_stream *cs)
88{
89}
90
91static void mux_pt_shutr(struct conn_stream *cs, int clean)
92{
93 if (conn_xprt_ready(cs->conn) && cs->conn->xprt->shutr)
94 cs->conn->xprt->shutr(cs->conn, clean);
95}
96
97static void mux_pt_shutw(struct conn_stream *cs, int clean)
98{
99 if (conn_xprt_ready(cs->conn) && cs->conn->xprt->shutw)
100 cs->conn->xprt->shutw(cs->conn, clean);
101}
102
103/*
104 * Called from the upper layer, to get more data
105 */
106static int mux_pt_rcv_buf(struct conn_stream *cs, struct buffer *buf, int count)
107{
108 int ret;
109
110 ret = cs->conn->xprt->rcv_buf(cs->conn, buf, count);
111 if (conn_xprt_read0_pending(cs->conn))
112 cs->flags |= CS_FL_EOS;
113 return (ret);
114}
115
116/* Called from the upper layer, to send data */
117static int mux_pt_snd_buf(struct conn_stream *cs, struct buffer *buf, int flags)
118{
119 return (cs->conn->xprt->snd_buf(cs->conn, buf, flags));
120}
121
122/* Send and get, using splicing */
123static int mux_pt_rcv_pipe(struct conn_stream *cs, struct pipe *pipe, unsigned int count)
124{
125 int ret;
126
127 ret = cs->conn->xprt->rcv_pipe(cs->conn, pipe, count);
128 if (conn_xprt_read0_pending(cs->conn))
129 cs->flags |= CS_FL_EOS;
130 return (ret);
131}
132
133static int mux_pt_snd_pipe(struct conn_stream *cs, struct pipe *pipe)
134{
135 return (cs->conn->xprt->snd_pipe(cs->conn, pipe));
136}
137
Willy Tarreau53a47662017-08-28 10:53:00 +0200138/* The mux operations */
139const struct mux_ops mux_pt_ops = {
140 .init = mux_pt_init,
141 .recv = mux_pt_recv,
142 .send = mux_pt_send,
143 .wake = mux_pt_wake,
Olivier Houchard7a3f0df2017-09-13 18:30:23 +0200144 .update_poll = mux_pt_update_poll,
145 .rcv_buf = mux_pt_rcv_buf,
146 .snd_buf = mux_pt_snd_buf,
147#if defined(CONFIG_HAP_LINUX_SPLICE)
148 .rcv_pipe = mux_pt_rcv_pipe,
149 .snd_pipe = mux_pt_snd_pipe,
150#endif
151 .attach = mux_pt_attach,
152 .detach = mux_pt_detach,
153 .shutr = mux_pt_shutr,
154 .shutw = mux_pt_shutw,
Willy Tarreau53a47662017-08-28 10:53:00 +0200155 .name = "PASS",
156};
Willy Tarreauf6490822017-09-21 19:43:21 +0200157
158/* ALPN selection : default mux has empty name */
159static struct alpn_mux_list alpn_mux_pt =
160 { .token = IST(""), .mode = ALPN_MODE_ANY, .mux = &mux_pt_ops };
161
162__attribute__((constructor))
163static void __mux_pt_init(void)
164{
165 alpn_register_mux(&alpn_mux_pt);
166}