| // Copyright 2016 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 "garnet/examples/netconnector/netconnector_example/netconnector_example_impl.h" |
| |
| #include <fuchsia/netconnector/cpp/fidl.h> |
| #include <lib/async/default.h> |
| #include <lib/zx/channel.h> |
| |
| #include "garnet/examples/netconnector/netconnector_example/netconnector_example_params.h" |
| #include "lib/fxl/logging.h" |
| |
| namespace examples { |
| namespace { |
| static constexpr char kRespondingServiceName[] = "netconnector::Example"; |
| |
| static const std::vector<std::string> kConversation = { |
| "Hello!", "Hello!", "Do you like my hat?", |
| "I do not.", "Good-by!", "Good-by!"}; |
| } // namespace |
| |
| NetConnectorExampleImpl::NetConnectorExampleImpl( |
| NetConnectorExampleParams* params, fit::closure quit_callback) |
| : quit_callback_(std::move(quit_callback)), |
| startup_context_(component::StartupContext::CreateFromStartupInfo()) { |
| // The MessageRelay makes using the channel easier. Hook up its callbacks. |
| message_relay_.SetMessageReceivedCallback( |
| [this](std::vector<uint8_t> message) { HandleReceivedMessage(message); }); |
| |
| // Quit when the local channel closes, unless we're registering our provider. |
| // In that case, we need to stay around to respond to future requests. |
| if (params->register_provider()) { |
| message_relay_.SetChannelClosedCallback([this]() { |
| if (conversation_iter_ == kConversation.end()) { |
| FXL_LOG(INFO) << "Channel closed, quitting"; |
| } else { |
| FXL_LOG(ERROR) << "Channel closed unexpectedly, quitting"; |
| } |
| |
| quit_callback_(); |
| }); |
| } |
| |
| // Start at the beginning of the conversation. The party that receives the |
| // last message in the conversation closes the channel. |
| conversation_iter_ = kConversation.begin(); |
| |
| if (params->request_device_name().empty()) { |
| // Params say we should be responding. Register the responding service. |
| FXL_LOG(INFO) << "Running as responder"; |
| startup_context_->outgoing_services()->AddServiceForName( |
| [this](zx::channel channel) { |
| message_relay_.SetChannel(std::move(channel)); |
| }, |
| kRespondingServiceName); |
| |
| if (params->register_provider()) { |
| // Register our provider with netconnector. |
| FXL_LOG(INFO) << "Registering provider"; |
| fuchsia::netconnector::NetConnectorPtr connector = |
| startup_context_->ConnectToEnvironmentService< |
| fuchsia::netconnector::NetConnector>(); |
| |
| fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> handle; |
| startup_context_->outgoing_services()->AddBinding(handle.NewRequest()); |
| |
| FXL_DCHECK(handle); |
| |
| connector->RegisterServiceProvider(kRespondingServiceName, |
| std::move(handle)); |
| } |
| } else { |
| // Params say we should be a requestor. |
| FXL_LOG(INFO) << "Running as requestor"; |
| fuchsia::netconnector::NetConnectorPtr connector = |
| startup_context_->ConnectToEnvironmentService< |
| fuchsia::netconnector::NetConnector>(); |
| |
| // Create a pair of channels. |
| zx::channel local; |
| zx::channel remote; |
| zx_status_t status = zx::channel::create(0u, &local, &remote); |
| |
| FXL_CHECK(status == ZX_OK) |
| << "zx::channel::create failed, status " << status; |
| |
| // Give the local end of the channel to the relay. |
| message_relay_.SetChannel(std::move(local)); |
| |
| // Pass the remote end to NetConnector. |
| fuchsia::sys::ServiceProviderPtr device_service_provider; |
| connector->GetDeviceServiceProvider(params->request_device_name(), |
| device_service_provider.NewRequest()); |
| |
| device_service_provider->ConnectToService(kRespondingServiceName, |
| std::move(remote)); |
| |
| // Start the conversation. |
| SendMessage(*conversation_iter_); |
| ++conversation_iter_; |
| FXL_DCHECK(conversation_iter_ != kConversation.end()); |
| } |
| } |
| |
| NetConnectorExampleImpl::~NetConnectorExampleImpl() {} |
| |
| void NetConnectorExampleImpl::SendMessage(const std::string& message_string) { |
| FXL_LOG(INFO) << "Sending message: '" << message_string << "'"; |
| |
| std::vector<uint8_t> message(message_string.size()); |
| std::memcpy(message.data(), message_string.data(), message.size()); |
| |
| message_relay_.SendMessage(std::move(message)); |
| } |
| |
| void NetConnectorExampleImpl::HandleReceivedMessage( |
| std::vector<uint8_t> message) { |
| std::string message_string(reinterpret_cast<char*>(message.data()), 0, |
| message.size()); |
| |
| FXL_LOG(INFO) << "Message received: '" << message_string << "'"; |
| |
| if (conversation_iter_ == kConversation.end()) { |
| FXL_LOG(ERROR) << "Expected the channel to close, closing channel"; |
| message_relay_.CloseChannel(); |
| return; |
| } |
| |
| if (message_string != *conversation_iter_) { |
| FXL_LOG(ERROR) << "Expected '" << *conversation_iter_ |
| << "', closing channel"; |
| message_relay_.CloseChannel(); |
| return; |
| } |
| |
| ++conversation_iter_; |
| if (conversation_iter_ == kConversation.end()) { |
| FXL_LOG(INFO) << "Conversation complete, closing channel"; |
| message_relay_.CloseChannel(); |
| return; |
| } |
| |
| SendMessage(*conversation_iter_); |
| ++conversation_iter_; |
| // We may have hit the end of the conversation here, but if so, the remote |
| // party is expected to close the channel. |
| } |
| |
| } // namespace examples |