1use fidl::{AsHandleRef, Peered, SocketOpts};
6use fidl_fuchsia_fdomain as proto;
7
8pub trait HandleType:
12 Sync + Sized + Into<fidl::NullableHandle> + fidl::AsHandleRef + 'static
13{
14 fn object_type(&self) -> fidl::ObjectType;
17
18 fn expected_type(&self, expected_type: fidl::ObjectType) -> Result<(), proto::Error> {
20 if expected_type == self.object_type() {
21 Ok(())
22 } else {
23 Err(proto::Error::WrongHandleType(proto::WrongHandleType {
24 expected: expected_type,
25 got: self.object_type(),
26 }))
27 }
28 }
29
30 fn socket_disposition(
32 &self,
33 _disposition: proto::SocketDisposition,
34 _disposition_peer: proto::SocketDisposition,
35 ) -> Result<(), proto::Error> {
36 self.expected_type(fidl::ObjectType::SOCKET)
37 }
38
39 fn read_socket(&self, _max_bytes: u64) -> Result<Option<Vec<u8>>, proto::Error> {
41 Err(self.expected_type(fidl::ObjectType::SOCKET).unwrap_err())
42 }
43
44 fn read_channel(&self) -> Result<Option<fidl::MessageBufEtc>, proto::Error> {
46 Err(self.expected_type(fidl::ObjectType::CHANNEL).unwrap_err())
47 }
48
49 fn write_socket(&self, _data: &[u8]) -> Result<usize, proto::Error> {
51 Err(self.expected_type(fidl::ObjectType::SOCKET).unwrap_err())
52 }
53
54 fn write_channel(
56 &self,
57 _data: &[u8],
58 _handles: &mut Vec<fidl::HandleDisposition<'static>>,
59 ) -> Option<Result<(), proto::WriteChannelError>> {
60 Some(Err(proto::WriteChannelError::Error(
61 self.expected_type(fidl::ObjectType::CHANNEL).unwrap_err(),
62 )))
63 }
64}
65
66impl HandleType for fidl::Socket {
67 fn object_type(&self) -> fidl::ObjectType {
68 fidl::ObjectType::SOCKET
69 }
70
71 #[cfg(not(target_os = "fuchsia"))]
72 fn socket_disposition(
73 &self,
74 _disposition: proto::SocketDisposition,
75 _disposition_peer: proto::SocketDisposition,
76 ) -> Result<(), proto::Error> {
77 Err(proto::Error::TargetError(fidl::Status::NOT_SUPPORTED.into_raw()))
78 }
79
80 #[cfg(target_os = "fuchsia")]
81 fn socket_disposition(
82 &self,
83 disposition: proto::SocketDisposition,
84 disposition_peer: proto::SocketDisposition,
85 ) -> Result<(), proto::Error> {
86 fn map_disposition(
87 disposition: proto::SocketDisposition,
88 ) -> Result<Option<zx::SocketWriteDisposition>, proto::Error> {
89 match disposition {
90 proto::SocketDisposition::NoChange => Ok(None),
91 proto::SocketDisposition::WriteDisabled => {
92 Ok(Some(zx::SocketWriteDisposition::Disabled))
93 }
94 proto::SocketDisposition::WriteEnabled => {
95 Ok(Some(zx::SocketWriteDisposition::Enabled))
96 }
97 disposition => {
98 Err(proto::Error::SocketDispositionUnknown(proto::SocketDispositionUnknown {
99 disposition,
100 }))
101 }
102 }
103 }
104
105 self.set_disposition(map_disposition(disposition)?, map_disposition(disposition_peer)?)
106 .map_err(|e| proto::Error::TargetError(e.into_raw()))
107 }
108
109 fn read_socket(&self, max_bytes: u64) -> Result<Option<Vec<u8>>, proto::Error> {
110 let max_bytes = max_bytes.try_into().unwrap_or(usize::MAX);
111 let mut buf = Vec::with_capacity(max_bytes);
112 #[cfg(target_os = "fuchsia")]
115 let read = unsafe {
116 let buf_ptr = buf.spare_capacity_mut();
117 let buf_ptr = buf_ptr.as_mut_ptr().cast::<u8>();
118 self.read_raw(buf_ptr, max_bytes)
119 };
120 #[cfg(not(target_os = "fuchsia"))]
121 let read = {
122 buf.resize(max_bytes, 0);
123 self.read(&mut buf)
124 };
125 match read {
126 Ok(size) => {
127 #[cfg(target_os = "fuchsia")]
130 unsafe {
131 buf.set_len(size);
132 }
133 #[cfg(not(target_os = "fuchsia"))]
134 buf.truncate(size);
135 Ok(Some(buf))
136 }
137 Err(fidl::Status::SHOULD_WAIT) => Ok(None),
138 Err(other) => Err(proto::Error::TargetError(other.into_raw())),
139 }
140 }
141
142 fn write_socket(&self, data: &[u8]) -> Result<usize, proto::Error> {
143 let mut wrote = 0;
144 loop {
145 match self.write(&data[wrote..]) {
146 Ok(count) => {
147 wrote += count;
148
149 if wrote >= data.len() {
150 break Ok(wrote);
151 }
152 }
153 Err(fidl::Status::SHOULD_WAIT) => break Ok(wrote),
154
155 Err(other) => break Err(proto::Error::TargetError(other.into_raw())),
156 }
157 }
158 }
159}
160
161impl HandleType for fidl::Channel {
162 fn object_type(&self) -> fidl::ObjectType {
163 fidl::ObjectType::CHANNEL
164 }
165
166 fn read_channel(&self) -> Result<Option<fidl::MessageBufEtc>, proto::Error> {
167 let mut buf = fidl::MessageBufEtc::new();
168 match self.read_etc(&mut buf) {
169 Err(fidl::Status::SHOULD_WAIT) => Ok(None),
170 other => other.map(|_| Some(buf)).map_err(|e| proto::Error::TargetError(e.into_raw())),
171 }
172 }
173
174 fn write_channel(
175 &self,
176 data: &[u8],
177 handles: &mut Vec<fidl::HandleDisposition<'static>>,
178 ) -> Option<Result<(), proto::WriteChannelError>> {
179 match self.write_etc(data, handles) {
180 Ok(()) => Some(Ok(())),
181 Err(fidl::Status::SHOULD_WAIT) => None,
182 Err(other) => {
183 if handles.iter().any(|x| x.result != fidl::Status::OK) {
184 Some(Err(proto::WriteChannelError::OpErrors(
185 handles
186 .iter_mut()
187 .map(|x| {
188 Result::from(x.result)
189 .err()
190 .map(|e| Box::new(proto::Error::TargetError(e.into_raw())))
191 })
192 .collect(),
193 )))
194 } else {
195 Some(Err(proto::WriteChannelError::Error(proto::Error::TargetError(
196 other.into_raw(),
197 ))))
198 }
199 }
200 }
201 }
202}
203
204impl HandleType for fidl::EventPair {
205 fn object_type(&self) -> fidl::ObjectType {
206 fidl::ObjectType::EVENTPAIR
207 }
208}
209
210impl HandleType for fidl::Event {
211 fn object_type(&self) -> fidl::ObjectType {
212 fidl::ObjectType::EVENT
213 }
214}
215
216pub struct Unknown(pub fidl::NullableHandle, pub fidl::ObjectType);
217
218impl Into<fidl::NullableHandle> for Unknown {
219 fn into(self) -> fidl::NullableHandle {
220 self.0
221 }
222}
223
224impl fidl::AsHandleRef for Unknown {
225 fn as_handle_ref(&self) -> fidl::HandleRef<'_> {
226 self.0.as_handle_ref()
227 }
228}
229
230impl HandleType for Unknown {
231 fn object_type(&self) -> fidl::ObjectType {
232 self.1
233 }
234}
235
236pub enum AnyHandle {
237 Socket(fidl::Socket),
238 EventPair(fidl::EventPair),
239 Event(fidl::Event),
240 Channel(fidl::Channel),
241 Unknown(Unknown),
242}
243
244#[derive(Debug, Copy, Clone, PartialEq, Eq)]
246pub(crate) enum IsDatagramSocket {
247 NotDatagram,
248 Datagram,
249 Unknown,
250}
251
252impl IsDatagramSocket {
253 pub fn is_datagram(&self) -> bool {
254 matches!(self, IsDatagramSocket::Datagram)
255 }
256}
257
258impl AnyHandle {
259 pub(crate) fn write_signals(&self) -> fidl::Signals {
261 let sock_signals = if let AnyHandle::Socket(_) = self {
262 fidl::Signals::SOCKET_WRITE_DISABLED
263 } else {
264 fidl::Signals::empty()
265 };
266
267 sock_signals | fidl::Signals::OBJECT_WRITABLE | fidl::Signals::OBJECT_PEER_CLOSED
268 }
269
270 pub(crate) fn read_signals(&self) -> fidl::Signals {
272 let sock_signals = if let AnyHandle::Socket(_) = self {
273 fidl::Signals::SOCKET_PEER_WRITE_DISABLED
274 } else {
275 fidl::Signals::empty()
276 };
277
278 sock_signals | fidl::Signals::OBJECT_READABLE | fidl::Signals::OBJECT_PEER_CLOSED
279 }
280
281 pub(crate) fn is_datagram_socket(&self) -> IsDatagramSocket {
283 let AnyHandle::Socket(socket) = self else {
284 return IsDatagramSocket::NotDatagram;
285 };
286
287 let Ok(info) = socket.info() else {
288 return IsDatagramSocket::Unknown;
289 };
290
291 if info.options == SocketOpts::DATAGRAM {
292 IsDatagramSocket::Datagram
293 } else {
294 IsDatagramSocket::NotDatagram
295 }
296 }
297
298 pub fn duplicate(&self, rights: fidl::Rights) -> Result<AnyHandle, proto::Error> {
300 let handle = self
301 .as_handle_ref()
302 .duplicate_handle(rights)
303 .map_err(|e| proto::Error::TargetError(e.into_raw()))?;
304
305 Ok(match self {
306 AnyHandle::Socket(_) => AnyHandle::Socket(fidl::Socket::from(handle)),
307 AnyHandle::EventPair(_) => AnyHandle::EventPair(fidl::EventPair::from(handle)),
308 AnyHandle::Event(_) => AnyHandle::Event(fidl::Event::from(handle)),
309 AnyHandle::Channel(_) => AnyHandle::Channel(fidl::Channel::from(handle)),
310 AnyHandle::Unknown(Unknown(_, ty)) => AnyHandle::Unknown(Unknown(handle, *ty)),
311 })
312 }
313
314 #[cfg(not(target_os = "fuchsia"))]
316 pub fn replace(self, _rights: fidl::Rights) -> Result<AnyHandle, proto::Error> {
317 Err(proto::Error::TargetError(fidl::Status::NOT_SUPPORTED.into_raw()))
318 }
319
320 #[cfg(target_os = "fuchsia")]
322 pub fn replace(self, rights: fidl::Rights) -> Result<AnyHandle, proto::Error> {
323 Ok(match self {
324 AnyHandle::Socket(h) => AnyHandle::Socket(
325 h.replace_handle(rights).map_err(|e| proto::Error::TargetError(e.into_raw()))?,
326 ),
327 AnyHandle::EventPair(h) => AnyHandle::EventPair(
328 h.replace_handle(rights).map_err(|e| proto::Error::TargetError(e.into_raw()))?,
329 ),
330 AnyHandle::Event(h) => AnyHandle::Event(
331 h.replace_handle(rights).map_err(|e| proto::Error::TargetError(e.into_raw()))?,
332 ),
333 AnyHandle::Channel(h) => AnyHandle::Channel(
334 h.replace_handle(rights).map_err(|e| proto::Error::TargetError(e.into_raw()))?,
335 ),
336 AnyHandle::Unknown(Unknown(h, ty)) => AnyHandle::Unknown(Unknown(
337 h.replace_handle(rights).map_err(|e| proto::Error::TargetError(e.into_raw()))?,
338 ty,
339 )),
340 })
341 }
342
343 pub fn signal(&self, clear: fidl::Signals, set: fidl::Signals) -> Result<(), proto::Error> {
344 match self {
345 AnyHandle::Socket(s) => s.signal(clear, set),
346 AnyHandle::EventPair(e) => e.signal(clear, set),
347 AnyHandle::Event(e) => e.signal(clear, set),
348 AnyHandle::Channel(c) => c.signal(clear, set),
349 AnyHandle::Unknown(u) => u.0.signal(clear, set),
350 }
351 .map_err(|e| proto::Error::TargetError(e.into_raw()))
352 }
353
354 pub fn signal_peer(
355 &self,
356 clear: fidl::Signals,
357 set: fidl::Signals,
358 ) -> Result<(), proto::Error> {
359 match self {
365 AnyHandle::Socket(h) => h.signal_peer(clear, set),
366 AnyHandle::EventPair(h) => h.signal_peer(clear, set),
367 AnyHandle::Event(_) => Err(fidl::Status::INVALID_ARGS),
368 AnyHandle::Channel(h) => h.signal_peer(clear, set),
369 AnyHandle::Unknown(_) => Err(fidl::Status::INVALID_ARGS),
370 }
371 .map_err(|e| proto::Error::TargetError(e.into_raw()))
372 }
373}
374
375impl From<fidl::Channel> for AnyHandle {
376 fn from(other: fidl::Channel) -> AnyHandle {
377 AnyHandle::Channel(other)
378 }
379}
380
381impl From<fidl::Socket> for AnyHandle {
382 fn from(other: fidl::Socket) -> AnyHandle {
383 AnyHandle::Socket(other)
384 }
385}
386
387impl From<fidl::EventPair> for AnyHandle {
388 fn from(other: fidl::EventPair) -> AnyHandle {
389 AnyHandle::EventPair(other)
390 }
391}
392
393impl From<fidl::Event> for AnyHandle {
394 fn from(other: fidl::Event) -> AnyHandle {
395 AnyHandle::Event(other)
396 }
397}
398
399macro_rules! impl_method {
400 ($this:ident => $h:ident . $meth:ident ( $($args:tt)* )) => {
401 match $this {
402 AnyHandle::Socket($h) => $h.$meth($($args)*),
403 AnyHandle::EventPair($h) => $h.$meth($($args)*),
404 AnyHandle::Event($h) => $h.$meth($($args)*),
405 AnyHandle::Channel($h) => $h.$meth($($args)*),
406 AnyHandle::Unknown($h) => $h.$meth($($args)*),
407 }
408 };
409}
410
411impl HandleType for AnyHandle {
412 fn object_type(&self) -> fidl::ObjectType {
413 impl_method!(self => h.object_type())
414 }
415
416 fn socket_disposition(
417 &self,
418 disposition: proto::SocketDisposition,
419 disposition_peer: proto::SocketDisposition,
420 ) -> Result<(), proto::Error> {
421 impl_method!(self => h.socket_disposition(disposition, disposition_peer))
422 }
423
424 fn read_socket(&self, max_bytes: u64) -> Result<Option<Vec<u8>>, proto::Error> {
425 impl_method!(self => h.read_socket(max_bytes))
426 }
427
428 fn read_channel(&self) -> Result<Option<fidl::MessageBufEtc>, proto::Error> {
429 impl_method!(self => h.read_channel())
430 }
431
432 fn write_socket(&self, data: &[u8]) -> Result<usize, proto::Error> {
433 impl_method!(self => h.write_socket(data))
434 }
435
436 fn write_channel(
437 &self,
438 data: &[u8],
439 handles: &mut Vec<fidl::HandleDisposition<'static>>,
440 ) -> Option<Result<(), proto::WriteChannelError>> {
441 impl_method!(self => h.write_channel(data, handles))
442 }
443}
444
445impl fidl::AsHandleRef for AnyHandle {
446 fn as_handle_ref(&self) -> fidl::HandleRef<'_> {
447 impl_method!(self => h.as_handle_ref())
448 }
449}
450
451impl Into<fidl::NullableHandle> for AnyHandle {
452 fn into(self) -> fidl::NullableHandle {
453 impl_method!(self => h.into())
454 }
455}