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