summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/notifier/base
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/sync/notifier/base')
-rw-r--r--chrome/browser/sync/notifier/base/async_dns_lookup.cc133
-rw-r--r--chrome/browser/sync/notifier/base/async_dns_lookup.h49
-rw-r--r--chrome/browser/sync/notifier/base/async_network_alive.h52
-rw-r--r--chrome/browser/sync/notifier/base/fastalloc.h59
-rw-r--r--chrome/browser/sync/notifier/base/linux/network_status_detector_task_linux.cc15
-rw-r--r--chrome/browser/sync/notifier/base/linux/time_linux.cc7
-rw-r--r--chrome/browser/sync/notifier/base/nethelpers.cc42
-rw-r--r--chrome/browser/sync/notifier/base/nethelpers.h25
-rw-r--r--chrome/browser/sync/notifier/base/network_status_detector_task.cc30
-rw-r--r--chrome/browser/sync/notifier/base/network_status_detector_task.h55
-rw-r--r--chrome/browser/sync/notifier/base/network_status_detector_task_mt.cc48
-rw-r--r--chrome/browser/sync/notifier/base/network_status_detector_task_mt.h34
-rw-r--r--chrome/browser/sync/notifier/base/posix/time_posix.cc54
-rw-r--r--chrome/browser/sync/notifier/base/signal_thread_task.h92
-rw-r--r--chrome/browser/sync/notifier/base/static_assert.h19
-rw-r--r--chrome/browser/sync/notifier/base/string.cc403
-rw-r--r--chrome/browser/sync/notifier/base/string.h381
-rw-r--r--chrome/browser/sync/notifier/base/string_unittest.cc362
-rw-r--r--chrome/browser/sync/notifier/base/task_pump.cc42
-rw-r--r--chrome/browser/sync/notifier/base/task_pump.h34
-rw-r--r--chrome/browser/sync/notifier/base/time.cc360
-rw-r--r--chrome/browser/sync/notifier/base/time.h114
-rw-r--r--chrome/browser/sync/notifier/base/time_unittest.cc73
-rw-r--r--chrome/browser/sync/notifier/base/timer.cc33
-rw-r--r--chrome/browser/sync/notifier/base/timer.h40
-rw-r--r--chrome/browser/sync/notifier/base/utils.h91
-rw-r--r--chrome/browser/sync/notifier/base/win32/async_network_alive_win32.cc233
-rw-r--r--chrome/browser/sync/notifier/base/win32/time_win32.cc158
28 files changed, 3038 insertions, 0 deletions
diff --git a/chrome/browser/sync/notifier/base/async_dns_lookup.cc b/chrome/browser/sync/notifier/base/async_dns_lookup.cc
new file mode 100644
index 0000000..0d3ce87
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/async_dns_lookup.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/async_dns_lookup.h"
+
+#ifdef POSIX
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#endif // POSIX
+
+#include <vector>
+
+#include "chrome/browser/sync/notifier/base/nethelpers.h"
+#include "chrome/browser/sync/notifier/gaia_auth/inet_aton.h"
+#include "talk/base/byteorder.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/socketaddress.h"
+#include "talk/base/thread.h"
+
+enum { MSG_TIMEOUT = talk_base::SignalThread::ST_MSG_FIRST_AVAILABLE };
+
+#ifndef WIN32
+const int WSAHOST_NOT_FOUND = 11001; // follows the format in winsock2.h
+#endif // WIN32
+
+namespace notifier {
+
+AsyncDNSLookup::AsyncDNSLookup(const talk_base::SocketAddress& server)
+ : server_(new talk_base::SocketAddress(server)),
+ error_(0) {
+ // Timeout after 5 seconds.
+ talk_base::Thread::Current()->PostDelayed(5000, this, MSG_TIMEOUT);
+}
+
+AsyncDNSLookup::~AsyncDNSLookup() {
+}
+
+void AsyncDNSLookup::DoWork() {
+ std::string hostname(server_->IPAsString());
+
+ in_addr addr;
+ if (inet_aton(hostname.c_str(), &addr)) {
+ talk_base::CritScope scope(&cs_);
+ ip_list_.push_back(talk_base::NetworkToHost32(addr.s_addr));
+ } else {
+ LOG_F(LS_VERBOSE) << "(" << hostname << ")";
+ hostent ent;
+ char buffer[8192];
+ int errcode = 0;
+ hostent* host = SafeGetHostByName(hostname.c_str(), &ent,
+ buffer, sizeof(buffer),
+ &errcode);
+ talk_base::Thread::Current()->Clear(this, MSG_TIMEOUT);
+ if (host) {
+ talk_base::CritScope scope(&cs_);
+
+ // Check to see if this already timed out.
+ if (error_ == 0) {
+ for (int index = 0; true; ++index) {
+ uint32* addr = reinterpret_cast<uint32*>(host->h_addr_list[index]);
+ if (addr == 0) { // 0 = end of list
+ break;
+ }
+ uint32 ip = talk_base::NetworkToHost32(*addr);
+ LOG_F(LS_VERBOSE) << "(" << hostname << ") resolved to: "
+ << talk_base::SocketAddress::IPToString(ip);
+ ip_list_.push_back(ip);
+ }
+ // Maintain the invariant that either the list is not empty
+ // or the error is non zero when we are done with processing
+ // the dnslookup.
+ if (ip_list_.empty() && error_ == 0) {
+ error_ = WSAHOST_NOT_FOUND;
+ }
+ }
+ FreeHostEnt(host);
+ } else {
+ { // Scoping for the critical section.
+ talk_base::CritScope scope(&cs_);
+
+ // Check to see if this already timed out.
+ if (error_ == 0) {
+ error_ = errcode;
+ }
+ }
+ LOG_F(LS_ERROR) << "(" << hostname << ") error: " << error_;
+ }
+ }
+}
+
+void AsyncDNSLookup::OnMessage(talk_base::Message* message) {
+ ASSERT(message);
+ if (message->message_id == MSG_TIMEOUT) {
+ OnTimeout();
+ } else {
+ talk_base::SignalThread::OnMessage(message);
+ }
+}
+
+void AsyncDNSLookup::OnTimeout() {
+ // Allow the scope for the critical section to be the whole
+ // method, just to be sure that the worker thread can't exit
+ // while we are doing SignalWorkDone (because that could possibly
+ // cause the class to be deleted).
+ talk_base::CritScope scope(&cs_);
+
+ // Check to see if the ip list was already filled (or errored out).
+ if (!ip_list_.empty() || error_ != 0) {
+ return;
+ }
+
+ // Worker thread is taking too long so timeout.
+ error_ = WSAHOST_NOT_FOUND;
+
+ // Rely on the caller to do the Release/Destroy.
+ //
+ // Doing this signal while holding cs_ won't cause a deadlock because
+ // the AsyncDNSLookup::DoWork thread doesn't have any locks at this point,
+ // and it is the only thread being held up by this.
+ SignalWorkDone(this);
+
+ // Ensure that no more "WorkDone" signaling is done.
+ // Don't call Release or Destroy since that was already done
+ // by the callback.
+ SignalWorkDone.disconnect_all();
+}
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/async_dns_lookup.h b/chrome/browser/sync/notifier/base/async_dns_lookup.h
new file mode 100644
index 0000000..123d311
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/async_dns_lookup.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_DNS_LOOKUP_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_DNS_LOOKUP_H_
+
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "talk/base/signalthread.h"
+
+namespace talk_base {
+class SocketAddress;
+class Task;
+}
+
+namespace notifier {
+
+class AsyncDNSLookup : public talk_base::SignalThread {
+ public:
+ explicit AsyncDNSLookup(const talk_base::SocketAddress& server);
+ virtual ~AsyncDNSLookup();
+
+ const int error() const {
+ return error_;
+ }
+
+ const std::vector<uint32>& ip_list() const {
+ return ip_list_;
+ }
+
+ protected:
+ // SignalThread Interface
+ virtual void DoWork();
+ virtual void OnMessage(talk_base::Message* message);
+
+ private:
+ void OnTimeout();
+
+ scoped_ptr<talk_base::SocketAddress> server_;
+ talk_base::CriticalSection cs_;
+ int error_;
+ std::vector<uint32> ip_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncDNSLookup);
+};
+} // namespace notifier
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_DNS_LOOKUP_H_
diff --git a/chrome/browser/sync/notifier/base/async_network_alive.h b/chrome/browser/sync/notifier/base/async_network_alive.h
new file mode 100644
index 0000000..330348d
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/async_network_alive.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_NETWORK_ALIVE_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_NETWORK_ALIVE_H_
+
+#include "talk/base/signalthread.h"
+
+namespace notifier {
+
+// System specific info needed for changes
+class PlatformNetworkInfo;
+
+class AsyncNetworkAlive : public talk_base::SignalThread {
+ public:
+ static AsyncNetworkAlive* Create();
+
+ virtual ~AsyncNetworkAlive() {}
+
+ bool alive() const {
+ return alive_;
+ }
+
+ bool error() const {
+ return error_;
+ }
+
+ void SetWaitForNetworkChange(PlatformNetworkInfo* previous_info) {
+ network_info_ = previous_info;
+ }
+
+ PlatformNetworkInfo* ReleaseInfo() {
+ PlatformNetworkInfo* info = network_info_;
+ network_info_ = NULL;
+ return info;
+ }
+
+ protected:
+ AsyncNetworkAlive() : network_info_(NULL), alive_(false), error_(false) {
+ }
+
+ protected:
+ PlatformNetworkInfo* network_info_;
+ bool alive_;
+ bool error_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncNetworkAlive);
+};
+} // namespace notifier
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_ASYNC_NETWORK_ALIVE_H_
diff --git a/chrome/browser/sync/notifier/base/fastalloc.h b/chrome/browser/sync/notifier/base/fastalloc.h
new file mode 100644
index 0000000..ed19a53
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/fastalloc.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_FASTALLOC_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_FASTALLOC_H_
+
+#include <assert.h>
+
+namespace notifier {
+
+template<class T, size_t Size>
+class FastAlloc {
+ public:
+ FastAlloc() : buffer_(NULL), size_(0) { };
+ ~FastAlloc() { freeBuffer(); }
+ T* get_buffer(size_t size) {
+ if (size_ != 0) {
+ // We only allow one call to get_buffer. This makes the logic here
+ // simpler, and the user has to worry less about someone else calling
+ // get_buffer again on the same FastAlloc object and invalidating the
+ // memory they were using.
+ assert(false && "get_buffer may one be called once");
+ return NULL;
+ }
+
+ if (size <= Size) {
+ buffer_ = internal_buffer_;
+ } else {
+ buffer_ = new T[size];
+ }
+
+ if (buffer_ != NULL) {
+ size_ = size;
+ }
+ return buffer_;
+ }
+
+ private:
+ void freeBuffer() {
+#ifdef DEBUG
+ memset(buffer_, 0xCC, size_ * sizeof(T));
+#endif
+
+ if (buffer_ != NULL && buffer_ != internal_buffer_) {
+ delete[] buffer_;
+ }
+ buffer_ = NULL;
+ size_ = 0;
+ }
+
+ T* buffer_;
+ T internal_buffer_[Size];
+ size_t size_;
+};
+
+}
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_FASTALLOC_H_
diff --git a/chrome/browser/sync/notifier/base/linux/network_status_detector_task_linux.cc b/chrome/browser/sync/notifier/base/linux/network_status_detector_task_linux.cc
new file mode 100644
index 0000000..e232bcb
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/linux/network_status_detector_task_linux.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/network_status_detector_task.h"
+
+namespace notifier {
+
+NetworkStatusDetectorTask* NetworkStatusDetectorTask::Create(
+ talk_base::Task* parent) {
+ // TODO(sync): No implementation for linux
+ return NULL;
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/linux/time_linux.cc b/chrome/browser/sync/notifier/base/linux/time_linux.cc
new file mode 100644
index 0000000..ea2acf5
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/linux/time_linux.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2009 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.
+//
+// Time functions
+
+#include "chrome/browser/sync/notifier/base/posix/time_posix.cc"
diff --git a/chrome/browser/sync/notifier/base/nethelpers.cc b/chrome/browser/sync/notifier/base/nethelpers.cc
new file mode 100644
index 0000000..23fc8d2
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/nethelpers.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/nethelpers.h"
+
+namespace notifier {
+
+hostent* SafeGetHostByName(const char* hostname, hostent* host,
+ char* buffer, size_t buffer_len,
+ int* herrno) {
+ hostent* result = NULL;
+#if WIN32
+ result = gethostbyname(hostname);
+ if (!result) {
+ *herrno = WSAGetLastError();
+ }
+#elif OS_LINUX
+ gethostbyname_r(hostname, host, buffer, buffer_len, &result, herrno);
+#elif OSX
+ result = getipnodebyname(hostname, AF_INET, AI_DEFAULT, herrno);
+#else
+#error "I don't know how to do gethostbyname safely on your system."
+#endif
+ return result;
+}
+
+// This function should mirror the above function, and free any resources
+// allocated by the above.
+void FreeHostEnt(hostent* host) {
+#if WIN32
+ // No need to free anything, struct returned is static memory.
+#elif OS_LINUX
+ // No need to free anything, we pass in a pointer to a struct.
+#elif OSX
+ freehostent(host);
+#else
+#error "I don't know how to free a hostent on your system."
+#endif
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/nethelpers.h b/chrome/browser/sync/notifier/base/nethelpers.h
new file mode 100644
index 0000000..d2b9fd4
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/nethelpers.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETHELPERS_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETHELPERS_H_
+
+#ifdef POSIX
+#include <netdb.h>
+#include <cstddef>
+#elif WIN32
+#include <winsock2.h>
+#endif
+
+namespace notifier {
+
+hostent* SafeGetHostByName(const char* hostname, hostent* host,
+ char* buffer, size_t buffer_len,
+ int* herrno);
+
+void FreeHostEnt(hostent* host);
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETHELPERS_H_
diff --git a/chrome/browser/sync/notifier/base/network_status_detector_task.cc b/chrome/browser/sync/notifier/base/network_status_detector_task.cc
new file mode 100644
index 0000000..f9acd88
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/network_status_detector_task.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/network_status_detector_task.h"
+
+namespace notifier {
+
+void NetworkStatusDetectorTask::DetectNetworkState() {
+ // If the detection has been finished, then just broadcast the current
+ // state. Otherwise, allow the signal to be sent when the initial
+ // detection is finished.
+ if (initial_detection_done_) {
+ SignalNetworkStateDetected(is_alive_, is_alive_);
+ }
+}
+
+void NetworkStatusDetectorTask::SetNetworkAlive(bool is_alive) {
+ bool was_alive = is_alive_;
+ is_alive_ = is_alive;
+
+ if (!initial_detection_done_ || was_alive != is_alive_) {
+ initial_detection_done_ = true;
+
+ // Tell everyone about the network state change.
+ SignalNetworkStateDetected(was_alive, is_alive_);
+ }
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/network_status_detector_task.h b/chrome/browser/sync/notifier/base/network_status_detector_task.h
new file mode 100644
index 0000000..4cf190e
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/network_status_detector_task.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_H_
+
+#include "chrome/browser/sync/notifier/base/time.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/task.h"
+
+namespace notifier {
+class AsyncNetworkAlive;
+
+// Detects the current network state and any changes to that.
+class NetworkStatusDetectorTask : public talk_base::Task,
+ public sigslot::has_slots<> {
+ public:
+ // Create an instance of (a subclass of) this class.
+ static NetworkStatusDetectorTask* Create(talk_base::Task* parent);
+
+ // Determines the current network state and
+ // then calls SignalNetworkStateDetected.
+ void DetectNetworkState();
+
+ // Fires whenever the network state is detected.
+ // SignalNetworkStateDetected(was_alive, is_alive);
+ sigslot::signal2<bool, bool> SignalNetworkStateDetected;
+
+ protected:
+ explicit NetworkStatusDetectorTask(talk_base::Task* parent)
+ : talk_base::Task(parent),
+ initial_detection_done_(false),
+ is_alive_(false) {
+ }
+
+ virtual ~NetworkStatusDetectorTask() { }
+
+ virtual int ProcessStart() = 0;
+
+ // Stay around until aborted.
+ virtual int ProcessResponse() {
+ return STATE_BLOCKED;
+ }
+
+ void SetNetworkAlive(bool is_alive);
+
+ private:
+ bool initial_detection_done_;
+ bool is_alive_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkStatusDetectorTask);
+};
+} // namespace notifier
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_H_
diff --git a/chrome/browser/sync/notifier/base/network_status_detector_task_mt.cc b/chrome/browser/sync/notifier/base/network_status_detector_task_mt.cc
new file mode 100644
index 0000000..d4e406c
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/network_status_detector_task_mt.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/network_status_detector_task_mt.h"
+
+#include "chrome/browser/sync/notifier/base/async_network_alive.h"
+#include "chrome/browser/sync/notifier/base/signal_thread_task.h"
+
+#include "talk/base/common.h"
+
+namespace notifier {
+
+void NetworkStatusDetectorTaskMT::OnNetworkAliveDone(
+ AsyncNetworkAlive* network_alive) {
+ ASSERT(network_alive);
+ SetNetworkAlive(network_alive->alive());
+ // If we got an error from detecting the network alive state,
+ // then stop retrying the detection.
+ if (network_alive->error()) {
+ return;
+ }
+ StartAsyncDetection(network_alive->ReleaseInfo());
+}
+
+void NetworkStatusDetectorTaskMT::StartAsyncDetection(
+ PlatformNetworkInfo* previous_info) {
+ // Use the AsyncNetworkAlive to determine the network state (and
+ // changes in the network state).
+ AsyncNetworkAlive* network_alive = AsyncNetworkAlive::Create();
+
+ if (previous_info) {
+ network_alive->SetWaitForNetworkChange(previous_info);
+ }
+ SignalThreadTask<AsyncNetworkAlive>* task =
+ new SignalThreadTask<AsyncNetworkAlive>(this, &network_alive);
+ task->SignalWorkDone.connect(
+ this, &NetworkStatusDetectorTaskMT::OnNetworkAliveDone);
+ task->Start();
+}
+
+NetworkStatusDetectorTask* NetworkStatusDetectorTask::Create(
+ talk_base::Task* parent) {
+ ASSERT(parent);
+ return new NetworkStatusDetectorTaskMT(parent);
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/network_status_detector_task_mt.h b/chrome/browser/sync/notifier/base/network_status_detector_task_mt.h
new file mode 100644
index 0000000..e1812f2
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/network_status_detector_task_mt.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_MT_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_MT_H_
+
+#include "chrome/browser/sync/notifier/base/network_status_detector_task.h"
+
+namespace notifier {
+
+class AsyncNetworkAlive;
+class PlatformNetworkInfo;
+
+class NetworkStatusDetectorTaskMT : public NetworkStatusDetectorTask {
+ public:
+ explicit NetworkStatusDetectorTaskMT(talk_base::Task* parent)
+ : NetworkStatusDetectorTask(parent) {
+ }
+
+ protected:
+ virtual int ProcessStart() {
+ StartAsyncDetection(NULL);
+ return STATE_RESPONSE;
+ }
+
+ private:
+ void OnNetworkAliveDone(AsyncNetworkAlive* network_alive);
+ void StartAsyncDetection(PlatformNetworkInfo* network_info);
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_NETWORK_STATUS_DETECTOR_TASK_MT_H_
diff --git a/chrome/browser/sync/notifier/base/posix/time_posix.cc b/chrome/browser/sync/notifier/base/posix/time_posix.cc
new file mode 100644
index 0000000..849f802
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/posix/time_posix.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2009 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.
+
+#include <assert.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chrome/browser/sync/notifier/base/time.h"
+
+namespace notifier {
+
+time64 GetCurrent100NSTime() {
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ time64 retval = tv.tv_sec * kSecsTo100ns;
+ retval += tv.tv_usec * kMicrosecsTo100ns;
+ retval += kStart100NsTimeToEpoch;
+ return retval;
+}
+
+time64 TmToTime64(const struct tm& tm) {
+ struct tm tm_temp;
+ memcpy(&tm_temp, &tm, sizeof(struct tm));
+ time_t t = timegm(&tm_temp);
+ return t * kSecsTo100ns;
+}
+
+bool Time64ToTm(time64 t, struct tm* tm) {
+ assert(tm != NULL);
+ time_t secs = t / kSecsTo100ns;
+ gmtime_r(&secs, tm);
+ return true;
+}
+
+bool UtcTimeToLocalTime(struct tm* tm) {
+ assert(tm != NULL);
+ time_t t = timegm(tm);
+ localtime_r(&t, tm);
+ return true;
+}
+
+bool LocalTimeToUtcTime(struct tm* tm) {
+ assert(tm != NULL);
+ time_t t = mktime(tm);
+ gmtime_r(&t, tm);
+ return true;
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/signal_thread_task.h b/chrome/browser/sync/notifier/base/signal_thread_task.h
new file mode 100644
index 0000000..93059d8
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/signal_thread_task.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
+
+#include "talk/base/common.h"
+#include "talk/base/signalthread.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/task.h"
+
+namespace notifier {
+
+template<class T>
+class SignalThreadTask : public talk_base::Task,
+ public sigslot::has_slots<> {
+ public:
+ // Takes ownership of signal_thread.
+ SignalThreadTask(talk_base::Task* task_parent, T** signal_thread)
+ : talk_base::Task(task_parent),
+ signal_thread_(NULL),
+ finished_(false) {
+ SetSignalThread(signal_thread);
+ }
+
+ virtual ~SignalThreadTask() {
+ ClearSignalThread();
+ }
+
+ virtual void Stop() {
+ Task::Stop();
+ ClearSignalThread();
+ }
+
+ virtual int ProcessStart() {
+ ASSERT(GetState() == talk_base::Task::STATE_START);
+ signal_thread_->SignalWorkDone.connect(
+ this,
+ &SignalThreadTask<T>::OnWorkDone);
+ signal_thread_->Start();
+ return talk_base::Task::STATE_RESPONSE;
+ }
+
+ int ProcessResponse() {
+ if (!finished_) {
+ return talk_base::Task::STATE_BLOCKED;
+ }
+ SignalWorkDone(signal_thread_);
+ ClearSignalThread();
+ return talk_base::Task::STATE_DONE;
+ }
+
+ sigslot::signal1<T*> SignalWorkDone;
+
+ private:
+ // Takes ownership of signal_thread
+ void SetSignalThread(T** signal_thread) {
+ ASSERT(!signal_thread_ && signal_thread && *signal_thread);
+ // Verify that no one is listening to the signal thread
+ // for work done. They should be using this class instead.
+ ASSERT((*signal_thread)->SignalWorkDone.is_empty());
+
+ signal_thread_ = *signal_thread;
+
+ // Helps callers not to use signal thread after this point
+ // since this class has taken ownership (and avoid the
+ // error of doing signal_thread->Start()).
+ *signal_thread = NULL;
+ }
+
+ void OnWorkDone(talk_base::SignalThread* signal_thread) {
+ ASSERT(signal_thread == signal_thread_);
+ finished_ = true;
+ Wake();
+ }
+
+ void ClearSignalThread() {
+ if (signal_thread_) {
+ signal_thread_->Destroy();
+ signal_thread_ = NULL;
+ }
+ }
+
+ T* signal_thread_;
+ bool finished_;
+ DISALLOW_COPY_AND_ASSIGN(SignalThreadTask);
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_SIGNAL_THREAD_TASK_H_
diff --git a/chrome/browser/sync/notifier/base/static_assert.h b/chrome/browser/sync/notifier/base/static_assert.h
new file mode 100644
index 0000000..78e6ac3
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/static_assert.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_STATIC_ASSERT_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_STATIC_ASSERT_H_
+
+template <bool> struct STATIC_ASSERTION_FAILURE;
+
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+
+template<int> struct static_assert_test{};
+
+#define STATIC_ASSERT(B) \
+typedef static_assert_test<\
+ sizeof(STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\
+ static_assert_typedef_ ## __LINE__
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_STATIC_ASSERT_H_
diff --git a/chrome/browser/sync/notifier/base/string.cc b/chrome/browser/sync/notifier/base/string.cc
new file mode 100644
index 0000000..c3ef54d
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/string.cc
@@ -0,0 +1,403 @@
+// Copyright (c) 2009 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.
+
+#ifdef OS_MACOSX
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#include <float.h>
+#include <string.h>
+
+#include "base/format_macros.h"
+#include "base/string_util.h"
+#include "chrome/browser/sync/notifier/base/string.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+#include "talk/base/stringencode.h"
+
+using base::snprintf;
+
+namespace notifier {
+
+std::string HtmlEncode(const std::string& src) {
+ size_t max_length = src.length() * 6 + 1;
+ std::string dest;
+ dest.resize(max_length);
+ size_t new_size = talk_base::html_encode(&dest[0], max_length,
+ src.data(), src.length());
+ dest.resize(new_size);
+ return dest;
+}
+
+std::string HtmlDecode(const std::string& src) {
+ size_t max_length = src.length() + 1;
+ std::string dest;
+ dest.resize(max_length);
+ size_t new_size = talk_base::html_decode(&dest[0], max_length,
+ src.data(), src.length());
+ dest.resize(new_size);
+ return dest;
+}
+
+std::string UrlEncode(const std::string& src) {
+ size_t max_length = src.length() * 6 + 1;
+ std::string dest;
+ dest.resize(max_length);
+ size_t new_size = talk_base::url_encode(&dest[0], max_length,
+ src.data(), src.length());
+ dest.resize(new_size);
+ return dest;
+}
+
+std::string UrlDecode(const std::string& src) {
+ size_t max_length = src.length() + 1;
+ std::string dest;
+ dest.resize(max_length);
+ size_t new_size = talk_base::url_decode(&dest[0], max_length,
+ src.data(), src.length());
+ dest.resize(new_size);
+ return dest;
+}
+
+int CharToHexValue(char hex) {
+ if (hex >= '0' && hex <= '9') {
+ return hex - '0';
+ } else if (hex >= 'A' && hex <= 'F') {
+ return hex - 'A' + 10;
+ } else if (hex >= 'a' && hex <= 'f') {
+ return hex - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+// Template function to convert a string to an int/int64
+// If strict is true, check for the validity and overflow
+template<typename T>
+bool ParseStringToIntTemplate(const char* str,
+ T* value,
+ bool strict,
+ T min_value) {
+ ASSERT(str);
+ ASSERT(value);
+
+ // Skip spaces
+ while (*str == ' ') {
+ ++str;
+ }
+
+ // Process sign
+ int c = static_cast<int>(*str++); // current char
+ int possible_sign = c; // save sign indication
+ if (c == '-' || c == '+') {
+ c = static_cast<int>(*str++);
+ }
+
+ // Process numbers
+ T total = 0;
+ while (c && (c = CharToDigit(static_cast<char>(c))) != -1) {
+ // Check for overflow
+ if (strict && (total < min_value / 10 ||
+ (total == min_value / 10 &&
+ c > ((-(min_value + 10)) % 10)))) {
+ return false;
+ }
+
+ // Accumulate digit
+ // Note that we accumulate in the negative direction so that we will not
+ // blow away with the largest negative number
+ total = 10 * total - c;
+
+ // Get next char
+ c = static_cast<int>(*str++);
+ }
+
+ // Fail if encountering non-numeric character
+ if (strict && c == -1) {
+ return false;
+ }
+
+ // Negate the number if needed
+ if (possible_sign == '-') {
+ *value = total;
+ } else {
+ // Check for overflow
+ if (strict && total == min_value) {
+ return false;
+ }
+
+ *value = -total;
+ }
+
+ return true;
+}
+
+// Convert a string to an int
+// If strict is true, check for the validity and overflow
+bool ParseStringToInt(const char* str, int* value, bool strict) {
+ return ParseStringToIntTemplate<int>(str, value, strict, kint32min);
+}
+
+// Convert a string to an int
+// This version does not check for the validity and overflow
+int StringToInt(const char* str) {
+ int value = 0;
+ ParseStringToInt(str, &value, false);
+ return value;
+}
+
+// Convert a string to an unsigned int.
+// If strict is true, check for the validity and overflow
+bool ParseStringToUint(const char* str, uint32* value, bool strict) {
+ ASSERT(str);
+ ASSERT(value);
+
+ int64 int64_value;
+ if (!ParseStringToInt64(str, &int64_value, strict)) {
+ return false;
+ }
+ if (int64_value < 0 || int64_value > kuint32max) {
+ return false;
+ }
+
+ *value = static_cast<uint32>(int64_value);
+ return true;
+}
+
+// Convert a string to an int
+// This version does not check for the validity and overflow
+uint32 StringToUint(const char* str) {
+ uint32 value = 0;
+ ParseStringToUint(str, &value, false);
+ return value;
+}
+
+// Convert a string to an int64
+// If strict is true, check for the validity and overflow
+bool ParseStringToInt64(const char* str, int64* value, bool strict) {
+ return ParseStringToIntTemplate<int64>(str, value, strict, kint64min);
+}
+
+// Convert a string to an int64
+// This version does not check for the validity and overflow
+int64 StringToInt64(const char* str) {
+ int64 value = 0;
+ ParseStringToInt64(str, &value, false);
+ return value;
+}
+
+// Convert a string to a double
+// If strict is true, check for the validity and overflow
+bool ParseStringToDouble(const char* str, double* value, bool strict) {
+ ASSERT(str);
+ ASSERT(value);
+
+ // Skip spaces
+ while (*str == ' ') {
+ ++str;
+ }
+
+ // Process sign
+ int c = static_cast<int>(*str++); // current char
+ int sign = c; // save sign indication
+ if (c == '-' || c == '+') {
+ c = static_cast<int>(*str++);
+ }
+
+ // Process numbers before "."
+ double total = 0.0;
+ while (c && (c != '.') && (c = CharToDigit(static_cast<char>(c))) != -1) {
+ // Check for overflow
+ if (strict && total >= DBL_MAX / 10) {
+ return false;
+ }
+
+ // Accumulate digit
+ total = 10.0 * total + c;
+
+ // Get next char
+ c = static_cast<int>(*str++);
+ }
+
+ // Process "."
+ if (c == '.') {
+ c = static_cast<int>(*str++);
+ } else {
+ // Fail if encountering non-numeric character
+ if (strict && c == -1) {
+ return false;
+ }
+ }
+
+ // Process numbers after "."
+ double power = 1.0;
+ while ((c = CharToDigit(static_cast<char>(c))) != -1) {
+ // Check for overflow
+ if (strict && total >= DBL_MAX / 10) {
+ return false;
+ }
+
+ // Accumulate digit
+ total = 10.0 * total + c;
+ power *= 10.0;
+
+ // Get next char
+ c = static_cast<int>(*str++);
+ }
+
+ // Get the final number
+ *value = total / power;
+ if (sign == '-') {
+ *value = -(*value);
+ }
+
+ return true;
+}
+
+// Convert a string to a double
+// This version does not check for the validity and overflow
+double StringToDouble(const char* str) {
+ double value = 0;
+ ParseStringToDouble(str, &value, false);
+ return value;
+}
+
+// Convert a float to a string
+std::string FloatToString(float f) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%f", f);
+ return std::string(buf);
+}
+
+std::string DoubleToString(double d) {
+ char buf[160];
+ snprintf(buf, sizeof(buf), "%.17g", d);
+ return std::string(buf);
+}
+
+std::string UIntToString(uint32 i) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%lu", i);
+ return std::string(buf);
+}
+
+// Convert an int to a string
+std::string IntToString(int i) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%d", i);
+ return std::string(buf);
+}
+
+// Convert an int64 to a string
+std::string Int64ToString(int64 i64) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%" PRId64 "d", i64);
+ return std::string(buf);
+}
+
+std::string UInt64ToString(uint64 i64) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%" PRId64 "u", i64);
+ return std::string(buf);
+}
+
+std::string Int64ToHexString(int64 i64) {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "%" PRId64 "x", i64);
+ return std::string(buf);
+}
+
+// Parse a single "delim" delimited string from "*source"
+// Modify *source to point after the delimiter.
+// If no delimiter is present after the string, set *source to NULL.
+//
+// Mainly a stringified wrapper around strpbrk()
+std::string SplitOneStringToken(const char** source, const char* delim) {
+ ASSERT(source);
+ ASSERT(delim);
+
+ if (!*source) {
+ return std::string();
+ }
+ const char* begin = *source;
+ *source = strpbrk(*source, delim);
+ if (*source) {
+ return std::string(begin, (*source)++);
+ } else {
+ return std::string(begin);
+ }
+}
+
+std::string LowerWithUnderToPascalCase(const char* lower_with_under) {
+ ASSERT(lower_with_under);
+
+ std::string pascal_case;
+ bool make_upper = true;
+ for (; *lower_with_under != '\0'; lower_with_under++) {
+ char current_char = *lower_with_under;
+ if (current_char == '_') {
+ ASSERT(!make_upper);
+ make_upper = true;
+ continue;
+ }
+ if (make_upper) {
+ current_char = toupper(current_char);
+ make_upper = false;
+ }
+ pascal_case.append(1, current_char);
+ }
+ return pascal_case;
+}
+
+std::string PascalCaseToLowerWithUnder(const char* pascal_case) {
+ ASSERT(pascal_case);
+
+ std::string lower_with_under;
+ bool previous_was_upper = true;
+ for(; *pascal_case != '\0'; pascal_case++) {
+ char current_char = *pascal_case;
+ if (isupper(current_char)) {
+ // DNSName should be dns_name
+ if ((islower(pascal_case[1]) && !lower_with_under.empty()) ||
+ !previous_was_upper) {
+ lower_with_under.append(1, '_');
+ }
+ current_char = tolower(current_char);
+ } else if (previous_was_upper) {
+ previous_was_upper = false;
+ }
+ lower_with_under.append(1, current_char);
+ }
+ return lower_with_under;
+}
+void StringReplace(std::string* s,
+ const char* old_sub,
+ const char* new_sub,
+ bool replace_all) {
+ ASSERT(s);
+
+ // If old_sub is empty, nothing to do
+ if (!old_sub || !*old_sub) {
+ return;
+ }
+
+ int old_sub_size = strlen(old_sub);
+ std::string res;
+ std::string::size_type start_pos = 0;
+
+ do {
+ std::string::size_type pos = s->find(old_sub, start_pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ res.append(*s, start_pos, pos - start_pos);
+ res.append(new_sub);
+ start_pos = pos + old_sub_size; // start searching again after the "old"
+ } while (replace_all);
+ res.append(*s, start_pos, s->length() - start_pos);
+
+ *s = res;
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/string.h b/chrome/browser/sync/notifier/base/string.h
new file mode 100644
index 0000000..725cc66
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/string.h
@@ -0,0 +1,381 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_STRING_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_STRING_H_
+
+#ifdef COMPILER_MSVC
+#include <xhash>
+#elif defined(__GNUC__)
+#include <ext/hash_map>
+#endif
+
+#include <ctype.h>
+#include <string>
+
+#include "chrome/browser/sync/notifier/base/fastalloc.h"
+#include "talk/base/basictypes.h"
+
+namespace notifier {
+
+// Does html encoding of strings.
+std::string HtmlEncode(const std::string& src);
+
+// Does html decoding of strings.
+std::string HtmlDecode(const std::string& src);
+
+// Does utl encoding of strings.
+std::string UrlEncode(const std::string& src);
+
+// Does url decoding of strings.
+std::string UrlDecode(const std::string& src);
+
+// Convert a character to a digit
+// if the character is not a digit return -1 (same as CRT)
+inline int CharToDigit(char c) {
+ return ((c) >= '0' && (c) <= '9' ? (c) - '0' : -1);
+}
+
+int CharToHexValue(char hex);
+
+// ----------------------------------------------------------------------
+// ParseStringToInt()
+// ParseStringToUint()
+// ParseStringToInt64()
+// ParseStringToDouble()
+// Convert a string to an int/int64/double
+// If strict is true, check for the validity and overflow
+// ----------------------------------------------------------------------
+
+bool ParseStringToInt(const char* str, int* value, bool strict);
+
+bool ParseStringToUint(const char* str, uint32* value, bool strict);
+
+bool ParseStringToInt64(const char* str, int64* value, bool strict);
+
+bool ParseStringToDouble(const char* str, double* value, bool strict);
+
+// ----------------------------------------------------------------------
+// StringToInt()
+// StringToUint()
+// StringToInt64()
+// StringToDouble()
+// Convert a string to an int/int64/double
+// Note that these functions do not check for the validity or overflow
+// ----------------------------------------------------------------------
+
+int StringToInt(const char* str);
+
+uint32 StringToUint(const char* str);
+
+int64 StringToInt64(const char* str);
+
+double StringToDouble(const char* str);
+
+// ----------------------------------------------------------------------
+// FloatToString()
+// DoubleToString()
+// IntToString()
+// UIntToString()
+// Int64ToString()
+// UInt64ToString()
+// Convert various types to their string representation. These
+// all do the obvious, trivial thing.
+// ----------------------------------------------------------------------
+
+std::string FloatToString(float f);
+std::string DoubleToString(double d);
+
+std::string IntToString(int i);
+std::string UIntToString(uint32 i);
+
+std::string Int64ToString(int64 i64);
+std::string UInt64ToString(uint64 i64);
+
+std::string Int64ToHexString(int64 i64);
+
+// ----------------------------------------------------------------------
+// StringStartsWith()
+// StringEndsWith()
+// Check if a string starts or ends with a pattern
+// ----------------------------------------------------------------------
+
+inline bool StringStartsWith(const std::string& s, const char* p) {
+ return s.find(p) == 0;
+}
+
+inline bool StringEndsWith(const std::string& s, const char* p) {
+ return s.rfind(p) == (s.length() - strlen(p));
+}
+
+// ----------------------------------------------------------------------
+// MakeStringEndWith()
+// If the string does not end with a pattern, make it end with it
+// ----------------------------------------------------------------------
+
+inline std::string MakeStringEndWith(const std::string& s, const char* p) {
+ if (StringEndsWith(s, p)) {
+ return s;
+ } else {
+ std::string ns(s);
+ ns += p;
+ return ns;
+ }
+}
+
+// Convert a lower_case_string to LowerCaseString
+std::string LowerWithUnderToPascalCase(const char* lower_with_under);
+
+// Convert a PascalCaseString to pascal_case_string
+std::string PascalCaseToLowerWithUnder(const char* pascal_case);
+
+// ----------------------------------------------------------------------
+// LowerString()
+// LowerStringToBuf()
+// Convert the characters in "s" to lowercase.
+// Changes contents of "s". LowerStringToBuf copies at most
+// "n" characters (including the terminating '\0') from "s"
+// to another buffer.
+// ----------------------------------------------------------------------
+
+inline void LowerString(char* s) {
+ for (; *s; ++s) {
+ *s = tolower(*s);
+ }
+}
+
+inline void LowerString(std::string* s) {
+ std::string::iterator end = s->end();
+ for (std::string::iterator i = s->begin(); i != end; ++i) {
+ *i = tolower(*i);
+ }
+}
+
+inline void LowerStringToBuf(const char* s, char* buf, int n) {
+ for (int i = 0; i < n - 1; ++i) {
+ char c = s[i];
+ buf[i] = tolower(c);
+ if (c == '\0') {
+ return;
+ }
+ }
+ buf[n - 1] = '\0';
+}
+
+// ----------------------------------------------------------------------
+// UpperString()
+// UpperStringToBuf()
+// Convert the characters in "s" to uppercase.
+// UpperString changes "s". UpperStringToBuf copies at most
+// "n" characters (including the terminating '\0') from "s"
+// to another buffer.
+// ----------------------------------------------------------------------
+
+inline void UpperString(char* s) {
+ for (; *s; ++s) {
+ *s = toupper(*s);
+ }
+}
+
+inline void UpperString(std::string* s) {
+ for (std::string::iterator iter = s->begin(); iter != s->end(); ++iter) {
+ *iter = toupper(*iter);
+ }
+}
+
+inline void UpperStringToBuf(const char* s, char* buf, int n) {
+ for (int i = 0; i < n - 1; ++i) {
+ char c = s[i];
+ buf[i] = toupper(c);
+ if (c == '\0') {
+ return;
+ }
+ }
+ buf[n - 1] = '\0';
+}
+
+// ----------------------------------------------------------------------
+// TrimStringLeft
+// Removes any occurrences of the characters in 'remove' from the start
+// of the string. Returns the number of chars trimmed.
+// ----------------------------------------------------------------------
+inline int TrimStringLeft(std::string* s, const char* remove) {
+ int i = 0;
+ for (; i < static_cast<int>(s->size()) && strchr(remove, (*s)[i]); ++i);
+ if (i > 0) s->erase(0, i);
+ return i;
+}
+
+// ----------------------------------------------------------------------
+// TrimStringRight
+// Removes any occurrences of the characters in 'remove' from the end
+// of the string. Returns the number of chars trimmed.
+// ----------------------------------------------------------------------
+inline int TrimStringRight(std::string* s, const char* remove) {
+ int size = static_cast<int>(s->size());
+ int i = size;
+ for (; i > 0 && strchr(remove, (*s)[i - 1]); --i);
+ if (i < size) {
+ s->erase(i);
+ }
+ return size - i;
+}
+
+// ----------------------------------------------------------------------
+// TrimString
+// Removes any occurrences of the characters in 'remove' from either
+// end of the string.
+// ----------------------------------------------------------------------
+inline int TrimString(std::string* s, const char* remove) {
+ return TrimStringRight(s, remove) + TrimStringLeft(s, remove);
+}
+
+// ----------------------------------------------------------------------
+// StringReplace()
+// Replace the "old" pattern with the "new" pattern in a string. If
+// replace_all is false, it only replaces the first instance of "old."
+// ----------------------------------------------------------------------
+
+void StringReplace(std::string* s,
+ const char* old_sub,
+ const char* new_sub,
+ bool replace_all);
+
+inline size_t HashString(const std::string &value) {
+#ifdef COMPILER_MSVC
+ return stdext::hash_value(value);
+#elif defined(__GNUC__)
+ __gnu_cxx::hash<const char*> h;
+ return h(value.c_str());
+#else
+ // Compile time error because we don't return a value
+#endif
+}
+
+// ----------------------------------------------------------------------
+// SplitOneStringToken()
+// Parse a single "delim" delimited string from "*source"
+// Modify *source to point after the delimiter.
+// If no delimiter is present after the string, set *source to NULL.
+//
+// If the start of *source is a delimiter, return an empty string.
+// If *source is NULL, return an empty string.
+// ----------------------------------------------------------------------
+std::string SplitOneStringToken(const char** source, const char* delim);
+
+//----------------------------------------------------------------------
+// CharTraits provides wrappers with common function names for char/wchar_t
+// specific CRT functions
+//----------------------------------------------------------------------
+
+template <class CharT> struct CharTraits {
+};
+
+template <>
+struct CharTraits<char> {
+ static inline size_t length(const char* s) {
+ return strlen(s);
+ }
+ static inline bool copy(char* dst, size_t dst_size, const char* s) {
+ if (s == NULL || dst == NULL)
+ return false;
+ else
+ return copy_num(dst, dst_size, s, strlen(s));
+ }
+ static inline bool copy_num(char* dst, size_t dst_size, const char* s,
+ size_t s_len) {
+ if (dst_size < (s_len + 1))
+ return false;
+ memcpy(dst, s, s_len);
+ dst[s_len] = '\0';
+ return true;
+ }
+};
+
+template <>
+struct CharTraits<wchar_t> {
+ static inline size_t length(const wchar_t* s) {
+ return wcslen(s);
+ }
+ static inline bool copy(wchar_t* dst, size_t dst_size, const wchar_t* s) {
+ if (s == NULL || dst == NULL)
+ return false;
+ else
+ return copy_num(dst, dst_size, s, wcslen(s));
+ }
+ static inline bool copy_num(wchar_t* dst, size_t dst_size, const wchar_t* s,
+ size_t s_len) {
+ if (dst_size < (s_len + 1)) {
+ return false;
+ }
+ memcpy(dst, s, s_len * sizeof(wchar_t));
+ dst[s_len] = '\0';
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------
+// This class manages a fixed-size, null-terminated string buffer. It is
+// meant to be allocated on the stack, and it makes no use of the heap
+// internally. In most cases you'll just want to use a std::(w)string, but
+// when you need to avoid the heap, you can use this class instead.
+//
+// Methods are provided to read the null-terminated buffer and to append
+// data to the buffer, and once the buffer fills-up, it simply discards any
+// extra append calls.
+//----------------------------------------------------------------------
+
+template <class CharT, int MaxSize>
+class FixedString {
+ public:
+ typedef CharTraits<CharT> char_traits;
+
+ FixedString() : index_(0), truncated_(false) {
+ buf_[0] = CharT(0);
+ }
+
+ ~FixedString() {
+ memset(buf_, 0xCC, sizeof(buf_));
+ }
+
+ // Returns true if the Append ever failed.
+ bool was_truncated() const { return truncated_; }
+
+ // Returns the number of characters in the string, excluding the null
+ // terminator.
+ size_t size() const { return index_; }
+
+ // Returns the null-terminated string.
+ const CharT* get() const { return buf_; }
+ CharT* get() { return buf_; }
+
+ // Append an array of characters. The operation is bounds checked, and if
+ // there is insufficient room, then the was_truncated() flag is set to true.
+ void Append(const CharT* s, size_t n) {
+ if (char_traits::copy_num(buf_ + index_, arraysize(buf_) - index_, s, n)) {
+ index_ += n;
+ } else {
+ truncated_ = true;
+ }
+ }
+
+ // Append a null-terminated string.
+ void Append(const CharT* s) {
+ Append(s, char_traits::length(s));
+ }
+
+ // Append a single character.
+ void Append(CharT c) {
+ Append(&c, 1);
+ }
+
+ private:
+ CharT buf_[MaxSize];
+ size_t index_;
+ bool truncated_;
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_STRING_H_
diff --git a/chrome/browser/sync/notifier/base/string_unittest.cc b/chrome/browser/sync/notifier/base/string_unittest.cc
new file mode 100644
index 0000000..954315a
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/string_unittest.cc
@@ -0,0 +1,362 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/string.h"
+#include "notifier/testing/notifier/unittest.h"
+
+namespace notifier {
+
+TEST_NOTIFIER_F(StringTest);
+
+TEST_F(StringTest, StringToInt) {
+ ASSERT_EQ(StringToInt("625"), 625);
+ ASSERT_EQ(StringToInt("6"), 6);
+ ASSERT_EQ(StringToInt("0"), 0);
+ ASSERT_EQ(StringToInt(" 122"), 122);
+ ASSERT_EQ(StringToInt("a"), 0);
+ ASSERT_EQ(StringToInt(" a"), 0);
+ ASSERT_EQ(StringToInt("2147483647"), 2147483647);
+ ASSERT_EQ(StringToInt("-2147483648"),
+ static_cast<int>(0x80000000)); // Hex constant avoids gcc warning.
+
+ int value = 0;
+ ASSERT_FALSE(ParseStringToInt("62.5", &value, true));
+ ASSERT_FALSE(ParseStringToInt("625e", &value, true));
+ ASSERT_FALSE(ParseStringToInt("2147483648", &value, true));
+ ASSERT_FALSE(ParseStringToInt("-2147483649", &value, true));
+ ASSERT_FALSE(ParseStringToInt("-4857004031", &value, true));
+}
+
+TEST_F(StringTest, StringToUint) {
+ ASSERT_EQ(StringToUint("625"), 625);
+ ASSERT_EQ(StringToUint("6"), 6);
+ ASSERT_EQ(StringToUint("0"), 0);
+ ASSERT_EQ(StringToUint(" 122"), 122);
+ ASSERT_EQ(StringToUint("a"), 0);
+ ASSERT_EQ(StringToUint(" a"), 0);
+ ASSERT_EQ(StringToUint("4294967295"), static_cast<uint32>(0xffffffff));
+
+ uint32 value = 0;
+ ASSERT_FALSE(ParseStringToUint("62.5", &value, true));
+ ASSERT_FALSE(ParseStringToUint("625e", &value, true));
+ ASSERT_FALSE(ParseStringToUint("4294967296", &value, true));
+ ASSERT_FALSE(ParseStringToUint("-1", &value, true));
+}
+
+TEST_F(StringTest, StringToInt64) {
+ ASSERT_EQ(StringToInt64("119600064000000000"),
+ INT64_C(119600064000000000));
+ ASSERT_EQ(StringToInt64(" 119600064000000000"),
+ INT64_C(119600064000000000));
+ ASSERT_EQ(StringToInt64("625"), 625);
+ ASSERT_EQ(StringToInt64("6"), 6);
+ ASSERT_EQ(StringToInt64("0"), 0);
+ ASSERT_EQ(StringToInt64(" 122"), 122);
+ ASSERT_EQ(StringToInt64("a"), 0);
+ ASSERT_EQ(StringToInt64(" a"), 0);
+ ASSERT_EQ(StringToInt64("9223372036854775807"), INT64_C(9223372036854775807));
+ ASSERT_EQ(StringToInt64("-9223372036854775808I64"),
+ static_cast<int64>(INT64_C(0x8000000000000000)));
+
+ int64 value = 0;
+ ASSERT_FALSE(ParseStringToInt64("62.5", &value, true));
+ ASSERT_FALSE(ParseStringToInt64("625e", &value, true));
+ ASSERT_FALSE(ParseStringToInt64("9223372036854775808", &value, true));
+ ASSERT_FALSE(ParseStringToInt64("-9223372036854775809", &value, true));
+}
+
+TEST_F(StringTest, StringToDouble) {
+ ASSERT_DOUBLE_EQ(StringToDouble("625"), 625);
+ ASSERT_DOUBLE_EQ(StringToDouble("-625"), -625);
+ ASSERT_DOUBLE_EQ(StringToDouble("-6.25"), -6.25);
+ ASSERT_DOUBLE_EQ(StringToDouble("6.25"), 6.25);
+ ASSERT_DOUBLE_EQ(StringToDouble("0.00"), 0);
+ ASSERT_DOUBLE_EQ(StringToDouble(" 55.1"), 55.1);
+ ASSERT_DOUBLE_EQ(StringToDouble(" 55.001"), 55.001);
+ ASSERT_DOUBLE_EQ(StringToDouble(" 1.001"), 1.001);
+
+ double value = 0.0;
+ ASSERT_FALSE(ParseStringToDouble("62*5", &value, true));
+}
+
+TEST_F(StringTest, Int64ToHexString) {
+ ASSERT_STREQ("1a8e79fe1d58000",
+ Int64ToHexString(INT64_C(119600064000000000)).c_str());
+ ASSERT_STREQ("271", Int64ToHexString(625).c_str());
+ ASSERT_STREQ("0", Int64ToHexString(0).c_str());
+}
+
+TEST_F(StringTest, StringStartsWith) {
+ { std::string s(""); ASSERT_TRUE(StringStartsWith(s, "")); }
+ { std::string s("abc"); ASSERT_TRUE(StringStartsWith(s, "ab")); }
+ { std::string s("abc"); ASSERT_FALSE(StringStartsWith(s, "bc")); }
+}
+
+TEST_F(StringTest, StringEndsWith) {
+ { std::string s(""); ASSERT_TRUE(StringEndsWith(s, "")); }
+ { std::string s("abc"); ASSERT_TRUE(StringEndsWith(s, "bc")); }
+ { std::string s("abc"); ASSERT_FALSE(StringEndsWith(s, "ab")); }
+}
+
+TEST_F(StringTest, MakeStringEndWith) {
+ {
+ std::string s("");
+ std::string t(MakeStringEndWith(s, ""));
+ ASSERT_STREQ(t.c_str(), "");
+ }
+ {
+ std::string s("abc");
+ std::string t(MakeStringEndWith(s, "def"));
+ ASSERT_STREQ(t.c_str(), "abcdef");
+ }
+ {
+ std::string s("abc");
+ std::string t(MakeStringEndWith(s, "bc"));
+ ASSERT_STREQ(t.c_str(), "abc");
+ }
+}
+
+TEST_F(StringTest, LowerString) {
+ { std::string s(""); LowerString(&s); ASSERT_STREQ(s.c_str(), ""); }
+ { std::string s("a"); LowerString(&s); ASSERT_STREQ(s.c_str(), "a"); }
+ { std::string s("A"); LowerString(&s); ASSERT_STREQ(s.c_str(), "a"); }
+ { std::string s("abc"); LowerString(&s); ASSERT_STREQ(s.c_str(), "abc"); }
+ { std::string s("ABC"); LowerString(&s); ASSERT_STREQ(s.c_str(), "abc"); }
+}
+
+TEST_F(StringTest, UpperString) {
+ { std::string s(""); UpperString(&s); ASSERT_STREQ(s.c_str(), ""); }
+ { std::string s("A"); UpperString(&s); ASSERT_STREQ(s.c_str(), "A"); }
+ { std::string s("a"); UpperString(&s); ASSERT_STREQ(s.c_str(), "A"); }
+ { std::string s("ABC"); UpperString(&s); ASSERT_STREQ(s.c_str(), "ABC"); }
+ { std::string s("abc"); UpperString(&s); ASSERT_STREQ(s.c_str(), "ABC"); }
+}
+
+TEST_F(StringTest, TrimString) {
+ const char* white = " \n\t";
+ std::string s, c;
+
+ // TrimStringLeft
+ s = ""; // empty
+ c = "";
+ ASSERT_EQ(TrimStringLeft(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t"; // all bad
+ c = "";
+ ASSERT_EQ(TrimStringLeft(&s, white), 3);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = "dog"; // nothing bad
+ c = "dog";
+ ASSERT_EQ(TrimStringLeft(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " dog "; // some bad
+ c = "dog ";
+ ASSERT_EQ(TrimStringLeft(&s, white), 1);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t\t I love my little dog \n\t ";
+ c = "I love my little dog \n\t ";
+ ASSERT_EQ(TrimStringLeft(&s, white), 5);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ // TrimStringRight
+ s = "";
+ c = "";
+ ASSERT_EQ(TrimStringRight(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t";
+ c = "";
+ ASSERT_EQ(TrimStringRight(&s, white), 3);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = "dog";
+ c = "dog";
+ ASSERT_EQ(TrimStringRight(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " dog ";
+ c = " dog";
+ ASSERT_EQ(TrimStringRight(&s, white), 1);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t\t I love my little dog \n\t ";
+ c = " \n\t\t I love my little dog";
+ ASSERT_EQ(TrimStringRight(&s, white), 4);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ // TrimString
+ s = "";
+ c = "";
+ ASSERT_EQ(TrimString(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t";
+ c = "";
+ ASSERT_EQ(TrimString(&s, white), 3);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = "dog";
+ c = "dog";
+ ASSERT_EQ(TrimString(&s, white), 0);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " dog ";
+ c = "dog";
+ ASSERT_EQ(TrimString(&s, white), 2);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+
+ s = " \n\t\t I love my little dog \n\t ";
+ c = "I love my little dog";
+ ASSERT_EQ(TrimString(&s, white), 9);
+ ASSERT_STREQ(s.c_str(), c.c_str());
+}
+
+TEST_F(StringTest, SplitOneStringToken) {
+ const char* teststrings[] = {
+ "alongword",
+ "alongword ",
+ "alongword ",
+ "alongword anotherword",
+ " alongword",
+ "",
+ };
+ const char* source = NULL;
+
+ source = teststrings[0];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "alongword");
+ ASSERT_STREQ(source, NULL);
+
+ source = teststrings[1];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "alongword");
+ ASSERT_STREQ(source, teststrings[1] + strlen("alongword") + 1);
+
+ source = teststrings[2];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "alongword");
+ ASSERT_STREQ(source, teststrings[2] + strlen("alongword") + 1);
+
+ source = teststrings[3];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "alongword");
+ ASSERT_STREQ(source, teststrings[3] + strlen("alongword") + 1);
+
+ source = teststrings[4];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "");
+ ASSERT_STREQ(source, teststrings[4] + 1);
+
+ source = teststrings[5];
+ ASSERT_STREQ(SplitOneStringToken(&source, " ").c_str(), "");
+ ASSERT_STREQ(source, NULL);
+}
+
+TEST_F(StringTest, FixedString) {
+ // Test basic operation.
+ const wchar_t kData[] = L"hello world";
+ FixedString<wchar_t, 40> buf;
+
+ buf.Append(kData);
+ EXPECT_EQ(arraysize(kData)-1, buf.size());
+ EXPECT_EQ(0, wcscmp(kData, buf.get()));
+
+ buf.Append(' ');
+ buf.Append(kData);
+ const wchar_t kExpected[] = L"hello world hello world";
+ EXPECT_EQ(arraysize(kExpected)-1, buf.size());
+ EXPECT_EQ(0, wcscmp(kExpected, buf.get()));
+ EXPECT_EQ(false, buf.was_truncated());
+
+ // Test overflow.
+ FixedString<wchar_t, 5> buf2;
+ buf2.Append(L"hello world");
+ EXPECT_EQ(static_cast<size_t>(0), buf2.size());
+ EXPECT_EQ(0, buf2.get()[0]);
+ EXPECT_EQ(true, buf2.was_truncated());
+}
+
+TEST_F(StringTest, LowerToPascalCase) {
+ EXPECT_STREQ("", LowerWithUnderToPascalCase("").c_str());
+ EXPECT_STREQ("A", LowerWithUnderToPascalCase("a").c_str());
+ EXPECT_STREQ("TestS", LowerWithUnderToPascalCase("test_s").c_str());
+ EXPECT_STREQ("XQ", LowerWithUnderToPascalCase("x_q").c_str());
+ EXPECT_STREQ("XQDNS", LowerWithUnderToPascalCase("x_qDNS").c_str());
+}
+
+TEST_F(StringTest, PascalCaseToLower) {
+ EXPECT_STREQ("", PascalCaseToLowerWithUnder("").c_str());
+ EXPECT_STREQ("a", PascalCaseToLowerWithUnder("A").c_str());
+ EXPECT_STREQ("test_s", PascalCaseToLowerWithUnder("TestS").c_str());
+ EXPECT_STREQ("xq", PascalCaseToLowerWithUnder("XQ").c_str());
+ EXPECT_STREQ("dns_name", PascalCaseToLowerWithUnder("DNSName").c_str());
+ EXPECT_STREQ("xqdns", PascalCaseToLowerWithUnder("XQDNS").c_str());
+ EXPECT_STREQ("xqdn_sa", PascalCaseToLowerWithUnder("XQDNSa").c_str());
+ EXPECT_STREQ("dns1", PascalCaseToLowerWithUnder("DNS1").c_str());
+}
+
+TEST_F(StringTest, HtmlEncode) {
+ EXPECT_STREQ("dns", HtmlEncode("dns").c_str());
+ EXPECT_STREQ("&amp;", HtmlEncode("&").c_str());
+ EXPECT_STREQ("&amp;amp;", HtmlEncode("&amp;").c_str());
+ EXPECT_STREQ("&lt;!&gt;", HtmlEncode("<!>").c_str());
+}
+
+TEST_F(StringTest, HtmlDecode) {
+ EXPECT_STREQ("dns", HtmlDecode("dns").c_str());
+ EXPECT_STREQ("&", HtmlDecode("&amp;").c_str());
+ EXPECT_STREQ("&amp;", HtmlDecode("&amp;amp;").c_str());
+ EXPECT_STREQ("<!>", HtmlDecode("&lt;!&gt;").c_str());
+}
+
+TEST_F(StringTest, UrlEncode) {
+ EXPECT_STREQ("%26", UrlEncode("&").c_str());
+ EXPECT_STREQ("%3f%20", UrlEncode("? ").c_str());
+ EXPECT_STREQ("as%20dfdsa", UrlEncode("as dfdsa").c_str());
+ EXPECT_STREQ("%3c!%3e", UrlEncode("<!>").c_str());
+ EXPECT_STREQ("!%23!", UrlEncode("!#!").c_str());
+ EXPECT_STREQ("!!", UrlEncode("!!").c_str());
+}
+
+TEST_F(StringTest, UrlDecode) {
+ EXPECT_STREQ("&", UrlDecode("%26").c_str());
+ EXPECT_STREQ("? ", UrlDecode("%3f%20").c_str());
+ EXPECT_STREQ("as dfdsa", UrlDecode("as%20dfdsa").c_str());
+ EXPECT_STREQ("<!>", UrlDecode("%3c!%3e").c_str());
+ EXPECT_STREQ("&amp;", UrlDecode("&amp;").c_str());
+}
+
+TEST_F(StringTest, StringReplace) {
+ // Test StringReplace core functionality.
+ std::string s = "<attribute name=abcd/>";
+ StringReplace(&s, "=", " = ", false);
+ EXPECT_STREQ(s.c_str(), "<attribute name = abcd/>");
+
+ // Test for negative case.
+ s = "<attribute name=abcd/>";
+ StringReplace(&s, "-", "=", false);
+ EXPECT_STREQ(s.c_str(), "<attribute name=abcd/>");
+
+ // Test StringReplace core functionality with replace_all flag set.
+ s = "<attribute name==abcd/>";
+ StringReplace(&s, "=", " = ", true);
+ EXPECT_STREQ(s.c_str(), "<attribute name = = abcd/>");
+
+ // Input is an empty string.
+ s = "";
+ StringReplace(&s, "=", " = ", false);
+ EXPECT_STREQ(s.c_str(), "");
+
+ // Input is an empty string and this is a request for repeated
+ // string replaces.
+ s = "";
+ StringReplace(&s, "=", " = ", true);
+ EXPECT_STREQ(s.c_str(), "");
+
+ // Input and string to replace is an empty string.
+ s = "";
+ StringReplace(&s, "", " = ", false);
+ EXPECT_STREQ(s.c_str(), "");
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/task_pump.cc b/chrome/browser/sync/notifier/base/task_pump.cc
new file mode 100644
index 0000000..7e99fc1
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/task_pump.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/task_pump.h"
+
+#include "chrome/browser/sync/notifier/base/time.h"
+#include "talk/base/common.h"
+#include "talk/base/thread.h"
+
+namespace notifier {
+
+// Don't add any messages because there are cleared and thrown away.
+enum { MSG_WAKE_UP = 1, MSG_TIMED_WAKE_UP };
+
+TaskPump::TaskPump() : timeout_change_count_(0), posted_(false) {
+}
+
+void TaskPump::OnMessage(talk_base::Message* msg) {
+ posted_ = false;
+ int initial_count = timeout_change_count_;
+
+ // If a task timed out, ensure that it is not blocked, so it will be deleted.
+ // This may result in a WakeTasks if a task is timed out.
+ PollTasks();
+
+ // Run tasks and handle timeouts.
+ RunTasks();
+}
+
+void TaskPump::WakeTasks() {
+ if (!posted_) {
+ // Do the requested wake up
+ talk_base::Thread::Current()->Post(this, MSG_WAKE_UP);
+ posted_ = true;
+ }
+}
+
+int64 TaskPump::CurrentTime() {
+ return GetCurrent100NSTime();
+}
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/task_pump.h b/chrome/browser/sync/notifier/base/task_pump.h
new file mode 100644
index 0000000..b6c00ec
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/task_pump.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_TASK_PUMP_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_TASK_PUMP_H_
+
+#include "talk/base/messagequeue.h"
+#include "talk/base/taskrunner.h"
+
+namespace notifier {
+
+class TaskPump : public talk_base::MessageHandler,
+ public talk_base::TaskRunner {
+ public:
+ TaskPump();
+
+ // MessageHandler interface.
+ virtual void OnMessage(talk_base::Message* msg);
+
+ // TaskRunner interface
+ virtual void WakeTasks();
+ virtual int64 CurrentTime();
+
+ private:
+ int timeout_change_count_;
+ bool posted_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskPump);
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_TASK_PUMP_H_
diff --git a/chrome/browser/sync/notifier/base/time.cc b/chrome/browser/sync/notifier/base/time.cc
new file mode 100644
index 0000000..ed3c414
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/time.cc
@@ -0,0 +1,360 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/time.h"
+
+#include <string>
+#include <time.h>
+
+#include "chrome/browser/sync/notifier/base/string.h"
+#include "chrome/browser/sync/notifier/base/utils.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+
+namespace notifier {
+
+// Get the current time represented in 100NS granularity since epoch
+// (Jan 1, 1970)
+time64 GetCurrent100NSTimeSinceEpoch() {
+ return GetCurrent100NSTime() - kStart100NsTimeToEpoch;
+}
+
+char* GetLocalTimeAsString() {
+ time64 long_time = GetCurrent100NSTime();
+ struct tm now;
+ Time64ToTm(long_time, &now);
+ char* time_string = asctime(&now);
+ if (time_string) {
+ int time_len = strlen(time_string);
+ if (time_len > 0) {
+ time_string[time_len - 1] = 0; // trim off terminating \n
+ }
+ }
+ return time_string;
+}
+
+// Parses RFC 822 Date/Time format
+// 5. DATE AND TIME SPECIFICATION
+// 5.1. SYNTAX
+//
+// date-time = [ day "," ] date time ; dd mm yy
+// ; hh:mm:ss zzz
+// day = "Mon" / "Tue" / "Wed" / "Thu"
+// / "Fri" / "Sat" / "Sun"
+//
+// date = 1*2DIGIT month 2DIGIT ; day month year
+// ; e.g. 20 Jun 82
+//
+// month = "Jan" / "Feb" / "Mar" / "Apr"
+// / "May" / "Jun" / "Jul" / "Aug"
+// / "Sep" / "Oct" / "Nov" / "Dec"
+//
+// time = hour zone ; ANSI and Military
+//
+// hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
+// ; 00:00:00 - 23:59:59
+//
+// zone = "UT" / "GMT" ; Universal Time
+// ; North American : UT
+// / "EST" / "EDT" ; Eastern: - 5/ - 4
+// / "CST" / "CDT" ; Central: - 6/ - 5
+// / "MST" / "MDT" ; Mountain: - 7/ - 6
+// / "PST" / "PDT" ; Pacific: - 8/ - 7
+// / 1ALPHA ; Military: Z = UT;
+// ; A:-1; (J not used)
+// ; M:-12; N:+1; Y:+12
+// / ( ("+" / "-") 4DIGIT ) ; Local differential
+// ; hours+min. (HHMM)
+// Return local time if ret_local_time == true, return UTC time otherwise
+const int kNumOfDays = 7;
+const int kNumOfMonth = 12;
+// Note: RFC822 does not include '-' as a separator, but Http Cookies use
+// it in the date field, like this: Wdy, DD-Mon-YYYY HH:MM:SS GMT
+// This differs from RFC822 only by those dashes. It is legacy quirk from
+// old Netscape cookie specification. So it makes sense to expand this
+// parser rather then add another one.
+// See http://wp.netscape.com/newsref/std/cookie_spec.html
+const char kRFC822_DateDelimiters[] = " ,:-";
+
+const char kRFC822_TimeDelimiter[] = ": ";
+const char* kRFC822_Day[] = {
+ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
+};
+const char* kRFC822_Month[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+struct TimeZoneInfo {
+ const char* zone_name;
+ int hour_dif;
+};
+
+const TimeZoneInfo kRFC822_TimeZone[] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -5 },
+ { "EDT", -4 },
+ { "CST", -6 },
+ { "CDT", -5 },
+ { "MST", -7 },
+ { "MDT", -6 },
+ { "PST", -8 },
+ { "PDT", -7 },
+ { "A", -1 }, // Military time zones
+ { "B", -2 },
+ { "C", -3 },
+ { "D", -4 },
+ { "E", -5 },
+ { "F", -6 },
+ { "G", -7 },
+ { "H", -8 },
+ { "I", -9 },
+ { "K", -10 },
+ { "L", -11 },
+ { "M", -12 },
+ { "N", 1 },
+ { "O", 2 },
+ { "P", 3 },
+ { "Q", 4 },
+ { "R", 5 },
+ { "S", 6 },
+ { "T", 7 },
+ { "U", 8 },
+ { "V", 9 },
+ { "W", 10 },
+ { "X", 11 },
+ { "Y", 12 },
+ { "Z", 0 },
+};
+
+bool ParseRFC822DateTime(const char* str, struct tm* time,
+ bool ret_local_time) {
+ ASSERT(str && *str);
+ ASSERT(time);
+
+ std::string str_date(str);
+ std::string str_token;
+ const char* str_curr = str_date.c_str();
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters);
+ if (str_token == "") {
+ return false;
+ }
+
+ for (int i = 0; i < kNumOfDays; ++i) {
+ if (str_token == kRFC822_Day[i]) {
+ // Skip spaces after ','
+ while (*str_curr == ' ' && *str_curr != '\0') {
+ str_curr++;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters);
+ if (str_token == "") {
+ return false;
+ }
+ break;
+ }
+ }
+
+ int day = 0;
+ if (!ParseStringToInt(str_token.c_str(), &day, true) || day < 0 || day > 31) {
+ return false;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters);
+ if (str_token == "") {
+ return false;
+ }
+
+ int month = -1;
+ for (int i = 0; i < kNumOfMonth; ++i) {
+ if (str_token == kRFC822_Month[i]) {
+ month = i; // month is 0 based number
+ break;
+ }
+ }
+ if (month == -1) { // month not found
+ return false;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters);
+ if (str_token == "") {
+ return false;
+ }
+
+ int year = 0;
+ if (!ParseStringToInt(str_token.c_str(), &year, true)) {
+ return false;
+ }
+ if (year < 100) { // two digit year format, convert to 1950 - 2050 range
+ if (year < 50) {
+ year += 2000;
+ } else {
+ year += 1900;
+ }
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter);
+ if (str_token == "") {
+ return false;
+ }
+
+ int hour = 0;
+ if (!ParseStringToInt(str_token.c_str(), &hour, true) ||
+ hour < 0 || hour > 23) {
+ return false;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter);
+ if (str_token == "") {
+ return false;
+ }
+
+ int minute = 0;
+ if (!ParseStringToInt(str_token.c_str(), &minute, true) ||
+ minute < 0 || minute > 59) {
+ return false;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter);
+ if (str_token == "") {
+ return false;
+ }
+
+ int second = 0;
+ // distingushed between XX:XX and XX:XX:XX time formats
+ if (str_token.size() == 2 && isdigit(str_token[0]) && isdigit(str_token[1])) {
+ second = 0;
+ if (!ParseStringToInt(str_token.c_str(), &second, true) ||
+ second < 0 || second > 59) {
+ return false;
+ }
+
+ str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter);
+ if (str_token == "") {
+ return false;
+ }
+ }
+
+ int bias = 0;
+ if (str_token[0] == '+' || str_token[0] == '-' || isdigit(str_token[0])) {
+ // numeric format
+ int zone = 0;
+ if (!ParseStringToInt(str_token.c_str(), &zone, true)) {
+ return false;
+ }
+
+ // zone is in HHMM format, need to convert to the number of minutes
+ bias = (zone / 100) * 60 + (zone % 100);
+ } else { // text format
+ for (size_t i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo);
+ ++i) {
+ if (str_token == kRFC822_TimeZone[i].zone_name) {
+ bias = kRFC822_TimeZone[i].hour_dif * 60;
+ break;
+ }
+ }
+ }
+
+ SetZero(*time);
+ time->tm_year = year - 1900;
+ time->tm_mon = month;
+ time->tm_mday = day;
+ time->tm_hour = hour;
+ time->tm_min = minute;
+ time->tm_sec = second;
+
+ time64 time_64 = TmToTime64(*time);
+ time_64 = time_64 - bias * kMinsTo100ns;
+
+ if (!Time64ToTm(time_64, time)) {
+ return false;
+ }
+
+ if (ret_local_time) {
+ if (!UtcTimeToLocalTime(time)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Parse a string to time span
+//
+// A TimeSpan value can be represented as
+// [d.]hh:mm:ss
+//
+// d = days (optional)
+// hh = hours as measured on a 24-hour clock
+// mm = minutes
+// ss = seconds
+bool ParseStringToTimeSpan(const char* str, time64* time_span) {
+ ASSERT(str);
+ ASSERT(time_span);
+
+ const char kColonDelimitor[] = ":";
+ const char kDotDelimitor = '.';
+
+ std::string str_span(str);
+ time64 span = 0;
+
+ int idx = str_span.find(kDotDelimitor);
+ if (idx != -1) {
+ std::string str_day = str_span.substr(0, idx);
+ int day = 0;
+ if (!ParseStringToInt(str_day.c_str(), &day, true) ||
+ day < 0 || day > 365) {
+ return false;
+ }
+ span = day;
+
+ str_span = str_span.substr(idx + 1);
+ }
+
+ const char* str_curr = str_span.c_str();
+ std::string str_token;
+
+ str_token = SplitOneStringToken(&str_curr, kColonDelimitor);
+ if (str_token == "") {
+ return false;
+ }
+
+ int hour = 0;
+ if (!ParseStringToInt(str_token.c_str(), &hour, true) ||
+ hour < 0 || hour > 23) {
+ return false;
+ }
+ span = span * 24 + hour;
+
+ str_token = SplitOneStringToken(&str_curr, kColonDelimitor);
+ if (str_token == "") {
+ return false;
+ }
+
+ int minute = 0;
+ if (!ParseStringToInt(str_token.c_str(), &minute, true) ||
+ minute < 0 || minute > 59) {
+ return false;
+ }
+ span = span * 60 + minute;
+
+ str_token = SplitOneStringToken(&str_curr, kColonDelimitor);
+ if (str_token == "") {
+ return false;
+ }
+
+ int second = 0;
+ if (!ParseStringToInt(str_token.c_str(), &second, true) ||
+ second < 0 || second > 59) {
+ return false;
+ }
+
+ *time_span = (span * 60 + second) * kSecsTo100ns;
+
+ return true;
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/time.h b/chrome/browser/sync/notifier/base/time.h
new file mode 100644
index 0000000..9bdb6f6
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/time.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIME_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIME_H_
+
+#include <time.h>
+
+#include "talk/base/basictypes.h"
+
+typedef uint64 time64;
+
+#define kMicrosecsTo100ns (static_cast<time64>(10))
+#define kMillisecsTo100ns (static_cast<time64>(10000))
+#define kSecsTo100ns (1000 * kMillisecsTo100ns)
+#define kMinsTo100ns (60 * kSecsTo100ns)
+#define kHoursTo100ns (60 * kMinsTo100ns)
+#define kDaysTo100ns (24 * kHoursTo100ns)
+const time64 kMaxTime100ns = UINT64_C(9223372036854775807);
+
+// Time difference in 100NS granularity between platform-dependent starting
+// time and Jan 1, 1970.
+#ifdef WIN32
+// On Windows time64 is seconds since Jan 1, 1601.
+#define kStart100NsTimeToEpoch (116444736000000000uI64) // Jan 1, 1970 in time64
+#else
+// On Unix time64 is seconds since Jan 1, 1970.
+#define kStart100NsTimeToEpoch (0) // Jan 1, 1970 in time64
+#endif
+
+// Time difference in 100NS granularity between platform-dependent starting
+// time and Jan 1, 1980.
+#define kStart100NsTimeTo1980 \
+ kStart100NsTimeToEpoch + UINT64_C(3155328000000000)
+
+#define kTimeGranularity (kDaysTo100ns)
+
+namespace notifier {
+
+// Get the current time represented in 100NS granularity
+// Different platform might return the value since different starting time.
+// Win32 platform returns the value since Jan 1, 1601.
+time64 GetCurrent100NSTime();
+
+// Get the current time represented in 100NS granularity since epoch
+// (Jan 1, 1970).
+time64 GetCurrent100NSTimeSinceEpoch();
+
+// Convert from struct tm to time64.
+time64 TmToTime64(const struct tm& tm);
+
+// Convert from time64 to struct tm.
+bool Time64ToTm(time64 t, struct tm* tm);
+
+// Convert from UTC time to local time.
+bool UtcTimeToLocalTime(struct tm* tm);
+
+// Convert from local time to UTC time.
+bool LocalTimeToUtcTime(struct tm* tm);
+
+// Returns the local time as a string suitable for logging
+// Note: This is *not* threadsafe, so only call it from the main thread.
+char* GetLocalTimeAsString();
+
+// Parses RFC 822 Date/Time format
+// 5. DATE AND TIME SPECIFICATION
+// 5.1. SYNTAX
+//
+// date-time = [ day "," ] date time ; dd mm yy
+// ; hh:mm:ss zzz
+// day = "Mon" / "Tue" / "Wed" / "Thu"
+// / "Fri" / "Sat" / "Sun"
+//
+// date = 1*2DIGIT month 2DIGIT ; day month year
+// ; e.g. 20 Jun 82
+//
+// month = "Jan" / "Feb" / "Mar" / "Apr"
+// / "May" / "Jun" / "Jul" / "Aug"
+// / "Sep" / "Oct" / "Nov" / "Dec"
+//
+// time = hour zone ; ANSI and Military
+//
+// hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
+// ; 00:00:00 - 23:59:59
+//
+// zone = "UT" / "GMT" ; Universal Time
+// ; North American : UT
+// / "EST" / "EDT" ; Eastern: - 5/ - 4
+// / "CST" / "CDT" ; Central: - 6/ - 5
+// / "MST" / "MDT" ; Mountain: - 7/ - 6
+// / "PST" / "PDT" ; Pacific: - 8/ - 7
+// / 1ALPHA ; Military: Z = UT;
+// ; A:-1; (J not used)
+// ; M:-12; N:+1; Y:+12
+// / ( ("+" / "-") 4DIGIT ) ; Local differential
+// ; hours+min. (HHMM)
+// Return local time if ret_local_time == true, return UTC time otherwise
+bool ParseRFC822DateTime(const char* str, struct tm* time, bool ret_local_time);
+
+// Parse a string to time span.
+//
+// A TimeSpan value can be represented as
+// [d.]hh:mm:ss
+//
+// d = days (optional)
+// hh = hours as measured on a 24-hour clock
+// mm = minutes
+// ss = seconds
+bool ParseStringToTimeSpan(const char* str, time64* time_span);
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIME_H_
diff --git a/chrome/browser/sync/notifier/base/time_unittest.cc b/chrome/browser/sync/notifier/base/time_unittest.cc
new file mode 100644
index 0000000..0a34b0a
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/time_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/time.h"
+#include "notifier/testing/notifier/unittest.h"
+
+namespace notifier {
+
+TEST_NOTIFIER_F(TimeTest);
+
+TEST_F(TimeTest, ParseRFC822DateTime) {
+ struct tm t = {0};
+
+ EXPECT_TRUE(ParseRFC822DateTime("Mon, 16 May 2005 15:44:18 -0700",
+ &t, false));
+ EXPECT_EQ(t.tm_year, 2005 - 1900);
+ EXPECT_EQ(t.tm_mon, 4);
+ EXPECT_EQ(t.tm_mday, 16);
+ EXPECT_EQ(t.tm_hour, 22);
+ EXPECT_EQ(t.tm_min, 44);
+ EXPECT_EQ(t.tm_sec, 18);
+
+ EXPECT_TRUE(ParseRFC822DateTime("Mon, 16 May 2005 15:44:18 -0700", &t, true));
+ EXPECT_EQ(t.tm_year, 2005 - 1900);
+ EXPECT_EQ(t.tm_mon, 4);
+ EXPECT_EQ(t.tm_mday, 16);
+ EXPECT_TRUE(t.tm_hour == 15 || t.tm_hour == 14); // daylight saving time
+ EXPECT_EQ(t.tm_min, 44);
+ EXPECT_EQ(t.tm_sec , 18);
+
+ EXPECT_TRUE(ParseRFC822DateTime("Tue, 17 May 2005 02:56:18 +0400",
+ &t, false));
+ EXPECT_EQ(t.tm_year, 2005 - 1900);
+ EXPECT_EQ(t.tm_mon, 4);
+ EXPECT_EQ(t.tm_mday, 16);
+ EXPECT_EQ(t.tm_hour, 22);
+ EXPECT_EQ(t.tm_min, 56);
+ EXPECT_EQ(t.tm_sec , 18);
+
+ EXPECT_TRUE(ParseRFC822DateTime("Tue, 17 May 2005 02:56:18 +0400", &t, true));
+ EXPECT_EQ(t.tm_year, 2005 - 1900);
+ EXPECT_EQ(t.tm_mon, 4);
+ EXPECT_EQ(t.tm_mday, 16);
+ EXPECT_TRUE(t.tm_hour == 15 || t.tm_hour == 14); // daylight saving time
+ EXPECT_EQ(t.tm_min, 56);
+ EXPECT_EQ(t.tm_sec, 18);
+}
+
+TEST_F(TimeTest, ParseStringToTimeSpan) {
+ time64 time_span = 0;
+
+ EXPECT_TRUE(ParseStringToTimeSpan("0:0:4", &time_span));
+ EXPECT_EQ(time_span, 4 * kSecsTo100ns);
+
+ EXPECT_TRUE(ParseStringToTimeSpan("0:3:4", &time_span));
+ EXPECT_EQ(time_span, (3 * 60 + 4) * kSecsTo100ns);
+
+ EXPECT_TRUE(ParseStringToTimeSpan("2:3:4", &time_span));
+ EXPECT_EQ(time_span, (2 * 3600 + 3 * 60 + 4) * kSecsTo100ns);
+
+ EXPECT_TRUE(ParseStringToTimeSpan("1.2:3:4", &time_span));
+ EXPECT_EQ(time_span, (1 * 86400 + 2 * 60 * 60 + 3 * 60 + 4) * kSecsTo100ns);
+
+ EXPECT_FALSE(ParseStringToTimeSpan("2:invalid:4", &time_span));
+}
+
+TEST_F(TimeTest, UseLocalTimeAsString) {
+ // Just call it to ensure that it doesn't assert.
+ GetLocalTimeAsString();
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/timer.cc b/chrome/browser/sync/notifier/base/timer.cc
new file mode 100644
index 0000000..7fa20b4
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/timer.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/sync/notifier/base/timer.h"
+
+namespace notifier {
+
+Timer::Timer(talk_base::Task* parent, int timeout_seconds, bool repeat)
+ : Task(parent),
+ repeat_(repeat) {
+
+ set_timeout_seconds(timeout_seconds);
+ Start();
+ ResumeTimeout();
+}
+
+Timer::~Timer() {
+}
+
+int Timer::OnTimeout() {
+ if (!repeat_) {
+ return STATE_DONE;
+ }
+ ResetTimeout();
+ return STATE_BLOCKED;
+}
+
+int Timer::ProcessStart() {
+ return STATE_BLOCKED;
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/timer.h b/chrome/browser/sync/notifier/base/timer.h
new file mode 100644
index 0000000..dd68c73
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/timer.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIMER_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIMER_H_
+
+#include "talk/base/task.h"
+
+namespace notifier {
+
+class Timer : private talk_base::Task {
+ public:
+ Timer(talk_base::Task* parent, int timeout_seconds, bool repeat);
+ ~Timer();
+
+ // Call Abort() to stop the timer.
+ using talk_base::Task::Abort;
+
+ // Call to find out when the timer is set to go off
+ // Returns int64
+ using talk_base::Task::get_timeout_time;
+
+ // Call to set the timeout interval.
+ using talk_base::Task::set_timeout_seconds;
+
+ using talk_base::Task::SignalTimeout;
+
+ private:
+ virtual int OnTimeout();
+ virtual int ProcessStart();
+
+ bool repeat_;
+
+ DISALLOW_COPY_AND_ASSIGN(Timer);
+};
+
+} // namespace notifier
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_TIMER_H_
diff --git a/chrome/browser/sync/notifier/base/utils.h b/chrome/browser/sync/notifier/base/utils.h
new file mode 100644
index 0000000..2105233
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/utils.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2009 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.
+//
+// Utility functions
+
+#ifndef CHROME_BROWSER_SYNC_NOTIFIER_BASE_UTILS_H_
+#define CHROME_BROWSER_SYNC_NOTIFIER_BASE_UTILS_H_
+
+#include <map>
+#include <string>
+
+#include "chrome/browser/sync/notifier/base/static_assert.h"
+
+// return error if the first argument evaluates to false
+#define RET_IF_FALSE(x) do { if (!(x)) return false; } while (false)
+
+// Protocol constants
+const char kHttpProto[] = "http://";
+const char kHttpsProto[] = "https://";
+
+// Initialize a POD to zero.
+// Using this function requires discipline. Don't use for types that have a
+// v-table or virtual bases.
+template <typename T>
+inline void SetZero(T& p) {
+ // Guard against the easy mistake of
+ // foo(int *p) { SetZero(p); } instead of
+ // SetZero(*p);
+ // which it should be.
+ STATIC_ASSERT(sizeof(T) != sizeof(void*));
+
+ // A POD (plain old data) object has one of these data types:
+ // a fundamental type, union, struct, array,
+ // or class--with no constructor. PODs don't have virtual functions or
+ // virtual bases.
+
+ // Test to see if the type has constructors.
+ union CtorTest {
+ T t;
+ int i;
+ };
+
+ // TODO(sync) There might be a way to test if the type has virtuals
+ // For now, if we zero a type with virtuals by mistake, it is going to crash
+ // predictable at run-time when the virtuals are called.
+ memset(&p, 0, sizeof(T));
+}
+
+// Used to delete each element in a vector<T*>/deque<T*>
+// (and then empty the sequence).
+template <class T>
+void CleanupSequence(T* items) {
+ for (typename T::iterator it(items->begin()); it != items->end(); ++it) {
+ delete (*it);
+ }
+ items->clear();
+}
+
+// Typically used to clean up values used in a hash_map
+// that had Type* as values.
+//
+// WARNING: This function assumes that T::clear will not access the values
+// (or the keys if they are the same as the values). This is true
+// for hash_map.
+template <class T>
+void CleanupMap(T* items) {
+ // This is likely slower than a for loop, but we have to do it this way. In
+ // some of the maps we use, deleting it->second causes it->first to be deleted
+ // as well, and that seems to send the iterator in a tizzy.
+ typename T::iterator it = items->begin();
+ while (it != items->end()) {
+ items->erase(it->first);
+ delete it->second;
+ it = items->begin();
+ }
+}
+
+// Get the value of an element in the map with the specified name
+template <class T>
+void GetMapElement(const std::map<const std::string, const T>& m,
+ const char* name,
+ T* value) {
+ typename std::map<const std::string, const T>::const_iterator iter(
+ m.find(name));
+ if (iter != m.end()) {
+ *value = iter->second;
+ }
+}
+
+#endif // CHROME_BROWSER_SYNC_NOTIFIER_BASE_UTILS_H_
diff --git a/chrome/browser/sync/notifier/base/win32/async_network_alive_win32.cc b/chrome/browser/sync/notifier/base/win32/async_network_alive_win32.cc
new file mode 100644
index 0000000..b344817
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/win32/async_network_alive_win32.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2009 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.
+
+#include <winsock2.h>
+
+#include "chrome/browser/sync/notifier/base/async_network_alive.h"
+#include "chrome/browser/sync/notifier/base/utils.h"
+#include "talk/base/criticalsection.h"
+#include "talk/base/logging.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/common.h"
+#include "third_party/smartany/scoped_any.h"
+
+namespace notifier {
+class PlatformNetworkInfo {
+ public:
+ PlatformNetworkInfo() : ws_handle_(NULL), event_handle_(NULL) {
+ }
+
+ ~PlatformNetworkInfo() {
+ Close();
+ }
+
+ void Close() {
+ talk_base::CritScope crit_scope(&crit_sect_);
+ if (ws_handle_) {
+ if (event_handle_) // unblock any waiting for network changes
+ SetEvent(get(event_handle_));
+ // finishes the iteration.
+ VERIFY(WSALookupServiceEnd(ws_handle_) == 0);
+ ws_handle_ = NULL;
+ LOG_F(LS_INFO) << "WSACleanup 1";
+ ::WSACleanup();
+ }
+ }
+
+ bool IsAlive(bool* error) {
+ ASSERT(error);
+ *error = false;
+
+ // If IsAlive was previously called, we need a new handle.
+ // Why? If we use the same handle, we only get diffs on what changed
+ // which isn't what we want.
+ Close();
+ int result = Initialize();
+ if (result != 0) {
+ LOG_F(LS_ERROR) << "failed:" << result;
+ // Default to alive on error.
+ *error = true;
+ return true;
+ }
+
+ bool alive = false;
+
+ // Retrieve network info and move to next one. In this function, we only
+ // need to know whether or not there is network connection.
+ // allocate 256 bytes for name, it should be enough for most cases.
+ // If the name is longer, it is OK as we will check the code returned and
+ // set correct network status.
+ char result_buffer[sizeof(WSAQUERYSET) + 256] = {0};
+ bool flush_previous_result = false;
+ do {
+ DWORD control_flags = LUP_RETURN_NAME;
+ if (flush_previous_result) {
+ control_flags |= LUP_FLUSHPREVIOUS;
+ }
+ DWORD length = sizeof(result_buffer);
+ reinterpret_cast<WSAQUERYSET*>(&result_buffer[0])->dwSize =
+ sizeof(WSAQUERYSET);
+ // ws_handle_ may be NULL (if exiting), but the call will simply fail
+ int result = ::WSALookupServiceNext(
+ ws_handle_,
+ control_flags,
+ &length,
+ reinterpret_cast<WSAQUERYSET*>(&result_buffer[0]));
+
+ if (result == 0) {
+ // get at least one connection, return "connected".
+ alive = true;
+ } else {
+ ASSERT(result == SOCKET_ERROR);
+ result = ::WSAGetLastError();
+ if (result == WSA_E_NO_MORE || result == WSAENOMORE) {
+ break;
+ }
+
+ // Error code WSAEFAULT means there is a network connection but the
+ // result_buffer size is too small to contain the results. The
+ // variable "length" returned from WSALookupServiceNext is the minimum
+ // number of bytes required. We do not need to retrieve detail info.
+ // Return "alive" in this case.
+ if (result == WSAEFAULT) {
+ alive = true;
+ flush_previous_result = true;
+ } else {
+ LOG_F(LS_WARNING) << "failed:" << result;
+ *error = true;
+ break;
+ }
+ }
+ } while (true);
+ LOG_F(LS_INFO) << "alive: " << alive;
+ return alive;
+ }
+
+ bool WaitForChange() {
+ // IsAlive must be called first.
+ int junk1 = 0, junk2 = 0;
+ DWORD bytes_returned = 0;
+ int result = SOCKET_ERROR;
+ {
+ talk_base::CritScope crit_scope(&crit_sect_);
+ if (!ws_handle_)
+ return false;
+ ASSERT(!event_handle_);
+ reset(event_handle_, ::CreateEvent(NULL, FALSE, FALSE, NULL));
+ if (!event_handle_) {
+ LOG_F(LS_WARNING) << "failed to CreateEvent";
+ return false;
+ }
+ WSAOVERLAPPED overlapped = {0};
+ overlapped.hEvent = get(event_handle_);
+ WSACOMPLETION completion;
+ ::SetZero(completion);
+ completion.Type = NSP_NOTIFY_EVENT;
+ completion.Parameters.Event.lpOverlapped = &overlapped;
+
+ LOG_F(LS_INFO) << "calling WSANSPIoctl";
+ // Do a non-blocking request for change notification. event_handle_
+ // will get signaled when there is a change, so we wait on it later.
+ // It can also be signaled by Close() in order allow clean termination.
+ result = ::WSANSPIoctl(ws_handle_,
+ SIO_NSP_NOTIFY_CHANGE,
+ &junk1,
+ 0,
+ &junk2,
+ 0,
+ &bytes_returned,
+ &completion);
+ }
+ if (NO_ERROR != result) {
+ result = ::WSAGetLastError();
+ if (WSA_IO_PENDING != result) {
+ LOG_F(LS_WARNING) << "failed: " << result;
+ reset(event_handle_);
+ return false;
+ }
+ }
+ LOG_F(LS_INFO) << "waiting";
+ WaitForSingleObject(get(event_handle_), INFINITE);
+ reset(event_handle_);
+ LOG_F(LS_INFO) << "changed";
+ return true;
+ }
+
+ private:
+ int Initialize() {
+ WSADATA wsa_data;
+ LOG_F(LS_INFO) << "calling WSAStartup";
+ int result = ::WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (result != ERROR_SUCCESS) {
+ LOG_F(LS_ERROR) << "failed:" << result;
+ return result;
+ }
+
+ WSAQUERYSET query_set = {0};
+ query_set.dwSize = sizeof(WSAQUERYSET);
+ query_set.dwNameSpace = NS_NLA;
+ // Initiate a client query to iterate through the
+ // currently connected networks.
+ if (0 != ::WSALookupServiceBegin(&query_set, LUP_RETURN_ALL,
+ &ws_handle_)) {
+ result = ::WSAGetLastError();
+ LOG_F(LS_INFO) << "WSACleanup 2";
+ ::WSACleanup();
+ ASSERT(ws_handle_ == NULL);
+ ws_handle_ = NULL;
+ return result;
+ }
+ return 0;
+ }
+ talk_base::CriticalSection crit_sect_;
+ HANDLE ws_handle_;
+ scoped_event event_handle_;
+ DISALLOW_COPY_AND_ASSIGN(PlatformNetworkInfo);
+};
+
+class AsyncNetworkAliveWin32 : public AsyncNetworkAlive {
+ public:
+ AsyncNetworkAliveWin32() {
+ }
+
+ virtual ~AsyncNetworkAliveWin32() {
+ if (network_info_) {
+ delete network_info_;
+ network_info_ = NULL;
+ }
+ }
+
+ protected:
+ // SignalThread Interface
+ virtual void DoWork() {
+ if (!network_info_) {
+ network_info_ = new PlatformNetworkInfo();
+ } else {
+ // Since network_info is set, it means that
+ // we are suppose to wait for network state changes.
+ if (!network_info_->WaitForChange()) {
+ // The wait was aborted so we must be shutting down.
+ alive_ = false;
+ error_ = true;
+ return;
+ }
+ }
+ alive_ = network_info_->IsAlive(&error_);
+ }
+
+ virtual void OnWorkStop() {
+ if (network_info_) {
+ network_info_->Close();
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncNetworkAliveWin32);
+};
+
+AsyncNetworkAlive* AsyncNetworkAlive::Create() {
+ return new AsyncNetworkAliveWin32();
+}
+
+} // namespace notifier
diff --git a/chrome/browser/sync/notifier/base/win32/time_win32.cc b/chrome/browser/sync/notifier/base/win32/time_win32.cc
new file mode 100644
index 0000000..34a53fe
--- /dev/null
+++ b/chrome/browser/sync/notifier/base/win32/time_win32.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2009 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.
+//
+// Time functions
+
+#include <time.h>
+#include <windows.h>
+
+#include "chrome/browser/sync/notifier/base/time.h"
+
+#include "chrome/browser/sync/notifier/base/utils.h"
+#include "talk/base/common.h"
+#include "talk/base/logging.h"
+
+namespace notifier {
+
+time64 FileTimeToTime64(const FILETIME& file_time) {
+ return static_cast<time64>(file_time.dwHighDateTime) << 32 |
+ file_time.dwLowDateTime;
+}
+
+void Time64ToFileTime(const time64& time, FILETIME* ft) {
+ ASSERT(ft);
+
+ ft->dwHighDateTime = static_cast<DWORD>(time >> 32);
+ ft->dwLowDateTime = static_cast<DWORD>(time & 0xffffffff);
+}
+
+void TmTimeToSystemTime(const struct tm& tm, SYSTEMTIME* sys_time) {
+ ASSERT(sys_time);
+
+ SetZero(*sys_time);
+ // tm's year is 1900 based, systemtime's year is absolute
+ sys_time->wYear = tm.tm_year + 1900;
+ // tm's month is 0 based, but systemtime's month is 1 based
+ sys_time->wMonth = tm.tm_mon + 1;
+ sys_time->wDay = tm.tm_mday;
+ sys_time->wDayOfWeek = tm.tm_wday;
+ sys_time->wHour = tm.tm_hour;
+ sys_time->wMinute = tm.tm_min;
+ sys_time->wSecond = tm.tm_sec;
+}
+
+void SystemTimeToTmTime(const SYSTEMTIME& sys_time, struct tm* tm) {
+ ASSERT(tm);
+
+ SetZero(*tm);
+ // tm's year is 1900 based, systemtime's year is absolute
+ tm->tm_year = sys_time.wYear - 1900;
+ // tm's month is 0 based, but systemtime's month is 1 based
+ tm->tm_mon = sys_time.wMonth - 1;
+ tm->tm_mday = sys_time.wDay;
+ tm->tm_wday = sys_time.wDayOfWeek;
+ tm->tm_hour = sys_time.wHour;
+ tm->tm_min = sys_time.wMinute;
+ tm->tm_sec = sys_time.wSecond;
+}
+
+time64 GetCurrent100NSTime() {
+ // In order to get the 100ns time we shouldn't use SystemTime
+ // as it's granularity is 1 ms. Below is the correct implementation.
+ // On the other hand the system clock granularity is 15 ms, so we
+ // are not gaining much by having the timestamp in nano-sec
+ // If we decise to go with ms, divide "time64 time" by 10000
+
+ FILETIME file_time;
+ ::GetSystemTimeAsFileTime(&file_time);
+
+ time64 time = FileTimeToTime64(file_time);
+ return time;
+}
+
+time64 TmToTime64(const struct tm& tm) {
+ SYSTEMTIME sys_time;
+ TmTimeToSystemTime(tm, &sys_time);
+
+ FILETIME file_time;
+ SetZero(file_time);
+ if (!::SystemTimeToFileTime(&sys_time, &file_time)) {
+ return 0;
+ }
+
+ return FileTimeToTime64(file_time);
+}
+
+bool Time64ToTm(time64 t, struct tm* tm) {
+ ASSERT(tm);
+
+ FILETIME file_time;
+ SetZero(file_time);
+ Time64ToFileTime(t, &file_time);
+
+ SYSTEMTIME sys_time;
+ SetZero(sys_time);
+ if (!::FileTimeToSystemTime(&file_time, &sys_time)) {
+ return false;
+ }
+
+ SystemTimeToTmTime(sys_time, tm);
+
+ return true;
+}
+
+bool UtcTimeToLocalTime(struct tm* tm) {
+ ASSERT(tm);
+
+ SYSTEMTIME utc_time;
+ TmTimeToSystemTime(*tm, &utc_time);
+
+ TIME_ZONE_INFORMATION time_zone;
+ if (::GetTimeZoneInformation(&time_zone) == TIME_ZONE_ID_INVALID) {
+ return false;
+ }
+
+ SYSTEMTIME local_time;
+ if (!::SystemTimeToTzSpecificLocalTime(&time_zone, &utc_time, &local_time)) {
+ return false;
+ }
+
+ SystemTimeToTmTime(local_time, tm);
+
+ return true;
+}
+
+bool LocalTimeToUtcTime(struct tm* tm) {
+ ASSERT(tm);
+
+ SYSTEMTIME local_time;
+ TmTimeToSystemTime(*tm, &local_time);
+
+ // Get the bias, which when added to local, gives UTC
+ TIME_ZONE_INFORMATION time_zone;
+ if (::GetTimeZoneInformation(&time_zone) == TIME_ZONE_ID_INVALID) {
+ return false;
+ }
+
+ // By negating the biases, we can get translation from UTC to local
+ time_zone.Bias *= -1;
+ time_zone.DaylightBias *= -1;
+ time_zone.StandardBias *= -1; // this is 0 but negating for completness
+
+ // We'll tell SystemTimeToTzSpecificLocalTime that the local time is actually
+ // UTC. With the negated bias, the "local" time that the API returns will
+ // actually be UTC. Casting the const off because
+ // SystemTimeToTzSpecificLocalTime's definition requires it, although the
+ // value is not modified.
+ SYSTEMTIME utc_time;
+ if (!::SystemTimeToTzSpecificLocalTime(&time_zone, &local_time, &utc_time)) {
+ return false;
+ }
+
+ SystemTimeToTmTime(utc_time, tm);
+
+ return true;
+}
+
+} // namespace notifier