blob: 422ea908c9593a1ce28e2149d08ff065cf64cf52 [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/network_time/timezone.h"
#include <fcntl.h>
#include <inttypes.h>
#include <sys/time.h>
#include <unistd.h>
#include <string>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include "fuchsia/hardware/rtc/cpp/fidl.h"
#include "garnet/bin/network_time/roughtime_server.h"
#include "garnet/bin/network_time/time_server_config.h"
#include "garnet/bin/network_time/time_util.h"
#include "lib/syslog/cpp/logger.h"
#include "zircon/system/ulib/zx/include/lib/zx/channel.h"
namespace time_server {
namespace rtc = fuchsia::hardware::rtc;
bool Timezone::Run() {
FX_LOGS(INFO) << "started";
return UpdateSystemTime(kDefaultUpdateAttempts);
}
bool Timezone::UpdateSystemTime(uint32_t tries) {
TimeServerConfig config;
if (!config.Parse(server_config_file_)) {
FX_LOGS(ERROR) << "Failed to parse config file";
return false;
}
const RoughTimeServer* server = nullptr;
std::vector<RoughTimeServer> servers = config.ServerList();
for (const auto& s : servers) {
if (!s.IsValid()) {
continue;
}
server = &s;
break;
}
if (server == nullptr) {
FX_LOGS(ERROR) << "No valid server";
return false;
}
for (uint32_t i = 0; i < tries; i++) {
FX_VLOGS(1) << "Updating system time, attempt: " << i + 1;
auto ret = server->GetTimeFromServer();
if (ret.first == NETWORK_ERROR) {
if (i != tries - 1) {
FX_VLOGS(1) << "Can't get time, sleeping for 1 sec";
sleep(1);
} else {
FX_LOGS(ERROR) << "Can't get time due to network error after " << tries
<< " attempts, abort";
return false;
}
continue;
} else if (ret.first != OK || !ret.second) {
FX_LOGS(ERROR) << "Error with roughtime server [" << ret.first
<< "], abort";
return false;
}
if (SetSystemTime(rtc_service_path_, *ret.second)) {
return true;
}
}
FX_LOGS(ERROR) << "Inexplicably failed to get time after " << tries
<< " attempts, abort";
return false;
}
bool Timezone::SetSystemTime(const std::string& rtc_service_path,
zx::time_utc time) {
int64_t epoch_seconds = time.get() / 1'000'000'000;
struct tm ptm;
gmtime_r(&epoch_seconds, &ptm);
const rtc::Time rtc_time = ToRtcTime(&ptm);
rtc::DeviceSyncPtr rtc_device_ptr;
zx_status_t status =
fdio_service_connect(rtc_service_path.c_str(),
rtc_device_ptr.NewRequest().TakeChannel().release());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Couldn't open RTC service at " << rtc_service_path
<< ": " << strerror(errno);
return false;
}
zx_status_t set_status;
status = rtc_device_ptr->Set(rtc_time, &set_status);
if ((status != ZX_OK) || (set_status != ZX_OK)) {
FX_LOGS(ERROR) << "rtc::DeviceSyncPtr->Set failed: " << status << "/"
<< set_status << " for " << ToIso8601String(epoch_seconds)
<< " (" << epoch_seconds << ")";
return false;
}
FX_LOGS(INFO) << "time set to: " << ToIso8601String(epoch_seconds);
return true;
}
} // namespace time_server