Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(406)

Side by Side Diff: components/network_time/network_time_tracker.cc

Issue 1835823002: network_time_tracker: add temporary time protocol. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: msvc Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/network_time/network_time_tracker.h" 5 #include "components/network_time/network_time_tracker.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/i18n/time_formatting.h" 10 #include "base/i18n/time_formatting.h"
11 #include "base/json/json_reader.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/tick_clock.h" 14 #include "base/time/tick_clock.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
16 #include "components/client_update_protocol/ecdsa.h"
15 #include "components/network_time/network_time_pref_names.h" 17 #include "components/network_time/network_time_pref_names.h"
16 #include "components/prefs/pref_registry_simple.h" 18 #include "components/prefs/pref_registry_simple.h"
17 #include "components/prefs/pref_service.h" 19 #include "components/prefs/pref_service.h"
20 #include "net/base/load_flags.h"
21 #include "net/http/http_response_headers.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "url/gurl.h"
18 24
19 namespace network_time { 25 namespace network_time {
20 26
21 namespace { 27 namespace {
22 28
23 // Number of time measurements performed in a given network time calculation. 29 // Number of time measurements performed in a given network time calculation.
24 const uint32_t kNumTimeMeasurements = 7; 30 const uint32_t kNumTimeMeasurements = 7;
25 31
26 // Amount of divergence allowed between wall clock and tick clock. 32 // Amount of divergence allowed between wall clock and tick clock.
27 const uint32_t kClockDivergenceSeconds = 60; 33 const uint32_t kClockDivergenceSeconds = 60;
28 34
29 // Maximum time lapse before deserialized data are considered stale. 35 // Maximum time lapse before deserialized data are considered stale.
30 const uint32_t kSerializedDataMaxAgeDays = 7; 36 const uint32_t kSerializedDataMaxAgeDays = 7;
31 37
32 // Name of a pref that stores the wall clock time, via |ToJsTime|. 38 // Name of a pref that stores the wall clock time, via |ToJsTime|.
33 const char kPrefTime[] = "local"; 39 const char kPrefTime[] = "local";
34 40
35 // Name of a pref that stores the tick clock time, via |ToInternalValue|. 41 // Name of a pref that stores the tick clock time, via |ToInternalValue|.
36 const char kPrefTicks[] = "ticks"; 42 const char kPrefTicks[] = "ticks";
37 43
38 // Name of a pref that stores the time uncertainty, via |ToInternalValue|. 44 // Name of a pref that stores the time uncertainty, via |ToInternalValue|.
39 const char kPrefUncertainty[] = "uncertainty"; 45 const char kPrefUncertainty[] = "uncertainty";
40 46
41 // Name of a pref that stores the network time via |ToJsTime|. 47 // Name of a pref that stores the network time via |ToJsTime|.
42 const char kPrefNetworkTime[] = "network"; 48 const char kPrefNetworkTime[] = "network";
43 49
50 // DO NOT SUBMIT
51 const char kTimeServiceURL[] = "http://localhost:6125/time/1/current";
52
53 // This is an ECDSA prime256v1 named-curve key.
54 // DO NOT SUBMIT.
55 const int kKeyVersion = 2;
56 const uint8_t kKeyPubBytes[] = {
57 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
58 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
59 0x42, 0x00, 0x04, 0xe0, 0x6b, 0x0d, 0x76, 0x75, 0xa3, 0x99, 0x7d, 0x7c,
60 0x1b, 0xd6, 0x3c, 0x73, 0xbb, 0x4b, 0xfe, 0x0a, 0xe7, 0x2f, 0x61, 0x3d,
61 0x77, 0x0a, 0xaa, 0x14, 0xd8, 0x5a, 0xbf, 0x14, 0x60, 0xec, 0xf6, 0x32,
62 0x77, 0xb5, 0xa7, 0xe6, 0x35, 0xa5, 0x61, 0xaf, 0xdc, 0xdf, 0x91, 0xce,
63 0x45, 0x34, 0x5f, 0x36, 0x85, 0x2f, 0xb9, 0x53, 0x00, 0x5d, 0x86, 0xe7,
64 0x04, 0x16, 0xe2, 0x3d, 0x21, 0x76, 0x2b};
65
44 } // namespace 66 } // namespace
45 67
46 // static 68 // static
47 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) { 69 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping, 70 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
49 new base::DictionaryValue()); 71 new base::DictionaryValue());
50 } 72 }
51 73
52 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock, 74 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock,
53 scoped_ptr<base::TickClock> tick_clock, 75 scoped_ptr<base::TickClock> tick_clock,
54 PrefService* pref_service) 76 PrefService* pref_service,
55 : clock_(std::move(clock)), 77 net::URLRequestContextGetter* getter)
78 : getter_(getter),
79 clock_(std::move(clock)),
56 tick_clock_(std::move(tick_clock)), 80 tick_clock_(std::move(tick_clock)),
57 pref_service_(pref_service) { 81 pref_service_(pref_service) {
58 const base::DictionaryValue* time_mapping = 82 const base::DictionaryValue* time_mapping =
59 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); 83 pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
60 double time_js = 0; 84 double time_js = 0;
61 double ticks_js = 0; 85 double ticks_js = 0;
62 double network_time_js = 0; 86 double network_time_js = 0;
63 double uncertainty_js = 0; 87 double uncertainty_js = 0;
64 if (time_mapping->GetDouble(kPrefTime, &time_js) && 88 if (time_mapping->GetDouble(kPrefTime, &time_js) &&
65 time_mapping->GetDouble(kPrefTicks, &ticks_js) && 89 time_mapping->GetDouble(kPrefTicks, &ticks_js) &&
66 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && 90 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) &&
67 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { 91 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) {
68 time_at_last_measurement_ = base::Time::FromJsTime(time_js); 92 time_at_last_measurement_ = base::Time::FromJsTime(time_js);
69 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue( 93 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue(
70 static_cast<int64_t>(ticks_js)); 94 static_cast<int64_t>(ticks_js));
71 network_time_uncertainty_ = base::TimeDelta::FromInternalValue( 95 network_time_uncertainty_ = base::TimeDelta::FromInternalValue(
72 static_cast<int64_t>(uncertainty_js)); 96 static_cast<int64_t>(uncertainty_js));
73 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js); 97 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js);
74 } 98 }
75 base::Time now = clock_->Now(); 99 base::Time now = clock_->Now();
76 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() || 100 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() ||
77 time_at_last_measurement_ > now || 101 time_at_last_measurement_ > now ||
78 now - time_at_last_measurement_ > 102 now - time_at_last_measurement_ >
79 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) { 103 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) {
80 // Drop saved mapping if either clock has run backward, or the data are too 104 // Drop saved mapping if either clock has run backward, or the data are too
81 // old. 105 // old.
82 pref_service_->ClearPref(prefs::kNetworkTimeMapping); 106 pref_service_->ClearPref(prefs::kNetworkTimeMapping);
83 network_time_at_last_measurement_ = base::Time(); // Reset. 107 network_time_at_last_measurement_ = base::Time(); // Reset.
84 } 108 }
109 if (getter != nullptr) {
110 query_signer_ = client_update_protocol::Ecdsa::Create(
111 kKeyVersion,
112 {reinterpret_cast<const char*>(kKeyPubBytes), sizeof(kKeyPubBytes)});
113 base::TimeDelta period = base::TimeDelta::FromMinutes(60);
114 query_timer_.Start(FROM_HERE, period, this,
115 &NetworkTimeTracker::QueryTimeService);
116 }
85 } 117 }
86 118
87 NetworkTimeTracker::~NetworkTimeTracker() { 119 NetworkTimeTracker::~NetworkTimeTracker() {
88 DCHECK(thread_checker_.CalledOnValidThread()); 120 DCHECK(thread_checker_.CalledOnValidThread());
89 } 121 }
90 122
123 void NetworkTimeTracker::QueryTimeService() {
124 DCHECK(thread_checker_.CalledOnValidThread());
125
126 base::Time network_time;
127 if (GetNetworkTime(&network_time, nullptr)) {
estark 2016/03/28 17:35:09 suggested comment: // If GetNetworkTime() returns
mab 2016/03/28 19:56:26 Done.
128 return;
129 }
130
131 std::string query_string;
132 query_signer_->SignRequest({"", 0}, &query_string);
133 GURL url(kTimeServiceURL);
134 GURL::Replacements replacements;
135 replacements.SetQueryStr(query_string);
136 url = url.ReplaceComponents(replacements);
137
138 // This cancels any outstanding fetch.
139 time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
140 if (time_fetcher_ == nullptr) {
141 VLOG(1) << "tried to make fetch happen; failed";
142 return;
143 }
144 time_fetcher_->SetRequestContext(getter_);
145 // Not expecting any cookies, but just in case.
146 time_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE |
147 net::LOAD_DO_NOT_SEND_COOKIES |
148 net::LOAD_DO_NOT_SAVE_COOKIES);
estark 2016/03/28 17:35:09 might also want LOAD_BYPASS_CACHE and, for extra p
mab 2016/03/28 19:56:26 Done.
149 time_fetcher_->Start();
150 fetch_started_ = tick_clock_->NowTicks();
151 }
152
153 static std::string GetServerETag(const net::URLFetcher* source) {
estark 2016/03/28 17:35:09 This should go in an anonymous namespace at the to
mab 2016/03/28 19:56:26 Done.
154 const auto response_headers(source->GetResponseHeaders());
estark 2016/03/28 17:35:09 personal style nit: I'm not a huge fan of auto her
mab 2016/03/28 19:56:26 Done.
155 if (response_headers == nullptr) {
156 return std::string();
157 }
158 std::string etag;
159 return response_headers->EnumerateHeader(nullptr, "ETag", &etag)
160 ? etag
161 : std::string();
162 }
163
164 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
165 DCHECK(thread_checker_.CalledOnValidThread());
166 DCHECK(source);
167 if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
168 source->GetResponseCode() != 200) {
169 VLOG(1) << "fetch failed, status=" << source->GetStatus().status()
170 << ",code=" << source->GetResponseCode();
171 return;
172 }
173
174 std::string response_body;
175 CHECK(source->GetResponseAsString(&response_body));
estark 2016/03/28 17:35:09 CHECK seems heavy-handed here. Can we just log and
mab 2016/03/28 19:56:26 Quite right, done.
176 DCHECK(query_signer_.get());
177 if (!query_signer_->ValidateResponse(response_body, GetServerETag(source))) {
178 VLOG(1) << "invalid signature";
estark 2016/03/28 17:35:09 missing return here, I think?
mab 2016/03/28 19:56:26 Done, sorry. I've been cheating a bunch since we'
179 }
180 response_body = response_body.substr(5); // Skips leading )]}'\n
181 base::JSONReader reader;
182 scoped_ptr<base::Value> value = reader.Read(response_body);
183 if (value == nullptr) {
184 VLOG(1) << "bad JSON";
185 return;
186 }
187 const base::DictionaryValue* dict;
188 if (!value->GetAsDictionary(&dict)) {
189 VLOG(1) << "not a dictionary";
190 return;
191 }
192 double current_time_millis;
193 if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
194 VLOG(1) << "no current_time_millis";
195 return;
196 }
197 // There's also a "server_nonce" key, which we can ignore.
198 base::Time current_time = base::Time::FromJsTime(current_time_millis);
199 base::TimeDelta resolution = base::TimeDelta::FromMilliseconds(1);
200 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
201 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
202 }
203
91 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time, 204 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
92 base::TimeDelta resolution, 205 base::TimeDelta resolution,
93 base::TimeDelta latency, 206 base::TimeDelta latency,
94 base::TimeTicks post_time) { 207 base::TimeTicks post_time) {
95 DCHECK(thread_checker_.CalledOnValidThread()); 208 DCHECK(thread_checker_.CalledOnValidThread());
96 DVLOG(1) << "Network time updating to " 209 DVLOG(1) << "Network time updating to "
97 << base::UTF16ToUTF8( 210 << base::UTF16ToUTF8(
98 base::TimeFormatFriendlyDateAndTime(network_time)); 211 base::TimeFormatFriendlyDateAndTime(network_time));
99 // Update network time on every request to limit dependency on ticks lag. 212 // Update network time on every request to limit dependency on ticks lag.
100 // TODO(mad): Find a heuristic to avoid augmenting the 213 // TODO(mad): Find a heuristic to avoid augmenting the
(...skipping 23 matching lines...) Expand all
124 237
125 base::DictionaryValue time_mapping; 238 base::DictionaryValue time_mapping;
126 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime()); 239 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime());
127 time_mapping.SetDouble(kPrefTicks, static_cast<double>( 240 time_mapping.SetDouble(kPrefTicks, static_cast<double>(
128 ticks_at_last_measurement_.ToInternalValue())); 241 ticks_at_last_measurement_.ToInternalValue()));
129 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>( 242 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>(
130 network_time_uncertainty_.ToInternalValue())); 243 network_time_uncertainty_.ToInternalValue()));
131 time_mapping.SetDouble(kPrefNetworkTime, 244 time_mapping.SetDouble(kPrefNetworkTime,
132 network_time_at_last_measurement_.ToJsTime()); 245 network_time_at_last_measurement_.ToJsTime());
133 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping); 246 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
247
248 query_timer_.Reset();
134 } 249 }
135 250
136 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time, 251 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
137 base::TimeDelta* uncertainty) const { 252 base::TimeDelta* uncertainty) const {
138 DCHECK(thread_checker_.CalledOnValidThread()); 253 DCHECK(thread_checker_.CalledOnValidThread());
139 DCHECK(network_time); 254 DCHECK(network_time);
140 if (network_time_at_last_measurement_.is_null()) { 255 if (network_time_at_last_measurement_.is_null()) {
141 return false; 256 return false;
142 } 257 }
143 DCHECK(!ticks_at_last_measurement_.is_null()); 258 DCHECK(!ticks_at_last_measurement_.is_null());
(...skipping 16 matching lines...) Expand all
160 return false; 275 return false;
161 } 276 }
162 *network_time = network_time_at_last_measurement_ + tick_delta; 277 *network_time = network_time_at_last_measurement_ + tick_delta;
163 if (uncertainty) { 278 if (uncertainty) {
164 *uncertainty = network_time_uncertainty_ + divergence; 279 *uncertainty = network_time_uncertainty_ + divergence;
165 } 280 }
166 return true; 281 return true;
167 } 282 }
168 283
169 } // namespace network_time 284 } // namespace network_time
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698