blob: ce12904c7c36273b7f3fb62680468c6335843584 [file] [log] [blame]
// 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)](
std::vector<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 std::vector<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