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 <deque> 32 #include <string> 33 #include "talk/xmpp/xmppengine.h" 34 #include "webrtc/base/sigslot.h" 35 #include "webrtc/base/task.h" 36 #include "webrtc/base/taskparent.h" 37 38 namespace 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 65 class 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. 71 class 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. 97 class XmppTaskParentInterface : public rtc::Task { 98 public: XmppTaskParentInterface(rtc::TaskParent * parent)99 explicit XmppTaskParentInterface(rtc::TaskParent* parent) 100 : Task(parent) { 101 } ~XmppTaskParentInterface()102 virtual ~XmppTaskParentInterface() {} 103 104 virtual XmppClientInterface* GetClient() = 0; 105 106 DISALLOW_EVIL_CONSTRUCTORS(XmppTaskParentInterface); 107 }; 108 109 class XmppTaskBase : public XmppTaskParentInterface { 110 public: XmppTaskBase(XmppTaskParentInterface * parent)111 explicit XmppTaskBase(XmppTaskParentInterface* parent) 112 : XmppTaskParentInterface(parent), 113 parent_(parent) { 114 } ~XmppTaskBase()115 virtual ~XmppTaskBase() {} 116 GetClient()117 virtual XmppClientInterface* GetClient() { 118 return parent_->GetClient(); 119 } 120 121 protected: 122 XmppTaskParentInterface* parent_; 123 124 DISALLOW_EVIL_CONSTRUCTORS(XmppTaskBase); 125 }; 126 127 class 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 task_id()136 std::string task_id() const { return id_; } set_task_id(std::string id)137 void set_task_id(std::string id) { id_ = id; } 138 139 #ifdef _DEBUG set_debug_force_timeout(const bool f)140 void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; } 141 #endif 142 HandleStanza(const XmlElement * stanza)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 174 private: 175 void StopImpl(); 176 177 bool stopped_; 178 std::deque<XmlElement*> stanza_queue_; 179 rtc::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