Home | History | Annotate | Download | only in xmpp
      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 
     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 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 
    109 class 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 
    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 
    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 
    174 private:
    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