/*! \file osmo_io_internal.h */ #pragma once #include <unistd.h> #include <stdbool.h> #include <netinet/sctp.h> #include <osmocom/core/osmo_io.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/msgb.h> #include <osmocom/core/select.h> #include <osmocom/core/socket.h> #include "../config.h" #define OSMO_IO_DEFAULT_MSGB_SIZE 1024 #define OSMO_IO_DEFAULT_MSGB_HEADROOM 128 extern const struct iofd_backend_ops iofd_poll_ops; #define OSMO_IO_BACKEND_DEFAULT "POLL" #if defined(HAVE_URING) extern const struct iofd_backend_ops iofd_uring_ops; #endif struct iofd_backend_ops { int (*register_fd)(struct osmo_io_fd *iofd); int (*unregister_fd)(struct osmo_io_fd *iofd); int (*close)(struct osmo_io_fd *iofd); void (*write_enable)(struct osmo_io_fd *iofd); void (*write_disable)(struct osmo_io_fd *iofd); void (*read_enable)(struct osmo_io_fd *iofd); void (*read_disable)(struct osmo_io_fd *iofd); void (*notify_connected)(struct osmo_io_fd *iofd); }; #define IOFD_FLAG_CLOSED (1<<0) #define IOFD_FLAG_IN_CALLBACK (1<<1) #define IOFD_FLAG_TO_FREE (1<<2) #define IOFD_FLAG_NOTIFY_CONNECTED (1<<3) #define IOFD_FLAG_FD_REGISTERED (1<<4) #define IOFD_FLAG_SET(iofd, flag) \ (iofd)->flags |= (flag) #define IOFD_FLAG_UNSET(iofd, flag) \ (iofd)->flags &= ~(flag) #define IOFD_FLAG_ISSET(iofd, flag) ((iofd)->flags & (flag)) struct osmo_io_fd { /*! linked list for internal management */ struct llist_head list; /*! actual operating-system level file decriptor */ int fd; /*! type of read/write mode to use */ enum osmo_io_fd_mode mode; /*! flags to guard closing/freeing of iofd */ uint32_t flags; /*! human-readable name to associte with fd */ char *name; /*! send/recv (msg) callback functions */ struct osmo_io_ops io_ops; /*! Pending msgb to keep partial data during segmentation */ struct msgb *pending; /*! data pointer passed through to call-back function */ void *data; /*! private number, extending \a data */ unsigned int priv_nr; /*! size of iofd_msghdr.cmsg[] when allocated in recvmsg path */ size_t cmsg_size; struct { /*! talloc context from which to allocate msgb when reading */ const void *ctx; /*! size of msgb to allocate (excluding headroom) */ unsigned int size; /*! headroom to allocate when allocating msgb's */ unsigned int headroom; } msgb_alloc; struct { /*! maximum length of write queue */ unsigned int max_length; /*! current length of write queue */ unsigned int current_length; /*! actual linked list implementing the transmit queue */ struct llist_head msg_queue; } tx_queue; union { struct { struct osmo_fd ofd; } poll; struct { bool read_enabled; bool write_enabled; void *read_msghdr; void *write_msghdr; /* TODO: index into array of registered fd's? */ /* osmo_fd for non-blocking connect handling */ struct osmo_fd connect_ofd; } uring; } u; }; enum iofd_msg_action { IOFD_ACT_READ, IOFD_ACT_WRITE, IOFD_ACT_RECVFROM, IOFD_ACT_SENDTO, IOFD_ACT_RECVMSG, IOFD_ACT_SENDMSG, }; /*! serialized version of 'struct msghdr' employed by sendmsg/recvmsg */ struct iofd_msghdr { /*! entry into osmo_io_fd.tx_queue.msg_queue */ struct llist_head list; enum iofd_msg_action action; /*! the 'struct msghdr' we are wrapping/ecapsulating here */ struct msghdr hdr; /*! socket address of the remote peer */ struct osmo_sockaddr osa; /*! io-vector we need to pass as argument to sendmsg/recvmsg; is set up * to point into msg below */ struct iovec iov[1]; /*! flags we pass as argument to sendmsg / recvmsg */ int flags; /*! message-buffer containing data for this I/O operation */ struct msgb *msg; /*! I/O file descriptor on which we perform this I/O operation */ struct osmo_io_fd *iofd; /*! control message buffer for passing sctp_sndrcvinfo along */ char cmsg[0]; /* size is determined by iofd->cmsg_size on recvmsg, and by mcghdr->msg_controllen on sendmsg */ }; enum iofd_seg_act { IOFD_SEG_ACT_HANDLE_ONE, IOFD_SEG_ACT_HANDLE_MORE, IOFD_SEG_ACT_DEFER, }; struct iofd_msghdr *iofd_msghdr_alloc(struct osmo_io_fd *iofd, enum iofd_msg_action action, struct msgb *msg, size_t cmsg_size); void iofd_msghdr_free(struct iofd_msghdr *msghdr); struct msgb *iofd_msgb_alloc(struct osmo_io_fd *iofd); struct msgb *iofd_msgb_pending(struct osmo_io_fd *iofd); struct msgb *iofd_msgb_pending_or_alloc(struct osmo_io_fd *iofd); void iofd_handle_recv(struct osmo_io_fd *iofd, struct msgb *msg, int rc, struct iofd_msghdr *msghdr); void iofd_handle_send_completion(struct osmo_io_fd *iofd, int rc, struct iofd_msghdr *msghdr); void iofd_handle_segmented_read(struct osmo_io_fd *iofd, struct msgb *msg, int rc); int iofd_txqueue_enqueue(struct osmo_io_fd *iofd, struct iofd_msghdr *msghdr); void iofd_txqueue_enqueue_front(struct osmo_io_fd *iofd, struct iofd_msghdr *msghdr); struct iofd_msghdr *iofd_txqueue_dequeue(struct osmo_io_fd *iofd);