| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "network_context.h" |
| |
| #include <lib/async/default.h> |
| |
| namespace netemul { |
| |
| constexpr uint16_t kDefaultMtu = 1500; |
| |
| class SetupHandle : fuchsia::netemul::network::SetupHandle { |
| public: |
| using FSetupHandle = fuchsia::netemul::network::SetupHandle; |
| using OnClosedCallback = fit::function<void(SetupHandle*)>; |
| |
| SetupHandle(fidl::InterfaceRequest<FSetupHandle> req, |
| async_dispatcher_t* dispatcher) |
| : binding_(this, std::move(req), dispatcher) { |
| binding_.set_error_handler([this](zx_status_t status) { |
| channels_.clear(); |
| if (on_closed_callback_) { |
| on_closed_callback_(this); |
| } |
| }); |
| } |
| |
| template <typename T> |
| fidl::InterfaceRequest<T> CreateChannel() { |
| fidl::InterfaceHandle<T> handle; |
| auto ret = handle.NewRequest(); |
| AddChannel(handle.TakeChannel()); |
| return ret; |
| } |
| |
| void AddChannel(zx::channel channel) { |
| channels_.push_back(std::move(channel)); |
| } |
| |
| void SetOnClosedCallback(OnClosedCallback callback) { |
| on_closed_callback_ = std::move(callback); |
| } |
| |
| private: |
| fidl::Binding<FSetupHandle> binding_; |
| std::vector<zx::channel> channels_; |
| OnClosedCallback on_closed_callback_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(SetupHandle); |
| }; |
| |
| NetworkContext::NetworkContext(async_dispatcher_t* dispatcher) |
| : network_manager_(this), endpoint_manager_(this) { |
| if (dispatcher == nullptr) { |
| dispatcher = async_get_default_dispatcher(); |
| } |
| dispatcher_ = dispatcher; |
| } |
| |
| NetworkContext::~NetworkContext() = default; |
| |
| void NetworkContext::GetNetworkManager( |
| ::fidl::InterfaceRequest<NetworkManager::FNetworkManager> net_manager) { |
| network_manager_.Bind(std::move(net_manager)); |
| } |
| |
| void NetworkContext::GetEndpointManager( |
| fidl::InterfaceRequest<EndpointManager::FEndpointManager> endp_manager) { |
| endpoint_manager_.Bind(std::move(endp_manager)); |
| } |
| |
| zx_status_t NetworkContext::Setup(std::vector<NetworkSetup> setup, |
| fidl::InterfaceRequest<FSetupHandle> req) { |
| auto setup_handle = |
| std::make_unique<SetupHandle>(std::move(req), dispatcher_); |
| |
| setup_handle->SetOnClosedCallback([this](SetupHandle* handle) { |
| for (auto i = setup_handles_.begin(); i != setup_handles_.end(); i++) { |
| if (i->get() == handle) { |
| setup_handles_.erase(i); |
| return; |
| } |
| } |
| }); |
| |
| for (auto& net_setup : setup) { |
| auto status = network_manager_.CreateNetwork( |
| net_setup.name, std::move(net_setup.config), |
| setup_handle->CreateChannel<Network::FNetwork>()); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| auto* network = network_manager_.GetNetwork(net_setup.name); |
| ZX_ASSERT(network != nullptr); |
| |
| for (auto& endp_setup : net_setup.endpoints) { |
| if (!endp_setup.config) { |
| // if not provided, use defaults: |
| endp_setup.config = std::make_unique<Endpoint::Config>(); |
| endp_setup.config->mtu = kDefaultMtu; |
| endp_setup.config->mac = nullptr; |
| endp_setup.config->backing = |
| fuchsia::netemul::network::EndpointBacking::ETHERTAP; |
| } |
| status = endpoint_manager_.CreateEndpoint( |
| endp_setup.name, std::move(*endp_setup.config), |
| setup_handle->CreateChannel<Endpoint::FEndpoint>()); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| if (endp_setup.link_up) { |
| auto* endpoint = endpoint_manager_.GetEndpoint(endp_setup.name); |
| ZX_ASSERT(endpoint != nullptr); |
| endpoint->SetLinkUp(true); |
| } |
| |
| status = network->AttachEndpoint(std::move(endp_setup.name)); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| } |
| setup_handles_.push_back(std::move(setup_handle)); |
| return ZX_OK; |
| } |
| |
| void NetworkContext::Setup(std::vector<NetworkSetup> setup, |
| SetupCallback callback) { |
| fidl::InterfaceHandle<SetupHandle::FSetupHandle> ifhandle; |
| auto status = Setup(std::move(setup), ifhandle.NewRequest()); |
| if (status != ZX_OK) { |
| ifhandle.TakeChannel().reset(); // dispose of channel |
| } |
| callback(status, std::move(ifhandle)); |
| } |
| |
| fidl::InterfaceRequestHandler<fuchsia::netemul::network::NetworkContext> |
| NetworkContext::GetHandler() { |
| return [this](fidl::InterfaceRequest<FNetworkContext> request) { |
| bindings_.AddBinding(this, std::move(request), dispatcher_); |
| }; |
| } |
| |
| } // namespace netemul |