/// Consumes the netstack and starts serving all the FIDL services it
/// implements to the outgoing service directory.
Consumes the netstack and starts serving all the FIDL services it
implements to the outgoing service directory.
Consumes the netstack and starts serving all the FIDL services it implements to the outgoing service directory .
pub async fn serve(self) -> Result<(), anyhow::Error> {
        use anyhow::Context as _;
        debug!("Serving netstack");
        {
            let mut ctx = self.lock().await;
            let ctx = ctx.deref_mut();
            // Add and initialize the loopback interface with the IPv4 and IPv6
            // loopback addresses and on-link routes to the loopback subnets.
            let Ctx {
                state,
                dispatcher:
                    BindingsDispatcher {
                        devices,
                        timers: _,
                        rng: _,
                        icmp_echo_sockets: _,
                        udp_sockets: _,
                    },
            } = ctx;
            let loopback = state
                .add_loopback_device(DEFAULT_LOOPBACK_MTU)
                .expect("error adding loopback device");
            let _binding_id: u64 = devices
                .add_active_device(
                    loopback,
                    DeviceSpecificInfo::Loopback(LoopbackInfo {
                        common_info: CommonInfo { mtu: DEFAULT_LOOPBACK_MTU, admin_enabled: true },
                    }),
                )
                .expect("error adding loopback device");
            initialize_device(ctx, loopback);
            // Don't need DAD and IGMP/MLD on loopback.
            set_ipv4_configuration(
                ctx,
                loopback,
                Ipv4DeviceConfiguration { ip_config: IpDeviceConfiguration { gmp_enabled: false } },
            );
            set_ipv6_configuration(
                ctx,
                loopback,
                Ipv6DeviceConfiguration {
                    dad_transmits: None,
                    ip_config: IpDeviceConfiguration { gmp_enabled: false },
                },
            );
            add_ip_addr_subnet(
                ctx,
                loopback,
                AddrSubnetEither::V4(
                    AddrSubnet::from_witness(
                        Ipv4::LOOPBACK_ADDRESS,
                        Ipv4::LOOPBACK_SUBNET.prefix(),
                    )
                    .expect("error creating IPv4 loopback AddrSub"),
                ),
            )
            .expect("error adding IPv4 loopback address");
            add_route(
                ctx,
                EntryEither::new(
                    Ipv4::LOOPBACK_SUBNET.into(),
                    EntryDest::Local { device: loopback },
                )
                .expect("error creating IPv4 route entry"),
            )
            .expect("error adding IPv4 loopback on-link subnet route");
            add_ip_addr_subnet(
                ctx,
                loopback,
                AddrSubnetEither::V6(
                    AddrSubnet::from_witness(
                        Ipv6::LOOPBACK_ADDRESS,
                        Ipv6::LOOPBACK_SUBNET.prefix(),
                    )
                    .expect("error creating IPv6 loopback AddrSub"),
                ),
            )
            .expect("error adding IPv6 loopback address");
            add_route(
                ctx,
                EntryEither::new(
                    Ipv6::LOOPBACK_SUBNET.into(),
                    EntryDest::Local { device: loopback },
                )
                .expect("error creating IPv6 route entry"),
            )
            .expect("error adding IPv6 loopback on-link subnet route");
            // Start servicing timers.
            let Ctx {
                state: _,
                dispatcher:
                    BindingsDispatcher {
                        devices: _,
                        timers,
                        rng: _,
                        icmp_echo_sockets: _,
                        udp_sockets: _,
                    },
            } = ctx;
            timers.spawn(self.clone());
        }
        let mut fs = ServiceFs::new_local();
        let _: &mut ServiceFsDir<'_, _> = fs
            .dir("svc")
            .add_fidl_service(Service::Debug)
            .add_fidl_service(Service::Stack)
            .add_fidl_service(Service::Socket)
            .add_fidl_service(Service::Interfaces);
        let services = fs.take_and_serve_directory_handle().context("directory handle")?;
        let (work_items, tasks) = {
            let (sender, receiver) = mpsc::unbounded();
            (
                futures::stream::select(
                    receiver.map(WorkItem::Spawned),
                    services.map(WorkItem::Incoming),
                ),
                sender,
            )
        };
        let () = work_items
            .for_each_concurrent(None, |wi| async {
                match wi {
                    WorkItem::Incoming(Service::Stack(stack)) => {
                        stack
                            .serve_with(|rs| {
                                stack_fidl_worker::StackFidlWorker::serve(self.clone(), rs)
                            })
                            .await
                    }
                    WorkItem::Incoming(Service::Socket(socket)) => {
                        socket.serve_with(|rs| socket::serve(self.clone(), rs)).await
                    }
                    WorkItem::Incoming(Service::Interfaces(interfaces)) => {
                        interfaces
                            .serve_with(|rs| {
                                interfaces_watcher::serve(
                                    self.clone(),
                                    rs,
                                    tasks.clone().with(|w| {
                                        futures::future::ok::<_, futures::channel::mpsc::SendError>(
                                            Task::Watcher(w),
                                        )
                                    }),
                                )
                            })
                            .await
                    }
                    WorkItem::Incoming(Service::Debug(debug)) => {
                        // TODO(https://fxbug.dev/88797): Implement this
                        // properly. This protocol is stubbed out to allow
                        // shared integration test code with Netstack2.
                        debug
                            .serve_with(|rs| rs.try_for_each(|req| async move {
                                match req {
                                    fidl_fuchsia_net_debug::InterfacesRequest::GetAdmin {
                                        id: _,
                                        control,
                                        control_handle: _,
                                    } => {
                                        let () = control
                                            .close_with_epitaph(zx::Status::NOT_SUPPORTED)
                                            .unwrap_or_else(|e| if e.is_closed() {
                                                debug!("control handle closed before sending epitaph: {:?}", e)
                                            } else {
                                                error!("failed to send epitaph: {:?}", e)
                                            });
                                        warn!(
                                            "TODO(https://fxbug.dev/88797): fuchsia.net.debug/Interfaces not implemented"
                                        );
                                    }
                                    fidl_fuchsia_net_debug::InterfacesRequest::GetMac {
                                        id: _,
                                        responder,
                                    } => {
                                        responder.control_handle().shutdown_with_epitaph(zx::Status::NOT_SUPPORTED)
                                    }
                                }
                                Result::<(), fidl::Error>::Ok(())
                            }))
                            .await
                    }
                    WorkItem::Spawned(Task::Watcher(watcher)) => {
                        watcher.await.unwrap_or_else(|err| {
                            error!("fuchsia.net.interfaces.Watcher error: {}", err)
                        })
                    }
                }
            })
            .await;
        debug!("Services stream finished");
        Ok(())
    }
pub async fn serve ( self ) -> Result < ( ) , anyhow :: Error > { use anyhow :: Context as _ ; debug ! ( " " ) ; { let mut ctx = self . lock ( ) . await ; let ctx = ctx . deref_mut ( ) ; // Add and initialize the loopback interface with the IPv4 and IPv6 // loopback addresses and on-link routes to the loopback subnets. let Ctx { state , dispatcher : BindingsDispatcher { devices , timers : _ , rng : _ , icmp_echo_sockets : _ , udp_sockets : _ , } , } = ctx ; let loopback = state . add_loopback_device ( DEFAULT_LOOPBACK_MTU ) . expect ( " " ) ; let _binding_id : u64 = devices . add_active_device ( loopback , DeviceSpecificInfo :: Loopback ( LoopbackInfo { common_info : CommonInfo { mtu : DEFAULT_LOOPBACK_MTU , admin_enabled : true } , } ) , ) . expect ( " " ) ; initialize_device ( ctx , loopback ) ; // Don't need DAD and IGMP/MLD on loopback. set_ipv4_configuration ( ctx , loopback , Ipv4DeviceConfiguration { ip_config : IpDeviceConfiguration { gmp_enabled : false } } , ) ; set_ipv6_configuration ( ctx , loopback , Ipv6DeviceConfiguration { dad_transmits : None , ip_config : IpDeviceConfiguration { gmp_enabled : false } , } , ) ; add_ip_addr_subnet ( ctx , loopback , AddrSubnetEither :: V4 ( AddrSubnet :: from_witness ( Ipv4 :: LOOPBACK_ADDRESS , Ipv4 :: LOOPBACK_SUBNET . prefix ( ) , ) . expect ( " " ) , ) , ) . expect ( " " ) ; add_route ( ctx , EntryEither :: new ( Ipv4 :: LOOPBACK_SUBNET . into ( ) , EntryDest :: Local { device : loopback } , ) . expect ( " " ) , ) . expect ( " " ) ; add_ip_addr_subnet ( ctx , loopback , AddrSubnetEither :: V6 ( AddrSubnet :: from_witness ( Ipv6 :: LOOPBACK_ADDRESS , Ipv6 :: LOOPBACK_SUBNET . prefix ( ) , ) . expect ( " " ) , ) , ) . expect ( " " ) ; add_route ( ctx , EntryEither :: new ( Ipv6 :: LOOPBACK_SUBNET . into ( ) , EntryDest :: Local { device : loopback } , ) . expect ( " " ) , ) . expect ( " " ) ; // Start servicing timers. let Ctx { state : _ , dispatcher : BindingsDispatcher { devices : _ , timers , rng : _ , icmp_echo_sockets : _ , udp_sockets : _ , } , } = ctx ; timers . spawn ( self . clone ( ) ) ; } let mut fs = ServiceFs :: new_local ( ) ; let _ : & mut ServiceFsDir < ' _ , _ > = fs . dir ( " " ) . add_fidl_service ( Service :: Debug ) . add_fidl_service ( Service :: Stack ) . add_fidl_service ( Service :: Socket ) . add_fidl_service ( Service :: Interfaces ) ; let services = fs . take_and_serve_directory_handle ( ) . context ( " " ) ? ; let ( work_items , tasks ) = { let ( sender , receiver ) = mpsc :: unbounded ( ) ; ( futures :: stream :: select ( receiver . map ( WorkItem :: Spawned ) , services . map ( WorkItem :: Incoming ) , ) , sender , ) } ; let ( ) = work_items . for_each_concurrent ( None , | wi | async { match wi { WorkItem :: Incoming ( Service :: Stack ( stack ) ) => { stack . serve_with ( | rs | { stack_fidl_worker :: StackFidlWorker :: serve ( self . clone ( ) , rs ) } ) . await } WorkItem :: Incoming ( Service :: Socket ( socket ) ) => { socket . serve_with ( | rs | socket :: serve ( self . clone ( ) , rs ) ) . await } WorkItem :: Incoming ( Service :: Interfaces ( interfaces ) ) => { interfaces . serve_with ( | rs | { interfaces_watcher :: serve ( self . clone ( ) , rs , tasks . clone ( ) . with ( | w | { futures :: future :: ok :: < _ , futures :: channel :: mpsc :: SendError > ( Task :: Watcher ( w ) , ) } ) , ) } ) . await } WorkItem :: Incoming ( Service :: Debug ( debug ) ) => { // TODO(https://fxbug.dev/88797): Implement this // properly. This protocol is stubbed out to allow // shared integration test code with Netstack2. debug . serve_with ( | rs | rs . try_for_each ( | req | async move { match req { fidl_fuchsia_net_debug :: InterfacesRequest :: GetAdmin { id : _ , control , control_handle : _ , } => { let ( ) = control . close_with_epitaph ( zx :: Status :: NOT_SUPPORTED ) . unwrap_or_else ( | e | if e . is_closed ( ) { debug ! ( " " e ) } else { error ! ( " " e ) } ) ; warn ! ( " " ) ; } fidl_fuchsia_net_debug :: InterfacesRequest :: GetMac { id : _ , responder , } => { responder . control_handle ( ) . shutdown_with_epitaph ( zx :: Status :: NOT_SUPPORTED ) } } Result :: < ( ) , fidl :: Error > :: Ok ( ( ) ) } ) ) . await } WorkItem :: Spawned ( Task :: Watcher ( watcher ) ) => { watcher . await . unwrap_or_else ( | err | { error ! ( " " err ) } ) } } } ) . await ; debug ! ( " " ) ; Ok ( ( ) ) }
Consumes the netstack and starts serving all the FIDL services it
implements to the outgoing service directory.
Consumes the netstack and starts serving all the FIDL services it implements to the outgoing service directory .
self