1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | // io_t 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 | |
13 | struct ipc_server_io_t : mos::NamedType<"IPC.ServerIO" > |
14 | { |
15 | io_t control_io; |
16 | IPCServer *server; |
17 | }; |
18 | |
19 | static void ipc_control_io_close(io_t *io) |
20 | { |
21 | if (io->type != IO_IPC) |
22 | mos_panic("ipc_control_io_close: io->type != IO_IPC" ); // handle error cases in io_close |
23 | |
24 | // we only deannounce the server, we don't free it |
25 | ipc_server_io_t *server_io = container_of(io, ipc_server_io_t, control_io); |
26 | ipc_server_close(server: server_io->server); |
27 | delete server_io; |
28 | } |
29 | |
30 | static const io_op_t ipc_control_io_op = { |
31 | .close = ipc_control_io_close, |
32 | }; |
33 | |
34 | static size_t ipc_client_io_write(io_t *io, const void *buf, size_t size) |
35 | { |
36 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
37 | return ipc_client_write(ipc: conn->ipc, buffer: buf, size); |
38 | } |
39 | |
40 | static size_t ipc_client_io_read(io_t *io, void *buf, size_t size) |
41 | { |
42 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
43 | return ipc_client_read(ipc: conn->ipc, buffer: buf, size); |
44 | } |
45 | |
46 | static void ipc_client_io_close(io_t *io) |
47 | { |
48 | if (io->type != IO_IPC) |
49 | mos_panic("ipc_client_io_close: io->type != IO_IPC" ); // handle error cases in io_close |
50 | |
51 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
52 | ipc_client_close_channel(ipc: conn->ipc); |
53 | delete conn; |
54 | } |
55 | |
56 | static size_t ipc_server_io_write(io_t *io, const void *buf, size_t size) |
57 | { |
58 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
59 | return ipc_server_write(ipc: conn->ipc, buffer: buf, size); |
60 | } |
61 | |
62 | static size_t ipc_server_io_read(io_t *io, void *buf, size_t size) |
63 | { |
64 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
65 | return ipc_server_read(ipc: conn->ipc, buffer: buf, size); |
66 | } |
67 | |
68 | static void ipc_server_io_close(io_t *io) |
69 | { |
70 | if (io->type != IO_IPC) |
71 | mos_panic("ipc_server_io_close: io->type != IO_IPC" ); // handle error cases in io_close |
72 | |
73 | ipc_conn_io_t *conn = container_of(io, ipc_conn_io_t, io); |
74 | ipc_server_close_channel(ipc: conn->ipc); |
75 | delete conn; |
76 | } |
77 | |
78 | static const io_op_t ipc_client_io_op = { |
79 | .read = ipc_client_io_read, |
80 | .write = ipc_client_io_write, |
81 | .close = ipc_client_io_close, |
82 | }; |
83 | |
84 | static const io_op_t ipc_server_io_op = { |
85 | .read = ipc_server_io_read, |
86 | .write = ipc_server_io_write, |
87 | .close = ipc_server_io_close, |
88 | }; |
89 | |
90 | PtrResult<ipc_conn_io_t> ipc_conn_io_create(IPCDescriptor *ipc, bool is_server_side) |
91 | { |
92 | ipc_conn_io_t *io = mos::create<ipc_conn_io_t>(); |
93 | if (io == nullptr) |
94 | return -ENOMEM; |
95 | |
96 | io->ipc = ipc; |
97 | io_init(io: &io->io, type: IO_IPC, flags: IO_READABLE | IO_WRITABLE, ops: is_server_side ? &ipc_server_io_op : &ipc_client_io_op); |
98 | return io; |
99 | } |
100 | |
101 | PtrResult<io_t> ipc_create(const char *name, size_t max_pending_connections) |
102 | { |
103 | auto server = ipc_server_create(name, max_pending_connections); |
104 | if (server.isErr()) |
105 | return server.getErr(); |
106 | |
107 | ipc_server_io_t *io = mos::create<ipc_server_io_t>(); |
108 | if (io == nullptr) |
109 | { |
110 | ipc_server_close(server: server.get()); |
111 | return -ENOMEM; |
112 | } |
113 | |
114 | io->server = server.get(); |
115 | io_init(io: &io->control_io, type: IO_IPC, flags: IO_NONE, ops: &ipc_control_io_op); |
116 | return &io->control_io; |
117 | } |
118 | |
119 | PtrResult<io_t> ipc_accept(io_t *server) |
120 | { |
121 | if (server->type != IO_IPC) |
122 | return -EBADF; // not an ipc server |
123 | |
124 | ipc_server_io_t *ipc_server = container_of(server, ipc_server_io_t, control_io); |
125 | auto ipc = ipc_server_accept(server: ipc_server->server); |
126 | if (ipc.isErr()) |
127 | return ipc.getErr(); |
128 | |
129 | auto io = ipc_conn_io_create(ipc: ipc.get(), is_server_side: true); |
130 | if (io.isErr()) |
131 | return io.getErr(); |
132 | |
133 | return &io->io; |
134 | } |
135 | |
136 | PtrResult<io_t> ipc_connect(const char *name, size_t buffer_size) |
137 | { |
138 | auto ipc = ipc_connect_to_server(name, buffer_size); |
139 | if (ipc.isErr()) |
140 | return ipc.getErr(); |
141 | |
142 | auto connio = ipc_conn_io_create(ipc: ipc.get(), is_server_side: false); |
143 | if (connio.isErr()) |
144 | return connio.getErr(); |
145 | |
146 | return &connio->io; |
147 | } |
148 | |