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