aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/netif/stream.h
blob: 3c4ec7ee2d56fdcaa42b061c49a5237a65b4c6db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#pragma once

#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>

#include <osmocom/core/msgb.h>

/*! \file stream.h */

/*! \brief Access SCTP flags from the msgb control buffer */
#define OSMO_STREAM_SCTP_MSG_FLAGS_NOTIFICATION 0x80 /* sctp_recvmsg() flags=MSG_NOTIFICATION, msgb_data() contains "union sctp_notification*" */
#define msgb_sctp_msg_flags(msg)	(msg)->cb[2]

/*! \brief Access the SCTP PPID from the msgb control buffer */
#define msgb_sctp_ppid(msg)             (msg)->cb[3]
/*! \brief Access the SCTP Stream ID from the msgb control buffer */
#define msgb_sctp_stream(msg)           (msg)->cb[4]

/*! \defgroup stream_srv Osmocom Stream Server
 *  @{
 *
 *  This code is intended to abstract any server-side use of stream-type sockets, such as TCP and SCTP.
 *
 *  The Osmocom stream socket helper is an abstraction layer for connected SOCK_STREAM/SOCK_SEQPACKET sockets.
 *  It encapsulates common functionality like binding, accepting client connections, etc.
 *
 *  osmo_stream_srv can operate in two different modes:
 *  1. The legacy mode using osmo_fd (from libosmocore)
 *  2. The modern (2023) mode using osmo_io (from libosmocore)
 *
 *  For any new applications, you definitely should use the modern mode, as it provides you with a higher
 *  layer of abstraction and allows you to perform efficient I/O using the io_uring backend of osmo_io.
 *
 *  The two main objects are osmo_stream_srv_link (main server accept()ing incoming connections) and
 *  osmo_stream_srv (a single given connection from a remote client).
 *
 *  A typical stream_srv usage would look like this:
 *
 *  * create new osmo_stream_srv_link using osmo_stream_srv_link_create()
 *  * call osmo_stream_srv_link_set_addr() to set local bind address/port
 *  * call osmo_stream_srv_link_set_accept_cb() to register the accept call-back
 *  * optionally call further osmo_stream_srv_link_set_*() functions
 *  * call osmo_stream_srv_link_open() to create socket and start listening
 *
 *  Whenever a client connects to your listening socket, the connection will now be automatically accept()ed
 *  and the registered accept_cb call-back called.  From within that accept_cb, you then
 *  * call osmo_stream_srv_create() to create a osmo_stream_srv for that specific connection
 *  * call osmo_stream_srv_set_read_cb() to register the read call-back for incoming data
 *  * call osmo_stream_srv_set_closed_cb() to register the closed call-back
 *  * call osmo_stream_srv_set_data() to associate opaque application-layer state
 *
 *  Whenever data from a client arrives on a connection, your registered read_cb will be called together
 *  with a message buffer containing the received data. Ownership of the message buffer is transferred
 *  into the call-back, i.e. in your application.  It's your responsibility to eventually msgb_free()
 *  it after usage.
 *
 *  Whenever your application wants to transmit something to a given connection, it uses the
 *  osmo_stream_srv_send() function.
 */

/*! \brief Osmocom Stream Server Link: A server socket listening/accepting */
struct osmo_stream_srv_link;

typedef int (*osmo_stream_srv_link_accept_cb_t)(struct osmo_stream_srv_link *link, int fd);

struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx);
void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link);

void osmo_stream_srv_link_set_name(struct osmo_stream_srv_link *link, const char *name);
const char *osmo_stream_srv_link_get_name(const struct osmo_stream_srv_link *link);
void osmo_stream_srv_link_set_nodelay(struct osmo_stream_srv_link *link, bool nodelay);
void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link, const char *addr);
int osmo_stream_srv_link_set_addrs(struct osmo_stream_srv_link *link, const char **addr, size_t addrcnt);
void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link, uint16_t port);
void osmo_stream_srv_link_set_proto(struct osmo_stream_srv_link *link, uint16_t proto);
int osmo_stream_srv_link_set_type(struct osmo_stream_srv_link *link, int type);
int osmo_stream_srv_link_set_domain(struct osmo_stream_srv_link *link, int domain);
void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link, osmo_stream_srv_link_accept_cb_t accept_cb);
void osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link, void *data);
void *osmo_stream_srv_link_get_data(struct osmo_stream_srv_link *link);
char *osmo_stream_srv_link_get_sockname(const struct osmo_stream_srv_link *link);
struct osmo_fd *osmo_stream_srv_link_get_ofd(struct osmo_stream_srv_link *link);
int osmo_stream_srv_link_get_fd(const struct osmo_stream_srv_link *link);
bool osmo_stream_srv_link_is_opened(const struct osmo_stream_srv_link *link);
int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link);
void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link);

enum osmo_stream_srv_link_param {
	OSMO_STREAM_SRV_LINK_PAR_SCTP_SOCKOPT_AUTH_SUPPORTED, /* uint8_t: 0 disable, 1 enable, 2 force disable, 3 force enable */
	OSMO_STREAM_SRV_LINK_PAR_SCTP_SOCKOPT_ASCONF_SUPPORTED, /* uint8_t: 0 disable, 1 enable, 2 force disable, 3 force enable */
	OSMO_STREAM_SRV_LINK_PAR_SCTP_INIT_NUM_OSTREAMS, /* uint16_t: amount of streams */
	OSMO_STREAM_SRV_LINK_PAR_SCTP_INIT_MAX_INSTREAMS, /* uint16_t: amount of streams */
};

int osmo_stream_srv_link_set_param(struct osmo_stream_srv_link *link, enum osmo_stream_srv_link_param par,
				   void *val, size_t val_len);

/*! \brief Osmocom Stream Server: Single connection accept()ed via \ref
 * osmo_stream_srv_link */
struct osmo_stream_srv;

typedef int (*osmo_stream_srv_read_cb_t)(struct osmo_stream_srv *conn);
typedef int (*osmo_stream_srv_closed_cb_t)(struct osmo_stream_srv *conn);

/*! Completion call-back function when something was read from from the stream client socket.
 * \param[in] conn Stream Server that got receive event.
 * \param[in] res return value of the read()/recvmsg()/... call, or -errno in case of error.
 * \param[in] msg message buffer containing the read data. Ownership is transferred to the
 * call-back, and it must make sure to msgb_free() it eventually! */
typedef int (*osmo_stream_srv_read_cb2_t)(struct osmo_stream_srv *conn, int res, struct msgb *msg);

typedef int (*osmo_stream_srv_segmentation_cb_t)(struct msgb *msg);

struct osmo_stream_srv *osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link, int fd,
					       osmo_stream_srv_read_cb_t read_cb,
					       osmo_stream_srv_closed_cb_t closed_cb,
					       void *data);
struct osmo_stream_srv *osmo_stream_srv_create2(void *ctx, struct osmo_stream_srv_link *link, int fd, void *data);
void osmo_stream_srv_set_name(struct osmo_stream_srv *conn, const char *name);
const char *osmo_stream_srv_get_name(const struct osmo_stream_srv *conn);
void osmo_stream_srv_set_read_cb(struct osmo_stream_srv *conn, osmo_stream_srv_read_cb2_t read_cb);
void osmo_stream_srv_set_closed_cb(struct osmo_stream_srv *conn, osmo_stream_srv_closed_cb_t close_cb);
void *osmo_stream_srv_get_data(struct osmo_stream_srv *conn);
struct osmo_stream_srv_link *osmo_stream_srv_get_master(struct osmo_stream_srv *conn);
const char *osmo_stream_srv_get_sockname(const struct osmo_stream_srv *conn);
struct osmo_fd *osmo_stream_srv_get_ofd(struct osmo_stream_srv *srv);
int osmo_stream_srv_get_fd(const struct osmo_stream_srv *srv);
struct osmo_io_fd *osmo_stream_srv_get_iofd(const struct osmo_stream_srv *srv);
void osmo_stream_srv_destroy(struct osmo_stream_srv *conn);

void osmo_stream_srv_set_flush_and_destroy(struct osmo_stream_srv *conn);
void osmo_stream_srv_set_data(struct osmo_stream_srv *conn, void *data);

void osmo_stream_srv_set_segmentation_cb(struct osmo_stream_srv *conn, osmo_stream_srv_segmentation_cb_t segmentation_cb);

void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg);
int osmo_stream_srv_recv(struct osmo_stream_srv *conn, struct msgb *msg);

void osmo_stream_srv_clear_tx_queue(struct osmo_stream_srv *conn);

/*! @} */

/*! \defgroup stream_cli Osmocom Stream Client
 *  @{
 *
 *  This code is intended to abstract any client use of stream-type sockets, such as TCP and SCTP
 *
 *  An osmo_stream_cli represents a client implementation of a SOCK_STREAM or SOCK_SEQPACKET socket. It
 *  contains all the common logic like non-blocking outbound connect to a remote server, re-connecting after
 *  disconnect or connect failure, etc.
 *
 *  osmo_stream_cli can operate in two different modes:
 *  1. The legacy mode using osmo_fd (from libosmocore)
 *  2. The modern (2023) mode using osmo_io_fd (from libosmocore)
 *
 *  For any new applications, you definitely should use the modern mode, as it provides you with a higher
 *  layer of abstraction and allows you to perform efficient I/O using the io_uring backend of osmo_io.
 *
 *  A typical usage of osmo_stream_cli would look as follows:
 *
 *  * call osmo_stream_cli_create() to create a new osmo_stream_cli
 *  * call osmo_stream_cli_set_addr() / osmo_stream_cli_set_port() to specify the remote address/port to connect to
 *  * optionally call further functions of the osmo_stream_cli_set_*() family
 *  * call osmo_stream_cli_set_connect_cb() to register the call-back called on completion of outbound connect()
 *  * call osmo_stream_cli_set_read_cb2() to register the call-back called when incoming data has been read
 *  * call osmo_stream_cli_open() to open the connection (start outbound connect process)
 *
 *  Once the connection is established, your connect_cb is called to notify you.
 *
 *  You may send data to the connection using osmo_tream_cli_send().
 *
 *  Any received inbound data on the connection is reported vie the read_cb.
 */

/*! \brief Osmocom Stream Client: Single client connection */
struct osmo_stream_cli;

typedef int (*osmo_stream_cli_connect_cb_t)(struct osmo_stream_cli *cli);
typedef int (*osmo_stream_cli_disconnect_cb_t)(struct osmo_stream_cli *cli);
typedef int (*osmo_stream_cli_read_cb_t)(struct osmo_stream_cli *cli);

/*! Completion call-back function when something was read from from the stream client socket.
 * \param[in] cli Stream Client that got receive event.
 * \param[in] res return value of the read()/recvmsg()/... call, or -errno in case of error.
 * \param[in] msg message buffer containing the read data. Ownership is transferred to the
 * call-back, and it must make sure to msgb_free() it eventually! */
typedef int (*osmo_stream_cli_read_cb2_t)(struct osmo_stream_cli *cli, int res, struct msgb *msg);

typedef int (*osmo_stream_cli_segmentation_cb_t)(struct msgb *msg);

void osmo_stream_cli_set_name(struct osmo_stream_cli *cli, const char *name);
const char *osmo_stream_cli_get_name(const struct osmo_stream_cli *cli);
void osmo_stream_cli_set_nodelay(struct osmo_stream_cli *cli, bool nodelay);
void osmo_stream_cli_set_addr(struct osmo_stream_cli *cli, const char *addr);
int osmo_stream_cli_set_addrs(struct osmo_stream_cli *cli, const char **addr, size_t addrcnt);
void osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port);
int osmo_stream_cli_set_type(struct osmo_stream_cli *cli, int type);
int osmo_stream_cli_set_domain(struct osmo_stream_cli *cli, int domain);
void osmo_stream_cli_set_proto(struct osmo_stream_cli *cli, uint16_t proto);
void osmo_stream_cli_set_local_addr(struct osmo_stream_cli *cli, const char *addr);
int osmo_stream_cli_set_local_addrs(struct osmo_stream_cli *cli, const char **addr, size_t addrcnt);
void osmo_stream_cli_set_local_port(struct osmo_stream_cli *cli, uint16_t port);
void osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data);
void osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout);
void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli);
char *osmo_stream_cli_get_sockname(const struct osmo_stream_cli *cli);
struct osmo_fd *osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli);
int osmo_stream_cli_get_fd(const struct osmo_stream_cli *cli);
struct osmo_io_fd *osmo_stream_cli_get_iofd(const struct osmo_stream_cli *cli);
void osmo_stream_cli_set_connect_cb(struct osmo_stream_cli *cli, osmo_stream_cli_connect_cb_t connect_cb);
void osmo_stream_cli_set_disconnect_cb(struct osmo_stream_cli *cli, osmo_stream_cli_disconnect_cb_t disconnect_cb);
void osmo_stream_cli_set_read_cb(struct osmo_stream_cli *cli, osmo_stream_cli_read_cb_t read_cb);
void osmo_stream_cli_set_read_cb2(struct osmo_stream_cli *cli, osmo_stream_cli_read_cb2_t read_cb);
void osmo_stream_cli_set_segmentation_cb(struct osmo_stream_cli *cli, osmo_stream_cli_segmentation_cb_t segmentation_cb);
void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli);
bool osmo_stream_cli_is_connected(struct osmo_stream_cli *cli);

struct osmo_stream_cli *osmo_stream_cli_create(void *ctx);
void osmo_stream_cli_destroy(struct osmo_stream_cli *cli);

int osmo_stream_cli_open(struct osmo_stream_cli *cli);
int osmo_stream_cli_open2(struct osmo_stream_cli *cli, int reconnect) \
	OSMO_DEPRECATED("Use osmo_stream_cli_set_reconnect_timeout() or osmo_stream_cli_reconnect() instead");
void osmo_stream_cli_close(struct osmo_stream_cli *cli);

void osmo_stream_cli_send(struct osmo_stream_cli *cli, struct msgb *msg);
int osmo_stream_cli_recv(struct osmo_stream_cli *cli, struct msgb *msg);

void osmo_stream_cli_clear_tx_queue(struct osmo_stream_cli *cli);

enum osmo_stream_cli_param {
	OSMO_STREAM_CLI_PAR_SCTP_SOCKOPT_AUTH_SUPPORTED, /* uint8_t: 0 disable, 1 enable, 2 force disable, 3 force enable */
	OSMO_STREAM_CLI_PAR_SCTP_SOCKOPT_ASCONF_SUPPORTED, /* uint8_t: 0 disable, 1 enable, 2 force disable, 3 force enable */
	OSMO_STREAM_CLI_PAR_SCTP_INIT_NUM_OSTREAMS, /* uint16_t: amount of streams */
	OSMO_STREAM_CLI_PAR_SCTP_INIT_MAX_INSTREAMS, /* uint16_t: amount of streams */
	OSMO_STREAM_CLI_PAR_SCTP_INIT_MAX_ATTEMPTS, /* uint16_t: amount of attempts */
	OSMO_STREAM_CLI_PAR_SCTP_INIT_TIMEOUT, /* uint16_t: milliseconds */
};

int osmo_stream_cli_set_param(struct osmo_stream_cli *cli, enum osmo_stream_cli_param par,
			      void *val, size_t val_len);

/*! @} */