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