summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-26 19:59:41 +0000
committergene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-26 19:59:41 +0000
commit05861d65af900b604d9e99e4eebb61deb45de1cd (patch)
tree172427792ac96feea1189b762287b0af74b7cea9
parentfc992beca7a034a8e6437faf73377d375ac2e44a (diff)
downloadchromium_src-05861d65af900b604d9e99e4eebb61deb45de1cd.zip
chromium_src-05861d65af900b604d9e99e4eebb61deb45de1cd.tar.gz
chromium_src-05861d65af900b604d9e99e4eebb61deb45de1cd.tar.bz2
Adding XMPP ping functionality to CloudPrint. XMPP ping and timeout is controlled thorugh Service State file.
BUG=157735 Review URL: https://chromiumcodereview.appspot.com/11232048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@164385 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/pref_names.cc4
-rw-r--r--chrome/common/pref_names.h2
-rw-r--r--chrome/service/cloud_print/cloud_print_consts.h9
-rw-r--r--chrome/service/cloud_print/cloud_print_proxy_backend.cc77
-rw-r--r--chrome/service/cloud_print/connector_settings.cc21
-rw-r--r--chrome/service/cloud_print/connector_settings.h20
-rw-r--r--chrome/service/cloud_print/connector_settings_unittest.cc25
-rw-r--r--chrome/service/service_process_prefs.cc15
-rw-r--r--chrome/service/service_process_prefs.h6
-rw-r--r--jingle/jingle.gyp3
-rw-r--r--jingle/notifier/listener/fake_push_client.cc10
-rw-r--r--jingle/notifier/listener/fake_push_client.h3
-rw-r--r--jingle/notifier/listener/non_blocking_push_client.cc28
-rw-r--r--jingle/notifier/listener/non_blocking_push_client.h2
-rw-r--r--jingle/notifier/listener/non_blocking_push_client_unittest.cc8
-rw-r--r--jingle/notifier/listener/push_client.h3
-rw-r--r--jingle/notifier/listener/push_client_observer.cc2
-rw-r--r--jingle/notifier/listener/push_client_observer.h4
-rw-r--r--jingle/notifier/listener/push_notifications_listen_task.cc3
-rw-r--r--jingle/notifier/listener/push_notifications_listen_task.h2
-rw-r--r--jingle/notifier/listener/push_notifications_send_update_task.cc8
-rw-r--r--jingle/notifier/listener/send_ping_task.cc80
-rw-r--r--jingle/notifier/listener/send_ping_task.h54
-rw-r--r--jingle/notifier/listener/send_ping_task_unittest.cc41
-rw-r--r--jingle/notifier/listener/xmpp_push_client.cc17
-rw-r--r--jingle/notifier/listener/xmpp_push_client.h8
-rw-r--r--jingle/notifier/listener/xmpp_push_client_unittest.cc12
27 files changed, 458 insertions, 9 deletions
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index eabe1ad..5cab24f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1934,6 +1934,10 @@ const char kCloudPrintRobotRefreshToken[] = "cloud_print.robot_refresh_token";
const char kCloudPrintRobotEmail[] = "cloud_print.robot_email";
// A boolean indicating whether we should connect to cloud print new printers.
const char kCloudPrintConnectNewPrinters[] = "cloud_print.connect_new_printers";
+// A boolean indicating whether we should ping XMPP connection.
+const char kCloudPrintXmppPingEnabled[] = "cloud_print.xmpp_ping_enabled";
+// An int value indicating the average timeout between xmpp pings.
+const char kCloudPrintXmppPingTimeout[] = "cloud_print.xmpp_ping_timeout_sec";
// List of printers which should not be connected.
const char kCloudPrintPrinterBlacklist[] = "cloud_print.printer_blacklist";
// A boolean indicating whether submitting jobs to Google Cloud Print is
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 0b44d49..4813b30 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -640,6 +640,8 @@ extern const char kCloudPrintEnableJobPoll[];
extern const char kCloudPrintRobotRefreshToken[];
extern const char kCloudPrintRobotEmail[];
extern const char kCloudPrintConnectNewPrinters[];
+extern const char kCloudPrintXmppPingEnabled[];
+extern const char kCloudPrintXmppPingTimeout[];
extern const char kCloudPrintPrinterBlacklist[];
extern const char kCloudPrintSubmitEnabled[];
diff --git a/chrome/service/cloud_print/cloud_print_consts.h b/chrome/service/cloud_print/cloud_print_consts.h
index 2d9254e..b5fb24c 100644
--- a/chrome/service/cloud_print/cloud_print_consts.h
+++ b/chrome/service/cloud_print/cloud_print_consts.h
@@ -64,6 +64,15 @@ const int kCloudPrintAuthMaxRetryCount = -1;
const int kMinJobPollIntervalSecs = 5*60; // 5 minutes in seconds
const int kMaxJobPollIntervalSecs = 8*60; // 8 minutes in seconds
+// When we have XMPP notifications available, we ping server to keep connection
+// alive or check connection status.
+const int kDefaultXmppPingTimeoutSecs = 5*60; // 5 minutes in seconds
+const int kMinimumXmppPingTimeoutSecs = 2*60; // 2 minutes in seconds
+const int kXmppPingCheckIntervalSecs = 60;
+
+// Number of failed pings before we try to reinstablish XMPP connection.
+const int kMaxFailedXmppPings = 2;
+
// The number of seconds before the OAuth2 access token is due to expire that
// we try and refresh it.
const int kTokenRefreshGracePeriodSecs = 5*60; // 5 minutes in seconds
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
index 16d7211..44df7b6 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
@@ -8,10 +8,12 @@
#include <vector>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/rand_util.h"
#include "base/values.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/service/cloud_print/cloud_print_auth.h"
#include "chrome/service/cloud_print/cloud_print_connector.h"
#include "chrome/service/cloud_print/cloud_print_consts.h"
@@ -88,6 +90,7 @@ class CloudPrintProxyBackend::Core
notifier::NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const notifier::Notification& notification) OVERRIDE;
+ virtual void OnPingResponse() OVERRIDE;
private:
friend class base::RefCountedThreadSafe<Core>;
@@ -119,6 +122,10 @@ class CloudPrintProxyBackend::Core
// Schedules a task to poll for jobs. Does nothing if a task is already
// scheduled.
void ScheduleJobPoll();
+ void PingXmppServer();
+ void ScheduleXmppPing();
+ void CheckXmppPingStatus();
+
CloudPrintTokenStore* GetTokenStore();
// Our parent CloudPrintProxyBackend
@@ -143,8 +150,13 @@ class CloudPrintProxyBackend::Core
bool job_poll_scheduled_;
// Indicates whether we should poll for jobs when we lose XMPP connection.
bool enable_job_poll_;
+ // Indicates whether a task to ping xmpp server has been scheduled.
+ bool xmpp_ping_scheduled_;
+ // Number of XMPP pings pending reply from the server.
+ int pending_xmpp_pings_;
// Connector settings.
ConnectorSettings settings_;
+ std::string robot_email_;
scoped_ptr<CloudPrintTokenStore> token_store_;
DISALLOW_COPY_AND_ASSIGN(Core);
@@ -240,7 +252,9 @@ CloudPrintProxyBackend::Core::Core(
oauth_client_info_(oauth_client_info),
notifications_enabled_(false),
job_poll_scheduled_(false),
- enable_job_poll_(enable_job_poll) {
+ enable_job_poll_(enable_job_poll),
+ xmpp_ping_scheduled_(false),
+ pending_xmpp_pings_(0) {
settings_.CopyFrom(settings);
}
@@ -305,6 +319,7 @@ void CloudPrintProxyBackend::Core::OnAuthenticationComplete(
CloudPrintTokenStore* token_store = GetTokenStore();
bool first_time = token_store->token().empty();
token_store->SetToken(access_token);
+ robot_email_ = robot_email;
// Let the frontend know that we have authenticated.
backend_->frontend_loop_->PostTask(
FROM_HERE,
@@ -350,6 +365,7 @@ void CloudPrintProxyBackend::Core::InitNotifications(
const std::string& access_token) {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
+ pending_xmpp_pings_ = 0;
notifier::NotifierOptions notifier_options;
notifier_options.request_context_getter =
g_service_process->GetServiceURLRequestContextGetter();
@@ -430,6 +446,53 @@ void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
}
}
+void CloudPrintProxyBackend::Core::PingXmppServer() {
+ xmpp_ping_scheduled_ = false;
+
+ if (!push_client_.get())
+ return;
+
+ push_client_->SendPing();
+
+ pending_xmpp_pings_++;
+ if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
+ // Check ping status when we close to the limit.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CloudPrintProxyBackend::Core::CheckXmppPingStatus, this),
+ base::TimeDelta::FromSeconds(kXmppPingCheckIntervalSecs));
+ }
+
+ // Schedule next ping if needed.
+ if (notifications_enabled_)
+ ScheduleXmppPing();
+}
+
+void CloudPrintProxyBackend::Core::ScheduleXmppPing() {
+ if (!settings_.xmpp_ping_enabled())
+ return;
+
+ if (!xmpp_ping_scheduled_) {
+ base::TimeDelta interval = base::TimeDelta::FromSeconds(
+ base::RandInt(settings_.xmpp_ping_timeout_sec() * 0.9,
+ settings_.xmpp_ping_timeout_sec() * 1.1));
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CloudPrintProxyBackend::Core::PingXmppServer, this),
+ interval);
+ xmpp_ping_scheduled_ = true;
+ }
+}
+
+void CloudPrintProxyBackend::Core::CheckXmppPingStatus() {
+ if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
+ // Reconnect to XMPP.
+ pending_xmpp_pings_ = 0;
+ push_client_.reset();
+ InitNotifications(robot_email_, GetTokenStore()->token());
+ }
+}
+
CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() {
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
if (!token_store_.get())
@@ -476,6 +539,9 @@ void CloudPrintProxyBackend::Core::OnNotificationsEnabled() {
// Note that ScheduleJobPoll will not schedule again if a job poll task is
// already scheduled.
ScheduleJobPoll();
+
+ // Schedule periodic ping for XMPP notification channel.
+ ScheduleXmppPing();
}
void CloudPrintProxyBackend::Core::OnNotificationsDisabled(
@@ -494,6 +560,10 @@ void CloudPrintProxyBackend::Core::OnNotificationsDisabled(
void CloudPrintProxyBackend::Core::OnIncomingNotification(
const notifier::Notification& notification) {
+ // Since we got some notification from the server,
+ // reset pending ping counter to 0.
+ pending_xmpp_pings_ = 0;
+
DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop());
VLOG(1) << "CP_CONNECTOR: Incoming notification.";
if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource,
@@ -501,3 +571,8 @@ void CloudPrintProxyBackend::Core::OnIncomingNotification(
HandlePrinterNotification(notification.data);
}
+void CloudPrintProxyBackend::Core::OnPingResponse() {
+ pending_xmpp_pings_ = 0;
+ VLOG(1) << "CP_CONNECTOR: Ping response received.";
+}
+
diff --git a/chrome/service/cloud_print/connector_settings.cc b/chrome/service/cloud_print/connector_settings.cc
index 0976c42..ccfc6e1 100644
--- a/chrome/service/cloud_print/connector_settings.cc
+++ b/chrome/service/cloud_print/connector_settings.cc
@@ -19,7 +19,9 @@ const char kDeleteOnEnumFail[] = "delete_on_enum_fail";
ConnectorSettings::ConnectorSettings()
: delete_on_enum_fail_(false),
- connect_new_printers_(true) {
+ connect_new_printers_(true),
+ xmpp_ping_enabled_(false),
+ xmpp_ping_timeout_sec_(kDefaultXmppPingTimeoutSecs) {
}
ConnectorSettings::~ConnectorSettings() {
@@ -56,6 +58,13 @@ void ConnectorSettings::InitFrom(ServiceProcessPrefs* prefs) {
connect_new_printers_ = prefs->GetBoolean(
prefs::kCloudPrintConnectNewPrinters, true);
+
+ xmpp_ping_enabled_ = prefs->GetBoolean(
+ prefs::kCloudPrintXmppPingEnabled, false);
+ int timeout = prefs->GetInt(
+ prefs::kCloudPrintXmppPingTimeout, kDefaultXmppPingTimeoutSecs);
+ SetXmppPingTimeoutSec(timeout);
+
const base::ListValue* printers = prefs->GetList(
prefs::kCloudPrintPrinterBlacklist);
if (printers) {
@@ -76,8 +85,18 @@ void ConnectorSettings::CopyFrom(const ConnectorSettings& source) {
proxy_id_ = source.proxy_id();
delete_on_enum_fail_ = source.delete_on_enum_fail();
connect_new_printers_ = source.connect_new_printers();
+ xmpp_ping_enabled_ = source.xmpp_ping_enabled();
+ xmpp_ping_timeout_sec_ = source.xmpp_ping_timeout_sec();
printer_blacklist_ = source.printer_blacklist_;
if (source.print_system_settings())
print_system_settings_.reset(source.print_system_settings()->DeepCopy());
}
+void ConnectorSettings::SetXmppPingTimeoutSec(int timeout) {
+ xmpp_ping_timeout_sec_ = timeout;
+ if (xmpp_ping_timeout_sec_ < kMinimumXmppPingTimeoutSecs) {
+ LOG(WARNING) <<
+ "CP_CONNECTOR: XMPP ping timeout is less then minimal value";
+ xmpp_ping_timeout_sec_ = kMinimumXmppPingTimeoutSecs;
+ }
+}
diff --git a/chrome/service/cloud_print/connector_settings.h b/chrome/service/cloud_print/connector_settings.h
index 9750727..4c9b086 100644
--- a/chrome/service/cloud_print/connector_settings.h
+++ b/chrome/service/cloud_print/connector_settings.h
@@ -42,12 +42,26 @@ class ConnectorSettings {
return connect_new_printers_;
};
+ bool xmpp_ping_enabled() const {
+ return xmpp_ping_enabled_;
+ }
+
+ void set_xmpp_ping_enabled(bool enabled) {
+ xmpp_ping_enabled_ = enabled;
+ }
+
+ int xmpp_ping_timeout_sec() const {
+ return xmpp_ping_timeout_sec_;
+ }
+
const base::DictionaryValue* print_system_settings() const {
return print_system_settings_.get();
};
bool IsPrinterBlacklisted(const std::string& name) const;
+ void SetXmppPingTimeoutSec(int timeout);
+
private:
// Cloud Print server url.
GURL server_url_;
@@ -63,6 +77,12 @@ class ConnectorSettings {
// If true register all new printers in cloud print.
bool connect_new_printers_;
+ // Indicate if XMPP pings are enabled.
+ bool xmpp_ping_enabled_;
+
+ // Indicate timeout between XMPP pings.
+ int xmpp_ping_timeout_sec_;
+
// List of printers which should not be connected.
std::set<std::string> printer_blacklist_;
diff --git a/chrome/service/cloud_print/connector_settings_unittest.cc b/chrome/service/cloud_print/connector_settings_unittest.cc
index 6aaa6c4..09ceeef 100644
--- a/chrome/service/cloud_print/connector_settings_unittest.cc
+++ b/chrome/service/cloud_print/connector_settings_unittest.cc
@@ -11,6 +11,7 @@
#include "base/message_loop_proxy.h"
#include "base/scoped_temp_dir.h"
#include "base/values.h"
+#include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/service/service_process_prefs.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -28,6 +29,8 @@ const char kServiceStateContent[] =
" 'service_url': 'http://cp.google.com',"
" 'xmpp_auth_token': 'xmp token',"
" 'connect_new_printers': false,"
+ " 'xmpp_ping_enabled': true,"
+ " 'xmpp_ping_timeout_sec': 256,"
" 'printer_blacklist': ["
" 'prn1',"
" 'prn2'"
@@ -83,6 +86,7 @@ TEST_F(ConnectorSettingsTest, InitFromEmpty) {
EXPECT_FALSE(settings.delete_on_enum_fail());
EXPECT_EQ(NULL, settings.print_system_settings());
EXPECT_TRUE(settings.connect_new_printers());
+ EXPECT_FALSE(settings.xmpp_ping_enabled());
EXPECT_FALSE(settings.IsPrinterBlacklisted("prn1"));
}
}
@@ -97,6 +101,8 @@ TEST_F(ConnectorSettingsTest, InitFromFile) {
EXPECT_TRUE(settings.delete_on_enum_fail());
EXPECT_TRUE(settings.print_system_settings());
EXPECT_FALSE(settings.connect_new_printers());
+ EXPECT_TRUE(settings.xmpp_ping_enabled());
+ EXPECT_EQ(settings.xmpp_ping_timeout_sec(), 256);
EXPECT_FALSE(settings.IsPrinterBlacklisted("prn0"));
EXPECT_TRUE(settings.IsPrinterBlacklisted("prn1"));
}
@@ -115,6 +121,25 @@ TEST_F(ConnectorSettingsTest, CopyFrom) {
EXPECT_EQ(settings1.print_system_settings()->size(),
settings2.print_system_settings()->size());
EXPECT_EQ(settings1.connect_new_printers(), settings2.connect_new_printers());
+ EXPECT_EQ(settings1.xmpp_ping_enabled(), settings2.xmpp_ping_enabled());
+ EXPECT_EQ(settings1.xmpp_ping_timeout_sec(),
+ settings2.xmpp_ping_timeout_sec());
EXPECT_TRUE(settings2.IsPrinterBlacklisted("prn1"));
}
+TEST_F(ConnectorSettingsTest, SettersTest) {
+ scoped_ptr<ServiceProcessPrefs> prefs(CreateTestFile("{}"));
+ ConnectorSettings settings;
+ settings.InitFrom(prefs.get());
+ EXPECT_FALSE(settings.xmpp_ping_enabled());
+
+ // Set and check valid settings.
+ settings.set_xmpp_ping_enabled(true);
+ settings.SetXmppPingTimeoutSec(256);
+ EXPECT_TRUE(settings.xmpp_ping_enabled());
+ EXPECT_EQ(settings.xmpp_ping_timeout_sec(), 256);
+
+ // Set invalid settings, and check correct defaults.
+ settings.SetXmppPingTimeoutSec(1);
+ EXPECT_EQ(settings.xmpp_ping_timeout_sec(), kMinimumXmppPingTimeoutSecs);
+}
diff --git a/chrome/service/service_process_prefs.cc b/chrome/service/service_process_prefs.cc
index 7de70a4..811647d 100644
--- a/chrome/service/service_process_prefs.cc
+++ b/chrome/service/service_process_prefs.cc
@@ -54,6 +54,21 @@ void ServiceProcessPrefs::SetBoolean(const std::string& key, bool value) {
prefs_->SetValue(key, Value::CreateBooleanValue(value));
}
+int ServiceProcessPrefs::GetInt(const std::string& key,
+ int default_value) const {
+ const Value* value;
+ int result = default_value;
+ if (prefs_->GetValue(key, &value) != PersistentPrefStore::READ_OK ||
+ !value->GetAsInteger(&result)) {
+ return default_value;
+ }
+ return result;
+}
+
+void ServiceProcessPrefs::SetInt(const std::string& key, int value) {
+ prefs_->SetValue(key, Value::CreateIntegerValue(value));
+}
+
const DictionaryValue* ServiceProcessPrefs::GetDictionary(
const std::string& key) const {
const Value* value;
diff --git a/chrome/service/service_process_prefs.h b/chrome/service/service_process_prefs.h
index 2bc3e5fe..018ce1d 100644
--- a/chrome/service/service_process_prefs.h
+++ b/chrome/service/service_process_prefs.h
@@ -43,6 +43,12 @@ class ServiceProcessPrefs {
// Set a boolean |value| for |key|.
void SetBoolean(const std::string& key, bool value);
+ // Returns an int preference for |key|.
+ int GetInt(const std::string& key, int default_value) const;
+
+ // Set an int |value| for |key|.
+ void SetInt(const std::string& key, int value);
+
// Returns a dictionary preference for |key|.
const base::DictionaryValue* GetDictionary(const std::string& key) const;
diff --git a/jingle/jingle.gyp b/jingle/jingle.gyp
index b1270b6..95a99ae 100644
--- a/jingle/jingle.gyp
+++ b/jingle/jingle.gyp
@@ -95,6 +95,8 @@
'notifier/listener/push_notifications_send_update_task.h',
'notifier/listener/push_notifications_subscribe_task.cc',
'notifier/listener/push_notifications_subscribe_task.h',
+ 'notifier/listener/send_ping_task.cc',
+ 'notifier/listener/send_ping_task.h',
'notifier/listener/xml_element_util.cc',
'notifier/listener/xml_element_util.h',
'notifier/listener/xmpp_push_client.cc',
@@ -179,6 +181,7 @@
'notifier/listener/push_client_unittest.cc',
'notifier/listener/push_notifications_send_update_task_unittest.cc',
'notifier/listener/push_notifications_subscribe_task_unittest.cc',
+ 'notifier/listener/send_ping_task_unittest.cc',
'notifier/listener/xml_element_util_unittest.cc',
'notifier/listener/xmpp_push_client_unittest.cc',
'run_all_unittests.cc',
diff --git a/jingle/notifier/listener/fake_push_client.cc b/jingle/notifier/listener/fake_push_client.cc
index 0565c3c..1106c93 100644
--- a/jingle/notifier/listener/fake_push_client.cc
+++ b/jingle/notifier/listener/fake_push_client.cc
@@ -8,7 +8,7 @@
namespace notifier {
-FakePushClient::FakePushClient() {}
+FakePushClient::FakePushClient() : sent_pings_(0) {}
FakePushClient::~FakePushClient() {}
@@ -35,6 +35,10 @@ void FakePushClient::SendNotification(const Notification& notification) {
sent_notifications_.push_back(notification);
}
+void FakePushClient::SendPing() {
+ sent_pings_++;
+}
+
void FakePushClient::EnableNotifications() {
FOR_EACH_OBSERVER(PushClientObserver, observers_,
OnNotificationsEnabled());
@@ -68,5 +72,9 @@ const std::vector<Notification>& FakePushClient::sent_notifications() const {
return sent_notifications_;
}
+int FakePushClient::sent_pings() const {
+ return sent_pings_;
+}
+
} // namespace notifier
diff --git a/jingle/notifier/listener/fake_push_client.h b/jingle/notifier/listener/fake_push_client.h
index 90e086c..2c1340d 100644
--- a/jingle/notifier/listener/fake_push_client.h
+++ b/jingle/notifier/listener/fake_push_client.h
@@ -29,6 +29,7 @@ class FakePushClient : public PushClient {
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
virtual void SendNotification(const Notification& notification) OVERRIDE;
+ virtual void SendPing() OVERRIDE;
// Triggers OnNotificationsEnabled on all observers.
void EnableNotifications();
@@ -43,6 +44,7 @@ class FakePushClient : public PushClient {
const std::string& email() const;
const std::string& token() const;
const std::vector<Notification>& sent_notifications() const;
+ int sent_pings() const;
private:
ObserverList<PushClientObserver> observers_;
@@ -50,6 +52,7 @@ class FakePushClient : public PushClient {
std::string email_;
std::string token_;
std::vector<Notification> sent_notifications_;
+ int sent_pings_;
DISALLOW_COPY_AND_ASSIGN(FakePushClient);
};
diff --git a/jingle/notifier/listener/non_blocking_push_client.cc b/jingle/notifier/listener/non_blocking_push_client.cc
index 5765d37..c42561e 100644
--- a/jingle/notifier/listener/non_blocking_push_client.cc
+++ b/jingle/notifier/listener/non_blocking_push_client.cc
@@ -38,12 +38,14 @@ class NonBlockingPushClient::Core
void UpdateSubscriptions(const SubscriptionList& subscriptions);
void UpdateCredentials(const std::string& email, const std::string& token);
void SendNotification(const Notification& data);
+ void SendPing();
virtual void OnNotificationsEnabled() OVERRIDE;
virtual void OnNotificationsDisabled(
NotificationsDisabledReason reason) OVERRIDE;
virtual void OnIncomingNotification(
const Notification& notification) OVERRIDE;
+ virtual void OnPingResponse() OVERRIDE;
private:
friend class base::RefCountedThreadSafe<NonBlockingPushClient::Core>;
@@ -110,6 +112,12 @@ void NonBlockingPushClient::Core::SendNotification(
delegate_push_client_->SendNotification(notification);
}
+void NonBlockingPushClient::Core::SendPing() {
+ DCHECK(delegate_task_runner_->BelongsToCurrentThread());
+ DCHECK(delegate_push_client_.get());
+ delegate_push_client_->SendPing();
+}
+
void NonBlockingPushClient::Core::OnNotificationsEnabled() {
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
parent_task_runner_->PostTask(
@@ -136,6 +144,14 @@ void NonBlockingPushClient::Core::OnIncomingNotification(
parent_push_client_, notification));
}
+void NonBlockingPushClient::Core::OnPingResponse() {
+ DCHECK(delegate_task_runner_->BelongsToCurrentThread());
+ parent_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&NonBlockingPushClient::OnPingResponse,
+ parent_push_client_));
+}
+
NonBlockingPushClient::NonBlockingPushClient(
const scoped_refptr<base::SingleThreadTaskRunner>& delegate_task_runner,
const CreateBlockingPushClientCallback&
@@ -195,6 +211,13 @@ void NonBlockingPushClient::SendNotification(
notification));
}
+void NonBlockingPushClient::SendPing() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ delegate_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&NonBlockingPushClient::Core::SendPing, core_.get()));
+}
+
void NonBlockingPushClient::OnNotificationsEnabled() {
DCHECK(thread_checker_.CalledOnValidThread());
FOR_EACH_OBSERVER(PushClientObserver, observers_,
@@ -215,4 +238,9 @@ void NonBlockingPushClient::OnIncomingNotification(
OnIncomingNotification(notification));
}
+void NonBlockingPushClient::OnPingResponse() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse());
+}
+
} // namespace notifier
diff --git a/jingle/notifier/listener/non_blocking_push_client.h b/jingle/notifier/listener/non_blocking_push_client.h
index 434f5f4..f5c6bc4 100644
--- a/jingle/notifier/listener/non_blocking_push_client.h
+++ b/jingle/notifier/listener/non_blocking_push_client.h
@@ -49,6 +49,7 @@ class NonBlockingPushClient : public PushClient {
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
virtual void SendNotification(const Notification& notification) OVERRIDE;
+ virtual void SendPing() OVERRIDE;
private:
class Core;
@@ -56,6 +57,7 @@ class NonBlockingPushClient : public PushClient {
void OnNotificationsEnabled();
void OnNotificationsDisabled(NotificationsDisabledReason reason);
void OnIncomingNotification(const Notification& notification);
+ void OnPingResponse();
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<NonBlockingPushClient> weak_ptr_factory_;
diff --git a/jingle/notifier/listener/non_blocking_push_client_unittest.cc b/jingle/notifier/listener/non_blocking_push_client_unittest.cc
index f9e0282..8908910 100644
--- a/jingle/notifier/listener/non_blocking_push_client_unittest.cc
+++ b/jingle/notifier/listener/non_blocking_push_client_unittest.cc
@@ -112,6 +112,14 @@ TEST_F(NonBlockingPushClientTest, SendNotification) {
fake_push_client_->sent_notifications()[0].Equals(notification));
}
+// Make sure SendPing() gets delegated properly.
+TEST_F(NonBlockingPushClientTest, SendPing) {
+ push_client_->SendPing();
+ EXPECT_EQ(0, fake_push_client_->sent_pings());
+ message_loop_.RunAllPending();
+ ASSERT_EQ(1, fake_push_client_->sent_pings());
+}
+
// Make sure notification state changes get propagated back to the
// parent.
TEST_F(NonBlockingPushClientTest, NotificationStateChange) {
diff --git a/jingle/notifier/listener/push_client.h b/jingle/notifier/listener/push_client.h
index f80f422..fd67337 100644
--- a/jingle/notifier/listener/push_client.h
+++ b/jingle/notifier/listener/push_client.h
@@ -50,6 +50,9 @@ class PushClient {
// Sends a notification (with no reliability guarantees).
virtual void SendNotification(const Notification& notification) = 0;
+
+ // Sends a ping (with no reliability guarantees).
+ virtual void SendPing() = 0;
};
} // namespace notifier
diff --git a/jingle/notifier/listener/push_client_observer.cc b/jingle/notifier/listener/push_client_observer.cc
index 04a877b..a958eea 100644
--- a/jingle/notifier/listener/push_client_observer.cc
+++ b/jingle/notifier/listener/push_client_observer.cc
@@ -8,4 +8,6 @@ namespace notifier {
PushClientObserver::~PushClientObserver() {}
+void PushClientObserver::OnPingResponse() {}
+
} // namespace notifier
diff --git a/jingle/notifier/listener/push_client_observer.h b/jingle/notifier/listener/push_client_observer.h
index d51deb2..d153ff0 100644
--- a/jingle/notifier/listener/push_client_observer.h
+++ b/jingle/notifier/listener/push_client_observer.h
@@ -39,6 +39,10 @@ class PushClientObserver {
// Called when a notification is received. The details of the
// notification are in |notification|.
virtual void OnIncomingNotification(const Notification& notification) = 0;
+
+ // Called when a ping response is received. Default implementation does
+ // nothing.
+ virtual void OnPingResponse();
};
} // namespace notifier
diff --git a/jingle/notifier/listener/push_notifications_listen_task.cc b/jingle/notifier/listener/push_notifications_listen_task.cc
index ad1da9f..2e6b2ca 100644
--- a/jingle/notifier/listener/push_notifications_listen_task.cc
+++ b/jingle/notifier/listener/push_notifications_listen_task.cc
@@ -18,6 +18,9 @@
namespace notifier {
+PushNotificationsListenTask::Delegate::~Delegate() {
+}
+
PushNotificationsListenTask::PushNotificationsListenTask(
buzz::XmppTaskParentInterface* parent, Delegate* delegate)
: buzz::XmppTask(parent, buzz::XmppEngine::HL_TYPE),
diff --git a/jingle/notifier/listener/push_notifications_listen_task.h b/jingle/notifier/listener/push_notifications_listen_task.h
index daf48d9..62d408b 100644
--- a/jingle/notifier/listener/push_notifications_listen_task.h
+++ b/jingle/notifier/listener/push_notifications_listen_task.h
@@ -31,7 +31,7 @@ class PushNotificationsListenTask : public buzz::XmppTask {
virtual void OnNotificationReceived(const Notification& notification) = 0;
protected:
- virtual ~Delegate() {}
+ virtual ~Delegate();
};
PushNotificationsListenTask(buzz::XmppTaskParentInterface* parent,
diff --git a/jingle/notifier/listener/push_notifications_send_update_task.cc b/jingle/notifier/listener/push_notifications_send_update_task.cc
index 50ec15e..4e0c127 100644
--- a/jingle/notifier/listener/push_notifications_send_update_task.cc
+++ b/jingle/notifier/listener/push_notifications_send_update_task.cc
@@ -32,7 +32,7 @@ int PushNotificationsSendUpdateTask::ProcessStart() {
DVLOG(1) << "Sending notification " << notification_.ToString()
<< " as stanza " << XmlElementToString(*stanza);
if (SendStanza(stanza.get()) != buzz::XMPP_RETURN_OK) {
- LOG(WARNING) << "Could not send stanza " << XmlElementToString(*stanza);
+ DLOG(WARNING) << "Could not send stanza " << XmlElementToString(*stanza);
}
return STATE_DONE;
}
@@ -72,8 +72,8 @@ buzz::XmlElement* PushNotificationsSendUpdateTask::MakeUpdateMessage(
if (!recipient.user_specific_data.empty()) {
std::string base64_data;
if (!base::Base64Encode(recipient.user_specific_data, &base64_data)) {
- LOG(WARNING) << "Could not encode data "
- << recipient.user_specific_data;
+ DLOG(WARNING) << "Could not encode data "
+ << recipient.user_specific_data;
} else {
recipient_element->SetBodyText(base64_data);
}
@@ -83,7 +83,7 @@ buzz::XmlElement* PushNotificationsSendUpdateTask::MakeUpdateMessage(
buzz::XmlElement* data = new buzz::XmlElement(kQnData, true);
std::string base64_data;
if (!base::Base64Encode(notification.data, &base64_data)) {
- LOG(WARNING) << "Could not encode data " << notification.data;
+ DLOG(WARNING) << "Could not encode data " << notification.data;
}
data->SetBodyText(base64_data);
push->AddElement(data);
diff --git a/jingle/notifier/listener/send_ping_task.cc b/jingle/notifier/listener/send_ping_task.cc
new file mode 100644
index 0000000..90b7196
--- /dev/null
+++ b/jingle/notifier/listener/send_ping_task.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "jingle/notifier/listener/send_ping_task.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "jingle/notifier/listener/xml_element_util.h"
+#include "talk/xmllite/qname.h"
+#include "talk/xmllite/xmlelement.h"
+#include "talk/xmpp/constants.h"
+#include "talk/xmpp/jid.h"
+#include "talk/xmpp/xmppclient.h"
+
+namespace notifier {
+
+SendPingTask::Delegate::~Delegate() {
+}
+
+SendPingTask::SendPingTask(buzz::XmppTaskParentInterface* parent,
+ Delegate* delegate)
+ : XmppTask(parent, buzz::XmppEngine::HL_SINGLE), delegate_(delegate) {
+}
+
+SendPingTask::~SendPingTask() {
+}
+
+int SendPingTask::ProcessStart() {
+ ping_task_id_ = task_id();
+ scoped_ptr<buzz::XmlElement> stanza(MakePingStanza(ping_task_id_));
+ DVLOG(1) << "Sending ping stanza " << XmlElementToString(*stanza);
+ if (SendStanza(stanza.get()) != buzz::XMPP_RETURN_OK) {
+ DLOG(WARNING) << "Could not send stanza " << XmlElementToString(*stanza);
+ return STATE_ERROR;
+ }
+ return STATE_RESPONSE;
+}
+
+int SendPingTask::ProcessResponse() {
+ const buzz::XmlElement* stanza = NextStanza();
+ if (stanza == NULL) {
+ return STATE_BLOCKED;
+ }
+
+ DVLOG(1) << "Received stanza " << XmlElementToString(*stanza);
+
+ std::string type = stanza->Attr(buzz::QN_TYPE);
+ if (type != buzz::STR_RESULT) {
+ DLOG(WARNING) << "No type=\"result\" attribute found in stanza "
+ << XmlElementToString(*stanza);
+ return STATE_ERROR;
+ }
+
+ delegate_->OnPingResponseReceived();
+ return STATE_DONE;
+}
+
+bool SendPingTask::HandleStanza(const buzz::XmlElement* stanza) {
+ // MatchResponseIq() matches the given Jid with the "from" field of the given
+ // stanza, which in this case should be the empty string
+ // (signifying the server).
+ if (MatchResponseIq(stanza, buzz::Jid(buzz::STR_EMPTY), ping_task_id_)) {
+ QueueStanza(stanza);
+ return true;
+ }
+ return false;
+}
+
+buzz::XmlElement* SendPingTask::MakePingStanza(const std::string& task_id) {
+ buzz::XmlElement* stanza = MakeIq(buzz::STR_GET,
+ buzz::Jid(buzz::STR_EMPTY),
+ task_id);
+ stanza->AddElement(new buzz::XmlElement(buzz::QN_PING));
+ return stanza;
+}
+
+} // namespace notifier
diff --git a/jingle/notifier/listener/send_ping_task.h b/jingle/notifier/listener/send_ping_task.h
new file mode 100644
index 0000000..9cd8b22
--- /dev/null
+++ b/jingle/notifier/listener/send_ping_task.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Methods for sending the update stanza to notify peers via xmpp.
+
+#ifndef JINGLE_NOTIFIER_LISTENER_SEND_PING_TASK_H_
+#define JINGLE_NOTIFIER_LISTENER_SEND_PING_TASK_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "talk/xmpp/xmpptask.h"
+
+namespace buzz {
+class XmlElement;
+} // namespace
+
+namespace notifier {
+
+class SendPingTask : public buzz::XmppTask {
+ public:
+ class Delegate {
+ public:
+ virtual void OnPingResponseReceived() = 0;
+
+ protected:
+ virtual ~Delegate();
+ };
+
+ SendPingTask(buzz::XmppTaskParentInterface* parent, Delegate* delegate);
+ virtual ~SendPingTask();
+
+ // Overridden from buzz::XmppTask.
+ virtual int ProcessStart() OVERRIDE;
+ virtual int ProcessResponse() OVERRIDE;
+ virtual bool HandleStanza(const buzz::XmlElement* stanza) OVERRIDE;
+
+ private:
+ static buzz::XmlElement* MakePingStanza(const std::string& task_id);
+
+ FRIEND_TEST_ALL_PREFIXES(SendPingTaskTest, MakePingStanza);
+
+ std::string ping_task_id_;
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(SendPingTask);
+};
+
+typedef SendPingTask::Delegate SendPingTaskDelegate;
+
+} // namespace notifier
+
+#endif // JINGLE_NOTIFIER_LISTENER_SEND_PING_TASK_H_
diff --git a/jingle/notifier/listener/send_ping_task_unittest.cc b/jingle/notifier/listener/send_ping_task_unittest.cc
new file mode 100644
index 0000000..1a2dd4b
--- /dev/null
+++ b/jingle/notifier/listener/send_ping_task_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "jingle/notifier/listener/send_ping_task.h"
+
+#include "base/base64.h"
+#include "base/memory/scoped_ptr.h"
+#include "jingle/notifier/listener/xml_element_util.h"
+#include "talk/xmpp/jid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace buzz {
+class XmlElement;
+}
+
+namespace notifier {
+
+class SendPingTaskTest : public testing::Test {
+ public:
+ SendPingTaskTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SendPingTaskTest);
+};
+
+TEST_F(SendPingTaskTest, MakePingStanza) {
+ std::string task_id = "42";
+
+ scoped_ptr<buzz::XmlElement> message(SendPingTask::MakePingStanza(task_id));
+
+ std::string expected_xml_string("<cli:iq type=\"get\" id=\"");
+ expected_xml_string += task_id;
+ expected_xml_string +=
+ "\" xmlns:cli=\"jabber:client\">"
+ "<ping:ping xmlns:ping=\"urn:xmpp:ping\"/></cli:iq>";
+
+ EXPECT_EQ(expected_xml_string, XmlElementToString(*message));
+}
+
+} // namespace notifier
diff --git a/jingle/notifier/listener/xmpp_push_client.cc b/jingle/notifier/listener/xmpp_push_client.cc
index 9b4811e..76ee4ee 100644
--- a/jingle/notifier/listener/xmpp_push_client.cc
+++ b/jingle/notifier/listener/xmpp_push_client.cc
@@ -8,6 +8,7 @@
#include "base/message_loop_proxy.h"
#include "jingle/notifier/base/notifier_options_util.h"
#include "jingle/notifier/listener/push_client_observer.h"
+#include "jingle/notifier/listener/send_ping_task.h"
#include "jingle/notifier/listener/push_notifications_send_update_task.h"
namespace notifier {
@@ -80,6 +81,11 @@ void XmppPushClient::OnNotificationReceived(
OnIncomingNotification(notification));
}
+void XmppPushClient::OnPingResponseReceived() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FOR_EACH_OBSERVER(PushClientObserver, observers_, OnPingResponse());
+}
+
void XmppPushClient::OnSubscribed() {
DCHECK(thread_checker_.CalledOnValidThread());
FOR_EACH_OBSERVER(PushClientObserver, observers_,
@@ -143,4 +149,15 @@ void XmppPushClient::SendNotification(const Notification& notification) {
task->Start();
}
+void XmppPushClient::SendPing() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!base_task_.get()) {
+ DVLOG(1) << "Push: Cannot send ping";
+ return;
+ }
+ // Owned by |base_task_|.
+ SendPingTask* task = new SendPingTask(base_task_, this);
+ task->Start();
+}
+
} // namespace notifier
diff --git a/jingle/notifier/listener/xmpp_push_client.h b/jingle/notifier/listener/xmpp_push_client.h
index 64725d8..08a1811 100644
--- a/jingle/notifier/listener/xmpp_push_client.h
+++ b/jingle/notifier/listener/xmpp_push_client.h
@@ -21,6 +21,7 @@
#include "jingle/notifier/listener/push_client.h"
#include "jingle/notifier/listener/push_notifications_listen_task.h"
#include "jingle/notifier/listener/push_notifications_subscribe_task.h"
+#include "jingle/notifier/listener/send_ping_task.h"
#include "talk/xmpp/xmppclientsettings.h"
namespace buzz {
@@ -36,7 +37,8 @@ class XmppPushClient :
public PushClient,
public Login::Delegate,
public PushNotificationsListenTaskDelegate,
- public PushNotificationsSubscribeTaskDelegate {
+ public PushNotificationsSubscribeTaskDelegate,
+ public SendPingTaskDelegate {
public:
explicit XmppPushClient(const NotifierOptions& notifier_options);
virtual ~XmppPushClient();
@@ -49,6 +51,7 @@ class XmppPushClient :
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
virtual void SendNotification(const Notification& notification) OVERRIDE;
+ virtual void SendPing() OVERRIDE;
// Login::Delegate implementation.
virtual void OnConnect(
@@ -64,6 +67,9 @@ class XmppPushClient :
virtual void OnSubscribed() OVERRIDE;
virtual void OnSubscriptionError() OVERRIDE;
+ // SendPingTaskDelegate implementation.
+ virtual void OnPingResponseReceived() OVERRIDE;
+
private:
base::ThreadChecker thread_checker_;
const NotifierOptions notifier_options_;
diff --git a/jingle/notifier/listener/xmpp_push_client_unittest.cc b/jingle/notifier/listener/xmpp_push_client_unittest.cc
index 3487479..3beb488 100644
--- a/jingle/notifier/listener/xmpp_push_client_unittest.cc
+++ b/jingle/notifier/listener/xmpp_push_client_unittest.cc
@@ -27,6 +27,7 @@ class MockObserver : public PushClientObserver {
MOCK_METHOD0(OnNotificationsEnabled, void());
MOCK_METHOD1(OnNotificationsDisabled, void(NotificationsDisabledReason));
MOCK_METHOD1(OnIncomingNotification, void(const Notification&));
+ MOCK_METHOD0(OnPingResponse, void());
};
class XmppPushClientTest : public testing::Test {
@@ -110,6 +111,17 @@ TEST_F(XmppPushClientTest, SendNotification) {
xmpp_push_client_->SendNotification(Notification());
}
+// Make sure nothing blows up when the XMPP push client sends a ping.
+//
+// TODO(akalin): Figure out how to test that the ping was actually sent.
+TEST_F(XmppPushClientTest, SendPing) {
+ EXPECT_CALL(mock_observer_, OnNotificationsEnabled());
+
+ xmpp_push_client_->OnConnect(fake_base_task_.AsWeakPtr());
+ xmpp_push_client_->OnSubscribed();
+ xmpp_push_client_->SendPing();
+}
+
// Make sure nothing blows up when the XMPP push client sends a
// notification when disconnected, and the client connects.
//