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 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
|
#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 modern mode is chosen by invoking osmo_stream_srv_create2().
* The legacy mode is chosen by invoking the older osmo_stream_srv_create().
*
* 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);
int osmo_stream_srv_link_set_priority(struct osmo_stream_srv_link *link, int sk_prio);
int osmo_stream_srv_link_set_ip_dscp(struct osmo_stream_srv_link *link, uint8_t ip_dscp);
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);
int osmo_stream_srv_link_set_tx_queue_max_length(struct osmo_stream_srv_link *link, unsigned int size);
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);
int osmo_stream_srv_link_set_msgb_alloc_info(struct osmo_stream_srv_link *link, unsigned int size, unsigned int headroom);
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);
typedef int (*osmo_stream_srv_segmentation_cb2_t)(struct osmo_stream_srv *conn, 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_set_segmentation_cb2(struct osmo_stream_srv *conn, osmo_stream_srv_segmentation_cb2_t segmentation_cb2);
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.
*
* The modern mode is chosen by invoking osmo_stream_cli_set_read_cb2().
* The legacy mode is chosen by invoking the older osmo_stream_cli_set_read_cb().
*
* 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);
typedef int (*osmo_stream_cli_segmentation_cb2_t)(struct osmo_stream_cli *cli, 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);
int osmo_stream_cli_set_priority(struct osmo_stream_cli *cli, int sk_prio);
int osmo_stream_cli_set_ip_dscp(struct osmo_stream_cli *cli, uint8_t ip_dscp);
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);
int osmo_stream_cli_set_tx_queue_max_length(struct osmo_stream_cli *cli, unsigned int size);
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_set_segmentation_cb2(struct osmo_stream_cli *cli, osmo_stream_cli_segmentation_cb2_t segmentation_cb2);
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);
/*! @} */
|