libtransistor
A userland library for the Nintendo Switch
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
ipcclient.hpp
Go to the documentation of this file.
1 
6 #pragma once
7 
8 #include<libtransistor/cpp/types.hpp>
10 #include<libtransistor/ipc.h>
11 
12 #include<tuple>
13 #include<vector>
14 
15 namespace trn {
16 namespace ipc {
17 namespace client {
18 
19 class Object;
20 
21 template<typename... T>
22 struct ArgPack;
23 
27  std::vector<ipc_buffer_t*> buffers;
28  uint64_t pid;
29 
31 };
32 
33 template<typename T, typename... Extra>
35 
36 template<typename T>
37 struct AccessorHelper<ipc::InRaw<T>> {
38  size_t offset;
39 
40  AccessorHelper(size_t offset) : offset(offset) {
41  }
42 
43  void Pack(TransactionFormat &f, ipc::InRaw<T> &arg) const {
44  *((T*) (((uint8_t*) f.rq.raw_data) + offset)) = arg.value;
45  }
46 
47  void Unpack(TransactionFormat &f, ipc::InRaw<T> &arg) const {
48  }
49 };
50 
51 template<typename T>
52 struct AccessorHelper<ipc::OutRaw<T>> {
53  size_t offset;
54 
55  AccessorHelper(size_t offset) : offset(offset) {
56  }
57 
58  void Pack(TransactionFormat &f, ipc::OutRaw<T> &arg) const {
59  }
60 
61  void Unpack(TransactionFormat &f, ipc::OutRaw<T> &arg) const {
62  arg = *((T*) (((uint8_t*) f.rs.raw_data) + offset));
63  }
64 };
65 
66 template<typename T>
67 struct AccessorHelper<ipc::InHandle<T, ipc::copy>> {
68  size_t index;
69 
70  AccessorHelper(size_t index) : index(index) {
71  }
72 
73  void Pack(TransactionFormat &f, ipc::InHandle<T, ipc::copy> &arg) const {
74  f.rq.copy_handles[index] = arg.handle;
75  }
76 
77  void Unpack(TransactionFormat &f, ipc::InHandle<T, ipc::copy> &arg) const {
78  }
79 };
80 
81 template<typename T>
82 struct AccessorHelper<ipc::InHandle<T, ipc::move>> {
83  size_t index;
84 
85  AccessorHelper(size_t index) : index(index) {
86  }
87 
88  void Pack(TransactionFormat &f, ipc::InHandle<T, ipc::move> &arg) const {
89  f.rq.move_handles[index] = arg.handle;
90  }
91 
92  void Unpack(TransactionFormat &f, ipc::InHandle<T, ipc::move> &arg) const {
93  }
94 };
95 
96 template<typename T, typename... Extra>
97 struct AccessorHelper<ipc::OutHandle<T, ipc::copy, Extra...>> {
98  size_t index;
99 
100  AccessorHelper(size_t index) : index(index) {
101  }
102 
104  }
105 
106  void Unpack(TransactionFormat &f, ipc::OutHandle<T, ipc::copy, Extra...> &arg) const {
107  arg = f.rs.copy_handles[index];
108  }
109 };
110 
111 template<typename T, typename... Extra>
112 struct AccessorHelper<ipc::OutHandle<T, ipc::move, Extra...>> {
113  size_t index;
114 
115  AccessorHelper(size_t index) : index(index) {
116  }
117 
119  }
120 
121  void Unpack(TransactionFormat &f, ipc::OutHandle<T, ipc::move, Extra...> &arg) const {
122  arg = f.rs.move_handles[index];
123  }
124 };
125 
126 template<typename T>
127 struct AccessorHelper<ipc::InObject<T>> {
128  size_t index;
129 
130  AccessorHelper(size_t index) : index(index) {
131  }
132 
133  void Pack(TransactionFormat &f, ipc::InObject<T> &arg) const {
134  f.rq.objects[index] = arg.value->object.object;
135  }
136 
137  void Unpack(TransactionFormat &f, ipc::InObject<T> &arg) const {
138  }
139 };
140 
141 template<typename T>
142 struct AccessorHelper<ipc::OutObject<T>> {
143  size_t index;
144 
145  AccessorHelper(size_t index) : index(index) {
146  }
147 
148  void Pack(TransactionFormat &f, ipc::OutObject<T> &arg) const {
149  }
150 
151  void Unpack(TransactionFormat &f, ipc::OutObject<T> &arg) const {
152  *(arg.value) = T(f.rs.objects[index]);
153  }
154 };
155 
156 template<typename T, uint32_t type>
157 struct AccessorHelper<ipc::Buffer<T, type>> {
158  ipc_buffer_t *buffer;
159 
160  AccessorHelper(ipc_buffer_t *buffer) : buffer(buffer) {
161  }
162 
163  void Pack(TransactionFormat &f, ipc::Buffer<T, type> &arg) const {
164  buffer->addr = (void*) arg.data;
165  buffer->size = arg.size;
166  }
167 
168  void Unpack(TransactionFormat &f, ipc::Buffer<T, type> &arg) const {
169  }
170 };
171 
172 template<>
173 struct AccessorHelper<ipc::InPid> {
174  AccessorHelper() {
175  }
176 
177  void Pack(TransactionFormat &f, ipc::InPid &arg) const {
178  }
179 
180  void Unpack(TransactionFormat &f, ipc::InPid &arg) const {
181  }
182 };
183 
184 template<>
185 struct AccessorHelper<ipc::OutPid> {
186  AccessorHelper() {
187  }
188 
189  void Pack(TransactionFormat &f, ipc::OutPid &arg) const {
190  }
191 
192  void Unpack(TransactionFormat &f, ipc::OutPid &arg) const {
193  *arg.value = f.pid;
194  }
195 };
196 
197 template<typename T, typename... Extra>
199 
200 template<typename T>
201 struct FormatMutator<ipc::InRaw<T>> {
202  static AccessorHelper<ipc::InRaw<T>> MutateFormat(TransactionFormat &fmt) {
203  fmt.rq.raw_data_size+= (alignof(T) - 1);
204  fmt.rq.raw_data_size-= fmt.rq.raw_data_size % alignof(T); // align
205  size_t offset = fmt.rq.raw_data_size;
206  fmt.rq.raw_data_size+= sizeof(T);
207  return AccessorHelper<ipc::InRaw<T>>(offset);
208  }
209 };
210 
211 template<typename T>
212 struct FormatMutator<ipc::OutRaw<T>> {
213  static AccessorHelper<ipc::OutRaw<T>> MutateFormat(TransactionFormat &fmt) {
214  fmt.rs.raw_data_size+= (alignof(T) - 1);
215  fmt.rs.raw_data_size-= fmt.rs.raw_data_size % alignof(T); // align
216  size_t offset = fmt.rs.raw_data_size;
217  fmt.rs.raw_data_size+= sizeof(T);
218  return AccessorHelper<ipc::OutRaw<T>>(offset);
219  }
220 };
221 
222 template<typename T>
223 struct FormatMutator<ipc::InHandle<T, ipc::copy>> {
225  return AccessorHelper<ipc::InHandle<T, ipc::copy>>(fmt.rq.num_copy_handles++);
226  }
227 };
228 
229 template<typename T>
230 struct FormatMutator<ipc::InHandle<T, ipc::move>> {
232  return AccessorHelper<ipc::InHandle<T, ipc::move>>(fmt.rq.num_move_handles++);
233  }
234 };
235 
236 template<typename T, typename... Extra>
237 struct FormatMutator<ipc::OutHandle<T, ipc::copy, Extra...>> {
238  static AccessorHelper<ipc::OutHandle<T, ipc::copy, Extra...>> MutateFormat(TransactionFormat &fmt) {
239  return AccessorHelper<ipc::OutHandle<T, ipc::copy, Extra...>>(fmt.rs.num_copy_handles++);
240  }
241 };
242 
243 template<typename T, typename... Extra>
244 struct FormatMutator<ipc::OutHandle<T, ipc::move, Extra...>> {
245  static AccessorHelper<ipc::OutHandle<T, ipc::move, Extra...>> MutateFormat(TransactionFormat &fmt) {
246  return AccessorHelper<ipc::OutHandle<T, ipc::move, Extra...>>(fmt.rs.num_move_handles++);
247  }
248 };
249 
250 template<typename T>
251 struct FormatMutator<ipc::InObject<T>> {
252  static AccessorHelper<ipc::InObject<T>> MutateFormat(TransactionFormat &fmt) {
253  return AccessorHelper<ipc::InObject<T>>(fmt.rq.num_objects++);
254  }
255 };
256 
257 template<typename T>
258 struct FormatMutator<ipc::OutObject<T>> {
259  static AccessorHelper<ipc::OutObject<T>> MutateFormat(TransactionFormat &fmt) {
260  return AccessorHelper<ipc::OutObject<T>>(fmt.rs.num_objects++);
261  }
262 };
263 
264 template<typename T, uint32_t type, size_t expected_size>
265 struct FormatMutator<ipc::Buffer<T, type, expected_size>> {
267  ipc_buffer_t *buffer = new ipc_buffer_t();
268  buffer->type = type;
269  buffer->size = expected_size;
270  fmt.buffers.push_back(buffer);
272  }
273 };
274 
275 template<>
276 struct FormatMutator<ipc::InPid> {
277  static AccessorHelper<ipc::InPid> MutateFormat(TransactionFormat &fmt) {
278  fmt.rq.send_pid = true;
280  }
281 };
282 
283 template<>
284 struct FormatMutator<ipc::OutPid> {
285  static AccessorHelper<ipc::OutPid> MutateFormat(TransactionFormat &fmt) {
286  fmt.rs.has_pid = true;
288  }
289 };
290 
291 template<typename T>
293 
294 template<typename Arg0, typename... Args>
295 struct FormatBuilder<ArgPack<Arg0, Args...>> {
296  static std::tuple<AccessorHelper<Arg0>, AccessorHelper<Args>...> Build(TransactionFormat &fmt) {
298  return std::tuple_cat(std::make_tuple(helper), FormatBuilder<ArgPack<Args...>>::Build(fmt));
299  }
300 };
301 
302 template<>
304  static std::tuple<> Build(TransactionFormat &fmt) {
305  // nothing to do
306  return std::make_tuple();
307  }
308 };
309 
310 class Object {
311  public:
312  Object();
313  Object(ipc_object_t object);
314  Object(const Object &) = delete;
315  Object &operator=(const Object &) = delete;
316  Object(Object &&other);
317  Object &operator=(Object &&other);
318  ~Object();
319 
320  bool is_valid;
321  ipc_object_t object;
322 
323  template<uint32_t id, typename... Args>
324  Result<std::nullopt_t> SendSyncRequest(Args &&... args) {
325  TransactionFormat fmt;
326  std::tuple<AccessorHelper<Args>...> accessors = FormatBuilder<ArgPack<Args...>>::Build(fmt);
327 
328  fmt.rq.request_id = id;
329  fmt.rq.raw_data = new uint8_t[fmt.rq.raw_data_size];
330  fmt.rq.num_buffers = fmt.buffers.size();
331  fmt.rq.buffers = fmt.buffers.data();
332  fmt.rq.objects = new ipc_object_t[fmt.rq.num_objects];
333  fmt.rq.copy_handles = new handle_t[fmt.rq.num_copy_handles];
334  fmt.rq.move_handles = new handle_t[fmt.rq.num_move_handles];
335 
336  fmt.rs.raw_data = new uint8_t[fmt.rs.raw_data_size];
337  fmt.rs.objects = new ipc_object_t[fmt.rs.num_objects];
338  fmt.rs.copy_handles = new handle_t[fmt.rs.num_copy_handles];
339  fmt.rs.move_handles = new handle_t[fmt.rs.num_move_handles];
340  fmt.rs.pid = &fmt.pid;
341 
342  Object::HelpPack(fmt, accessors, std::index_sequence_for<Args...>(), args...);
343 
344  ResultCode r = ipc_send(object, &fmt.rq, &fmt.rs);
345  if(!r.IsOk()) {
346  return tl::make_unexpected(r);
347  }
348 
349  Object::HelpUnpack(fmt, accessors, std::index_sequence_for<Args...>(), args...);
350 
351  return std::nullopt;
352  }
353  private:
354  template<typename... Args, std::size_t... I>
355  static void HelpPack(TransactionFormat &fmt, const std::tuple<AccessorHelper<Args>...> &accessors, std::index_sequence<I...>, Args &... args) {
356  ((std::get<I>(accessors).Pack(fmt, args)),...);
357  }
358 
359  template<typename... Args, std::size_t... I>
360  static void HelpUnpack(TransactionFormat &fmt, const std::tuple<AccessorHelper<Args>...> &accessors, std::index_sequence<I...>, Args &... args) {
361  ((std::get<I>(accessors).Unpack(fmt, args)),...);
362  }
363 };
364 
365 }
366 }
367 }
IPC (C++ header)
handle_t * copy_handles
Array of num_copy_handles handles to be copied.
Definition: ipc.h:85
ipc_object_t * objects
Array of num_objects objects to be referenced.
Definition: ipc.h:87
size_t raw_data_size
size in bytes of raw_data
Definition: ipc.h:152
ipc_buffer_t ** buffers
This should point to an array of num_buffers buffers.
Definition: ipc.h:77
size_t raw_data_size
Size in bytes of raw_data.
Definition: ipc.h:80
Definition: ipcclient.hpp:22
ipc_request_t ipc_default_request
An IPC request with default values set.
Definition: ipc.hpp:45
Definition: ipc.hpp:139
Definition: ipc.hpp:28
Definition: ipcclient.hpp:292
ipc_response_fmt_t ipc_default_response_fmt
An IPC response format with default values set.
Definition: ipc.hpp:62
Definition: ipcclient.hpp:310
Represents either an object within an IPC domain or a standalone object.
Definition: ipc.h:32
handle_t * move_handles
Array of num_move_handles handles to be moved.
Definition: ipc.h:86
Describes format expectations for an incoming IPC response.
Definition: ipc.h:144
Definition: types.hpp:13
result_t ipc_send(ipc_object_t object, ipc_request_t *rq, ipc_response_fmt_t *rs)
Send a request described by rq to object and then unpack the response.
uint32_t handle_t
Resource handle.
Definition: types.h:38
Definition: ipc.hpp:127
Definition: ipc.hpp:65
Represents an unmarshalled outgoing IPC request.
Definition: ipc.h:74
Buffer for transfer over IPC.
Definition: ipc.h:62
Definition: ipcclient.hpp:198
Definition: ipcclient.hpp:34
Definition: ipcclient.hpp:24
Definition: ipc.hpp:34
Interprocess Communication data structures and functions.
uint64_t size
Size in bytes.
Definition: ipc.h:64
Definition: ipc.hpp:89
Definition: ipc.hpp:135
Definition: ipc.hpp:22
Definition: ipc.hpp:61