blob: afbadecbdadaf2b15f0c096440e48137ef7826b3 [file] [log] [blame]
// 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