[rust-netstack] Add SocketProvider FIDL interface

This adds a stub of the fuchsia.net.SocketProvider interface, which
simply returns ENOSYS for all calls to Socket. Functionality will be
added in a later CL.

Test: Manually run.
Change-Id: Ib82bdd81b03896b14a1c80f18bc645b8bc3db92c
diff --git a/bin/recovery_netstack/BUILD.gn b/bin/recovery_netstack/BUILD.gn
index 3bb4c10..42f9ab5 100644
--- a/bin/recovery_netstack/BUILD.gn
+++ b/bin/recovery_netstack/BUILD.gn
@@ -23,6 +23,7 @@
     "//third_party/rust-crates/rustc_deps:byteorder",
     "//third_party/rust-crates/rustc_deps:failure",
     "//third_party/rust-crates/rustc_deps:futures-preview",
+    "//third_party/rust-crates/rustc_deps:libc",
     "//third_party/rust-crates/rustc_deps:log",
     "//zircon/public/fidl/fuchsia-net-stack:fuchsia-net-stack-rustc",
     "//zircon/public/fidl/fuchsia-net:fuchsia-net-rustc",
diff --git a/bin/recovery_netstack/src/eventloop.rs b/bin/recovery_netstack/src/eventloop.rs
index dbb5fb7..46f4606 100644
--- a/bin/recovery_netstack/src/eventloop.rs
+++ b/bin/recovery_netstack/src/eventloop.rs
@@ -20,14 +20,15 @@
 //! messages, since they can be thought of as the entrypoint for the whole loop (as nothing happens
 //! until a FIDL call is made).
 //!
-//! # FIDL Server
+//! # FIDL Worker
 //!
-//! The FIDL part of the event loop implements the fuchsia.net.stack.Stack interface. The type of
-//! the event loop message for a FIDL call is simply the generated FIDL type. When the event loop
-//! starts up, we use `fuchsia_app` to start a FIDL server that simply sends all of the events it
-//! receives to the event loop (via the sender end of the mpsc queue). When `EventLoop` receives
-//! this message, it calls the `handle_fidl_request` method, which, depending on what the request
-//! is, either:
+//! The FIDL part of the event loop implements the fuchsia.net.stack.Stack and
+//! fuchsia.net.SocketProvider interfaces. The type of the event loop message for a FIDL call is
+//! simply the generated FIDL type. When the event loop starts up, we use `fuchsia_app` to start a
+//! FIDL server that simply sends all of the events it receives to the event loop (via the sender
+//! end of the mpsc queue). When `EventLoop` receives this message, it calls the
+//! `handle_fidl_stack_request` or `handle_fidl_socket_provider_request` method, which, depending
+//! on what the request is, either:
 //!
 //! * Responds with the requested information.
 //! * Modifies the state of the netstack in the requested way.
@@ -83,6 +84,7 @@
 use fidl_fuchsia_hardware_ethernet as fidl_ethernet;
 use fidl_fuchsia_hardware_ethernet_ext::{EthernetInfo, EthernetStatus, MacAddress};
 use fidl_fuchsia_net as fidl_net;
+use fidl_fuchsia_net::SocketProviderRequest;
 use fidl_fuchsia_net_ext as fidl_net_ext;
 use fidl_fuchsia_net_stack as fidl_net_stack;
 use fidl_fuchsia_net_stack::{
@@ -197,7 +199,9 @@
 /// The events that can trigger an action in the event loop.
 pub enum Event {
     /// A request from the fuchsia.net.stack.Stack FIDL interface.
-    FidlEvent(StackRequest),
+    FidlStackEvent(StackRequest),
+    /// A request from the fuchsia.net.SocketProvider FIDL interface.
+    FidlSocketProviderEvent(SocketProviderRequest),
     /// An event from an ethernet interface. Either a status change or a frame.
     EthEvent((DeviceId, eth::Event)),
     /// An indication that an ethernet device is ready to be used.
@@ -246,8 +250,11 @@
                     eth_worker.spawn(self.ctx.dispatcher().event_send.clone());
                     setup.responder.send(None, eth_id.id());
                 }
-                Some(Event::FidlEvent(req)) => {
-                    await!(self.handle_fidl_request(req));
+                Some(Event::FidlStackEvent(req)) => {
+                    await!(self.handle_fidl_stack_request(req));
+                }
+                Some(Event::FidlSocketProviderEvent(req)) => {
+                    await!(self.handle_fidl_socket_provider_request(req));
                 }
                 Some(Event::EthEvent((id, eth::Event::StatusChanged))) => {
                     info!("device {:?} status changed", id.id());
@@ -272,7 +279,30 @@
         Ok(())
     }
 
-    async fn handle_fidl_request(&mut self, req: StackRequest) {
+    async fn handle_fidl_socket_provider_request(&mut self, req: SocketProviderRequest) {
+        match req {
+            SocketProviderRequest::Socket {
+                domain,
+                type_,
+                protocol,
+                responder,
+            } => match (domain as i32, type_ as i32) {
+                _ => {
+                    responder.send(libc::ENOSYS as i16, None);
+                }
+            },
+            SocketProviderRequest::GetAddrInfo {
+                node,
+                service,
+                hints,
+                responder,
+            } => {
+                // TODO(wesleyac)
+            }
+        }
+    }
+
+    async fn handle_fidl_stack_request(&mut self, req: StackRequest) {
         match req {
             StackRequest::AddEthernetInterface {
                 topological_path,
@@ -383,8 +413,7 @@
 
     fn fidl_enable_interface(&mut self, id: u64, responder: StackEnableInterfaceResponder) {}
 
-    fn fidl_disable_interface(&mut self, id: u64, responder: StackDisableInterfaceResponder) {
-    }
+    fn fidl_disable_interface(&mut self, id: u64, responder: StackDisableInterfaceResponder) {}
 
     fn fidl_add_interface_address(
         &mut self, id: u64, addr: InterfaceAddress, responder: StackAddInterfaceAddressResponder,
diff --git a/bin/recovery_netstack/src/fidl_worker.rs b/bin/recovery_netstack/src/fidl_worker.rs
index d877218..3c13a82 100644
--- a/bin/recovery_netstack/src/fidl_worker.rs
+++ b/bin/recovery_netstack/src/fidl_worker.rs
@@ -8,6 +8,7 @@
     crate::eventloop::Event,
     failure::Error,
     fidl::endpoints::{RequestStream, ServiceMarker},
+    fidl_fuchsia_net::{SocketProviderMarker, SocketProviderRequestStream},
     fidl_fuchsia_net_stack::{StackMarker, StackRequestStream},
     fuchsia_app::server::ServicesServer,
     fuchsia_async as fasync,
@@ -19,23 +20,43 @@
 
 impl FidlWorker {
     pub fn spawn(self, event_chan: mpsc::UnboundedSender<Event>) -> Result<(), Error> {
-        fasync::spawn_local(
-            ServicesServer::new()
-                .add_service((StackMarker::NAME, move |chan| {
-                    self.spawn_stack(chan, event_chan.clone())
-                }))
-                .start()?
-                .unwrap_or_else(|e: Error| error!("{:?}", e)),
-        );
+        let stack_event_chan = event_chan.clone();
+        let socket_event_chan = event_chan.clone();
+        {
+            fasync::spawn_local(
+                ServicesServer::new()
+                    .add_service((StackMarker::NAME, move |chan| {
+                        Self::spawn_stack(chan, stack_event_chan.clone())
+                    }))
+                    .add_service((SocketProviderMarker::NAME, move |chan| {
+                        Self::spawn_socket_provider(chan, socket_event_chan.clone())
+                    }))
+                    .start()?
+                    .unwrap_or_else(|e: Error| error!("{:?}", e)),
+            );
+        }
         Ok(())
     }
 
-    fn spawn_stack(&self, chan: fasync::Channel, event_chan: mpsc::UnboundedSender<Event>) {
+    fn spawn_stack(chan: fasync::Channel, event_chan: mpsc::UnboundedSender<Event>) {
         fasync::spawn_local(
             async move {
                 let mut stream = StackRequestStream::from_channel(chan);
                 while let Some(req) = await!(stream.try_next())? {
-                    event_chan.unbounded_send(Event::FidlEvent(req))?;
+                    event_chan.unbounded_send(Event::FidlStackEvent(req))?;
+                }
+                Ok(())
+            }
+                .unwrap_or_else(|e: Error| error!("{:?}", e)),
+        );
+    }
+
+    fn spawn_socket_provider(chan: fasync::Channel, event_chan: mpsc::UnboundedSender<Event>) {
+        fasync::spawn_local(
+            async move {
+                let mut stream = SocketProviderRequestStream::from_channel(chan);
+                while let Some(req) = await!(stream.try_next())? {
+                    event_chan.unbounded_send(Event::FidlSocketProviderEvent(req))?;
                 }
                 Ok(())
             }