summaryrefslogtreecommitdiffstats
path: root/rlz/lib/financial_ping.cc
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-21 14:10:52 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-21 14:10:52 +0000
commit0a5e34a5386fa254a3b133f0a5f7667f1f790f67 (patch)
treed1dd0e80264f900004c56ad5ce6b56efea0bec49 /rlz/lib/financial_ping.cc
parentb049c382ff842f546e2bcc261ce23438bc8764bf (diff)
downloadchromium_src-0a5e34a5386fa254a3b133f0a5f7667f1f790f67.zip
chromium_src-0a5e34a5386fa254a3b133f0a5f7667f1f790f67.tar.gz
chromium_src-0a5e34a5386fa254a3b133f0a5f7667f1f790f67.tar.bz2
Check-in rlz code to src\rlz from http://code.google.com/p/rlz/.
Review URL: https://chromiumcodereview.appspot.com/10597002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143381 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'rlz/lib/financial_ping.cc')
-rw-r--r--rlz/lib/financial_ping.cc354
1 files changed, 354 insertions, 0 deletions
diff --git a/rlz/lib/financial_ping.cc b/rlz/lib/financial_ping.cc
new file mode 100644
index 0000000..aad3db3
--- /dev/null
+++ b/rlz/lib/financial_ping.cc
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Library functions related to the Financial Server ping.
+
+#include "rlz/lib/financial_ping.h"
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "rlz/lib/assert.h"
+#include "rlz/lib/lib_values.h"
+#include "rlz/lib/machine_id.h"
+#include "rlz/lib/rlz_lib.h"
+#include "rlz/lib/rlz_value_store.h"
+#include "rlz/lib/string_utils.h"
+
+#if !defined(OS_WIN)
+#include "base/time.h"
+#endif
+
+#if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
+
+#include <windows.h>
+#include <wininet.h>
+
+namespace {
+
+class InternetHandle {
+ public:
+ InternetHandle(HINTERNET handle) { handle_ = handle; }
+ ~InternetHandle() { if (handle_) InternetCloseHandle(handle_); }
+ operator HINTERNET() const { return handle_; }
+ bool operator!() const { return (handle_ == NULL); }
+
+ private:
+ HINTERNET handle_;
+};
+
+} // namespace
+
+#else
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+
+#endif
+
+namespace {
+
+// Returns the time relative to a fixed point in the past in multiples of
+// 100 ns stepts. The point in the past is arbitrary but can't change, as the
+// result of this value is stored on disk.
+int64 GetSystemTimeAsInt64() {
+#if defined(OS_WIN)
+ FILETIME now_as_file_time;
+ // Relative to Jan 1, 1601 (UTC).
+ GetSystemTimeAsFileTime(&now_as_file_time);
+
+ LARGE_INTEGER integer;
+ integer.HighPart = now_as_file_time.dwHighDateTime;
+ integer.LowPart = now_as_file_time.dwLowDateTime;
+ return integer.QuadPart;
+#else
+ // Seconds since epoch (Jan 1, 1970).
+ double now_seconds = base::Time::Now().ToDoubleT();
+ return static_cast<int64>(now_seconds * 1000 * 1000 * 10);
+#endif
+}
+
+} // namespace
+
+
+namespace rlz_lib {
+
+bool FinancialPing::FormRequest(Product product,
+ const AccessPoint* access_points, const char* product_signature,
+ const char* product_brand, const char* product_id,
+ const char* product_lang, bool exclude_machine_id,
+ std::string* request) {
+ if (!request) {
+ ASSERT_STRING("FinancialPing::FormRequest: request is NULL");
+ return false;
+ }
+
+ request->clear();
+
+ ScopedRlzValueStoreLock lock;
+ RlzValueStore* store = lock.GetStore();
+ if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
+ return false;
+
+ if (!access_points) {
+ ASSERT_STRING("FinancialPing::FormRequest: access_points is NULL");
+ return false;
+ }
+
+ if (!product_signature) {
+ ASSERT_STRING("FinancialPing::FormRequest: product_signature is NULL");
+ return false;
+ }
+
+ if (!SupplementaryBranding::GetBrand().empty()) {
+ if (SupplementaryBranding::GetBrand() != product_brand) {
+ ASSERT_STRING("FinancialPing::FormRequest: supplementary branding bad");
+ return false;
+ }
+ }
+
+ base::StringAppendF(request, "%s?", kFinancialPingPath);
+
+ // Add the signature, brand, product id and language.
+ base::StringAppendF(request, "%s=%s", kProductSignatureCgiVariable,
+ product_signature);
+ if (product_brand)
+ base::StringAppendF(request, "&%s=%s", kProductBrandCgiVariable,
+ product_brand);
+
+ if (product_id)
+ base::StringAppendF(request, "&%s=%s", kProductIdCgiVariable, product_id);
+
+ if (product_lang)
+ base::StringAppendF(request, "&%s=%s", kProductLanguageCgiVariable,
+ product_lang);
+
+ // Add the product events.
+ char cgi[kMaxCgiLength + 1];
+ cgi[0] = 0;
+ bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
+ if (has_events)
+ base::StringAppendF(request, "&%s", cgi);
+
+ // If we don't have any events, we should ping all the AP's on the system
+ // that we know about and have a current RLZ value, even if they are not
+ // used by this product.
+ AccessPoint all_points[LAST_ACCESS_POINT];
+ if (!has_events) {
+ char rlz[kMaxRlzLength + 1];
+ int idx = 0;
+ for (int ap = NO_ACCESS_POINT + 1; ap < LAST_ACCESS_POINT; ap++) {
+ rlz[0] = 0;
+ AccessPoint point = static_cast<AccessPoint>(ap);
+ if (GetAccessPointRlz(point, rlz, arraysize(rlz)) &&
+ rlz[0] != '\0')
+ all_points[idx++] = point;
+ }
+ all_points[idx] = NO_ACCESS_POINT;
+ }
+
+ // Add the RLZ's and the DCC if needed. This is the same as get PingParams.
+ // This will also include the RLZ Exchange Protocol CGI Argument.
+ cgi[0] = 0;
+ if (GetPingParams(product, has_events ? access_points : all_points,
+ cgi, arraysize(cgi)))
+ base::StringAppendF(request, "&%s", cgi);
+
+ if (has_events && !exclude_machine_id) {
+ std::string machine_id;
+ if (GetMachineId(&machine_id)) {
+ base::StringAppendF(request, "&%s=%s", kMachineIdCgiVariable,
+ machine_id.c_str());
+ }
+ }
+
+ return true;
+}
+
+#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
+// The URLRequestContextGetter used by FinancialPing::PingServer().
+net::URLRequestContextGetter* g_context;
+
+bool FinancialPing::SetURLRequestContext(
+ net::URLRequestContextGetter* context) {
+ ScopedRlzValueStoreLock lock;
+ RlzValueStore* store = lock.GetStore();
+ if (!store)
+ return false;
+
+ g_context = context;
+ return true;
+}
+
+namespace {
+
+class FinancialPingUrlFetcherDelegate : public net::URLFetcherDelegate {
+ public:
+ FinancialPingUrlFetcherDelegate(MessageLoop* loop) : loop_(loop) { }
+ virtual void OnURLFetchComplete(const net::URLFetcher* source);
+ private:
+ MessageLoop* loop_;
+};
+
+void FinancialPingUrlFetcherDelegate::OnURLFetchComplete(
+ const net::URLFetcher* source) {
+ loop_->Quit();
+}
+
+} // namespace
+
+#endif
+
+bool FinancialPing::PingServer(const char* request, std::string* response) {
+ if (!response)
+ return false;
+
+ response->clear();
+
+#if defined(RLZ_NETWORK_IMPLEMENTATION_WIN_INET)
+ // Initialize WinInet.
+ InternetHandle inet_handle = InternetOpenA(kFinancialPingUserAgent,
+ INTERNET_OPEN_TYPE_PRECONFIG,
+ NULL, NULL, 0);
+ if (!inet_handle)
+ return false;
+
+ // Open network connection.
+ InternetHandle connection_handle = InternetConnectA(inet_handle,
+ kFinancialServer, kFinancialPort, "", "", INTERNET_SERVICE_HTTP,
+ INTERNET_FLAG_NO_CACHE_WRITE, 0);
+ if (!connection_handle)
+ return false;
+
+ // Prepare the HTTP request.
+ InternetHandle http_handle = HttpOpenRequestA(connection_handle,
+ "GET", request, NULL, NULL, kFinancialPingResponseObjects,
+ INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES, NULL);
+ if (!http_handle)
+ return false;
+
+ // Timeouts are probably:
+ // INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_RECEIVE_TIMEOUT
+
+ // Send the HTTP request. Note: Fails if user is working in off-line mode.
+ if (!HttpSendRequest(http_handle, NULL, 0, NULL, 0))
+ return false;
+
+ // Check the response status.
+ DWORD status;
+ DWORD status_size = sizeof(status);
+ if (!HttpQueryInfo(http_handle, HTTP_QUERY_STATUS_CODE |
+ HTTP_QUERY_FLAG_NUMBER, &status, &status_size, NULL) ||
+ 200 != status)
+ return false;
+
+ // Get the response text.
+ scoped_array<char> buffer(new char[kMaxPingResponseLength]);
+ if (buffer.get() == NULL)
+ return false;
+
+ DWORD bytes_read = 0;
+ while (InternetReadFile(http_handle, buffer.get(), kMaxPingResponseLength,
+ &bytes_read) && bytes_read > 0) {
+ response->append(buffer.get(), bytes_read);
+ bytes_read = 0;
+ };
+
+ return true;
+#else
+ // Run a blocking event loop to match the win inet implementation.
+ MessageLoop loop;
+ FinancialPingUrlFetcherDelegate delegate(&loop);
+
+ std::string url = base::StringPrintf("http://%s:%d%s",
+ kFinancialServer, kFinancialPort,
+ request);
+
+ scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
+ GURL(url), net::URLFetcher::GET, &delegate));
+
+ fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA |
+ net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+
+ // Ensure rlz_lib::SetURLRequestContext() has been called before sending
+ // pings.
+ CHECK(g_context);
+ fetcher->SetRequestContext(g_context);
+
+ const base::TimeDelta kTimeout = base::TimeDelta::FromMinutes(5);
+ loop.PostTask(
+ FROM_HERE,
+ base::Bind(&net::URLFetcher::Start, base::Unretained(fetcher.get())));
+ loop.PostNonNestableDelayedTask(
+ FROM_HERE, MessageLoop::QuitClosure(), kTimeout);
+
+ loop.Run();
+
+ if (fetcher->GetResponseCode() != 200)
+ return false;
+
+ return fetcher->GetResponseAsString(response);
+#endif
+}
+
+bool FinancialPing::IsPingTime(Product product, bool no_delay) {
+ ScopedRlzValueStoreLock lock;
+ RlzValueStore* store = lock.GetStore();
+ if (!store || !store->HasAccess(RlzValueStore::kReadAccess))
+ return false;
+
+ int64 last_ping = 0;
+ if (!store->ReadPingTime(product, &last_ping))
+ return true;
+
+ uint64 now = GetSystemTimeAsInt64();
+ int64 interval = now - last_ping;
+
+ // If interval is negative, clock was probably reset. So ping.
+ if (interval < 0)
+ return true;
+
+ // Check if this product has any unreported events.
+ char cgi[kMaxCgiLength + 1];
+ cgi[0] = 0;
+ bool has_events = GetProductEventsAsCgi(product, cgi, arraysize(cgi));
+ if (no_delay && has_events)
+ return true;
+
+ return interval >= (has_events ? kEventsPingInterval : kNoEventsPingInterval);
+}
+
+
+bool FinancialPing::UpdateLastPingTime(Product product) {
+ ScopedRlzValueStoreLock lock;
+ RlzValueStore* store = lock.GetStore();
+ if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
+ return false;
+
+ uint64 now = GetSystemTimeAsInt64();
+ return store->WritePingTime(product, now);
+}
+
+
+bool FinancialPing::ClearLastPingTime(Product product) {
+ ScopedRlzValueStoreLock lock;
+ RlzValueStore* store = lock.GetStore();
+ if (!store || !store->HasAccess(RlzValueStore::kWriteAccess))
+ return false;
+ return store->ClearPingTime(product);
+}
+
+} // namespace