blob: 2e726d9f73c50da8dbc3cecc0d57da1226923a30 [file] [log] [blame]
Harald Welte8857f3b2022-11-18 13:54:44 +01001/*! \file osmo_io_poll.c
2 * New osmocom async I/O API.
3 *
4 * (C) 2022 by Harald Welte <laforge@osmocom.org>
5 * (C) 2022-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
6 * Author: Daniel Willmann <dwillmann@sysmocom.de>
7 *
8 * All Rights Reserved.
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
22
23#include "../config.h"
24#if defined(__linux__)
25
26#include <errno.h>
27#include <stdio.h>
28#include <talloc.h>
29#include <unistd.h>
30#include <stdbool.h>
31#include <sys/socket.h>
32
33#include <osmocom/core/osmo_io.h>
34#include <osmocom/core/linuxlist.h>
35#include <osmocom/core/logging.h>
36#include <osmocom/core/msgb.h>
37#include <osmocom/core/select.h>
38#include <osmocom/core/socket.h>
39#include <osmocom/core/talloc.h>
40#include <osmocom/core/utils.h>
41
42#include "osmo_io_internal.h"
43
44static void iofd_poll_ofd_cb_recvmsg_sendmsg(struct osmo_fd *ofd, unsigned int what)
45{
46 struct osmo_io_fd *iofd = ofd->data;
47 struct msgb *msg;
48 int rc, flags = 0;
49
50 if (what & OSMO_FD_READ) {
51 struct iofd_msghdr hdr;
Harald Welte1047ed72023-11-18 18:51:58 +010052
Harald Welte8857f3b2022-11-18 13:54:44 +010053 msg = iofd_msgb_pending_or_alloc(iofd);
54 if (!msg) {
Daniel Willmanna8a27c22023-06-26 19:26:16 +020055 LOGPIO(iofd, LOGL_ERROR, "Could not allocate msgb for reading\n");
Harald Welte8857f3b2022-11-18 13:54:44 +010056 OSMO_ASSERT(0);
57 }
58
59 hdr.msg = msg;
arehbein5099d992023-06-16 22:37:44 +020060 hdr.iov[0].iov_base = msg->tail;
Harald Welte8857f3b2022-11-18 13:54:44 +010061 hdr.iov[0].iov_len = msgb_tailroom(msg);
Daniel Willmann435856b2023-09-05 14:11:55 +020062 hdr.hdr = (struct msghdr) {
63 .msg_iov = &hdr.iov[0],
64 .msg_iovlen = 1,
65 .msg_name = &hdr.osa.u.sa,
66 .msg_namelen = sizeof(struct osmo_sockaddr),
67 };
Harald Welte1047ed72023-11-18 18:51:58 +010068 if (iofd->mode == OSMO_IO_FD_MODE_RECVMSG_SENDMSG) {
69 hdr.hdr.msg_control = alloca(iofd->cmsg_size);
70 hdr.hdr.msg_controllen = iofd->cmsg_size;
71 }
Harald Welte8857f3b2022-11-18 13:54:44 +010072
73 rc = recvmsg(ofd->fd, &hdr.hdr, flags);
74 if (rc > 0)
75 msgb_put(msg, rc);
76
Andreas Eversberg76f76782024-02-14 14:33:10 +010077 iofd_handle_recv(iofd, msg, (rc < 0 && errno > 0) ? -errno : rc, &hdr);
Harald Welte8857f3b2022-11-18 13:54:44 +010078 }
79
Daniel Willmannf89162f2023-06-26 19:24:46 +020080 if (IOFD_FLAG_ISSET(iofd, IOFD_FLAG_CLOSED))
Harald Welte8857f3b2022-11-18 13:54:44 +010081 return;
82
83 if (what & OSMO_FD_WRITE) {
84 struct iofd_msghdr *msghdr = iofd_txqueue_dequeue(iofd);
85 if (msghdr) {
Harald Welte8857f3b2022-11-18 13:54:44 +010086 rc = sendmsg(ofd->fd, &msghdr->hdr, msghdr->flags);
Daniel Willmann84611882023-11-21 10:17:00 +010087 iofd_handle_send_completion(iofd, rc, msghdr);
Daniel Willmanncbbd17e2023-05-17 17:08:10 +020088 } else {
Harald Welteb365b1d2024-02-23 16:08:49 +010089 /* Socket is writable, but we have no data to send. A non-blocking/async
90 connect() is signalled this way. */
91 switch (iofd->mode) {
92 case OSMO_IO_FD_MODE_READ_WRITE:
Daniel Willmanncbbd17e2023-05-17 17:08:10 +020093 iofd->io_ops.write_cb(iofd, 0, NULL);
Harald Welteb365b1d2024-02-23 16:08:49 +010094 break;
95 case OSMO_IO_FD_MODE_RECVFROM_SENDTO:
96 iofd->io_ops.sendto_cb(iofd, 0, NULL, NULL);
97 break;
Harald Welte1047ed72023-11-18 18:51:58 +010098 case OSMO_IO_FD_MODE_RECVMSG_SENDMSG:
99 iofd->io_ops.sendmsg_cb(iofd, 0, NULL);
100 break;
Harald Welteb365b1d2024-02-23 16:08:49 +0100101 default:
102 break;
103 }
Daniel Willmanncbbd17e2023-05-17 17:08:10 +0200104 if (osmo_iofd_txqueue_len(iofd) == 0)
105 iofd_poll_ops.write_disable(iofd);
Harald Welte8857f3b2022-11-18 13:54:44 +0100106 }
Harald Welte8857f3b2022-11-18 13:54:44 +0100107 }
108}
109
110static int iofd_poll_ofd_cb_dispatch(struct osmo_fd *ofd, unsigned int what)
111{
112 struct osmo_io_fd *iofd = ofd->data;
113
Daniel Willmannf89162f2023-06-26 19:24:46 +0200114 IOFD_FLAG_SET(iofd, IOFD_FLAG_IN_CALLBACK);
Harald Welte8857f3b2022-11-18 13:54:44 +0100115 iofd_poll_ofd_cb_recvmsg_sendmsg(ofd, what);
Daniel Willmannf89162f2023-06-26 19:24:46 +0200116 IOFD_FLAG_UNSET(iofd, IOFD_FLAG_IN_CALLBACK);
Harald Welte8857f3b2022-11-18 13:54:44 +0100117
Daniel Willmannf89162f2023-06-26 19:24:46 +0200118 if (IOFD_FLAG_ISSET(iofd, IOFD_FLAG_TO_FREE)) {
Harald Welte8857f3b2022-11-18 13:54:44 +0100119 talloc_free(iofd);
120 return 0;
121 }
122
123 return 0;
124}
125
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100126static int iofd_poll_register(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100127{
128 struct osmo_fd *ofd = &iofd->u.poll.ofd;
Andreas Eversberg848faf92024-02-09 12:38:17 +0100129 int rc;
130
131 if (IOFD_FLAG_ISSET(iofd, IOFD_FLAG_FD_REGISTERED))
132 return 0;
Harald Welte8857f3b2022-11-18 13:54:44 +0100133 osmo_fd_setup(ofd, iofd->fd, 0, &iofd_poll_ofd_cb_dispatch, iofd, 0);
Andreas Eversberg848faf92024-02-09 12:38:17 +0100134 rc = osmo_fd_register(ofd);
135 if (!rc)
136 IOFD_FLAG_SET(iofd, IOFD_FLAG_FD_REGISTERED);
137 return rc;
Harald Welte8857f3b2022-11-18 13:54:44 +0100138}
139
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100140static int iofd_poll_unregister(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100141{
142 struct osmo_fd *ofd = &iofd->u.poll.ofd;
Andreas Eversberg848faf92024-02-09 12:38:17 +0100143
144 if (!IOFD_FLAG_ISSET(iofd, IOFD_FLAG_FD_REGISTERED))
145 return 0;
Harald Welte8857f3b2022-11-18 13:54:44 +0100146 osmo_fd_unregister(ofd);
Andreas Eversberg848faf92024-02-09 12:38:17 +0100147 IOFD_FLAG_UNSET(iofd, IOFD_FLAG_FD_REGISTERED);
Harald Welte8857f3b2022-11-18 13:54:44 +0100148
149 return 0;
150}
151
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100152static int iofd_poll_close(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100153{
Andreas Eversberg848faf92024-02-09 12:38:17 +0100154 iofd_poll_unregister(iofd);
Harald Welte8857f3b2022-11-18 13:54:44 +0100155 osmo_fd_close(&iofd->u.poll.ofd);
156
157 return 0;
158}
159
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100160static void iofd_poll_read_enable(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100161{
162 osmo_fd_read_enable(&iofd->u.poll.ofd);
163}
164
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100165static void iofd_poll_read_disable(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100166{
167 osmo_fd_read_disable(&iofd->u.poll.ofd);
168}
169
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100170static void iofd_poll_write_enable(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100171{
172 osmo_fd_write_enable(&iofd->u.poll.ofd);
173}
174
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100175static void iofd_poll_write_disable(struct osmo_io_fd *iofd)
Harald Welte8857f3b2022-11-18 13:54:44 +0100176{
177 osmo_fd_write_disable(&iofd->u.poll.ofd);
178}
179
Andreas Eversberg3c0d5002024-02-15 13:14:03 +0100180static void iofd_poll_notify_connected(struct osmo_io_fd *iofd)
Andreas Eversberg848faf92024-02-09 12:38:17 +0100181{
182 int rc;
183
184 rc = iofd_poll_register(iofd);
185 if (rc < 0)
186 return;
187 osmo_fd_write_enable(&iofd->u.poll.ofd);
188}
189
Harald Welte8857f3b2022-11-18 13:54:44 +0100190const struct iofd_backend_ops iofd_poll_ops = {
191 .register_fd = iofd_poll_register,
192 .unregister_fd = iofd_poll_unregister,
193 .close = iofd_poll_close,
194 .write_enable = iofd_poll_write_enable,
195 .write_disable = iofd_poll_write_disable,
196 .read_enable = iofd_poll_read_enable,
197 .read_disable = iofd_poll_read_disable,
Andreas Eversberg848faf92024-02-09 12:38:17 +0100198 .notify_connected = iofd_poll_notify_connected,
Harald Welte8857f3b2022-11-18 13:54:44 +0100199};
200
201#endif /* defined(__linux__) */