1 /*
2  *  Copyright 2004 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 #ifndef THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
12 #define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
13 
14 #include <deque>
15 #include <memory>
16 #include <string>
17 
18 #include "base/macros.h"
19 #include "third_party/libjingle_xmpp/task_runner/task.h"
20 #include "third_party/libjingle_xmpp/task_runner/taskparent.h"
21 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
22 #include "third_party/webrtc/rtc_base/third_party/sigslot/sigslot.h"
23 
24 namespace jingle_xmpp {
25 
26 /////////////////////////////////////////////////////////////////////
27 //
28 // XMPPTASK
29 //
30 /////////////////////////////////////////////////////////////////////
31 //
32 // See Task and XmppClient first.
33 //
34 // XmppTask is a task that is designed to go underneath XmppClient and be
35 // useful there.  It has a way of finding its XmppClient parent so you
36 // can have it nested arbitrarily deep under an XmppClient and it can
37 // still find the XMPP services.
38 //
39 // Tasks register themselves to listen to particular kinds of stanzas
40 // that are sent out by the client.  Rather than processing stanzas
41 // right away, they should decide if they own the sent stanza,
42 // and if so, queue it and Wake() the task, or if a stanza does not belong
43 // to you, return false right away so the next XmppTask can take a crack.
44 // This technique (synchronous recognize, but asynchronous processing)
45 // allows you to have arbitrary logic for recognizing stanzas yet still,
46 // for example, disconnect a client while processing a stanza -
47 // without reentrancy problems.
48 //
49 /////////////////////////////////////////////////////////////////////
50 
51 class XmppTask;
52 
53 // XmppClientInterface is an abstract interface for sending and
54 // handling stanzas.  It can be implemented for unit tests or
55 // different network environments.  It will usually be implemented by
56 // XmppClient.
57 class XmppClientInterface {
58  public:
59   XmppClientInterface();
60   virtual ~XmppClientInterface();
61 
62   virtual XmppEngine::State GetState() const = 0;
63   virtual const Jid& jid() const = 0;
64   virtual std::string NextId() = 0;
65   virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0;
66   virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza,
67                                            XmppStanzaError error_code,
68                                            const std::string& message) = 0;
69   virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0;
70   virtual void RemoveXmppTask(XmppTask* task) = 0;
71   sigslot::signal0<> SignalDisconnected;
72 
73   DISALLOW_COPY_AND_ASSIGN(XmppClientInterface);
74 };
75 
76 // XmppTaskParentInterface is the interface require for any parent of
77 // an XmppTask.  It needs, for example, a way to get an
78 // XmppClientInterface.
79 
80 // We really ought to inherit from a TaskParentInterface, but we tried
81 // that and it's way too complicated to change
82 // Task/TaskParent/TaskRunner.  For now, this works.
83 class XmppTaskParentInterface : public jingle_xmpp::Task {
84  public:
XmppTaskParentInterface(jingle_xmpp::TaskParent * parent)85   explicit XmppTaskParentInterface(jingle_xmpp::TaskParent* parent)
86       : Task(parent) {
87   }
~XmppTaskParentInterface()88   virtual ~XmppTaskParentInterface() {}
89 
90   virtual XmppClientInterface* GetClient() = 0;
91 
92   DISALLOW_COPY_AND_ASSIGN(XmppTaskParentInterface);
93 };
94 
95 class XmppTaskBase : public XmppTaskParentInterface {
96  public:
XmppTaskBase(XmppTaskParentInterface * parent)97   explicit XmppTaskBase(XmppTaskParentInterface* parent)
98       : XmppTaskParentInterface(parent),
99         parent_(parent) {
100   }
~XmppTaskBase()101   virtual ~XmppTaskBase() {}
102 
GetClient()103   virtual XmppClientInterface* GetClient() {
104     return parent_->GetClient();
105   }
106 
107  protected:
108   XmppTaskParentInterface* parent_;
109 
110   DISALLOW_COPY_AND_ASSIGN(XmppTaskBase);
111 };
112 
113 class XmppTask : public XmppTaskBase,
114                  public XmppStanzaHandler,
115                  public sigslot::has_slots<>
116 {
117  public:
118   XmppTask(XmppTaskParentInterface* parent,
119            XmppEngine::HandlerLevel level = XmppEngine::HL_NONE);
120   virtual ~XmppTask();
121 
task_id()122   std::string task_id() const { return id_; }
set_task_id(std::string id)123   void set_task_id(std::string id) { id_ = id; }
124 
125 #if !defined(NDEBUG)
set_debug_force_timeout(const bool f)126   void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; }
127 #endif
128 
HandleStanza(const XmlElement * stanza)129   virtual bool HandleStanza(const XmlElement* stanza) { return false; }
130 
131  protected:
132   XmppReturnStatus SendStanza(const XmlElement* stanza);
133   XmppReturnStatus SetResult(const std::string& code);
134   XmppReturnStatus SendStanzaError(const XmlElement* element_original,
135                                    XmppStanzaError code,
136                                    const std::string& text);
137 
138   virtual void Stop();
139   virtual void OnDisconnect();
140 
141   virtual void QueueStanza(const XmlElement* stanza);
142   const XmlElement* NextStanza();
143 
144   bool MatchStanzaFrom(const XmlElement* stanza, const Jid& match_jid);
145 
146   bool MatchResponseIq(const XmlElement* stanza, const Jid& to,
147                        const std::string& task_id);
148 
149   static bool MatchRequestIq(const XmlElement* stanza, const std::string& type,
150                              const QName& qn);
151   static XmlElement *MakeIqResult(const XmlElement* query);
152   static XmlElement *MakeIq(const std::string& type,
153                             const Jid& to, const std::string& task_id);
154 
155   // Returns true if the task is under the specified rate limit and updates the
156   // rate limit accordingly
157   bool VerifyTaskRateLimit(const std::string task_name, int max_count,
158                            int per_x_seconds);
159 
160 private:
161   void StopImpl();
162 
163   bool stopped_;
164   std::deque<XmlElement*> stanza_queue_;
165   std::unique_ptr<XmlElement> next_stanza_;
166   std::string id_;
167 
168 #if !defined(NDEBUG)
169   bool debug_force_timeout_;
170 #endif
171 };
172 
173 }  // namespace jingle_xmpp
174 
175 #endif // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPTASK_H_
176