1// SPDX-License-Identifier: GPL-3.0-or-later
2// IO wrapper for IPC channels
3
4#include "mos/ipc/ipc_io.hpp"
5
6#include "mos/io/io.hpp"
7#include "mos/ipc/ipc.hpp"
8#include "mos/misc/panic.hpp"
9
10#include <mos/allocator.hpp>
11#include <mos_stdlib.hpp>
12
13struct IPC_ControlIO : IO
14{
15 IPC_ControlIO() : IO(IO_NONE, IO_IPC) {};
16 void on_closed();
17};
18
19struct ipc_server_io_t : mos::NamedType<"IPC.ServerIO">
20{
21 IPC_ControlIO control_io;
22 IPCServer *server;
23};
24
25void IPC_ControlIO::on_closed()
26{
27 if (io_type != IO_IPC)
28 mos_panic("ipc_control_io_close: io->type != IO_IPC"); // handle error cases in io_close
29
30 // we only deannounce the server, we don't free it
31 ipc_server_io_t *server_io = container_of(this, ipc_server_io_t, control_io);
32 ipc_server_close(server: server_io->server);
33 delete server_io;
34}
35
36struct IpcServerIO : IpcConnectionIO, mos::NamedType<"IPC.ServerIO">
37{
38 IpcServerIO(IpcDescriptor *desc) : IpcConnectionIO(desc) {};
39 virtual ~IpcServerIO() {};
40
41 size_t on_read(void *buf, size_t size)
42 {
43 return ipc_server_read(ipc: descriptor, buffer: buf, size);
44 }
45 size_t on_write(const void *buf, size_t size)
46 {
47 return ipc_server_write(ipc: descriptor, buffer: buf, size);
48 }
49 void on_closed()
50 {
51 ipc_server_close_channel(ipc: descriptor);
52 }
53};
54
55struct IpcClientIO : IpcConnectionIO, mos::NamedType<"IPC.ClientIO">
56{
57 IpcClientIO(IpcDescriptor *desc) : IpcConnectionIO(desc) {};
58 virtual ~IpcClientIO() {};
59
60 size_t on_read(void *buf, size_t size)
61 {
62 return ipc_client_read(ipc: descriptor, buffer: buf, size);
63 }
64 size_t on_write(const void *buf, size_t size)
65 {
66 return ipc_client_write(ipc: descriptor, buffer: buf, size);
67 }
68 void on_closed()
69 {
70 ipc_client_close_channel(ipc: descriptor);
71 }
72};
73
74PtrResult<IpcConnectionIO> ipc_conn_io_create(IpcDescriptor *desc, bool isServerSide)
75{
76 if (isServerSide)
77 {
78 auto io = mos::create<IpcServerIO>(args&: desc);
79 if (io == nullptr)
80 return -ENOMEM;
81 return io;
82 }
83 else
84 {
85 auto io = mos::create<IpcClientIO>(args&: desc);
86 if (io == nullptr)
87 return -ENOMEM;
88 return io;
89 }
90}
91
92PtrResult<IO> ipc_create(const char *name, size_t max_pending_connections)
93{
94 auto server = ipc_server_create(name, max_pending_connections);
95 if (server.isErr())
96 return server.getErr();
97
98 ipc_server_io_t *io = mos::create<ipc_server_io_t>();
99 if (io == nullptr)
100 {
101 ipc_server_close(server: server.get());
102 return -ENOMEM;
103 }
104
105 io->server = server.get();
106 return &io->control_io;
107}
108
109PtrResult<IO> ipc_accept(IO *server)
110{
111 if (server->io_type != IO_IPC)
112 return -EBADF; // not an ipc server
113
114 ipc_server_io_t *ipc_server = container_of(static_cast<IPC_ControlIO *>(server), ipc_server_io_t, control_io);
115 const auto ipc = ipc_server_accept(server: ipc_server->server);
116 if (ipc.isErr())
117 return ipc.getErr();
118
119 const auto io = ipc_conn_io_create(desc: ipc.get(), isServerSide: true);
120 if (io.isErr())
121 return io.getErr();
122
123 return io;
124}
125
126PtrResult<IO> ipc_connect(const char *name, size_t buffer_size)
127{
128 const auto ipc = ipc_connect_to_server(name, buffer_size);
129 if (ipc.isErr())
130 return ipc.getErr();
131
132 const auto io = ipc_conn_io_create(desc: ipc.get(), isServerSide: false);
133 if (io.isErr())
134 return io.getErr();
135
136 return io;
137}
138