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

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: estark review 1 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
66 static std::string GetServerETag(const net::URLFetcher* source) {
67 const net::HttpResponseHeaders* response_headers =
68 source->GetResponseHeaders();
69 if (response_headers == nullptr) {
70 return std::string();
71 }
72 std::string etag;
73 return response_headers->EnumerateHeader(nullptr, "ETag", &etag)
74 ? etag
75 : std::string();
76 }
77
44 } // namespace 78 } // namespace
45 79
46 // static 80 // static
47 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) { 81 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping, 82 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
49 new base::DictionaryValue()); 83 new base::DictionaryValue());
50 } 84 }
51 85
52 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock, 86 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock,
53 scoped_ptr<base::TickClock> tick_clock, 87 scoped_ptr<base::TickClock> tick_clock,
54 PrefService* pref_service) 88 PrefService* pref_service,
55 : clock_(std::move(clock)), 89 net::URLRequestContextGetter* getter)
90 : getter_(getter),
91 clock_(std::move(clock)),
56 tick_clock_(std::move(tick_clock)), 92 tick_clock_(std::move(tick_clock)),
57 pref_service_(pref_service) { 93 pref_service_(pref_service) {
estark 2016/03/28 23:18:59 Initialize |query_signer_| and |time_fetcher_| to
mab 2016/03/29 03:13:03 Whoa. Surprised that's necessary for scoped_ptr.
58 const base::DictionaryValue* time_mapping = 94 const base::DictionaryValue* time_mapping =
59 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); 95 pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
60 double time_js = 0; 96 double time_js = 0;
61 double ticks_js = 0; 97 double ticks_js = 0;
62 double network_time_js = 0; 98 double network_time_js = 0;
63 double uncertainty_js = 0; 99 double uncertainty_js = 0;
64 if (time_mapping->GetDouble(kPrefTime, &time_js) && 100 if (time_mapping->GetDouble(kPrefTime, &time_js) &&
65 time_mapping->GetDouble(kPrefTicks, &ticks_js) && 101 time_mapping->GetDouble(kPrefTicks, &ticks_js) &&
66 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && 102 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) &&
67 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { 103 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) {
68 time_at_last_measurement_ = base::Time::FromJsTime(time_js); 104 time_at_last_measurement_ = base::Time::FromJsTime(time_js);
69 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue( 105 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue(
70 static_cast<int64_t>(ticks_js)); 106 static_cast<int64_t>(ticks_js));
71 network_time_uncertainty_ = base::TimeDelta::FromInternalValue( 107 network_time_uncertainty_ = base::TimeDelta::FromInternalValue(
72 static_cast<int64_t>(uncertainty_js)); 108 static_cast<int64_t>(uncertainty_js));
73 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js); 109 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js);
74 } 110 }
75 base::Time now = clock_->Now(); 111 base::Time now = clock_->Now();
76 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() || 112 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() ||
77 time_at_last_measurement_ > now || 113 time_at_last_measurement_ > now ||
78 now - time_at_last_measurement_ > 114 now - time_at_last_measurement_ >
79 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) { 115 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) {
80 // Drop saved mapping if either clock has run backward, or the data are too 116 // Drop saved mapping if either clock has run backward, or the data are too
81 // old. 117 // old.
82 pref_service_->ClearPref(prefs::kNetworkTimeMapping); 118 pref_service_->ClearPref(prefs::kNetworkTimeMapping);
83 network_time_at_last_measurement_ = base::Time(); // Reset. 119 network_time_at_last_measurement_ = base::Time(); // Reset.
84 } 120 }
121 if (getter != nullptr) {
122 query_signer_ = client_update_protocol::Ecdsa::Create(
123 kKeyVersion,
124 {reinterpret_cast<const char*>(kKeyPubBytes), sizeof(kKeyPubBytes)});
125 base::TimeDelta period = base::TimeDelta::FromMinutes(60);
126 query_timer_.Start(FROM_HERE, period, this,
127 &NetworkTimeTracker::QueryTimeService);
128 }
85 } 129 }
86 130
87 NetworkTimeTracker::~NetworkTimeTracker() { 131 NetworkTimeTracker::~NetworkTimeTracker() {
88 DCHECK(thread_checker_.CalledOnValidThread()); 132 DCHECK(thread_checker_.CalledOnValidThread());
89 } 133 }
90 134
135 void NetworkTimeTracker::QueryTimeService() {
136 DCHECK(thread_checker_.CalledOnValidThread());
137
138 // If GetNetworkTime() returns true, the NetworkTimeTracker thinks
139 // it is in sync, so there is no need to query.
140 base::Time network_time;
141 if (GetNetworkTime(&network_time, nullptr)) {
142 return;
143 }
144
145 std::string query_string;
146 query_signer_->SignRequest({"", 0}, &query_string);
147 GURL url(kTimeServiceURL);
148 GURL::Replacements replacements;
149 replacements.SetQueryStr(query_string);
150 url = url.ReplaceComponents(replacements);
151
152 // This cancels any outstanding fetch.
153 time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
154 if (time_fetcher_ == nullptr) {
155 VLOG(1) << "tried to make fetch happen; failed";
156 return;
157 }
158 time_fetcher_->SetRequestContext(getter_);
159 // Not expecting any cookies, but just in case.
160 time_fetcher_->SetLoadFlags(
161 net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES |
162 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_BYPASS_CACHE |
163 net::LOAD_DO_NOT_SEND_AUTH_DATA);
164 time_fetcher_->Start();
165 fetch_started_ = tick_clock_->NowTicks();
166 }
167
168 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 DCHECK(source);
171 if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
172 source->GetResponseCode() != 200) {
173 VLOG(1) << "fetch failed, status=" << source->GetStatus().status()
174 << ",code=" << source->GetResponseCode();
175 return;
176 }
177
178 std::string response_body;
179 if (!source->GetResponseAsString(&response_body)) {
180 VLOG(1) << "failed to get response";
181 return;
182 }
183 DCHECK(query_signer_.get());
184 if (!query_signer_->ValidateResponse(response_body, GetServerETag(source))) {
185 VLOG(1) << "invalid signature";
186 return;
187 }
188 response_body = response_body.substr(5); // Skips leading )]}'\n
189 base::JSONReader reader;
190 scoped_ptr<base::Value> value = reader.Read(response_body);
191 if (value == nullptr) {
192 VLOG(1) << "bad JSON";
193 return;
194 }
195 const base::DictionaryValue* dict;
196 if (!value->GetAsDictionary(&dict)) {
197 VLOG(1) << "not a dictionary";
198 return;
199 }
200 double current_time_millis;
201 if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
202 VLOG(1) << "no current_time_millis";
203 return;
204 }
205 // There's also a "server_nonce" key, which we can ignore.
206 base::Time current_time = base::Time::FromJsTime(current_time_millis);
207 // The extra 10 seconds comes from a property of the time server that we
208 // happen to know, which its maximum allowable clock skew. It's unlikely that
209 // it would ever be that badly wrong, but all the same it's included here to
210 // document the very rough nature of the time service provided by this class.
211 base::TimeDelta resolution =
212 base::TimeDelta::FromMilliseconds(1) + base::TimeDelta::FromSeconds(10);
213 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
214 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
215 }
216
91 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time, 217 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
92 base::TimeDelta resolution, 218 base::TimeDelta resolution,
93 base::TimeDelta latency, 219 base::TimeDelta latency,
94 base::TimeTicks post_time) { 220 base::TimeTicks post_time) {
95 DCHECK(thread_checker_.CalledOnValidThread()); 221 DCHECK(thread_checker_.CalledOnValidThread());
96 DVLOG(1) << "Network time updating to " 222 DVLOG(1) << "Network time updating to "
97 << base::UTF16ToUTF8( 223 << base::UTF16ToUTF8(
98 base::TimeFormatFriendlyDateAndTime(network_time)); 224 base::TimeFormatFriendlyDateAndTime(network_time));
99 // Update network time on every request to limit dependency on ticks lag. 225 // Update network time on every request to limit dependency on ticks lag.
100 // TODO(mad): Find a heuristic to avoid augmenting the 226 // TODO(mad): Find a heuristic to avoid augmenting the
(...skipping 23 matching lines...) Expand all
124 250
125 base::DictionaryValue time_mapping; 251 base::DictionaryValue time_mapping;
126 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime()); 252 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime());
127 time_mapping.SetDouble(kPrefTicks, static_cast<double>( 253 time_mapping.SetDouble(kPrefTicks, static_cast<double>(
128 ticks_at_last_measurement_.ToInternalValue())); 254 ticks_at_last_measurement_.ToInternalValue()));
129 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>( 255 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>(
130 network_time_uncertainty_.ToInternalValue())); 256 network_time_uncertainty_.ToInternalValue()));
131 time_mapping.SetDouble(kPrefNetworkTime, 257 time_mapping.SetDouble(kPrefNetworkTime,
132 network_time_at_last_measurement_.ToJsTime()); 258 network_time_at_last_measurement_.ToJsTime());
133 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping); 259 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
260
261 query_timer_.Reset();
134 } 262 }
135 263
136 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time, 264 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
137 base::TimeDelta* uncertainty) const { 265 base::TimeDelta* uncertainty) const {
138 DCHECK(thread_checker_.CalledOnValidThread()); 266 DCHECK(thread_checker_.CalledOnValidThread());
139 DCHECK(network_time); 267 DCHECK(network_time);
140 if (network_time_at_last_measurement_.is_null()) { 268 if (network_time_at_last_measurement_.is_null()) {
141 return false; 269 return false;
142 } 270 }
143 DCHECK(!ticks_at_last_measurement_.is_null()); 271 DCHECK(!ticks_at_last_measurement_.is_null());
(...skipping 16 matching lines...) Expand all
160 return false; 288 return false;
161 } 289 }
162 *network_time = network_time_at_last_measurement_ + tick_delta; 290 *network_time = network_time_at_last_measurement_ + tick_delta;
163 if (uncertainty) { 291 if (uncertainty) {
164 *uncertainty = network_time_uncertainty_ + divergence; 292 *uncertainty = network_time_uncertainty_ + divergence;
165 } 293 }
166 return true; 294 return true;
167 } 295 }
168 296
169 } // namespace network_time 297 } // namespace network_time
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698