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

Side by Side Diff: common/ping.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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
« no previous file with comments | « common/ping.h ('k') | common/ping_event.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/common/ping.h"
17 #include "base/scoped_ptr.h"
18 #include "omaha/base/constants.h"
19 #include "omaha/base/debug.h"
20 #include "omaha/base/logging.h"
21 #include "omaha/base/scoped_any.h"
22 #include "omaha/base/scoped_impersonation.h"
23 #include "omaha/base/string.h"
24 #include "omaha/base/utils.h"
25 #include "omaha/base/vista_utils.h"
26 #include "omaha/common/app_registry_utils.h"
27 #include "omaha/common/command_line.h"
28 #include "omaha/common/command_line_builder.h"
29 #include "omaha/common/config_manager.h"
30 #include "omaha/common/goopdate_utils.h"
31 #include "omaha/common/update_request.h"
32 #include "omaha/common/update_response.h"
33 #include "omaha/goopdate/app.h"
34 #include "omaha/goopdate/app_bundle.h"
35 #include "omaha/goopdate/update_request_utils.h"
36 #include "omaha/goopdate/update_response_utils.h"
37
38 namespace omaha {
39
40 const TCHAR* const Ping::kRegKeyPing = _T("Pings");
41 const time64 Ping::kPingExpiry100ns = 10 * kDaysTo100ns; // 10 days.
42
43 Ping::Ping(bool is_machine,
44 const CString& session_id,
45 const CString& install_source)
46 : is_machine_(is_machine),
47 ping_request_(xml::UpdateRequest::Create(is_machine,
48 session_id,
49 install_source,
50 CString())) {
51 }
52
53 Ping::~Ping() {
54 }
55
56 void Ping::BuildRequest(const App* app, bool is_update_check) {
57 update_request_utils::BuildRequest(app, is_update_check, ping_request_.get());
58 }
59
60 void Ping::LoadAppDataFromExtraArgs(const CommandLineExtraArgs& extra_args) {
61 const CString installation_id = GuidToString(extra_args.installation_id);
62 for (size_t i = 0; i != extra_args.apps.size(); ++i) {
63 AppData app_data;
64 app_data.app_id = GuidToString(extra_args.apps[i].app_guid);
65 app_data.language = extra_args.language;
66 app_data.brand_code = extra_args.brand_code;
67 app_data.client_id = extra_args.client_id;
68 app_data.installation_id = installation_id;
69 app_data.experiment_labels = extra_args.apps[i].experiment_labels;
70 apps_data_.push_back(app_data);
71 }
72
73 omaha_data_.app_id = kGoogleUpdateAppId;
74 omaha_data_.language = extra_args.language;
75 omaha_data_.brand_code = extra_args.brand_code;
76 omaha_data_.client_id = extra_args.client_id;
77 omaha_data_.installation_id = installation_id;
78 omaha_data_.experiment_labels = extra_args.experiment_labels;
79 }
80
81 void Ping::LoadOmahaDataFromRegistry() {
82 omaha_data_.app_id = kGoogleUpdateAppId;
83 app_registry_utils::GetClientStateData(
84 is_machine_,
85 kGoogleUpdateAppId,
86 NULL,
87 NULL, // ap is not used yet.
88 &omaha_data_.language,
89 &omaha_data_.brand_code,
90 &omaha_data_.client_id,
91 &omaha_data_.installation_id,
92 &omaha_data_.experiment_labels);
93 }
94
95 void Ping::LoadAppDataFromRegistry(const std::vector<CString>& app_ids) {
96 for (size_t i = 0; i != app_ids.size(); ++i) {
97 AppData app_data;
98 app_data.app_id = app_ids[i];
99 app_registry_utils::GetClientStateData(
100 is_machine_,
101 app_data.app_id,
102 &app_data.pv,
103 NULL, // ap is not used yet.
104 &app_data.language,
105 &app_data.brand_code,
106 &app_data.client_id,
107 &app_data.installation_id,
108 &app_data.experiment_labels);
109 apps_data_.push_back(app_data);
110 }
111
112 LoadOmahaDataFromRegistry();
113 }
114
115 HRESULT Ping::Send(bool is_fire_and_forget) {
116 CORE_LOG(L3, (_T("[Ping::Send]")));
117
118 ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_));
119
120 if (ping_request_->IsEmpty()) {
121 CORE_LOG(L3, (_T("[Ping::Send did not send empty ping]")));
122 return S_FALSE;
123 }
124
125 CString request_string;
126 HRESULT hr = BuildRequestString(&request_string);
127 if (FAILED(hr)) {
128 CORE_LOG(LE, (_T("[BuildRequestString failed][0x%08x]"), hr));
129 return hr;
130 }
131
132 const DWORD wait_timeout_ms = is_fire_and_forget ? 0 : INFINITE;
133 hr = SendUsingGoogleUpdate(request_string, wait_timeout_ms);
134 if (SUCCEEDED(hr)) {
135 return hr;
136 }
137
138 CORE_LOG(LE, (_T("[Ping::SendUsingGoogleUpdate failed][0x%x]"), hr));
139
140 hr = SendInProcess(request_string);
141 if (SUCCEEDED(hr)) {
142 return hr;
143 }
144
145 CORE_LOG(LE, (_T("[Ping::SendInProcess failed][0x%x]"), hr));
146
147 return PersistPing(is_machine_, request_string);
148 }
149
150 void Ping::BuildOmahaPing(const CString& version,
151 const CString& next_version,
152 const PingEventPtr& ping_event) {
153 xml::request::App app(BuildOmahaApp(version, next_version));
154 app.ping_events.push_back(ping_event);
155 ping_request_->AddApp(app);
156 }
157
158 void Ping::BuildOmahaPing(const CString& version,
159 const CString& next_version,
160 const PingEventPtr& ping_event1,
161 const PingEventPtr& ping_event2) {
162 xml::request::App app(BuildOmahaApp(version, next_version));
163 app.ping_events.push_back(ping_event1);
164 app.ping_events.push_back(ping_event2);
165 ping_request_->AddApp(app);
166 }
167
168 xml::request::App Ping::BuildOmahaApp(const CString& version,
169 const CString& next_version) const {
170 xml::request::App app;
171
172 app.app_id = omaha_data_.app_id;
173 app.lang = omaha_data_.language;
174 app.brand_code = omaha_data_.brand_code;
175 app.client_id = omaha_data_.client_id;
176 app.experiments = omaha_data_.experiment_labels;
177 app.iid = omaha_data_.installation_id;
178
179 app.version = version;
180 app.next_version = next_version;
181
182 return app;
183 }
184
185 void Ping::BuildAppsPing(const PingEventPtr& ping_event) {
186 for (size_t i = 0; i != apps_data_.size(); ++i) {
187 xml::request::App app;
188
189 app.version = apps_data_[i].pv;
190 app.app_id = apps_data_[i].app_id;
191 app.lang = apps_data_[i].language;
192 app.brand_code = apps_data_[i].brand_code;
193 app.client_id = apps_data_[i].client_id;
194 app.experiments = apps_data_[i].experiment_labels;
195 app.iid = apps_data_[i].installation_id;
196
197 app.ping_events.push_back(ping_event);
198 ping_request_->AddApp(app);
199 }
200 }
201
202 HRESULT Ping::SendUsingGoogleUpdate(const CString& request_string,
203 DWORD wait_timeout_ms) const {
204 CStringA request_string_utf8(WideToUtf8(request_string));
205 CStringA ping_string_utf8;
206 WebSafeBase64Escape(request_string_utf8, &ping_string_utf8);
207
208 CommandLineBuilder builder(COMMANDLINE_MODE_PING);
209 builder.set_ping_string(Utf8ToWideChar(ping_string_utf8,
210 ping_string_utf8.GetLength()));
211 CString args = builder.GetCommandLineArgs();
212
213 scoped_process ping_process;
214 HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(is_machine_,
215 args,
216 address(ping_process));
217 if (FAILED(hr)) {
218 CORE_LOG(LE, (_T("[failed to start ping process][0x%08x]"), hr));
219 return hr;
220 }
221
222 if (wait_timeout_ms) {
223 DWORD result = ::WaitForSingleObject(get(ping_process), wait_timeout_ms);
224 DWORD exit_code(0);
225 if (result == WAIT_OBJECT_0 &&
226 ::GetExitCodeProcess(get(ping_process), &exit_code)) {
227 ASSERT1(exit_code == 0 || FAILED(exit_code));
228 return (exit_code == 0) ? S_OK : exit_code;
229 } else {
230 if (result == WAIT_TIMEOUT) {
231 CORE_LOG(LW, (_T("[ping process did not finish in time][pid=%u]"),
232 ::GetProcessId(get(ping_process))));
233 VERIFY1(::TerminateProcess(get(ping_process), UINT_MAX));
234 }
235 return E_FAIL;
236 }
237 }
238
239 return S_OK;
240 }
241
242 HRESULT Ping::SendInProcess(const CString& request_string) const {
243 HRESULT hr = SendString(is_machine_, HeadersVector(), request_string);
244 if (FAILED(hr)) {
245 CORE_LOG(LE, (_T("[SendString failed][0x%08x]"), hr));
246 return hr;
247 }
248
249 return S_OK;
250 }
251
252 HRESULT Ping::BuildRequestString(CString* request_string) const {
253 ASSERT1(request_string);
254 return ping_request_->Serialize(request_string);
255 }
256
257 CString Ping::GetPingRegPath(bool is_machine) {
258 CString ping_reg_path = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
259 return AppendRegKeyPath(ping_reg_path, kRegKeyPing);
260 }
261
262 HRESULT Ping::LoadPersistedPings(bool is_machine, PingsVector* pings) {
263 ASSERT1(pings);
264
265 RegKey ping_reg_key;
266 HRESULT hr = ping_reg_key.Open(GetPingRegPath(is_machine), KEY_READ);
267 if (FAILED(hr)) {
268 CORE_LOG(LW, (_T("[Unable to open Ping regkey][0x%x]"), hr));
269 return hr;
270 }
271
272 int num_pings = ping_reg_key.GetValueCount();
273 for (int i = 0; i < num_pings; ++i) {
274 CString persisted_time_string;
275 hr = ping_reg_key.GetValueNameAt(i, &persisted_time_string, NULL);
276 if (FAILED(hr)) {
277 CORE_LOG(LW, (_T("[GetValueNameAt failed][%d]"), i));
278 continue;
279 }
280
281 time64 persisted_time = _tcstoui64(persisted_time_string, NULL, 10);
282 if (persisted_time == 0 || persisted_time == _UI64_MAX) {
283 CORE_LOG(LW, (_T("[Incorrect time value][%s]"), persisted_time_string));
284 continue;
285 }
286
287 CString ping_string;
288 hr = ping_reg_key.GetValue(persisted_time_string, &ping_string);
289 if (FAILED(hr)) {
290 CORE_LOG(LW, (_T("[GetValue failed][%s]"), persisted_time_string));
291 continue;
292 }
293
294 pings->push_back(std::make_pair(persisted_time, ping_string));
295 }
296
297 return S_OK;
298 }
299
300 bool Ping::IsPingExpired(time64 persisted_time) {
301 const time64 now = GetCurrent100NSTime();
302
303 if (now < persisted_time) {
304 CORE_LOG(LW, (_T("[Incorrect clock time][%I64u][%I64u]"),
305 now, persisted_time));
306 return true;
307 }
308
309 const time64 time_difference = now - persisted_time;
310 CORE_LOG(L3, (_T("[%I64u][%I64u][%I64u]"),
311 now, persisted_time, time_difference));
312
313 const bool result = time_difference >= kPingExpiry100ns;
314 CORE_LOG(L3, (_T("[IsPingExpired][%d]"), result));
315 return result;
316 }
317
318 HRESULT Ping::DeletePersistedPing(bool is_machine, time64 persisted_time) {
319 CString persisted_time_string;
320 persisted_time_string.Format(_T("%I64u"), persisted_time);
321 CORE_LOG(L3, (_T("[Ping::DeletePersistedPing][%s]"), persisted_time_string));
322
323 CString ping_reg_path(GetPingRegPath(is_machine));
324 HRESULT hr = RegKey::DeleteValue(ping_reg_path, persisted_time_string);
325
326 if (RegKey::IsKeyEmpty(ping_reg_path)) {
327 VERIFY1(SUCCEEDED(RegKey::DeleteKey(ping_reg_path)));
328 }
329
330 return hr;
331 }
332
333 HRESULT Ping::PersistPing(bool is_machine, const CString& ping_string) {
334 CString time_now_str;
335 time_now_str.Format(_T("%I64u"), GetCurrent100NSTime());
336 CORE_LOG(L3, (_T("[Ping::PersistPing][%s][%s]"), time_now_str, ping_string));
337
338 return RegKey::SetValue(GetPingRegPath(is_machine),
339 time_now_str,
340 ping_string);
341 }
342
343 HRESULT Ping::SendPersistedPings(bool is_machine) {
344 PingsVector pings;
345 HRESULT hr = LoadPersistedPings(is_machine, &pings);
346 if (FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))) {
347 return hr;
348 }
349
350 for (size_t i = 0; i != pings.size(); ++i) {
351 time64 persisted_time = pings[i].first;
352 int32 request_age = Time64ToInt32(GetCurrent100NSTime()) -
353 Time64ToInt32(persisted_time);
354 const CString& ping_string(pings[i].second);
355
356 CORE_LOG(L3, (_T("[Resending ping][%I64u][%d][%s]"),
357 persisted_time, request_age, ping_string));
358
359 CString request_age_string;
360 request_age_string.Format(_T("%d"), request_age);
361 HeadersVector headers;
362 headers.push_back(std::make_pair(kHeaderXRequestAge, request_age_string));
363
364 hr = SendString(is_machine, headers, ping_string);
365
366 if (SUCCEEDED(hr) || IsPingExpired(persisted_time)) {
367 CORE_LOG(L3, (_T("[Deleting ping][0x%x]"), hr));
368 VERIFY1(SUCCEEDED(DeletePersistedPing(is_machine, persisted_time)));
369 }
370 }
371
372 return S_OK;
373 }
374
375 // TODO(omaha): Ping support for authenticated proxies.
376 HRESULT Ping::SendString(bool is_machine,
377 const HeadersVector& headers,
378 const CString& request_string) {
379 ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine));
380
381 CORE_LOG(L3, (_T("[ping request string][%s]"), request_string));
382
383 CString url;
384 ConfigManager::Instance()->GetPingUrl(&url);
385
386 // Impersonate the user if the caller is machine, running as local system,
387 // and a user is logged on to the system.
388 scoped_handle impersonation_token(
389 goopdate_utils::GetImpersonationTokenForMachineProcess(is_machine));
390 scoped_impersonation impersonate_user(get(impersonation_token));
391
392 WebServicesClient web_service_client(is_machine);
393 HRESULT hr(web_service_client.Initialize(url, headers, false));
394 if (FAILED(hr)) {
395 CORE_LOG(LE, (_T("[WebServicesClient::Initialize failed][0x%08x]"), hr));
396 return hr;
397 }
398
399 scoped_ptr<xml::UpdateResponse> response(xml::UpdateResponse::Create());
400 hr = web_service_client.SendString(&request_string, response.get());
401 if (FAILED(hr)) {
402 CORE_LOG(LE, (_T("[WebServicesClient::SendString failed][0x%08x]"), hr));
403 return hr;
404 }
405
406 // If a ping is sent but the response is corrupted in some way (or we can't
407 // persist the labels for some reason), returning a failure code would result
408 // in the ping being persisted and re-sent later. For this reason, we always
409 // return a success code if we sent the ping, even if following actions fail.
410 VERIFY1(SUCCEEDED(update_response_utils::ApplyExperimentLabelDeltas(
411 is_machine,
412 response.get())));
413
414 return S_OK;
415 }
416
417 HRESULT Ping::HandlePing(bool is_machine, const CString& ping_string) {
418 CORE_LOG(L3, (_T("[Ping::HandlePing][%s]"), ping_string));
419
420 CStringA ping_string_utf8(WideToUtf8(ping_string));
421
422 CStringA request_string_utf8;
423 int out_buffer_length = ping_string_utf8.GetLength();
424 char* out_buffer = request_string_utf8.GetBufferSetLength(out_buffer_length);
425
426 out_buffer_length = WebSafeBase64Unescape(ping_string_utf8,
427 ping_string_utf8.GetLength(),
428 out_buffer,
429 out_buffer_length);
430 ASSERT1(out_buffer_length <= ping_string_utf8.GetLength());
431 request_string_utf8.ReleaseBufferSetLength(out_buffer_length);
432
433 CString request_string(Utf8ToWideChar(request_string_utf8,
434 request_string_utf8.GetLength()));
435
436 return Ping::SendString(is_machine, HeadersVector(), request_string);
437 }
438
439 } // namespace omaha
440
OLDNEW
« no previous file with comments | « common/ping.h ('k') | common/ping_event.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698