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

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: and iOS Created 4 years, 7 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/base/net_errors.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/url_request/url_fetcher.h"
24 #include "net/url_request/url_fetcher_response_writer.h"
25 #include "net/url_request/url_request_context_getter.h"
18 26
19 namespace network_time { 27 namespace network_time {
20 28
21 namespace { 29 namespace {
22 30
31 // Minimum number of minutes between time queries.
32 const uint32_t kMinimumQueryDelayMinutes = 60;
33
23 // Number of time measurements performed in a given network time calculation. 34 // Number of time measurements performed in a given network time calculation.
24 const uint32_t kNumTimeMeasurements = 7; 35 const uint32_t kNumTimeMeasurements = 7;
25 36
26 // Amount of divergence allowed between wall clock and tick clock. 37 // Amount of divergence allowed between wall clock and tick clock.
27 const uint32_t kClockDivergenceSeconds = 60; 38 const uint32_t kClockDivergenceSeconds = 60;
28 39
29 // Maximum time lapse before deserialized data are considered stale. 40 // Maximum time lapse before deserialized data are considered stale.
30 const uint32_t kSerializedDataMaxAgeDays = 7; 41 const uint32_t kSerializedDataMaxAgeDays = 7;
31 42
32 // Name of a pref that stores the wall clock time, via |ToJsTime|. 43 // Name of a pref that stores the wall clock time, via |ToJsTime|.
33 const char kPrefTime[] = "local"; 44 const char kPrefTime[] = "local";
34 45
35 // Name of a pref that stores the tick clock time, via |ToInternalValue|. 46 // Name of a pref that stores the tick clock time, via |ToInternalValue|.
36 const char kPrefTicks[] = "ticks"; 47 const char kPrefTicks[] = "ticks";
37 48
38 // Name of a pref that stores the time uncertainty, via |ToInternalValue|. 49 // Name of a pref that stores the time uncertainty, via |ToInternalValue|.
39 const char kPrefUncertainty[] = "uncertainty"; 50 const char kPrefUncertainty[] = "uncertainty";
40 51
41 // Name of a pref that stores the network time via |ToJsTime|. 52 // Name of a pref that stores the network time via |ToJsTime|.
42 const char kPrefNetworkTime[] = "network"; 53 const char kPrefNetworkTime[] = "network";
43 54
55 // Time server's maximum allowable clock skew, in seconds. (This is a property
56 // of the time server that we happen to know. It's unlikely that it would ever
57 // be that badly wrong, but all the same it's included here to document the very
58 // rough nature of the time service provided by this class.)
59 const uint32_t kTimeServerMaxSkewSeconds = 10;
60
61 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current";
62
63 // This is an ECDSA prime256v1 named-curve key.
64 const int kKeyVersion = 1;
65 const uint8_t kKeyPubBytes[] = {
66 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
67 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
68 0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36,
69 0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36,
70 0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec,
71 0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b,
72 0xc3, 0xc6, 0xa4, 0x7b, 0xa4, 0x41, 0xfc, 0xa7, 0x02, 0x54, 0xab, 0xe3,
73 0xe4, 0xb1, 0x00, 0xf5, 0xd5, 0x09, 0x11};
74
75 std::string GetServerProof(const net::URLFetcher* source) {
76 const net::HttpResponseHeaders* response_headers =
77 source->GetResponseHeaders();
78 if (!response_headers) {
79 return std::string();
80 }
81 std::string proof;
82 return response_headers->EnumerateHeader(nullptr, "x-cup-server-proof",
83 &proof)
84 ? proof
85 : std::string();
86 }
87
88 // Limits the amount of data that will be buffered from the server's response.
89 class SizeLimitingStringWriter : public net::URLFetcherStringWriter {
90 public:
91 SizeLimitingStringWriter(size_t limit) : limit_(limit) {}
92
93 int Write(net::IOBuffer* buffer,
94 int num_bytes,
95 const net::CompletionCallback& callback) override {
96 if (data().length() + num_bytes > limit_) {
97 return net::ERR_FILE_TOO_BIG;
98 }
99 return net::URLFetcherStringWriter::Write(buffer, num_bytes, callback);
100 }
101
102 private:
103 size_t limit_;
104 };
105
44 } // namespace 106 } // namespace
45 107
46 // static 108 // static
47 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) { 109 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping, 110 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
49 new base::DictionaryValue()); 111 new base::DictionaryValue());
50 } 112 }
51 113
52 NetworkTimeTracker::NetworkTimeTracker( 114 NetworkTimeTracker::NetworkTimeTracker(
53 std::unique_ptr<base::Clock> clock, 115 std::unique_ptr<base::Clock> clock,
54 std::unique_ptr<base::TickClock> tick_clock, 116 std::unique_ptr<base::TickClock> tick_clock,
55 PrefService* pref_service) 117 PrefService* pref_service,
56 : clock_(std::move(clock)), 118 scoped_refptr<net::URLRequestContextGetter> getter)
119 : server_url_(kTimeServiceURL),
120 max_response_size_(1024),
121 getter_(std::move(getter)),
122 clock_(std::move(clock)),
57 tick_clock_(std::move(tick_clock)), 123 tick_clock_(std::move(tick_clock)),
58 pref_service_(pref_service) { 124 pref_service_(pref_service) {
59 const base::DictionaryValue* time_mapping = 125 const base::DictionaryValue* time_mapping =
60 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); 126 pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
61 double time_js = 0; 127 double time_js = 0;
62 double ticks_js = 0; 128 double ticks_js = 0;
63 double network_time_js = 0; 129 double network_time_js = 0;
64 double uncertainty_js = 0; 130 double uncertainty_js = 0;
65 if (time_mapping->GetDouble(kPrefTime, &time_js) && 131 if (time_mapping->GetDouble(kPrefTime, &time_js) &&
66 time_mapping->GetDouble(kPrefTicks, &ticks_js) && 132 time_mapping->GetDouble(kPrefTicks, &ticks_js) &&
67 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && 133 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) &&
68 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { 134 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) {
69 time_at_last_measurement_ = base::Time::FromJsTime(time_js); 135 time_at_last_measurement_ = base::Time::FromJsTime(time_js);
70 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue( 136 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue(
71 static_cast<int64_t>(ticks_js)); 137 static_cast<int64_t>(ticks_js));
72 network_time_uncertainty_ = base::TimeDelta::FromInternalValue( 138 network_time_uncertainty_ = base::TimeDelta::FromInternalValue(
73 static_cast<int64_t>(uncertainty_js)); 139 static_cast<int64_t>(uncertainty_js));
74 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js); 140 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js);
75 } 141 }
76 base::Time now = clock_->Now(); 142 base::Time now = clock_->Now();
77 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() || 143 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() ||
78 time_at_last_measurement_ > now || 144 time_at_last_measurement_ > now ||
79 now - time_at_last_measurement_ > 145 now - time_at_last_measurement_ >
80 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) { 146 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) {
81 // Drop saved mapping if either clock has run backward, or the data are too 147 // Drop saved mapping if either clock has run backward, or the data are too
82 // old. 148 // old.
83 pref_service_->ClearPref(prefs::kNetworkTimeMapping); 149 pref_service_->ClearPref(prefs::kNetworkTimeMapping);
84 network_time_at_last_measurement_ = base::Time(); // Reset. 150 network_time_at_last_measurement_ = base::Time(); // Reset.
85 } 151 }
152
153 base::StringPiece public_key = {reinterpret_cast<const char*>(kKeyPubBytes),
154 sizeof(kKeyPubBytes)};
155 query_signer_ =
156 client_update_protocol::Ecdsa::Create(kKeyVersion, public_key);
157
158 QueueTimeQuery(base::TimeDelta::FromMinutes(kMinimumQueryDelayMinutes));
86 } 159 }
87 160
88 NetworkTimeTracker::~NetworkTimeTracker() { 161 NetworkTimeTracker::~NetworkTimeTracker() {
89 DCHECK(thread_checker_.CalledOnValidThread()); 162 DCHECK(thread_checker_.CalledOnValidThread());
90 } 163 }
91 164
92 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time, 165 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
93 base::TimeDelta resolution, 166 base::TimeDelta resolution,
94 base::TimeDelta latency, 167 base::TimeDelta latency,
95 base::TimeTicks post_time) { 168 base::TimeTicks post_time) {
(...skipping 29 matching lines...) Expand all
125 198
126 base::DictionaryValue time_mapping; 199 base::DictionaryValue time_mapping;
127 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime()); 200 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime());
128 time_mapping.SetDouble(kPrefTicks, static_cast<double>( 201 time_mapping.SetDouble(kPrefTicks, static_cast<double>(
129 ticks_at_last_measurement_.ToInternalValue())); 202 ticks_at_last_measurement_.ToInternalValue()));
130 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>( 203 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>(
131 network_time_uncertainty_.ToInternalValue())); 204 network_time_uncertainty_.ToInternalValue()));
132 time_mapping.SetDouble(kPrefNetworkTime, 205 time_mapping.SetDouble(kPrefNetworkTime,
133 network_time_at_last_measurement_.ToJsTime()); 206 network_time_at_last_measurement_.ToJsTime());
134 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping); 207 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
208
209 query_timer_.Reset();
mmenke 2016/05/02 17:47:28 This seems really unexpected. Suggest moving it t
mab 2016/05/05 19:57:42 Added a comment explaining why this is here.
210 }
211
212 void NetworkTimeTracker::SetTimeServerURLForTesting(const GURL& url) {
213 server_url_ = url;
214 }
215
216 void NetworkTimeTracker::SetMaxResponseSizeForTesting(size_t limit) {
217 max_response_size_ = limit;
135 } 218 }
136 219
137 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time, 220 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
138 base::TimeDelta* uncertainty) const { 221 base::TimeDelta* uncertainty) const {
139 DCHECK(thread_checker_.CalledOnValidThread()); 222 DCHECK(thread_checker_.CalledOnValidThread());
140 DCHECK(network_time); 223 DCHECK(network_time);
141 if (network_time_at_last_measurement_.is_null()) { 224 if (network_time_at_last_measurement_.is_null()) {
142 return false; 225 return false;
143 } 226 }
144 DCHECK(!ticks_at_last_measurement_.is_null()); 227 DCHECK(!ticks_at_last_measurement_.is_null());
(...skipping 15 matching lines...) Expand all
160 network_time_at_last_measurement_ = base::Time(); 243 network_time_at_last_measurement_ = base::Time();
161 return false; 244 return false;
162 } 245 }
163 *network_time = network_time_at_last_measurement_ + tick_delta; 246 *network_time = network_time_at_last_measurement_ + tick_delta;
164 if (uncertainty) { 247 if (uncertainty) {
165 *uncertainty = network_time_uncertainty_ + divergence; 248 *uncertainty = network_time_uncertainty_ + divergence;
166 } 249 }
167 return true; 250 return true;
168 } 251 }
169 252
253 void NetworkTimeTracker::QueryTimeService() {
254 DCHECK(thread_checker_.CalledOnValidThread());
255
256 // If GetNetworkTime() returns true, the NetworkTimeTracker thinks it is in
257 // sync, so there is no need to query.
258 base::Time network_time;
259 if (GetNetworkTime(&network_time, nullptr)) {
260 return;
261 }
262
263 std::string query_string;
264 query_signer_->SignRequest(nullptr, &query_string);
265 GURL url = server_url_;
266 GURL::Replacements replacements;
267 replacements.SetQueryStr(query_string);
268 url = url.ReplaceComponents(replacements);
269
270 // This cancels any outstanding fetch.
271 time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
272 if (!time_fetcher_) {
273 DVLOG(1) << "tried to make fetch happen; failed";
274 return;
275 }
276 time_fetcher_->SaveResponseWithWriter(
277 std::unique_ptr<net::URLFetcherResponseWriter>(
278 new SizeLimitingStringWriter(max_response_size_)));
279 DCHECK(getter_);
280 time_fetcher_->SetRequestContext(getter_.get());
281 // Not expecting any cookies, but just in case.
282 time_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
283 net::LOAD_DO_NOT_SAVE_COOKIES |
284 net::LOAD_DO_NOT_SEND_COOKIES |
285 net::LOAD_DO_NOT_SEND_AUTH_DATA);
286 time_fetcher_->Start();
287 fetch_started_ = tick_clock_->NowTicks();
288 }
289
290 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
291 DCHECK(thread_checker_.CalledOnValidThread());
292 DCHECK(time_fetcher_);
293 DCHECK_EQ(source, time_fetcher_.get());
294
295 // Since the timer is a repeating timer, it's unnecessary to reset it
296 // explicitly, but doing so is a convenient way to back off in the event of an
297 // error. Do that by default, and (if the query was successful) reset it to
298 // the standard interval.
mmenke 2016/05/02 17:47:28 Since you always set the timer delay, any reason n
mab 2016/05/05 19:57:42 I guess the main reason is that it obviates the ne
299 DCHECK(query_timer_.IsRunning());
300 base::TimeDelta delay = query_timer_.GetCurrentDelay();
301 if (delay < base::TimeDelta::FromDays(2)) {
302 delay *= 2;
303 }
304 QueueTimeQuery(delay);
305
306 if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
307 time_fetcher_->GetResponseCode() != 200) {
308 DVLOG(1) << "fetch failed, status=" << time_fetcher_->GetStatus().status()
309 << ",code=" << time_fetcher_->GetResponseCode();
310 time_fetcher_.reset();
mmenke 2016/05/02 17:47:28 optional: May want to extract most of this functi
mab 2016/05/05 19:57:42 That's a great idea. Done.
311 return;
312 }
313
314 std::string response_body;
315 if (!time_fetcher_->GetResponseAsString(&response_body)) {
316 DVLOG(1) << "failed to get response";
317 time_fetcher_.reset();
318 return;
319 }
320 DCHECK(query_signer_);
321 if (!query_signer_->ValidateResponse(response_body,
322 GetServerProof(time_fetcher_.get()))) {
323 DVLOG(1) << "invalid signature";
324 time_fetcher_.reset();
325 return;
326 }
327 time_fetcher_.reset();
328 response_body = response_body.substr(5); // Skips leading )]}'\n
329 std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
330 if (!value) {
331 DVLOG(1) << "bad JSON";
332 return;
333 }
334 const base::DictionaryValue* dict;
335 if (!value->GetAsDictionary(&dict)) {
336 DVLOG(1) << "not a dictionary";
337 return;
338 }
339 double current_time_millis;
340 if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
341 DVLOG(1) << "no current_time_millis";
342 return;
343 }
344 // There is a "server_nonce" key here too, but it serves no purpose other than
345 // to make the server's response unpredictable.
346 base::Time current_time = base::Time::FromJsTime(current_time_millis);
347 base::TimeDelta resolution =
348 base::TimeDelta::FromMilliseconds(1) +
349 base::TimeDelta::FromSeconds(kTimeServerMaxSkewSeconds);
350 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
351 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
352
353 // Normal completion, so, no backoff.
354 QueueTimeQuery(base::TimeDelta::FromMinutes(kMinimumQueryDelayMinutes));
355 }
356
357 void NetworkTimeTracker::QueueTimeQuery(base::TimeDelta delay) {
358 query_timer_.Start(FROM_HERE, delay, this,
359 &NetworkTimeTracker::QueryTimeService);
360 }
361
170 } // namespace network_time 362 } // namespace network_time
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698