OLD | NEW |
---|---|
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", ¤t_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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |