blob: 9e8ab82b99ef2e7b3f255658402343b875f49b11 [file] [log] [blame]
Eric Wild1e17c4f2020-03-24 17:19:27 +01001/*
2* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3* Author: Pau Espin Pedrol <pespin@sysmocom.de>
4*
5* SPDX-License-Identifier: 0BSD
6*
7* Permission to use, copy, modify, and/or distribute this software for any purpose
8* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE
9* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
10* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
11* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
13* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
14* USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <string.h>
20#include <errno.h>
21#include <assert.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <inttypes.h>
25#include <sys/mman.h>
26#include <sys/stat.h> /* For mode constants */
27#include <fcntl.h> /* For O_* constants */
28
29#include <debug.h>
30#include <osmocom/core/application.h>
31#include <osmocom/core/talloc.h>
32#include <osmocom/core/select.h>
33#include <osmocom/core/socket.h>
34#include <osmocom/core/logging.h>
35#include <osmocom/core/utils.h>
36#include <osmocom/core/msgb.h>
37#include <osmocom/core/select.h>
38#include <osmocom/core/timer.h>
39
40#include "shm.h"
41#include "ipc-driver-test.h"
42
43extern volatile int ipc_exit_requested;
44static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
45{
46 int rc = 0;
47
48 switch (msg_type) {
49 case IPC_IF_MSG_GREETING_REQ:
50 rc = ipc_rx_greeting_req(&ipc_prim->u.greeting_req);
51 break;
52 case IPC_IF_MSG_INFO_REQ:
53 rc = ipc_rx_info_req(&ipc_prim->u.info_req);
54 break;
55 case IPC_IF_MSG_OPEN_REQ:
56 rc = ipc_rx_open_req(&ipc_prim->u.open_req);
57 break;
58 default:
59 LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type 0x%02x\n", msg_type);
60 rc = -EINVAL;
61 }
62
63 return rc;
64}
65
66int ipc_sock_send(struct msgb *msg)
67{
68 struct ipc_sock_state *state = global_ipc_sock_state;
69 struct osmo_fd *conn_bfd;
70
71 if (!state) {
72 LOGP(DDEV, LOGL_INFO,
73 "IPC socket not created, "
74 "dropping message\n");
75 msgb_free(msg);
76 return -EINVAL;
77 }
78 conn_bfd = &state->conn_bfd;
79 if (conn_bfd->fd <= 0) {
80 LOGP(DDEV, LOGL_NOTICE,
81 "IPC socket not connected, "
82 "dropping message\n");
83 msgb_free(msg);
84 return -EIO;
85 }
86 msgb_enqueue(&state->upqueue, msg);
Harald Welte94def472020-10-19 12:28:26 +020087 osmo_fd_write_enable(conn_bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +010088
89 return 0;
90}
91
92void ipc_sock_close(struct ipc_sock_state *state)
93{
94 struct osmo_fd *bfd = &state->conn_bfd;
95
96 LOGP(DDEV, LOGL_NOTICE, "IPC socket has LOST connection\n");
97
98 ipc_exit_requested = 1;
99
Pau Espin Pedrol8a436242023-03-14 11:34:16 +0100100 osmo_fd_unregister(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100101 close(bfd->fd);
102 bfd->fd = -1;
Eric Wild1e17c4f2020-03-24 17:19:27 +0100103
104 /* re-enable the generation of ACCEPT for new connections */
Harald Welte94def472020-10-19 12:28:26 +0200105 osmo_fd_read_enable(&state->listen_bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100106
107 /* flush the queue */
108 while (!llist_empty(&state->upqueue)) {
109 struct msgb *msg = msgb_dequeue(&state->upqueue);
110 msgb_free(msg);
111 }
112}
113
114int ipc_sock_read(struct osmo_fd *bfd)
115{
116 struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
117 struct ipc_sk_if *ipc_prim;
118 struct msgb *msg;
119 int rc;
120
121 msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");
122 if (!msg)
123 return -ENOMEM;
124
125 ipc_prim = (struct ipc_sk_if *)msg->tail;
126
127 rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
128 if (rc == 0)
129 goto close;
130
131 if (rc < 0) {
132 if (errno == EAGAIN) {
133 msgb_free(msg);
134 return 0;
135 }
136 goto close;
137 }
138
139 if (rc < (int)sizeof(*ipc_prim)) {
140 LOGP(DDEV, LOGL_ERROR,
141 "Received %d bytes on Unix Socket, but primitive size "
142 "is %zu, discarding\n",
143 rc, sizeof(*ipc_prim));
144 msgb_free(msg);
145 return 0;
146 }
147
148 rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
149
150 /* as we always synchronously process the message in IPC_rx() and
151 * its callbacks, we can free the message here. */
152 msgb_free(msg);
153
154 return rc;
155
156close:
157 msgb_free(msg);
158 ipc_sock_close(state);
159 return -1;
160}
161
162static int ipc_sock_write(struct osmo_fd *bfd)
163{
164 struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
165 int rc;
166
167 while (!llist_empty(&state->upqueue)) {
168 struct msgb *msg, *msg2;
169 struct ipc_sk_if *ipc_prim;
170
171 /* peek at the beginning of the queue */
172 msg = llist_entry(state->upqueue.next, struct msgb, list);
173 ipc_prim = (struct ipc_sk_if *)msg->data;
174
Harald Welte94def472020-10-19 12:28:26 +0200175 osmo_fd_write_disable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100176
177 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
178 if (!msgb_length(msg)) {
179 LOGP(DDEV, LOGL_ERROR,
180 "message type (%d) with ZERO "
181 "bytes!\n",
182 ipc_prim->msg_type);
183 goto dontsend;
184 }
185
186 /* try to send it over the socket */
187 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
188 if (rc == 0)
189 goto close;
190 if (rc < 0) {
191 if (errno == EAGAIN) {
Harald Welte94def472020-10-19 12:28:26 +0200192 osmo_fd_write_enable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100193 break;
194 }
195 goto close;
196 }
197
198 dontsend:
199 /* _after_ we send it, we can deueue */
200 msg2 = msgb_dequeue(&state->upqueue);
201 assert(msg == msg2);
202 msgb_free(msg);
203 }
204 return 0;
205
206close:
207 ipc_sock_close(state);
208 return -1;
209}
210
211static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
212{
213 int rc = 0;
214
Harald Welte08970c52020-10-18 22:41:40 +0200215 if (flags & OSMO_FD_READ)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100216 rc = ipc_sock_read(bfd);
217 if (rc < 0)
218 return rc;
219
Harald Welte08970c52020-10-18 22:41:40 +0200220 if (flags & OSMO_FD_WRITE)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100221 rc = ipc_sock_write(bfd);
222
223 return rc;
224}
225
226/* accept connection coming from IPC */
227int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
228{
229 struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
230 struct osmo_fd *conn_bfd = &state->conn_bfd;
231 struct sockaddr_un un_addr;
232 socklen_t len;
233 int rc;
234
235 len = sizeof(un_addr);
236 rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
237 if (rc < 0) {
238 LOGP(DDEV, LOGL_ERROR, "Failed to accept a new connection\n");
239 return -1;
240 }
241
242 if (conn_bfd->fd >= 0) {
243 LOGP(DDEV, LOGL_NOTICE,
244 "ip clent connects but we already have "
245 "another active connection ?!?\n");
246 /* We already have one IPC connected, this is all we support */
Harald Welte94def472020-10-19 12:28:26 +0200247 osmo_fd_read_disable(&state->listen_bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100248 close(rc);
249 return 0;
250 }
251
Harald Weltec5989fe2020-10-19 12:27:36 +0200252 osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, ipc_sock_cb, state, 0);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100253
254 if (osmo_fd_register(conn_bfd) != 0) {
255 LOGP(DDEV, LOGL_ERROR,
256 "Failed to register new connection "
257 "fd\n");
258 close(conn_bfd->fd);
259 conn_bfd->fd = -1;
260 return -1;
261 }
262
263 LOGP(DDEV, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
264
265 return 0;
266}