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

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: a wild dependency check appears! 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 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current";
51
52 // This is an ECDSA prime256v1 named-curve key.
53 const int kKeyVersion = 1;
54 const uint8_t kKeyPubBytes[] = {
55 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
56 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
57 0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36,
58 0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36,
59 0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec,
60 0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b,
61 0xc3, 0xc6, 0xa4, 0x7b, 0xa4, 0x41, 0xfc, 0xa7, 0x02, 0x54, 0xab, 0xe3,
62 0xe4, 0xb1, 0x00, 0xf5, 0xd5, 0x09, 0x11};
63
64 static std::string GetServerProof(const net::URLFetcher* source) {
65 const net::HttpResponseHeaders* response_headers =
66 source->GetResponseHeaders();
67 if (response_headers == nullptr) {
68 return std::string();
69 }
70 std::string proof;
71 return response_headers->EnumerateHeader(nullptr, "x-cup-server-proof",
waffles 2016/04/26 21:16:46 Hm, filed crbug/606958 for this, but this is fine
72 &proof)
73 ? proof
74 : std::string();
75 }
76
44 } // namespace 77 } // namespace
45 78
46 // static 79 // static
47 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) { 80 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping, 81 registry->RegisterDictionaryPref(prefs::kNetworkTimeMapping,
49 new base::DictionaryValue()); 82 new base::DictionaryValue());
50 } 83 }
51 84
52 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock, 85 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::Clock> clock,
53 scoped_ptr<base::TickClock> tick_clock, 86 scoped_ptr<base::TickClock> tick_clock,
54 PrefService* pref_service) 87 PrefService* pref_service,
55 : clock_(std::move(clock)), 88 net::URLRequestContextGetter* getter)
89 : getter_(getter),
90 time_fetcher_(nullptr),
Nicolas Zea 2016/04/27 18:58:22 nit: both time_fetcher_ and query_signer_ are scop
mab 2016/04/27 20:00:37 Done.
91 query_signer_(nullptr),
92 clock_(std::move(clock)),
56 tick_clock_(std::move(tick_clock)), 93 tick_clock_(std::move(tick_clock)),
57 pref_service_(pref_service) { 94 pref_service_(pref_service) {
58 const base::DictionaryValue* time_mapping = 95 const base::DictionaryValue* time_mapping =
59 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); 96 pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
60 double time_js = 0; 97 double time_js = 0;
61 double ticks_js = 0; 98 double ticks_js = 0;
62 double network_time_js = 0; 99 double network_time_js = 0;
63 double uncertainty_js = 0; 100 double uncertainty_js = 0;
64 if (time_mapping->GetDouble(kPrefTime, &time_js) && 101 if (time_mapping->GetDouble(kPrefTime, &time_js) &&
65 time_mapping->GetDouble(kPrefTicks, &ticks_js) && 102 time_mapping->GetDouble(kPrefTicks, &ticks_js) &&
66 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && 103 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) &&
67 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { 104 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) {
68 time_at_last_measurement_ = base::Time::FromJsTime(time_js); 105 time_at_last_measurement_ = base::Time::FromJsTime(time_js);
69 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue( 106 ticks_at_last_measurement_ = base::TimeTicks::FromInternalValue(
70 static_cast<int64_t>(ticks_js)); 107 static_cast<int64_t>(ticks_js));
71 network_time_uncertainty_ = base::TimeDelta::FromInternalValue( 108 network_time_uncertainty_ = base::TimeDelta::FromInternalValue(
72 static_cast<int64_t>(uncertainty_js)); 109 static_cast<int64_t>(uncertainty_js));
73 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js); 110 network_time_at_last_measurement_ = base::Time::FromJsTime(network_time_js);
74 } 111 }
75 base::Time now = clock_->Now(); 112 base::Time now = clock_->Now();
76 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() || 113 if (ticks_at_last_measurement_ > tick_clock_->NowTicks() ||
77 time_at_last_measurement_ > now || 114 time_at_last_measurement_ > now ||
78 now - time_at_last_measurement_ > 115 now - time_at_last_measurement_ >
79 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) { 116 base::TimeDelta::FromDays(kSerializedDataMaxAgeDays)) {
80 // Drop saved mapping if either clock has run backward, or the data are too 117 // Drop saved mapping if either clock has run backward, or the data are too
81 // old. 118 // old.
82 pref_service_->ClearPref(prefs::kNetworkTimeMapping); 119 pref_service_->ClearPref(prefs::kNetworkTimeMapping);
83 network_time_at_last_measurement_ = base::Time(); // Reset. 120 network_time_at_last_measurement_ = base::Time(); // Reset.
84 } 121 }
122 if (getter != nullptr) {
123 query_signer_ = client_update_protocol::Ecdsa::Create(
124 kKeyVersion,
125 {reinterpret_cast<const char*>(kKeyPubBytes), sizeof(kKeyPubBytes)});
126 base::TimeDelta period = base::TimeDelta::FromMinutes(60);
Nicolas Zea 2016/04/27 18:58:22 nit: although this is only used here, might be goo
mab 2016/04/27 20:00:37 Done.
127 query_timer_.Start(FROM_HERE, period, this,
128 &NetworkTimeTracker::QueryTimeService);
129 }
85 } 130 }
86 131
87 NetworkTimeTracker::~NetworkTimeTracker() { 132 NetworkTimeTracker::~NetworkTimeTracker() {
88 DCHECK(thread_checker_.CalledOnValidThread()); 133 DCHECK(thread_checker_.CalledOnValidThread());
89 } 134 }
90 135
136 void NetworkTimeTracker::QueryTimeService() {
137 DCHECK(thread_checker_.CalledOnValidThread());
138
139 // If GetNetworkTime() returns true, the NetworkTimeTracker thinks
140 // it is in sync, so there is no need to query.
141 base::Time network_time;
142 if (GetNetworkTime(&network_time, nullptr)) {
143 return;
144 }
145
146 std::string query_string;
147 query_signer_->SignRequest({"", 0}, &query_string);
148 GURL url(kTimeServiceURL);
149 GURL::Replacements replacements;
150 replacements.SetQueryStr(query_string);
151 url = url.ReplaceComponents(replacements);
152
153 // This cancels any outstanding fetch.
154 time_fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
155 if (time_fetcher_ == nullptr) {
156 VLOG(1) << "tried to make fetch happen; failed";
Nicolas Zea 2016/04/27 18:58:22 Why VLOG vs DVLOG (here and elsewhere)? Unless the
mab 2016/04/27 20:00:36 Done.
157 return;
158 }
159 time_fetcher_->SetRequestContext(getter_);
160 // Not expecting any cookies, but just in case.
161 time_fetcher_->SetLoadFlags(
162 net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES |
163 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_BYPASS_CACHE |
164 net::LOAD_DO_NOT_SEND_AUTH_DATA);
165 time_fetcher_->Start();
166 fetch_started_ = tick_clock_->NowTicks();
167 }
168
169 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
170 DCHECK(thread_checker_.CalledOnValidThread());
171 DCHECK(source);
172 if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
173 source->GetResponseCode() != 200) {
174 VLOG(1) << "fetch failed, status=" << source->GetStatus().status()
175 << ",code=" << source->GetResponseCode();
176 return;
177 }
178
179 std::string response_body;
180 if (!source->GetResponseAsString(&response_body)) {
181 VLOG(1) << "failed to get response";
182 return;
183 }
184 DCHECK(query_signer_.get());
185 if (!query_signer_->ValidateResponse(response_body, GetServerProof(source))) {
186 VLOG(1) << "invalid signature";
187 return;
188 }
189 response_body = response_body.substr(5); // Skips leading )]}'\n
190 base::JSONReader reader;
191 scoped_ptr<base::Value> value = reader.Read(response_body);
192 if (value == nullptr) {
193 VLOG(1) << "bad JSON";
194 return;
195 }
196 const base::DictionaryValue* dict;
197 if (!value->GetAsDictionary(&dict)) {
198 VLOG(1) << "not a dictionary";
199 return;
200 }
201 double current_time_millis;
202 if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
203 VLOG(1) << "no current_time_millis";
204 return;
205 }
206 // There's also a "server_nonce" key, which we can ignore.
207 base::Time current_time = base::Time::FromJsTime(current_time_millis);
208 // The extra 10 seconds comes from a property of the time server that we
209 // happen to know, which its maximum allowable clock skew. It's unlikely that
Nicolas Zea 2016/04/27 18:58:22 nit: which its -> which is its
mab 2016/04/27 20:00:37 Done.
210 // it would ever be that badly wrong, but all the same it's included here to
211 // document the very rough nature of the time service provided by this class.
212 base::TimeDelta resolution =
213 base::TimeDelta::FromMilliseconds(1) + base::TimeDelta::FromSeconds(10);
214 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
215 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
216 }
217
91 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time, 218 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time,
92 base::TimeDelta resolution, 219 base::TimeDelta resolution,
93 base::TimeDelta latency, 220 base::TimeDelta latency,
94 base::TimeTicks post_time) { 221 base::TimeTicks post_time) {
waffles 2016/04/26 21:16:46 IIRC, this is called by a number of services, do w
mab 2016/04/27 18:07:41 We do, but I also think it makes sense to move awa
95 DCHECK(thread_checker_.CalledOnValidThread()); 222 DCHECK(thread_checker_.CalledOnValidThread());
96 DVLOG(1) << "Network time updating to " 223 DVLOG(1) << "Network time updating to "
97 << base::UTF16ToUTF8( 224 << base::UTF16ToUTF8(
98 base::TimeFormatFriendlyDateAndTime(network_time)); 225 base::TimeFormatFriendlyDateAndTime(network_time));
99 // Update network time on every request to limit dependency on ticks lag. 226 // Update network time on every request to limit dependency on ticks lag.
100 // TODO(mad): Find a heuristic to avoid augmenting the 227 // TODO(mad): Find a heuristic to avoid augmenting the
101 // network_time_uncertainty_ too much by a particularly long latency. 228 // network_time_uncertainty_ too much by a particularly long latency.
102 // Maybe only update when the the new time either improves in accuracy or 229 // Maybe only update when the the new time either improves in accuracy or
103 // drifts too far from |network_time_at_last_measurement_|. 230 // drifts too far from |network_time_at_last_measurement_|.
104 network_time_at_last_measurement_ = network_time; 231 network_time_at_last_measurement_ = network_time;
(...skipping 19 matching lines...) Expand all
124 251
125 base::DictionaryValue time_mapping; 252 base::DictionaryValue time_mapping;
126 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime()); 253 time_mapping.SetDouble(kPrefTime, time_at_last_measurement_.ToJsTime());
127 time_mapping.SetDouble(kPrefTicks, static_cast<double>( 254 time_mapping.SetDouble(kPrefTicks, static_cast<double>(
128 ticks_at_last_measurement_.ToInternalValue())); 255 ticks_at_last_measurement_.ToInternalValue()));
129 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>( 256 time_mapping.SetDouble(kPrefUncertainty, static_cast<double>(
130 network_time_uncertainty_.ToInternalValue())); 257 network_time_uncertainty_.ToInternalValue()));
131 time_mapping.SetDouble(kPrefNetworkTime, 258 time_mapping.SetDouble(kPrefNetworkTime,
132 network_time_at_last_measurement_.ToJsTime()); 259 network_time_at_last_measurement_.ToJsTime());
133 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping); 260 pref_service_->Set(prefs::kNetworkTimeMapping, time_mapping);
261
262 query_timer_.Reset();
134 } 263 }
135 264
136 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time, 265 bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
137 base::TimeDelta* uncertainty) const { 266 base::TimeDelta* uncertainty) const {
138 DCHECK(thread_checker_.CalledOnValidThread()); 267 DCHECK(thread_checker_.CalledOnValidThread());
139 DCHECK(network_time); 268 DCHECK(network_time);
140 if (network_time_at_last_measurement_.is_null()) { 269 if (network_time_at_last_measurement_.is_null()) {
141 return false; 270 return false;
142 } 271 }
143 DCHECK(!ticks_at_last_measurement_.is_null()); 272 DCHECK(!ticks_at_last_measurement_.is_null());
(...skipping 16 matching lines...) Expand all
160 return false; 289 return false;
161 } 290 }
162 *network_time = network_time_at_last_measurement_ + tick_delta; 291 *network_time = network_time_at_last_measurement_ + tick_delta;
163 if (uncertainty) { 292 if (uncertainty) {
164 *uncertainty = network_time_uncertainty_ + divergence; 293 *uncertainty = network_time_uncertainty_ + divergence;
165 } 294 }
166 return true; 295 return true;
167 } 296 }
168 297
169 } // namespace network_time 298 } // namespace network_time
OLDNEW
« no previous file with comments | « components/network_time/network_time_tracker.h ('k') | components/network_time/network_time_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698