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, Handle, HandleBased, HandleRef, 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
156/// A type which allows querying a remote FIDL server over a channel, blocking the calling thread.
157#[cfg(target_os = "fuchsia")]
158pub trait SynchronousProxy: Sized + Send + Sync {
159 /// The async proxy for the same protocol.
160 type Proxy: Proxy<Protocol = Self::Protocol>;
161
162 /// The protocol which this `Proxy` controls.
163 type Protocol: ProtocolMarker<Proxy = Self::Proxy>;
164
165 /// Create a proxy over the given channel.
166 fn from_channel(inner: Channel) -> Self;
167
168 /// Convert the proxy back into a channel.
169 fn into_channel(self) -> Channel;
170
171 /// Get a reference to the proxy's underlying channel.
172 ///
173 /// This should only be used for non-effectful operations. Reading or
174 /// writing to the channel is unsafe because the proxy assumes it has
175 /// exclusive control over these operations.
176 fn as_channel(&self) -> &Channel;
177
178 /// Returns true if the proxy has received the `PEER_CLOSED` signal.
179 ///
180 /// # Errors
181 ///
182 /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
183 /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
184 /// errors are propagated.
185 fn is_closed(&self) -> Result<bool, zx::Status> {
186 use zx::Peered;
187 self.as_channel().is_closed()
188 }
189}
190
191/// A stream of requests coming into a FIDL server over a channel.
192pub trait RequestStream: Sized + Send + Stream + TryStream<Error = crate::Error> + Unpin {
193 /// The protocol which this `RequestStream` serves.
194 type Protocol: ProtocolMarker<RequestStream = Self>;
195
196 /// The control handle for this `RequestStream`.
197 type ControlHandle: ControlHandle;
198
199 /// Returns a copy of the `ControlHandle` for the given stream.
200 /// This handle can be used to send events or shut down the request stream.
201 fn control_handle(&self) -> Self::ControlHandle;
202
203 /// Create a request stream from the given channel.
204 fn from_channel(inner: AsyncChannel) -> Self;
205
206 /// Convert this channel into its underlying components.
207 fn into_inner(self) -> (Arc<ServeInner>, bool);
208
209 /// Create this channel from its underlying components.
210 fn from_inner(inner: Arc<ServeInner>, is_terminated: bool) -> Self;
211
212 /// Convert this FIDL request stream into a request stream of another FIDL protocol.
213 fn cast_stream<T: RequestStream>(self) -> T {
214 let inner = self.into_inner();
215 T::from_inner(inner.0, inner.1)
216 }
217}
218
219/// The Request type associated with a Marker.
220pub type Request<Marker> = <<Marker as ProtocolMarker>::RequestStream as futures::TryStream>::Ok;
221
222/// A type associated with a `RequestStream` that can be used to send FIDL
223/// events or to shut down the request stream.
224pub trait ControlHandle {
225 /// Set the server to shutdown. The underlying channel is only closed the
226 /// next time the stream is polled.
227 // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
228 fn shutdown(&self);
229
230 /// Sets the server to shutdown with an epitaph. The underlying channel is
231 /// only closed the next time the stream is polled.
232 // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
233 fn shutdown_with_epitaph(&self, status: zx_status::Status);
234
235 /// Returns true if the server has received the `PEER_CLOSED` signal.
236 fn is_closed(&self) -> bool;
237
238 /// Returns a future that completes when the server receives the
239 /// `PEER_CLOSED` signal.
240 fn on_closed(&self) -> OnSignalsRef<'_>;
241
242 /// Sets and clears the signals provided on peer handle.
243 #[cfg(target_os = "fuchsia")]
244 fn signal_peer(
245 &self,
246 clear_mask: zx::Signals,
247 set_mask: zx::Signals,
248 ) -> Result<(), zx_status::Status>;
249}
250
251/// A type associated with a particular two-way FIDL method, used by servers to
252/// send a response to the client.
253pub trait Responder {
254 /// The control handle for this protocol.
255 type ControlHandle: ControlHandle;
256
257 /// Returns the `ControlHandle` for this protocol.
258 fn control_handle(&self) -> &Self::ControlHandle;
259
260 /// Drops the responder without setting the channel to shutdown.
261 ///
262 /// This method shouldn't normally be used. Instead, send a response to
263 /// prevent the channel from shutting down.
264 fn drop_without_shutdown(self);
265}
266
267/// A marker for a particular FIDL service.
268#[cfg(target_os = "fuchsia")]
269pub trait ServiceMarker: Clone + Sized + Send + Sync + 'static {
270 /// The type of the proxy object upon which calls are made to a remote FIDL service.
271 type Proxy: ServiceProxy<Service = Self>;
272
273 /// The request type for this particular FIDL service.
274 type Request: ServiceRequest<Service = Self>;
275
276 /// The name of the service. Used for service lookup and discovery.
277 const SERVICE_NAME: &'static str;
278}
279
280/// A request to initiate a connection to a FIDL service.
281#[cfg(target_os = "fuchsia")]
282pub trait ServiceRequest: Sized + Send + Sync {
283 /// The FIDL service for which this request is destined.
284 type Service: ServiceMarker<Request = Self>;
285
286 /// Dispatches a connection attempt to this FIDL service's member protocol
287 /// identified by `name`, producing an instance of this trait.
288 fn dispatch(name: &str, channel: AsyncChannel) -> Self;
289
290 /// Returns an array of the service members' names.
291 fn member_names() -> &'static [&'static str];
292}
293
294/// Proxy by which a client sends messages to a FIDL service.
295#[cfg(target_os = "fuchsia")]
296pub trait ServiceProxy: Sized {
297 /// The FIDL service this proxy represents.
298 type Service: ServiceMarker<Proxy = Self>;
299
300 /// Create a proxy from a MemberOpener implementation.
301 #[doc(hidden)]
302 fn from_member_opener(opener: Box<dyn MemberOpener>) -> Self;
303}
304
305/// Used to create an indirection between the fuchsia.io.Directory protocol
306/// and this library, which cannot depend on fuchsia.io.
307#[doc(hidden)]
308#[cfg(target_os = "fuchsia")]
309pub trait MemberOpener: Send + Sync {
310 /// Opens a member protocol of a FIDL service by name, serving that protocol
311 /// on the given channel.
312 fn open_member(&self, member: &str, server_end: Channel) -> Result<(), Error>;
313
314 /// Returns the name of the instance that was opened.
315 fn instance_name(&self) -> &str;
316}
317
318/// The `Client` end of a FIDL connection.
319#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
320pub struct ClientEnd<T> {
321 inner: Channel,
322 phantom: PhantomData<T>,
323}
324
325impl<T> ClientEnd<T> {
326 /// Create a new client from the provided channel.
327 pub fn new(inner: Channel) -> Self {
328 ClientEnd { inner, phantom: PhantomData }
329 }
330
331 /// Get a reference to the underlying channel
332 pub fn channel(&self) -> &Channel {
333 &self.inner
334 }
335
336 /// Extract the underlying channel.
337 pub fn into_channel(self) -> Channel {
338 self.inner
339 }
340}
341
342impl<T: ProtocolMarker> ClientEnd<T> {
343 /// Convert the `ClientEnd` into a `Proxy` through which FIDL calls may be made.
344 ///
345 /// # Panics
346 ///
347 /// If called outside the context of an active async executor.
348 pub fn into_proxy(self) -> T::Proxy {
349 T::Proxy::from_channel(AsyncChannel::from_channel(self.inner))
350 }
351
352 /// Convert the `ClientEnd` into a `SynchronousProxy` through which thread-blocking FIDL calls
353 /// may be made.
354 #[cfg(target_os = "fuchsia")]
355 pub fn into_sync_proxy(self) -> T::SynchronousProxy {
356 T::SynchronousProxy::from_channel(self.inner)
357 }
358}
359
360impl<T> AsHandleRef for ClientEnd<T> {
361 fn as_handle_ref(&self) -> HandleRef<'_> {
362 self.inner.as_handle_ref()
363 }
364}
365
366impl<T> From<ClientEnd<T>> for Handle {
367 fn from(client: ClientEnd<T>) -> Handle {
368 client.into_channel().into()
369 }
370}
371
372impl<T> From<ClientEnd<T>> for Channel {
373 fn from(client: ClientEnd<T>) -> Channel {
374 client.into_channel()
375 }
376}
377
378impl<T> From<Handle> for ClientEnd<T> {
379 fn from(handle: Handle) -> Self {
380 ClientEnd { inner: handle.into(), phantom: PhantomData }
381 }
382}
383
384impl<T> From<Channel> for ClientEnd<T> {
385 fn from(chan: Channel) -> Self {
386 ClientEnd { inner: chan, phantom: PhantomData }
387 }
388}
389
390impl<T: ProtocolMarker> ::std::fmt::Debug for ClientEnd<T> {
391 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
392 write!(f, "ClientEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
393 }
394}
395
396impl<T> HandleBased for ClientEnd<T> {}
397
398/// Trait implemented by types that can be converted from a client.
399pub trait FromClient {
400 /// The protocol.
401 type Protocol: ProtocolMarker;
402
403 /// Converts from a client.
404 fn from_client(value: ClientEnd<Self::Protocol>) -> Self;
405}
406
407impl<T: ProtocolMarker> FromClient for ClientEnd<T> {
408 type Protocol = T;
409
410 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
411 value
412 }
413}
414
415// NOTE: We can only have one blanket implementation. Synchronous proxies have an implementation
416// that is generated by the compiler.
417impl<T: Proxy> FromClient for T {
418 type Protocol = T::Protocol;
419
420 fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
421 Self::from_channel(AsyncChannel::from_channel(value.into_channel()))
422 }
423}
424
425/// The `Server` end of a FIDL connection.
426#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
427pub struct ServerEnd<T> {
428 inner: Channel,
429 phantom: PhantomData<T>,
430}
431
432impl<T> ServerEnd<T> {
433 /// Create a new `ServerEnd` from the provided channel.
434 pub fn new(inner: Channel) -> ServerEnd<T> {
435 ServerEnd { inner, phantom: PhantomData }
436 }
437
438 /// Get a reference to the underlying channel
439 pub fn channel(&self) -> &Channel {
440 &self.inner
441 }
442
443 /// Extract the inner channel.
444 pub fn into_channel(self) -> Channel {
445 self.inner
446 }
447
448 /// Create a stream of requests off of the channel.
449 ///
450 /// # Panics
451 ///
452 /// If called outside the context of an active async executor.
453 pub fn into_stream(self) -> T::RequestStream
454 where
455 T: ProtocolMarker,
456 {
457 T::RequestStream::from_channel(AsyncChannel::from_channel(self.inner))
458 }
459
460 /// Create a stream of requests and an event-sending handle
461 /// from the channel.
462 ///
463 /// # Panics
464 ///
465 /// If called outside the context of an active async executor.
466 pub fn into_stream_and_control_handle(
467 self,
468 ) -> (T::RequestStream, <T::RequestStream as RequestStream>::ControlHandle)
469 where
470 T: ProtocolMarker,
471 {
472 let stream = self.into_stream();
473 let control_handle = stream.control_handle();
474 (stream, control_handle)
475 }
476
477 /// Writes an epitaph into the underlying channel before closing it.
478 pub fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
479 self.inner.close_with_epitaph(status)
480 }
481}
482
483impl<T> AsHandleRef for ServerEnd<T> {
484 fn as_handle_ref(&self) -> HandleRef<'_> {
485 self.inner.as_handle_ref()
486 }
487}
488
489impl<T> From<ServerEnd<T>> for Handle {
490 fn from(server: ServerEnd<T>) -> Handle {
491 server.into_channel().into()
492 }
493}
494
495impl<T> From<ServerEnd<T>> for Channel {
496 fn from(server: ServerEnd<T>) -> Channel {
497 server.into_channel()
498 }
499}
500
501impl<T> From<Handle> for ServerEnd<T> {
502 fn from(handle: Handle) -> Self {
503 ServerEnd { inner: handle.into(), phantom: PhantomData }
504 }
505}
506
507impl<T> From<Channel> for ServerEnd<T> {
508 fn from(chan: Channel) -> Self {
509 ServerEnd { inner: chan, phantom: PhantomData }
510 }
511}
512
513impl<T: ProtocolMarker> ::std::fmt::Debug for ServerEnd<T> {
514 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
515 write!(f, "ServerEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
516 }
517}
518
519impl<T> HandleBased for ServerEnd<T> {}
520
521/// Creates client and server endpoints connected to by a channel.
522pub fn create_endpoints<T: ProtocolMarker>() -> (ClientEnd<T>, ServerEnd<T>) {
523 let (client, server) = Channel::create();
524 let client_end = ClientEnd::<T>::new(client);
525 let server_end = ServerEnd::new(server);
526 (client_end, server_end)
527}
528
529/// Create a client proxy and a server endpoint connected to it by a channel.
530///
531/// Useful for sending channel handles to calls that take arguments
532/// of type `server_end:SomeProtocol`
533///
534/// # Panics
535///
536/// If called outside the context of an active async executor.
537pub fn create_proxy<T: ProtocolMarker>() -> (T::Proxy, ServerEnd<T>) {
538 let (client, server) = create_endpoints();
539 (client.into_proxy(), server)
540}
541
542/// Create a synchronous client proxy and a server endpoint connected to it by a channel.
543///
544/// Useful for sending channel handles to calls that take arguments
545/// of type `server_end:SomeProtocol`
546#[cfg(target_os = "fuchsia")]
547pub fn create_sync_proxy<T: ProtocolMarker>() -> (T::SynchronousProxy, ServerEnd<T>) {
548 let (client, server) = create_endpoints();
549 (client.into_sync_proxy(), server)
550}
551
552/// Create a request stream and a client endpoint connected to it by a channel.
553///
554/// Useful for sending channel handles to calls that take arguments
555/// of type `client_end:SomeProtocol`
556///
557/// # Panics
558///
559/// If called outside the context of an active async executor.
560pub fn create_request_stream<T: ProtocolMarker>() -> (ClientEnd<T>, T::RequestStream) {
561 let (client, server) = create_endpoints();
562 (client, server.into_stream())
563}
564
565/// Create a request stream and proxy connected to one another.
566///
567/// Useful for testing where both the request stream and proxy are
568/// used in the same process.
569///
570/// # Panics
571///
572/// If called outside the context of an active async executor.
573pub fn create_proxy_and_stream<T: ProtocolMarker>() -> (T::Proxy, T::RequestStream) {
574 let (client, server) = create_endpoints::<T>();
575 (client.into_proxy(), server.into_stream())
576}
577
578/// Create a request stream and synchronous proxy connected to one another.
579///
580/// Useful for testing where both the request stream and proxy are
581/// used in the same process.
582///
583/// # Panics
584///
585/// If called outside the context of an active async executor.
586#[cfg(target_os = "fuchsia")]
587pub fn create_sync_proxy_and_stream<T: ProtocolMarker>() -> (T::SynchronousProxy, T::RequestStream)
588{
589 let (client, server) = create_endpoints::<T>();
590 (client.into_sync_proxy(), server.into_stream())
591}
592
593/// The type of a client-initiated method.
594#[derive(Copy, Clone, Debug)]
595pub enum MethodType {
596 /// One-way method, also known as fire-and-forget.
597 OneWay,
598 /// Two-way method.
599 TwoWay,
600}