| // Copyright 2017 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/bin/netconnector/host_name.h" |
| |
| #include <fuchsia/netstack/cpp/fidl.h> |
| #include <limits.h> |
| #include <unistd.h> |
| |
| #include "garnet/lib/inet/socket_address.h" |
| #include "lib/component/cpp/startup_context.h" |
| #include "lib/fxl/files/unique_fd.h" |
| #include "lib/fxl/logging.h" |
| |
| namespace netconnector { |
| namespace { |
| |
| static const std::string kFuchsia = "fuchsia-unset-device-name"; |
| |
| class NetstackClient { |
| public: |
| static void GetInterfaces( |
| fuchsia::netstack::Netstack::GetInterfacesCallback callback) { |
| NetstackClient* client = new NetstackClient(); |
| client->netstack_->GetInterfaces( |
| [client, callback = std::move(callback)]( |
| fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces) { |
| callback(std::move(interfaces)); |
| delete client; |
| }); |
| } |
| |
| private: |
| NetstackClient() |
| : context_(component::StartupContext::CreateFromStartupInfo()) { |
| FXL_DCHECK(context_); |
| netstack_ = |
| context_->ConnectToEnvironmentService<fuchsia::netstack::Netstack>(); |
| FXL_DCHECK(netstack_); |
| } |
| |
| std::unique_ptr<component::StartupContext> context_; |
| fuchsia::netstack::NetstackPtr netstack_; |
| }; |
| |
| // Returns a host address, preferably V4. Returns an invalid address if no |
| // network interface could be found or if the interface hasn't obtained an |
| // address. |
| inet::IpAddress GetHostAddress() { |
| static inet::IpAddress ip_address; |
| if (ip_address) |
| return ip_address; |
| |
| NetstackClient::GetInterfaces( |
| [](const fidl::VectorPtr<fuchsia::netstack::NetInterface>& interfaces) { |
| for (const auto& interface : *interfaces) { |
| if (interface.addr.Which() == fuchsia::net::IpAddress::Tag::kIpv4) { |
| ip_address = inet::IpAddress(&interface.addr); |
| break; |
| } |
| if (interface.addr.Which() == fuchsia::net::IpAddress::Tag::kIpv6) { |
| ip_address = inet::IpAddress(&interface.addr); |
| // Keep looking...v4 is preferred. |
| } |
| } |
| }); |
| |
| return inet::IpAddress::kInvalid; |
| } |
| |
| } // namespace |
| |
| bool NetworkIsReady() { return GetHostAddress().is_valid(); } |
| |
| // TODO: this should probably be an asynchronous interface. |
| std::string GetHostName() { |
| char host_name_buffer[HOST_NAME_MAX + 1]; |
| int result = gethostname(host_name_buffer, sizeof(host_name_buffer)); |
| |
| std::string host_name; |
| |
| if (result < 0) { |
| FXL_LOG(ERROR) << "gethostname failed, errno " << errno; |
| host_name = kFuchsia; |
| } else { |
| host_name = host_name_buffer; |
| } |
| |
| // TODO(dalesat): Just use gethostname when NET-79 is fixed. |
| |
| if (host_name == kFuchsia) { |
| // Seems we have the hard-coded host name. Supplement it with part of the |
| // IP address. |
| inet::IpAddress address = GetHostAddress(); |
| if (address) { |
| uint16_t suffix = address.is_v4() |
| ? static_cast<uint16_t>( |
| address.as_bytes()[address.byte_count() - 1]) |
| : address.as_words()[address.word_count() - 1]; |
| std::ostringstream os; |
| os << host_name << "-" << suffix; |
| host_name = os.str(); |
| } |
| } |
| |
| return host_name; |
| } |
| |
| } // namespace netconnector |