1/* 2 * libjingle 3 * Copyright 2004--2006, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#ifndef TALK_XMPP_XMPPTASK_H_ 29#define TALK_XMPP_XMPPTASK_H_ 30 31#include <string> 32#include <deque> 33#include "talk/base/sigslot.h" 34#include "talk/base/task.h" 35#include "talk/base/taskparent.h" 36#include "talk/xmpp/xmppengine.h" 37 38namespace buzz { 39 40///////////////////////////////////////////////////////////////////// 41// 42// XMPPTASK 43// 44///////////////////////////////////////////////////////////////////// 45// 46// See Task and XmppClient first. 47// 48// XmppTask is a task that is designed to go underneath XmppClient and be 49// useful there. It has a way of finding its XmppClient parent so you 50// can have it nested arbitrarily deep under an XmppClient and it can 51// still find the XMPP services. 52// 53// Tasks register themselves to listen to particular kinds of stanzas 54// that are sent out by the client. Rather than processing stanzas 55// right away, they should decide if they own the sent stanza, 56// and if so, queue it and Wake() the task, or if a stanza does not belong 57// to you, return false right away so the next XmppTask can take a crack. 58// This technique (synchronous recognize, but asynchronous processing) 59// allows you to have arbitrary logic for recognizing stanzas yet still, 60// for example, disconnect a client while processing a stanza - 61// without reentrancy problems. 62// 63///////////////////////////////////////////////////////////////////// 64 65class XmppTask; 66 67// XmppClientInterface is an abstract interface for sending and 68// handling stanzas. It can be implemented for unit tests or 69// different network environments. It will usually be implemented by 70// XmppClient. 71class XmppClientInterface { 72 public: 73 XmppClientInterface(); 74 virtual ~XmppClientInterface(); 75 76 virtual XmppEngine::State GetState() const = 0; 77 virtual const Jid& jid() const = 0; 78 virtual std::string NextId() = 0; 79 virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0; 80 virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza, 81 XmppStanzaError error_code, 82 const std::string& message) = 0; 83 virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0; 84 virtual void RemoveXmppTask(XmppTask* task) = 0; 85 sigslot::signal0<> SignalDisconnected; 86 87 DISALLOW_EVIL_CONSTRUCTORS(XmppClientInterface); 88}; 89 90// XmppTaskParentInterface is the interface require for any parent of 91// an XmppTask. It needs, for example, a way to get an 92// XmppClientInterface. 93 94// We really ought to inherit from a TaskParentInterface, but we tried 95// that and it's way too complicated to change 96// Task/TaskParent/TaskRunner. For now, this works. 97class XmppTaskParentInterface : public talk_base::Task { 98 public: 99 explicit XmppTaskParentInterface(talk_base::TaskParent* parent) 100 : Task(parent) { 101 } 102 virtual ~XmppTaskParentInterface() {} 103 104 virtual XmppClientInterface* GetClient() = 0; 105 106 DISALLOW_EVIL_CONSTRUCTORS(XmppTaskParentInterface); 107}; 108 109class XmppTaskBase : public XmppTaskParentInterface { 110 public: 111 explicit XmppTaskBase(XmppTaskParentInterface* parent) 112 : XmppTaskParentInterface(parent), 113 parent_(parent) { 114 } 115 virtual ~XmppTaskBase() {} 116 117 virtual XmppClientInterface* GetClient() { 118 return parent_->GetClient(); 119 } 120 121 protected: 122 XmppTaskParentInterface* parent_; 123 124 DISALLOW_EVIL_CONSTRUCTORS(XmppTaskBase); 125}; 126 127class XmppTask : public XmppTaskBase, 128 public XmppStanzaHandler, 129 public sigslot::has_slots<> 130{ 131 public: 132 XmppTask(XmppTaskParentInterface* parent, 133 XmppEngine::HandlerLevel level = XmppEngine::HL_NONE); 134 virtual ~XmppTask(); 135 136 std::string task_id() const { return id_; } 137 void set_task_id(std::string id) { id_ = id; } 138 139#ifdef _DEBUG 140 void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; } 141#endif 142 143 virtual bool HandleStanza(const XmlElement* stanza) { return false; } 144 145 protected: 146 XmppReturnStatus SendStanza(const XmlElement* stanza); 147 XmppReturnStatus SetResult(const std::string& code); 148 XmppReturnStatus SendStanzaError(const XmlElement* element_original, 149 XmppStanzaError code, 150 const std::string& text); 151 152 virtual void Stop(); 153 virtual void OnDisconnect(); 154 155 virtual void QueueStanza(const XmlElement* stanza); 156 const XmlElement* NextStanza(); 157 158 bool MatchStanzaFrom(const XmlElement* stanza, const Jid& match_jid); 159 160 bool MatchResponseIq(const XmlElement* stanza, const Jid& to, 161 const std::string& task_id); 162 163 static bool MatchRequestIq(const XmlElement* stanza, const std::string& type, 164 const QName& qn); 165 static XmlElement *MakeIqResult(const XmlElement* query); 166 static XmlElement *MakeIq(const std::string& type, 167 const Jid& to, const std::string& task_id); 168 169 // Returns true if the task is under the specified rate limit and updates the 170 // rate limit accordingly 171 bool VerifyTaskRateLimit(const std::string task_name, int max_count, 172 int per_x_seconds); 173 174private: 175 void StopImpl(); 176 177 bool stopped_; 178 std::deque<XmlElement*> stanza_queue_; 179 talk_base::scoped_ptr<XmlElement> next_stanza_; 180 std::string id_; 181 182#ifdef _DEBUG 183 bool debug_force_timeout_; 184#endif 185}; 186 187} // namespace buzz 188 189#endif // TALK_XMPP_XMPPTASK_H_ 190