fidl/endpoints.rs
1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Wrapper types for the endpoints of a connection.
6
7use crate::epitaph::ChannelEpitaphExt;
8use crate::{
9 AsHandleRef, AsyncChannel, Channel, Epitaph, Error, HandleRef, NullableHandle, OnSignalsRef,
10 ServeInner,
11};
12use futures::{Stream, TryStream};
13use std::marker::PhantomData;
14use std::sync::Arc;
15
16/// A marker for a particular FIDL protocol.
17///
18/// Implementations of this trait can be used to manufacture instances of a FIDL
19/// protocol and get metadata about a particular protocol.
20pub trait ProtocolMarker: Sized + Send + Sync + 'static {
21 /// The type of the structure against which FIDL requests are made.
22 /// Queries made against the proxy are sent to the paired `ServerEnd`.
23 type Proxy: Proxy<Protocol = Self>;
24
25 /// The type of the structure against which thread-blocking FIDL requests are made.
26 /// Queries made against the proxy are sent to the paired `ServerEnd`.
27 #[cfg(target_os = "fuchsia")]
28 type SynchronousProxy: SynchronousProxy<Protocol = Self>;
29
30 /// The type of the stream of requests coming into a server.
31 type RequestStream: RequestStream<Protocol = Self>;
32
33 /// The name of the protocol suitable for debug purposes.
34 ///
35 /// For discoverable protocols, this should be identical to
36 /// `<Self as DiscoverableProtocolMarker>::PROTOCOL_NAME`.
37 const DEBUG_NAME: &'static str;
38}
39
40/// A marker for a particular FIDL protocol that is also discoverable.
41///
42/// Discoverable protocols may be referred to by a string name, and can be
43/// conveniently exported in a service directory via an entry of that name.
44///
45/// If you get an error about this trait not being implemented, you probably
46/// need to add the `@discoverable` attribute to the FIDL protocol, like this:
47///
48/// ```fidl
49/// @discoverable
50/// protocol MyProtocol { ... };
51/// ```
52pub trait DiscoverableProtocolMarker: ProtocolMarker {
53 /// The name of the protocol (to be used for service lookup and discovery).
54 const PROTOCOL_NAME: &'static str = <Self as ProtocolMarker>::DEBUG_NAME;
55}
56
57/// A type which allows querying a remote FIDL server over a channel.
58pub trait Proxy: Sized + Send + Sync {
59 /// The protocol which this `Proxy` controls.
60 type Protocol: ProtocolMarker<Proxy = Self>;
61
62 /// Create a proxy over the given channel.
63 fn from_channel(inner: AsyncChannel) -> Self;
64
65 /// Attempt to convert the proxy back into a channel.
66 ///
67 /// This will only succeed if there are no active clones of this proxy
68 /// and no currently-alive `EventStream` or response futures that came from
69 /// this proxy.
70 fn into_channel(self) -> Result<AsyncChannel, Self>;
71
72 /// Attempt to convert the proxy back into a client end.
73 ///
74 /// This will only succeed if there are no active clones of this proxy
75 /// and no currently-alive `EventStream` or response futures that came from
76 /// this proxy.
77 fn into_client_end(self) -> Result<ClientEnd<Self::Protocol>, Self> {
78 match self.into_channel() {
79 Ok(channel) => Ok(ClientEnd::new(channel.into_zx_channel())),
80 Err(proxy) => Err(proxy),
81 }
82 }
83
84 /// Get a reference to the proxy's underlying channel.
85 ///
86 /// This should only be used for non-effectful operations. Reading or
87 /// writing to the channel is unsafe because the proxy assumes it has
88 /// exclusive control over these operations.
89 fn as_channel(&self) -> &AsyncChannel;
90
91 /// Returns true if the proxy has received the `PEER_CLOSED` signal.
92 fn is_closed(&self) -> bool {
93 self.as_channel().is_closed()
94 }
95
96 /// Returns a future that completes when the proxy receives the
97 /// `PEER_CLOSED` signal.
98 fn on_closed(&self) -> OnSignalsRef<'_> {
99 self.as_channel().on_closed()
100 }
101}
102
103/// This gives native Zircon proxies a domain method like FDomain proxies have.
104/// This makes it easier in some cases to build the same code for both FDomain
105/// and regular FIDL.
106pub trait ProxyHasDomain {
107 /// Get a "client" for this proxy. This is just an object which has methods
108 /// for a few common handle creation operations.
109 fn domain(&self) -> ZirconClient {
110 ZirconClient
111 }
112}
113
114impl<T: Proxy> ProxyHasDomain for T {}
115
116/// The fake "client" produced by `ProxyHasDomain`. Analogous to an FDomain client.
117pub struct ZirconClient;
118
119impl ZirconClient {
120 /// Equivalent to [`EventPair::create`]
121 pub fn create_event_pair(&self) -> (crate::EventPair, crate::EventPair) {
122 crate::EventPair::create()
123 }
124
125 /// Equivalent to [`Event::create`]
126 pub fn create_event(&self) -> crate::Event {
127 crate::Event::create()
128 }
129
130 /// Equivalent to [`Socket::create_stream`]
131 pub fn create_stream_socket(&self) -> (crate::Socket, crate::Socket) {
132 crate::Socket::create_stream()
133 }
134
135 /// Equivalent to [`Socket::create_datagram`]
136 pub fn create_datagram_socket(&self) -> (crate::Socket, crate::Socket) {
137 crate::Socket::create_datagram()
138 }
139
140 /// Equivalent to [`Channel::create`]
141 pub fn create_channel(&self) -> (Channel, Channel) {
142 Channel::create()
143 }
144
145 /// Equivalent to the module level [`create_endpoints`]
146 pub fn create_endpoints<T: ProtocolMarker>(&self) -> (ClientEnd<T>, ServerEnd<T>) {
147 create_endpoints::<T>()
148 }
149
150 /// Equivalent to the module level [`create_proxy`]
151 pub fn create_proxy<T: ProtocolMarker>(&self) -> (T::Proxy, ServerEnd<T>) {
152 create_proxy::<T>()
153 }
154
155 /// Equivalent to the module level [`create_request_stream`]
156 pub fn create_request_stream<T: ProtocolMarker>(&self) -> (ClientEnd<T>, T::RequestStream) {
157 create_request_stream::<T>()
158 }
159
160 /// Equivalent to the module level [`create_proxy_and_stream`]
161 pub fn create_proxy_and_stream<T: ProtocolMarker>(&self) -> (T::Proxy, T::RequestStream) {
162 create_proxy_and_stream::<T>()
163 }
164}
165
166/// A type which allows querying a remote FIDL server over a channel, blocking the calling thread.
167#[cfg(target_os = "fuchsia")]
168pub trait SynchronousProxy: Sized + Send + Sync {
169 /// The async proxy for the same protocol.
170 type Proxy: Proxy<Protocol = Self::Protocol>;
171
172 /// The protocol which this `Proxy` controls.
173 type Protocol: ProtocolMarker<Proxy = Self::Proxy>;
174
175 /// Create a proxy over the given channel.
176 fn from_channel(inner: Channel) -> Self;
177
178 /// Convert the proxy back into a channel.
179 fn into_channel(self) -> Channel;
180
181 /// Get a reference to the proxy's underlying channel.
182 ///
183 /// This should only be used for non-effectful operations. Reading or
184 /// writing to the channel is unsafe because the proxy assumes it has
185 /// exclusive control over these operations.
186 fn as_channel(&self) -> &Channel;
187
188 /// Returns true if the proxy has received the `PEER_CLOSED` signal.
189 ///
190 /// # Errors
191 ///
192 /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
193 /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
194 /// errors are propagated.
195 fn is_closed(&self) -> Result<bool, zx::Status> {
196 use zx::Peered;
197 self.as_channel().is_closed()
198 }
199}
200
201/// A stream of requests coming into a FIDL server over a channel.
202pub trait RequestStream: Sized + Send + Stream + TryStream<Error = crate::Error> + Unpin {
203 /// The protocol which this `RequestStream` serves.
204 type Protocol: ProtocolMarker<RequestStream = Self>;
205
206 /// The control handle for this `RequestStream`.
207 type ControlHandle: ControlHandle;
208
209 /// Returns a copy of the `ControlHandle` for the given stream.
210 /// This handle can be used to send events or shut down the request stream.
211 fn control_handle(&self) -> Self::ControlHandle;
212
213 /// Create a request stream from the given channel.
214 fn from_channel(inner: AsyncChannel) -> Self;
215
216 /// Convert this channel into its underlying components.
217 fn into_inner(self) -> (Arc<ServeInner>, bool);
218
219 /// Create this channel from its underlying components.
220 fn from_inner(inner: Arc<ServeInner>, is_terminated: bool) -> Self;
221
222 /// Convert this FIDL request stream into a request stream of another FIDL protocol.
223 fn cast_stream<T: RequestStream>(self) -> T {
224 let inner = self.into_inner();
225 T::from_inner(inner.0, inner.1)
226 }
227}
228
229/// The Request type associated with a Marker.
230pub type Request<Marker> = <<Marker as ProtocolMarker>::RequestStream as futures::TryStream>::Ok;
231
232/// A type associated with a `RequestStream` that can be used to send FIDL
233/// events or to shut down the request stream.
234pub trait ControlHandle {
235 /// Set the server to shutdown. The underlying channel is only closed the
236 /// next time the stream is polled.
237 // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
238 fn shutdown(&self);
239
240 /// Sets the server to shutdown with an epitaph. The underlying channel is
241 /// only closed the next time the stream is polled.
242 // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
243 fn shutdown_with_epitaph(&self, status: Epitaph);
244
245 /// Returns true if the server has received the `PEER_CLOSED` signal.
246 fn is_closed(&self) -> bool;
247
248 /// Returns a future that completes when the server receives the
249 /// `PEER_CLOSED` signal.
250 fn on_closed(&self) -> OnSignalsRef<'_>;
251
252 /// Sets and clears the signals provided on peer handle.
253 #[cfg(target_os = "fuchsia")]
254 fn signal_peer(
255 &self,
256 clear_mask: zx::Signals,
257 set_mask: zx::Signals,
258 ) -> Result<(), zx_status::Status>;
259}
260
261/// A type associated with a particular two-way FIDL method, used by servers to
262/// send a response to the client.
263pub trait Responder {
264 /// The control handle for this protocol.
265 type ControlHandle: ControlHandle;
266
267 /// Returns the `ControlHandle` for this protocol.
268 fn control_handle(&self) -> &Self::ControlHandle;
269
270 /// Drops the responder without setting the channel to shutdown.
271 ///
272 /// This method shouldn't normally be used. Instead, send a response to
273 /// prevent the channel from shutting down.
274 fn drop_without_shutdown(self);
275}
276
277/// A marker for a particular FIDL service.
278#[cfg(target_os = "fuchsia")]
279pub trait ServiceMarker: Clone + Sized + Send + Sync + 'static {
280 /// The type of the proxy object upon which calls are made to a remote FIDL service.
281 type Proxy: ServiceProxy<Service = Self>;
282
283 /// The request type for this particular FIDL service.
284 type Request: ServiceRequest<Service = Self>;
285
286 /// The name of the service. Used for service lookup and discovery.
287 const SERVICE_NAME: &'static str;
288}
289
290/// A request to initiate a connection to a FIDL service.
291#[cfg(target_os = "fuchsia")]
292pub trait ServiceRequest: Sized + Send + Sync {
293 /// The FIDL service for which this request is destined.
294 type Service: ServiceMarker<Request = Self>;
295
296 /// Dispatches a connection attempt to this FIDL service's member protocol
297 /// identified by `name`, producing an instance of this trait.
298 fn dispatch(name: &str, channel: AsyncChannel) -> Self;
299
300 /// Returns an array of the service members' names.
301 fn member_names() -> &'static [&'static str];
302}
303
304/// Proxy by which a client sends messages to a FIDL service.
305#[cfg(target_os = "fuchsia")]
306pub trait ServiceProxy: Sized {
307 /// The FIDL service this proxy represents.
308 type Service: ServiceMarker<Proxy = Self>;
309
310 /// Create a proxy from a MemberOpener implementation.
311 #[doc(hidden)]
312 fn from_member_opener(opener: Box<dyn MemberOpener>) -> Self;
313}
314
315/// Used to create an indirection between the fuchsia.io.Directory protocol
316/// and this library, which cannot depend on fuchsia.io.
317#[doc(hidden)]
318#[cfg(target_os = "fuchsia")]
319pub trait MemberOpener: Send + Sync {
320 /// Opens a member protocol of a FIDL service by name, serving that protocol
321 /// on the given channel.
322 fn open_member(&self, member: &str, server_end: Channel) -> Result<(), Error>;
323
324 /// Returns the name of the instance that was opened.
325 fn instance_name(&self) -> &str;
326}
327
328/// The `Client` end of a FIDL connection.
329#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
330pub struct ClientEnd<T> {
331 inner: Channel,
332 phantom: PhantomData<T>,
333}
334
335impl<T> ClientEnd<T> {
336 /// Create a new client from the provided channel.
337 pub fn new(inner: Channel) -> Self {
338 ClientEnd { inner, phantom: PhantomData }
339 }
340
341 /// Get a reference to the underlying channel
342 pub fn channel(&self) -> &Channel {
343 &self.inner
344 }
345
346 /// Extract the underlying channel.
347 pub fn into_channel(self) -> Channel {
348 self.inner
349 }
350}
351
352impl<T: ProtocolMarker> ClientEnd<T> {
353 /// Convert the `ClientEnd` into a `Proxy` through which FIDL calls may be made.
354 ///
355 /// # Panics
356 ///
357 /// If called outside the context of an active async executor.
358 pub fn into_proxy(self) -> T::Proxy {
359 T::Proxy::from_channel(AsyncChannel::from_channel(self.inner))
360 }
361
362 /// Convert the `ClientEnd` into a `SynchronousProxy` through which thread-blocking FIDL calls
363 /// may be made.
364 #[cfg(target_os = "fuchsia")]
365 pub fn into_sync_proxy(self) -> T::SynchronousProxy {
366 T::SynchronousProxy::from_channel(self.inner)
367 }
368}
369
370impl<T> AsHandleRef for ClientEnd<T> {
371 fn as_handle_ref(&self) -> HandleRef<'_> {
372 self.inner.as_handle_ref()
373 }
374}
375
376impl<T> From<ClientEnd<T>> for NullableHandle {
377 fn from(client: ClientEnd<T>) -> NullableHandle {
378 client.into_channel().into()
379 }
380}
381
382impl<T> From<ClientEnd<T>> for Channel {
383 fn from(client: ClientEnd<T>) -> Channel {
384 client.into_channel()
385 }
386}
387
388impl<T> From<NullableHandle> for ClientEnd<T> {
389 fn from(handle: NullableHandle) -> Self {
390 ClientEnd { inner: handle.into(), phantom: PhantomData }
391 }
392}
393
394impl<T> From<Channel> for ClientEnd<T> {
395 fn from(chan: Channel) -> Self {
396 ClientEnd { inner: chan, phantom: PhantomData }
397 }
398}
399
400impl<T: ProtocolMarker> ::std::fmt::Debug for ClientEnd<T> {
401 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
402 write!(f, "ClientEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
403 }
404}
405
406/// Trait implemented by types that can be converted from a client.
407pub trait FromClient {
408 /// The protocol.
409 type Protocol: ProtocolMarker;
410
411 /// Converts from a client.
412 fn from_client(value: ClientEnd<Self::Protocol>) -> Self;
413}
414
415impl<T: ProtocolMarker> FromClient for ClientEnd<T> {
416 type Protocol = T;
417
418 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
419 value
420 }
421}
422
423// NOTE: We can only have one blanket implementation. Synchronous proxies have an implementation
424// that is generated by the compiler.
425impl<T: Proxy> FromClient for T {
426 type Protocol = T::Protocol;
427
428 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
429 Self::from_channel(AsyncChannel::from_channel(value.into_channel()))
430 }
431}
432
433/// The `Server` end of a FIDL connection.
434#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
435pub struct ServerEnd<T> {
436 inner: Channel,
437 phantom: PhantomData<T>,
438}
439
440impl<T> ServerEnd<T> {
441 /// Create a new `ServerEnd` from the provided channel.
442 pub fn new(inner: Channel) -> ServerEnd<T> {
443 ServerEnd { inner, phantom: PhantomData }
444 }
445
446 /// Get a reference to the underlying channel
447 pub fn channel(&self) -> &Channel {
448 &self.inner
449 }
450
451 /// Extract the inner channel.
452 pub fn into_channel(self) -> Channel {
453 self.inner
454 }
455
456 /// Create a stream of requests off of the channel.
457 ///
458 /// # Panics
459 ///
460 /// If called outside the context of an active async executor.
461 pub fn into_stream(self) -> T::RequestStream
462 where
463 T: ProtocolMarker,
464 {
465 T::RequestStream::from_channel(AsyncChannel::from_channel(self.inner))
466 }
467
468 /// Create a stream of requests and an event-sending handle
469 /// from the channel.
470 ///
471 /// # Panics
472 ///
473 /// If called outside the context of an active async executor.
474 pub fn into_stream_and_control_handle(
475 self,
476 ) -> (T::RequestStream, <T::RequestStream as RequestStream>::ControlHandle)
477 where
478 T: ProtocolMarker,
479 {
480 let stream = self.into_stream();
481 let control_handle = stream.control_handle();
482 (stream, control_handle)
483 }
484
485 /// Writes an epitaph into the underlying channel before closing it.
486 pub fn close_with_epitaph(
487 self,
488 status: impl Into<Result<(), zx_status::Status>>,
489 ) -> Result<(), Error> {
490 self.inner.close_with_epitaph(status)
491 }
492}
493
494impl<T> AsHandleRef for ServerEnd<T> {
495 fn as_handle_ref(&self) -> HandleRef<'_> {
496 self.inner.as_handle_ref()
497 }
498}
499
500impl<T> From<ServerEnd<T>> for NullableHandle {
501 fn from(server: ServerEnd<T>) -> NullableHandle {
502 server.into_channel().into()
503 }
504}
505
506impl<T> From<ServerEnd<T>> for Channel {
507 fn from(server: ServerEnd<T>) -> Channel {
508 server.into_channel()
509 }
510}
511
512impl<T> From<NullableHandle> for ServerEnd<T> {
513 fn from(handle: NullableHandle) -> Self {
514 ServerEnd { inner: handle.into(), phantom: PhantomData }
515 }
516}
517
518impl<T> From<Channel> for ServerEnd<T> {
519 fn from(chan: Channel) -> Self {
520 ServerEnd { inner: chan, phantom: PhantomData }
521 }
522}
523
524impl<T: ProtocolMarker> ::std::fmt::Debug for ServerEnd<T> {
525 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
526 write!(f, "ServerEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
527 }
528}
529
530/// Creates client and server endpoints connected to by a channel.
531pub fn create_endpoints<T: ProtocolMarker>() -> (ClientEnd<T>, ServerEnd<T>) {
532 let (client, server) = Channel::create();
533 let client_end = ClientEnd::<T>::new(client);
534 let server_end = ServerEnd::new(server);
535 (client_end, server_end)
536}
537
538/// Create a client proxy and a server endpoint connected to it by a channel.
539///
540/// Useful for sending channel handles to calls that take arguments
541/// of type `server_end:SomeProtocol`
542///
543/// # Panics
544///
545/// If called outside the context of an active async executor.
546pub fn create_proxy<T: ProtocolMarker>() -> (T::Proxy, ServerEnd<T>) {
547 let (client, server) = create_endpoints();
548 (client.into_proxy(), server)
549}
550
551/// Create a synchronous client proxy and a server endpoint connected to it by a channel.
552///
553/// Useful for sending channel handles to calls that take arguments
554/// of type `server_end:SomeProtocol`
555#[cfg(target_os = "fuchsia")]
556pub fn create_sync_proxy<T: ProtocolMarker>() -> (T::SynchronousProxy, ServerEnd<T>) {
557 let (client, server) = create_endpoints();
558 (client.into_sync_proxy(), server)
559}
560
561/// Create a request stream and a client endpoint connected to it by a channel.
562///
563/// Useful for sending channel handles to calls that take arguments
564/// of type `client_end:SomeProtocol`
565///
566/// # Panics
567///
568/// If called outside the context of an active async executor.
569pub fn create_request_stream<T: ProtocolMarker>() -> (ClientEnd<T>, T::RequestStream) {
570 let (client, server) = create_endpoints();
571 (client, server.into_stream())
572}
573
574/// Create a request stream and proxy connected to one another.
575///
576/// Useful for testing where both the request stream and proxy are
577/// used in the same process.
578///
579/// # Panics
580///
581/// If called outside the context of an active async executor.
582pub fn create_proxy_and_stream<T: ProtocolMarker>() -> (T::Proxy, T::RequestStream) {
583 let (client, server) = create_endpoints::<T>();
584 (client.into_proxy(), server.into_stream())
585}
586
587/// Create a request stream and synchronous proxy connected to one another.
588///
589/// Useful for testing where both the request stream and proxy are
590/// used in the same process.
591///
592/// # Panics
593///
594/// If called outside the context of an active async executor.
595#[cfg(target_os = "fuchsia")]
596pub fn create_sync_proxy_and_stream<T: ProtocolMarker>() -> (T::SynchronousProxy, T::RequestStream)
597{
598 let (client, server) = create_endpoints::<T>();
599 (client.into_sync_proxy(), server.into_stream())
600}
601
602/// The type of a client-initiated method.
603#[derive(Copy, Clone, Debug)]
604pub enum MethodType {
605 /// One-way method, also known as fire-and-forget.
606 OneWay,
607 /// Two-way method.
608 TwoWay,
609}