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, Error, HandleBased, HandleRef, NullableHandle,
10 OnSignalsRef, 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: zx_status::Status);
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
406impl<T> HandleBased for ClientEnd<T> {}
407
408/// Trait implemented by types that can be converted from a client.
409pub trait FromClient {
410 /// The protocol.
411 type Protocol: ProtocolMarker;
412
413 /// Converts from a client.
414 fn from_client(value: ClientEnd<Self::Protocol>) -> Self;
415}
416
417impl<T: ProtocolMarker> FromClient for ClientEnd<T> {
418 type Protocol = T;
419
420 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
421 value
422 }
423}
424
425// NOTE: We can only have one blanket implementation. Synchronous proxies have an implementation
426// that is generated by the compiler.
427impl<T: Proxy> FromClient for T {
428 type Protocol = T::Protocol;
429
430 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
431 Self::from_channel(AsyncChannel::from_channel(value.into_channel()))
432 }
433}
434
435/// The `Server` end of a FIDL connection.
436#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
437pub struct ServerEnd<T> {
438 inner: Channel,
439 phantom: PhantomData<T>,
440}
441
442impl<T> ServerEnd<T> {
443 /// Create a new `ServerEnd` from the provided channel.
444 pub fn new(inner: Channel) -> ServerEnd<T> {
445 ServerEnd { inner, phantom: PhantomData }
446 }
447
448 /// Get a reference to the underlying channel
449 pub fn channel(&self) -> &Channel {
450 &self.inner
451 }
452
453 /// Extract the inner channel.
454 pub fn into_channel(self) -> Channel {
455 self.inner
456 }
457
458 /// Create a stream of requests off of the channel.
459 ///
460 /// # Panics
461 ///
462 /// If called outside the context of an active async executor.
463 pub fn into_stream(self) -> T::RequestStream
464 where
465 T: ProtocolMarker,
466 {
467 T::RequestStream::from_channel(AsyncChannel::from_channel(self.inner))
468 }
469
470 /// Create a stream of requests and an event-sending handle
471 /// from the channel.
472 ///
473 /// # Panics
474 ///
475 /// If called outside the context of an active async executor.
476 pub fn into_stream_and_control_handle(
477 self,
478 ) -> (T::RequestStream, <T::RequestStream as RequestStream>::ControlHandle)
479 where
480 T: ProtocolMarker,
481 {
482 let stream = self.into_stream();
483 let control_handle = stream.control_handle();
484 (stream, control_handle)
485 }
486
487 /// Writes an epitaph into the underlying channel before closing it.
488 pub fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
489 self.inner.close_with_epitaph(status)
490 }
491}
492
493impl<T> AsHandleRef for ServerEnd<T> {
494 fn as_handle_ref(&self) -> HandleRef<'_> {
495 self.inner.as_handle_ref()
496 }
497}
498
499impl<T> From<ServerEnd<T>> for NullableHandle {
500 fn from(server: ServerEnd<T>) -> NullableHandle {
501 server.into_channel().into()
502 }
503}
504
505impl<T> From<ServerEnd<T>> for Channel {
506 fn from(server: ServerEnd<T>) -> Channel {
507 server.into_channel()
508 }
509}
510
511impl<T> From<NullableHandle> for ServerEnd<T> {
512 fn from(handle: NullableHandle) -> Self {
513 ServerEnd { inner: handle.into(), phantom: PhantomData }
514 }
515}
516
517impl<T> From<Channel> for ServerEnd<T> {
518 fn from(chan: Channel) -> Self {
519 ServerEnd { inner: chan, phantom: PhantomData }
520 }
521}
522
523impl<T: ProtocolMarker> ::std::fmt::Debug for ServerEnd<T> {
524 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
525 write!(f, "ServerEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
526 }
527}
528
529impl<T> HandleBased for ServerEnd<T> {}
530
531/// Creates client and server endpoints connected to by a channel.
532pub fn create_endpoints<T: ProtocolMarker>() -> (ClientEnd<T>, ServerEnd<T>) {
533 let (client, server) = Channel::create();
534 let client_end = ClientEnd::<T>::new(client);
535 let server_end = ServerEnd::new(server);
536 (client_end, server_end)
537}
538
539/// Create a client proxy and a server endpoint connected to it by a channel.
540///
541/// Useful for sending channel handles to calls that take arguments
542/// of type `server_end:SomeProtocol`
543///
544/// # Panics
545///
546/// If called outside the context of an active async executor.
547pub fn create_proxy<T: ProtocolMarker>() -> (T::Proxy, ServerEnd<T>) {
548 let (client, server) = create_endpoints();
549 (client.into_proxy(), server)
550}
551
552/// Create a synchronous client proxy and a server endpoint connected to it by a channel.
553///
554/// Useful for sending channel handles to calls that take arguments
555/// of type `server_end:SomeProtocol`
556#[cfg(target_os = "fuchsia")]
557pub fn create_sync_proxy<T: ProtocolMarker>() -> (T::SynchronousProxy, ServerEnd<T>) {
558 let (client, server) = create_endpoints();
559 (client.into_sync_proxy(), server)
560}
561
562/// Create a request stream and a client endpoint connected to it by a channel.
563///
564/// Useful for sending channel handles to calls that take arguments
565/// of type `client_end:SomeProtocol`
566///
567/// # Panics
568///
569/// If called outside the context of an active async executor.
570pub fn create_request_stream<T: ProtocolMarker>() -> (ClientEnd<T>, T::RequestStream) {
571 let (client, server) = create_endpoints();
572 (client, server.into_stream())
573}
574
575/// Create a request stream and proxy connected to one another.
576///
577/// Useful for testing where both the request stream and proxy are
578/// used in the same process.
579///
580/// # Panics
581///
582/// If called outside the context of an active async executor.
583pub fn create_proxy_and_stream<T: ProtocolMarker>() -> (T::Proxy, T::RequestStream) {
584 let (client, server) = create_endpoints::<T>();
585 (client.into_proxy(), server.into_stream())
586}
587
588/// Create a request stream and synchronous proxy connected to one another.
589///
590/// Useful for testing where both the request stream and proxy are
591/// used in the same process.
592///
593/// # Panics
594///
595/// If called outside the context of an active async executor.
596#[cfg(target_os = "fuchsia")]
597pub fn create_sync_proxy_and_stream<T: ProtocolMarker>() -> (T::SynchronousProxy, T::RequestStream)
598{
599 let (client, server) = create_endpoints::<T>();
600 (client.into_sync_proxy(), server.into_stream())
601}
602
603/// The type of a client-initiated method.
604#[derive(Copy, Clone, Debug)]
605pub enum MethodType {
606 /// One-way method, also known as fire-and-forget.
607 OneWay,
608 /// Two-way method.
609 TwoWay,
610}