blob: 8c931ddd54ba34876049d050823e20ada4d5a3f3 [file] [log] [blame]
Harald Welte8857f3b2022-11-18 13:54:44 +01001/*! \file osmo_io.h
2 * io(_uring) abstraction osmo fd compatibility
3 */
4
5#pragma once
6
Harald Welte1047ed72023-11-18 18:51:58 +01007#include <sys/socket.h>
8
Harald Welte8857f3b2022-11-18 13:54:44 +01009#include <osmocom/core/linuxlist.h>
10#include <osmocom/core/logging.h>
11#include <osmocom/core/msgb.h>
12#include <osmocom/core/socket.h>
13#include <osmocom/core/utils.h>
14
Harald Weltee988ec32024-03-14 21:29:28 +010015/*! \defgroup osmo_io Osmocom I/O interface
16 * @{
17 *
18 * osmo_io is the new (2023) interface for performing asynchronous I/O.
19 * osmo_io encapsulates asynchronous, non-blocking I/O to sockets or other file descriptors
20 * with a submission/completion model.
21 *
22 * For writes, the API user submits write requests, and receives
23 * completion call-backs once the write completes.
24 *
25 * For reads, the API user specifies the size (and headroom) for message buffers, and osmo_io
26 * internally allocates msgb's accordingly. Whenever data arrives at the socket/file descriptor,
27 * osmo_io reads the data into such a msgb and hands it to a read-completion call-back provided
28 * by the API user.
29 *
30 * A given socket/file descriptor is represented by struct osmo_io_fd. osmo_io_fd are named,
31 * i.e. the API user can provide a meaningful name describing the purpose (such as protocol/interface or the
32 * name of the remote peer). This allows osmo_io to log any related [error] messages using this name as
33 * context.
34 *
35 * When implementing some SOCK_STREAM / SOCK_SEQPACKET based client/server transports (such as those on top
36 * of TCP or SCTP), you are most likely better off using the osmo_stream_cli / osmo_stream_srv abstractions
37 * provided by libosmo-netif. They in turn can be used in an osmo_io mode, see the respective documentation.
38 *
39 * If you use osmo_io_fd directly, the life-cycle usually will look as follows:
40 *
41 * 1. open some socket and bind and/or connect it
42 * 2. Allocate an osmo_io_fd using osmo_iofd_setup(), configuring the mode and specifying the call-backs
43 * 3. Registering it with osmo_iofd_register(), which enables reading
44 * 4. Handle inbound data via {read,recvfrom,recvmsg} call-backs; write to it using
45 * osmo_iofd_{write,sendto_sendmsg}_msg()
46 * 5. Eventually un-register it using osmo_iofd_unregister(). Afterwards, you can re-cycle the iofd by
47 * calling osmo_iofd_register() with a new file-descriptor, or free it using osmo_iofd_free().
48 *
49 * \file osmo_io.h */
Harald Welte8857f3b2022-11-18 13:54:44 +010050
Harald Weltee988ec32024-03-14 21:29:28 +010051/*! log macro used for logging information related to the osmo_io_fd.
52 * \param[in] iofd osmo_io_fd about which we're logging
53 * \param[in] level log-level (LOGL_DEBUG, LOGL_INFO, LOGL_NOTICE, LOGL_ERROR, LOGL_FATAL)
54 * \param[in] fmt printf-style format string
55 * \param[in] args arguments to the format string
56 */
Harald Welte8857f3b2022-11-18 13:54:44 +010057#define LOGPIO(iofd, level, fmt, args...) \
58 LOGP(DLIO, level, "iofd(%s)" fmt, iofd->name, ## args)
59
60struct osmo_io_fd;
61
Harald Weltee988ec32024-03-14 21:29:28 +010062/*! The _mode_ of an osmo_io_fd determines if read/write, recvfrom/sendmsg or recvmsg/sendmsg semantics are
63 * used. */
Harald Welte8857f3b2022-11-18 13:54:44 +010064enum osmo_io_fd_mode {
Harald Weltee988ec32024-03-14 21:29:28 +010065 /*! use read() / write() semantics with read_cb/write_cb in osmo_io_ops */
Harald Welte8857f3b2022-11-18 13:54:44 +010066 OSMO_IO_FD_MODE_READ_WRITE,
Harald Weltee988ec32024-03-14 21:29:28 +010067 /*! use recvfrom() / sendto() semantics with recvfrom_cb/sendto_cb in osmo_io_ops */
Harald Welte8857f3b2022-11-18 13:54:44 +010068 OSMO_IO_FD_MODE_RECVFROM_SENDTO,
Harald Weltee988ec32024-03-14 21:29:28 +010069 /*! emulate recvmsg() / sendmsg() semantics with recvmsg_cb/sendto_cb in osmo_io_ops */
Harald Welte1047ed72023-11-18 18:51:58 +010070 OSMO_IO_FD_MODE_RECVMSG_SENDMSG,
Harald Welte8857f3b2022-11-18 13:54:44 +010071};
72
Harald Weltee988ec32024-03-14 21:29:28 +010073/*! The back-end used by osmo_io. There can be multiple different back-ends available on a given system;
74 * only one of it is used for all I/O performed via osmo_io in one given process. */
Harald Welte8857f3b2022-11-18 13:54:44 +010075enum osmo_io_backend {
Harald Weltee988ec32024-03-14 21:29:28 +010076 /*! classic back-end using poll(2) and direct read/write/recvfrom/sendto/recvmsg/sendmsg syscalls */
Harald Welte8857f3b2022-11-18 13:54:44 +010077 OSMO_IO_BACKEND_POLL,
Harald Weltee988ec32024-03-14 21:29:28 +010078 /*! back-end using io_uring to perform efficient I/O and reduce syscall overhead */
Daniel Willmannf91d2aa2023-01-04 18:20:55 +010079 OSMO_IO_BACKEND_IO_URING,
Harald Welte8857f3b2022-11-18 13:54:44 +010080};
81
82extern const struct value_string osmo_io_backend_names[];
Harald Weltee988ec32024-03-14 21:29:28 +010083/*! return the string name of an osmo_io_backend */
Harald Welte8857f3b2022-11-18 13:54:44 +010084static inline const char *osmo_io_backend_name(enum osmo_io_backend val)
85{ return get_value_string(osmo_io_backend_names, val); }
86
Harald Welte09ab0412024-03-07 10:11:52 +010087extern const struct value_string osmo_iofd_mode_names[];
Harald Weltee988ec32024-03-14 21:29:28 +010088/*! return the string name of an osmo_io_mode */
Harald Welte09ab0412024-03-07 10:11:52 +010089static inline const char *osmo_iofd_mode_name(enum osmo_io_fd_mode val)
90{ return get_value_string(osmo_iofd_mode_names, val); }
91
Harald Weltee988ec32024-03-14 21:29:28 +010092/*! I/O operations (call-back functions) related to an osmo_io_fd */
Harald Welte8857f3b2022-11-18 13:54:44 +010093struct osmo_io_ops {
Harald Welteb365b1d2024-02-23 16:08:49 +010094 /* mode OSMO_IO_FD_MODE_READ_WRITE: */
95 struct {
Harald Weltee988ec32024-03-14 21:29:28 +010096 /*! completion call-back function when something was read from fd. Only valid in
97 * OSMO_IO_FD_MODE_READ_WRITE.
98 * \param[in] iofd osmo_io_fd for which read() has completed.
99 * \param[in] res return value of the read() call, or -errno in case of error.
100 * \param[in] msg message buffer containing the read data. Ownership is transferred to the
101 * call-back, and it must make sure to msgb_free() it eventually! */
Harald Welteb365b1d2024-02-23 16:08:49 +0100102 void (*read_cb)(struct osmo_io_fd *iofd, int res, struct msgb *msg);
Harald Weltee988ec32024-03-14 21:29:28 +0100103 /*! completion call-back function when write issued via osmo_iofd_write_msgb() has completed
104 * on fd. Only valid in OSMO_IO_FD_MODE_READ_WRITE.
105 * \param[in] iofd on which a write() has completed.
106 * \param[in] res return value of the write() call, or -errno in case of error.
107 * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the
108 * call-back; it is automatically freed after the call-back terminates! */
Harald Welteb365b1d2024-02-23 16:08:49 +0100109 void (*write_cb)(struct osmo_io_fd *iofd, int res,
110 struct msgb *msg);
Harald Weltee988ec32024-03-14 21:29:28 +0100111 /*! optional call-back function to segment the data at message boundaries. This is useful when
112 * message boundaries are to be preserved over a SOCK_STREAM transport socket like TCP. Can
113 * be NULL for any application not requiring de-segmentation of received data.
114 *
115 * The call-back needs to return the size of the next message. If it returns
Harald Welteb365b1d2024-02-23 16:08:49 +0100116 * -EAGAIN or a value larger than msgb_length() (message is incomplete)
117 * osmo_io will wait for more data to be read. Other negative values
118 * cause the msg to be discarded.
119 * If a full message was received (segmentation_cb() returns a value <= msgb_length())
120 * the msgb will be trimmed to size by osmo_io and forwarded to the read call-back. Any
121 * parsing done to the msgb by segmentation_cb() will be preserved for the read_cb()
122 * (e.g. setting lxh or msgb->cb). */
123 int (*segmentation_cb)(struct msgb *msg);
124 };
Harald Welte8857f3b2022-11-18 13:54:44 +0100125
Harald Welteb365b1d2024-02-23 16:08:49 +0100126 /* mode OSMO_IO_FD_MODE_RECVFROM_SENDTO: */
127 struct {
Harald Weltee988ec32024-03-14 21:29:28 +0100128 /*! completion call-back function when recvfrom(2) has completed.
129 * Only valid in OSMO_IO_FD_MODE_RECVFROM_SENDTO.
130 * \param[in] iofd osmo_io_fd for which recvfrom() has completed.
131 * \param[in] res return value of the recvfrom() call, or -errno in case of error.
132 * \param[in] msg message buffer containing the read data. Ownership is transferred to the
133 * call-back, and it must make sure to msgb_free() it eventually!
134 * \param[in] saddr socket-address of sender from which data was received. */
Harald Welteb365b1d2024-02-23 16:08:49 +0100135 void (*recvfrom_cb)(struct osmo_io_fd *iofd, int res,
136 struct msgb *msg,
137 const struct osmo_sockaddr *saddr);
Harald Weltee988ec32024-03-14 21:29:28 +0100138 /*! completion call-back function when sendto() issued via osmo_iofd_sendto_msgb() has
139 * completed on fd. Only valid in OSMO_IO_FD_MODE_RECVFROM_SENDTO.
140 * \param[in] iofd on which a sendto() has completed.
141 * \param[in] res return value of the sendto() call, or -errno in case of error.
142 * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the
143 * call-back; it is automatically freed after the call-back terminates!
144 * \param[in] daddr socket-address of destination to which data was sent. */
Harald Welteb365b1d2024-02-23 16:08:49 +0100145 void (*sendto_cb)(struct osmo_io_fd *iofd, int res,
146 struct msgb *msg,
147 const struct osmo_sockaddr *daddr);
Harald Welte8857f3b2022-11-18 13:54:44 +0100148 };
Harald Welte1047ed72023-11-18 18:51:58 +0100149
150 /* mode OSMO_IO_FD_MODE_RECVMSG_SENDMSG: */
151 struct {
Harald Weltee988ec32024-03-14 21:29:28 +0100152 /*! completion call-back function when recvmsg(2) has completed.
153 * Only valid in OSMO_IO_FD_MODE_RECVMSG_SENDMSG.
154 * \param[in] iofd osmo_io_fd for which recvmsg() has completed.
155 * \param[in] res return value of the recvmsg() call, or -errno in case of error.
156 * \param[in] msg message buffer containing the read data. Ownership is transferred to the
157 * call-back, and it must make sure to msgb_free() it eventually!
158 * \param[in] msgh msghdr containing metadata related to the recvmsg call. Only valid until
159 * call-back ends. */
Harald Welte1047ed72023-11-18 18:51:58 +0100160 void (*recvmsg_cb)(struct osmo_io_fd *iofd, int res,
161 struct msgb *msg, const struct msghdr *msgh);
Harald Weltee988ec32024-03-14 21:29:28 +0100162 /*! completion call-back function when sendmsg() issued via osmo_iofd_sendmsg_msgb() has
163 * completed on fd. Only valid in Only valid in OSMO_IO_FD_MODE_RECVMSG_SENDMSG.
164 * \param[in] iofd on which a sendmsg() has completed.
165 * \param[in] res return value of the sendmsg() call, or -errno in case of error.
166 * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the
167 * call-back; it is automatically freed after the call-back terminates! */
Harald Welte1047ed72023-11-18 18:51:58 +0100168 void (*sendmsg_cb)(struct osmo_io_fd *iofd, int res, struct msgb *msg);
169 };
Harald Welte8857f3b2022-11-18 13:54:44 +0100170};
171
arehbein2a405d42023-09-25 22:03:41 +0200172void osmo_iofd_init(void);
Harald Welte8857f3b2022-11-18 13:54:44 +0100173
174struct osmo_io_fd *osmo_iofd_setup(const void *ctx, int fd, const char *name,
175 enum osmo_io_fd_mode mode, const struct osmo_io_ops *ioops, void *data);
Harald Welte1047ed72023-11-18 18:51:58 +0100176int osmo_iofd_set_cmsg_size(struct osmo_io_fd *iofd, size_t cmsg_size);
Harald Welte8857f3b2022-11-18 13:54:44 +0100177int osmo_iofd_register(struct osmo_io_fd *iofd, int fd);
178int osmo_iofd_unregister(struct osmo_io_fd *iofd);
179unsigned int osmo_iofd_txqueue_len(struct osmo_io_fd *iofd);
180void osmo_iofd_txqueue_clear(struct osmo_io_fd *iofd);
181int osmo_iofd_close(struct osmo_io_fd *iofd);
182void osmo_iofd_free(struct osmo_io_fd *iofd);
Harald Welte8857f3b2022-11-18 13:54:44 +0100183
Daniel Willmanne2a8dc42023-06-30 10:51:53 +0200184void osmo_iofd_notify_connected(struct osmo_io_fd *iofd);
185
Harald Welte8857f3b2022-11-18 13:54:44 +0100186int osmo_iofd_write_msgb(struct osmo_io_fd *iofd, struct msgb *msg);
187int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int sendto_flags,
188 const struct osmo_sockaddr *dest);
Harald Welte1047ed72023-11-18 18:51:58 +0100189int osmo_iofd_sendmsg_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int sendmsg_flags,
190 const struct msghdr *msgh);
Harald Welte8857f3b2022-11-18 13:54:44 +0100191
192void osmo_iofd_set_alloc_info(struct osmo_io_fd *iofd, unsigned int size, unsigned int headroom);
Daniel Willmanna9303f32023-07-07 11:20:48 +0200193void osmo_iofd_set_txqueue_max_length(struct osmo_io_fd *iofd, unsigned int size);
Harald Welte8857f3b2022-11-18 13:54:44 +0100194void *osmo_iofd_get_data(const struct osmo_io_fd *iofd);
195void osmo_iofd_set_data(struct osmo_io_fd *iofd, void *data);
196
197unsigned int osmo_iofd_get_priv_nr(const struct osmo_io_fd *iofd);
198void osmo_iofd_set_priv_nr(struct osmo_io_fd *iofd, unsigned int priv_nr);
199
200int osmo_iofd_get_fd(const struct osmo_io_fd *iofd);
201const char *osmo_iofd_get_name(const struct osmo_io_fd *iofd);
Pau Espin Pedrol63e45e62023-06-16 16:19:45 +0200202void osmo_iofd_set_name(struct osmo_io_fd *iofd, const char *name);
arehbein0c374c62023-05-14 21:43:11 +0200203
Harald Welteb365b1d2024-02-23 16:08:49 +0100204int osmo_iofd_set_ioops(struct osmo_io_fd *iofd, const struct osmo_io_ops *ioops);
Harald Weltef574aea2024-02-23 12:07:03 +0100205void osmo_iofd_get_ioops(struct osmo_io_fd *iofd, struct osmo_io_ops *ioops);
Harald Weltee988ec32024-03-14 21:29:28 +0100206
207/*! @} */