summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 00:46:13 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-20 00:46:13 +0000
commit60b4db44f97540f61996863830ad122b33b00c40 (patch)
treedd732298aa0182533739a0bebb0f7e9959292731
parent1a4a5cc452e74bd71a9702a43e8ba116900e8629 (diff)
downloadchromium_src-60b4db44f97540f61996863830ad122b33b00c40.zip
chromium_src-60b4db44f97540f61996863830ad122b33b00c40.tar.gz
chromium_src-60b4db44f97540f61996863830ad122b33b00c40.tar.bz2
Implemented AddressWatchTask for OS X.
Added some utility methods to ServerConnectionManager. BUG=32430 TEST=Manual testing with a laptop Review URL: http://codereview.chromium.org/543098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36586 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.cc20
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.h6
-rwxr-xr-xchrome/browser/sync/engine/syncapi.cc141
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h3
4 files changed, 169 insertions, 1 deletions
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc
index 10c6aef..bbdef87 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.cc
+++ b/chrome/browser/sync/engine/net/server_connection_manager.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/sync/protocol/sync.pb.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
+#include "googleurl/src/gurl.h"
namespace browser_sync {
@@ -273,6 +274,13 @@ bool ServerConnectionManager::CheckServerReachable() {
return server_is_reachable;
}
+void ServerConnectionManager::SetServerUnreachable() {
+ if (server_reachable_) {
+ server_reachable_ = false;
+ NotifyStatusChanged();
+ }
+}
+
void ServerConnectionManager::kill() {
{
AutoLock lock(terminate_all_io_mutex_);
@@ -343,6 +351,18 @@ void ServerConnectionManager::GetServerParameters(string* server_url,
*use_ssl = use_ssl_;
}
+std::string ServerConnectionManager::GetServerHost() const {
+ string server_url;
+ int port;
+ bool use_ssl;
+ GetServerParameters(&server_url, &port, &use_ssl);
+ // We just want the hostname, so we don't need to switch on use_ssl.
+ server_url = "http://" + server_url;
+ GURL gurl(server_url);
+ DCHECK(gurl.is_valid()) << gurl;
+ return gurl.host();
+}
+
bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
syncable::DirectoryManager* manager,
const std::string& share) {
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.h b/chrome/browser/sync/engine/net/server_connection_manager.h
index c34d4ae..28a2e4e 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/server_connection_manager.h
@@ -214,6 +214,10 @@ class ServerConnectionManager {
// Updates status and broadcasts events on change.
bool CheckServerReachable();
+ // Updates server status to "unreachable" and broadcasts events if
+ // necessary.
+ void SetServerUnreachable();
+
// Signal the shutdown event to notify listeners.
virtual void kill();
@@ -251,6 +255,8 @@ class ServerConnectionManager {
int* port,
bool* use_ssl) const;
+ std::string GetServerHost() const;
+
bool terminate_all_io() const {
AutoLock lock(terminate_all_io_mutex_);
return terminate_all_io_;
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index 8dcf8c5..623b779 100755
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -9,6 +9,11 @@
#if defined(OS_WIN)
#include <windows.h>
#include <iphlpapi.h>
+#elif defined(OS_MACOSX)
+#include <SystemConfiguration/SCNetworkReachability.h>
+#include "base/condition_variable.h"
+#include "base/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
#endif
#if defined(OS_LINUX)
@@ -25,6 +30,7 @@
#include "base/basictypes.h"
#include "base/command_line.h"
+#include "base/lock.h"
#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
@@ -77,7 +83,9 @@ using syncable::DirectoryManager;
typedef GoogleServiceAuthError AuthError;
+#if defined(OS_WIN)
static const int kServerReachablePollingIntervalMsec = 60000 * 60;
+#endif
static const int kThreadExitTimeoutMsec = 60000;
static const int kSSLPort = 443;
@@ -85,11 +93,90 @@ struct AddressWatchTaskParams {
browser_sync::ServerConnectionManager* conn_mgr;
#if defined(OS_WIN)
HANDLE exit_flag;
+
+ AddressWatchTaskParams() : conn_mgr(NULL), exit_flag() {}
#elif defined(OS_LINUX)
int exit_pipe[2];
+
+ AddressWatchTaskParams() : conn_mgr(NULL) {}
+#elif defined(OS_MACOSX)
+ // Protects run_loop and run_loop_initialized.
+ Lock run_loop_lock;
+ // May be NULL if an error was encountered by the AddressWatchTask.
+ CFRunLoopRef run_loop;
+ bool run_loop_initialized;
+ // Signalled when run_loop and run_loop_initialized are set.
+ ConditionVariable params_set;
+
+ AddressWatchTaskParams()
+ : conn_mgr(NULL),
+ run_loop(NULL),
+ run_loop_initialized(false),
+ params_set(&run_loop_lock) {}
#endif
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AddressWatchTaskParams);
};
+#if defined(OS_MACOSX)
+CFStringRef NetworkReachabilityCopyDescription(const void *info) {
+ return base::SysUTF8ToCFStringRef(
+ StringPrintf("AddressWatchTask(0x%p)", info));
+}
+
+void NetworkReachabilityChangedCallback(SCNetworkReachabilityRef target,
+ SCNetworkConnectionFlags flags,
+ void* info) {
+ bool network_active = ((flags & (kSCNetworkFlagsReachable |
+ kSCNetworkFlagsConnectionRequired |
+ kSCNetworkFlagsConnectionAutomatic |
+ kSCNetworkFlagsInterventionRequired)) ==
+ kSCNetworkFlagsReachable);
+ LOG(INFO) << "Network reachability changed: it is now "
+ << (network_active ? "active" : "inactive");
+ AddressWatchTaskParams* params =
+ static_cast<AddressWatchTaskParams*>(info);
+ if (network_active) {
+ params->conn_mgr->CheckServerReachable();
+ } else {
+ params->conn_mgr->SetServerUnreachable();
+ }
+}
+
+SCNetworkReachabilityRef CreateAndScheduleNetworkReachability(
+ SCNetworkReachabilityContext* network_reachability_context,
+ const char* nodename) {
+ scoped_cftyperef<SCNetworkReachabilityRef> network_reachability(
+ SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, nodename));
+ if (!network_reachability.get()) {
+ LOG(WARNING) << "Could not create network reachability object";
+ return NULL;
+ }
+
+ if (!SCNetworkReachabilitySetCallback(network_reachability.get(),
+ &NetworkReachabilityChangedCallback,
+ network_reachability_context)) {
+ LOG(WARNING) << "Could not set network reachability callback";
+ return NULL;
+ }
+
+ if (!SCNetworkReachabilityScheduleWithRunLoop(network_reachability.get(),
+ CFRunLoopGetCurrent(),
+ kCFRunLoopDefaultMode)) {
+ LOG(WARNING) << "Could not schedule network reachability with run loop";
+ return NULL;
+ }
+
+ return network_reachability.release();
+}
+#endif
+
+// TODO(akalin): This code needs some serious refactoring. At the
+// very least, all the gross platform-specific code should be put in
+// one place; ideally, the code shared between this and the network
+// status detector (in sync/notifier) will be put in one place.
+
// This thread calls CheckServerReachable() whenever a change occurs in the
// table that maps IP addresses to interfaces, for example when the user
// unplugs his network cable.
@@ -175,6 +262,44 @@ class AddressWatchTask : public Task {
}
}
close(params_->exit_pipe[0]);
+#elif defined(OS_MACOSX)
+ SCNetworkReachabilityContext network_reachability_context;
+ network_reachability_context.version = 0;
+ network_reachability_context.info = static_cast<void *>(params_);
+ network_reachability_context.retain = NULL;
+ network_reachability_context.release = NULL;
+ network_reachability_context.copyDescription =
+ &NetworkReachabilityCopyDescription;
+
+ std::string hostname = params_->conn_mgr->GetServerHost();
+ scoped_cftyperef<SCNetworkReachabilityRef> network_reachability(
+ CreateAndScheduleNetworkReachability(
+ &network_reachability_context, hostname.c_str()));
+ if (!network_reachability.get()) {
+ {
+ AutoLock auto_lock(params_->run_loop_lock);
+ params_->run_loop = NULL;
+ params_->run_loop_initialized = true;
+ }
+ params_->params_set.Signal();
+ LOG(INFO) << "The address watch thread has stopped due to an error";
+ return;
+ }
+
+ CFRunLoopRef run_loop = CFRunLoopGetCurrent();
+ {
+ AutoLock auto_lock(params_->run_loop_lock);
+ params_->run_loop = run_loop;
+ params_->run_loop_initialized = true;
+ }
+ params_->params_set.Signal();
+
+ CFRunLoopRun();
+
+ {
+ AutoLock auto_lock(params_->run_loop_lock);
+ params_->run_loop = NULL;
+ }
#endif
LOG(INFO) << "The address watch thread has stopped";
}
@@ -1026,6 +1151,15 @@ bool SyncManager::SyncInternal::Init(
address_watch_thread_.message_loop()->PostTask(FROM_HERE,
new AddressWatchTask(&address_watch_params_));
+#if defined(OS_MACOSX)
+ {
+ AutoLock auto_lock(address_watch_params_.run_loop_lock);
+ while (!address_watch_params_.run_loop_initialized) {
+ address_watch_params_.params_set.Wait();
+ }
+ }
+#endif
+
// Hand over the bridged POST factory to be owned by the connection
// dir_manager.
connection_manager()->SetHttpPostProviderFactory(post_factory);
@@ -1238,6 +1372,13 @@ void SyncManager::SyncInternal::Shutdown() {
LOG(WARNING) << "Error sending error signal to AddressWatchTask";
}
close(address_watch_params_.exit_pipe[1]);
+#elif defined(OS_MACOSX)
+ {
+ AutoLock auto_lock(address_watch_params_.run_loop_lock);
+ if (address_watch_params_.run_loop) {
+ CFRunLoopStop(address_watch_params_.run_loop);
+ }
+ }
#endif
address_watch_thread_.Stop();
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 59ce96c..63ec7c1 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -189,7 +189,8 @@ class SyncBackendHost {
const std::wstring& test_user,
sync_api::HttpPostProviderFactory* factory,
sync_api::HttpPostProviderFactory* auth_factory) {
- DoInitialize(GURL(), bookmark_model_worker, false, factory,
+ DoInitialize(GURL("http://www.example.com/example/path"),
+ bookmark_model_worker, false, factory,
auth_factory, std::string());
syncapi_->SetupForTestMode(test_user);
}