| // 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 "overnet_app.h" |
| #include <fuchsia/overnet/cpp/fidl.h> |
| #include "bound_channel.h" |
| #include "fidl_utils.h" |
| #include "fuchsia_port.h" |
| |
| namespace overnetstack { |
| |
| OvernetApp::OvernetApp(overnet::Timer* timer) |
| : startup_context_(component::StartupContext::CreateFromStartupInfo()), |
| timer_(timer) { |
| UpdateDescription(); |
| } |
| |
| OvernetApp::~OvernetApp() {} |
| |
| overnet::NodeId OvernetApp::GenerateNodeId() { |
| uint64_t out; |
| zx_cprng_draw(&out, sizeof(out)); |
| return overnet::NodeId(out); |
| } |
| |
| overnet::Status OvernetApp::Start() { |
| for (size_t i = 0; i < actors_.size(); i++) { |
| auto status = actors_[i]->Start(); |
| if (status.is_error()) { |
| actors_.resize(i); |
| return status.WithContext("Trying to start actor"); |
| } |
| } |
| ReadNextIntroduction(); |
| return overnet::Status::Ok(); |
| } |
| |
| void OvernetApp::RegisterServiceProvider( |
| const std::string& name, std::unique_ptr<ServiceProvider> provider) { |
| service_providers_.emplace(name, std::move(provider)); |
| UpdateDescription(); |
| } |
| |
| void OvernetApp::UpdateDescription() { |
| fuchsia::overnet::PeerDescription desc; |
| desc.services = desc.services.New(0); |
| for (const auto& svc : service_providers_) { |
| desc.services.push_back(svc.first); |
| } |
| endpoint_.SetDescription(EncodeMessage(&desc)); |
| } |
| |
| void OvernetApp::BindStream(overnet::RouterEndpoint::NewStream ns, |
| zx::channel channel) { |
| ZX_ASSERT(channel.is_valid()); |
| zx_info_handle_basic_t info; |
| auto err = channel.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), |
| nullptr, nullptr); |
| ZX_ASSERT(err == ZX_OK); |
| ZX_ASSERT(info.type == ZX_OBJ_TYPE_CHANNEL); |
| new BoundChannel(this, std::move(ns), std::move(channel)); |
| ZX_ASSERT(!channel.is_valid()); |
| } |
| |
| void OvernetApp::ConnectToLocalService(const overnet::Introduction& intro, |
| zx::channel channel) { |
| auto svc_slice = intro[overnet::Introduction::Key::ServiceName]; |
| if (!svc_slice.has_value()) { |
| OVERNET_TRACE(DEBUG) << "No service name in local service request"; |
| return; |
| } |
| const std::string svc(svc_slice->begin(), svc_slice->end()); |
| auto it = service_providers_.find(svc); |
| if (it == service_providers_.end()) { |
| OVERNET_TRACE(DEBUG) << "Local service not found: " << svc; |
| return; |
| } |
| it->second->Connect(intro, std::move(channel)); |
| } |
| |
| void OvernetApp::ReadNextIntroduction() { |
| // Loop, reading service creation requests, and attempting to bind them to |
| // local services. |
| endpoint_.RecvIntro( |
| [this](overnet::StatusOr<overnet::RouterEndpoint::ReceivedIntroduction> |
| status) { |
| if (status.is_error()) { |
| OVERNET_TRACE(ERROR) |
| << "Failed to read introduction: " << status.AsStatus(); |
| return; |
| } |
| zx_handle_t a, b; |
| auto err = zx_channel_create(0, &a, &b); |
| if (err != ZX_OK) { |
| status->new_stream.Fail( |
| ToOvernetStatus(err).WithContext("ReadNextIntroduction")); |
| return; |
| } |
| BindStream(std::move(status->new_stream), zx::channel(a)); |
| ConnectToLocalService(std::move(status->introduction), zx::channel(b)); |
| ReadNextIntroduction(); |
| }); |
| } |
| |
| } // namespace overnetstack |