buffet: Add periodic pings to XMPP connection

In order to monitor XMPP connection, we are implementing support
for XMPP pings described in XEP-0199 extension to XMPP standard
(see: http://xmpp.org/extensions/xep-0199.html#c2s).

Now we send ping requests to XMPP server every 60 seconds and if
we receive no response, we assume the connection is broken and
initiate immediate re-connection.

BUG=brillo:1138
TEST=`FEATURES=test emerge-link buffet`

Change-Id: Id2c092a0454b360d2c18bef5e30e3461ceeddab8
Reviewed-on: https://chromium-review.googlesource.com/274060
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Trybot-Ready: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/notification/xmpp_channel.cc b/buffet/notification/xmpp_channel.cc
index ab657d1..9bf9463 100644
--- a/buffet/notification/xmpp_channel.cc
+++ b/buffet/notification/xmpp_channel.cc
@@ -75,6 +75,7 @@
 
 const char kDefaultXmppHost[] = "talk.google.com";
 const uint16_t kDefaultXmppPort = 5222;
+const uint64_t kPingIntervalSeconds = 60;  // 1 minute.
 
 }  // namespace
 
@@ -88,6 +89,7 @@
       task_runner_{task_runner},
       iq_stanza_handler_{new IqStanzaHandler{this, task_runner}} {
   read_socket_data_.resize(4096);
+  ping_timer_.SetTaskRunner(task_runner);
 }
 
 void XmppChannel::OnMessageRead(size_t size) {
@@ -417,6 +419,8 @@
     delegate_->OnDisconnected();
 
   weak_ptr_factory_.InvalidateWeakPtrs();
+  StopPingTimer();
+
   if (tls_stream_) {
     tls_stream_->CloseBlocking(nullptr);
     tls_stream_.reset();
@@ -432,6 +436,7 @@
 void XmppChannel::OnConnected() {
   state_ = XmppState::kStarted;
   RestartXmppStream();
+  StartPingTimer();
 }
 
 void XmppChannel::RestartXmppStream() {
@@ -442,4 +447,34 @@
   SendMessage(BuildXmppStartStreamCommand());
 }
 
+void XmppChannel::StartPingTimer() {
+  ping_timer_.Start(FROM_HERE,
+                    base::TimeDelta::FromSeconds(kPingIntervalSeconds),
+                    base::Bind(&XmppChannel::PingServer,
+                               weak_ptr_factory_.GetWeakPtr()));
+}
+
+void XmppChannel::StopPingTimer() {
+  ping_timer_.Stop();
+}
+
+void XmppChannel::PingServer() {
+  // Send an XMPP Ping request as defined in XEP-0199 extension:
+  // http://xmpp.org/extensions/xep-0199.html
+  iq_stanza_handler_->SendRequest(
+      "get", jid_, account_, "<ping xmlns='urn:xmpp:ping'/>",
+      base::Bind(&XmppChannel::OnPingResponse, weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&XmppChannel::OnPingTimeout, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void XmppChannel::OnPingResponse(std::unique_ptr<XmlNode> reply) {
+  // Ping response received from server. Everything seems to be in order.
+  // Nothing else to do.
+}
+
+void XmppChannel::OnPingTimeout() {
+  LOG(WARNING) << "XMPP channel seems to be disconnected - ping timed out";
+  Restart();
+}
+
 }  // namespace buffet