1/*
2 *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/libjingle/xmpp/pingtask.h"
12
13#include "webrtc/libjingle/xmpp/constants.h"
14#include "webrtc/base/logging.h"
15#include "webrtc/base/scoped_ptr.h"
16
17namespace buzz {
18
19PingTask::PingTask(buzz::XmppTaskParentInterface* parent,
20                   rtc::MessageQueue* message_queue,
21                   uint32_t ping_period_millis,
22                   uint32_t ping_timeout_millis)
23    : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
24      message_queue_(message_queue),
25      ping_period_millis_(ping_period_millis),
26      ping_timeout_millis_(ping_timeout_millis),
27      next_ping_time_(0),
28      ping_response_deadline_(0) {
29  ASSERT(ping_period_millis >= ping_timeout_millis);
30}
31
32bool PingTask::HandleStanza(const buzz::XmlElement* stanza) {
33  if (!MatchResponseIq(stanza, Jid(STR_EMPTY), task_id())) {
34    return false;
35  }
36
37  if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT &&
38      stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) {
39    return false;
40  }
41
42  QueueStanza(stanza);
43  return true;
44}
45
46// This task runs indefinitely and remains in either the start or blocked
47// states.
48int PingTask::ProcessStart() {
49  if (ping_period_millis_ < ping_timeout_millis_) {
50    LOG(LS_ERROR) << "ping_period_millis should be >= ping_timeout_millis";
51    return STATE_ERROR;
52  }
53  const buzz::XmlElement* stanza = NextStanza();
54  if (stanza != NULL) {
55    // Received a ping response of some sort (don't care what it is).
56    ping_response_deadline_ = 0;
57  }
58
59  uint32_t now = rtc::Time();
60
61  // If the ping timed out, signal.
62  if (ping_response_deadline_ != 0 && now >= ping_response_deadline_) {
63    SignalTimeout();
64    return STATE_ERROR;
65  }
66
67  // Send a ping if it's time.
68  if (now >= next_ping_time_) {
69    rtc::scoped_ptr<buzz::XmlElement> stanza(
70        MakeIq(buzz::STR_GET, Jid(STR_EMPTY), task_id()));
71    stanza->AddElement(new buzz::XmlElement(QN_PING));
72    SendStanza(stanza.get());
73
74    ping_response_deadline_ = now + ping_timeout_millis_;
75    next_ping_time_ = now + ping_period_millis_;
76
77    // Wake ourselves up when it's time to send another ping or when the ping
78    // times out (so we can fire a signal).
79    message_queue_->PostDelayed(ping_timeout_millis_, this);
80    message_queue_->PostDelayed(ping_period_millis_, this);
81  }
82
83  return STATE_BLOCKED;
84}
85
86void PingTask::OnMessage(rtc::Message* msg) {
87  // Get the task manager to run this task so we can send a ping or signal or
88  // process a ping response.
89  Wake();
90}
91
92} // namespace buzz
93