Home | History | Annotate | Download | only in xmpp
      1 /*
      2  * libjingle
      3  * Copyright 2004--2005, 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_XMPPENGINEIMPL_H_
     29 #define TALK_XMPP_XMPPENGINEIMPL_H_
     30 
     31 #include <sstream>
     32 #include <vector>
     33 #include "talk/xmpp/xmppengine.h"
     34 #include "talk/xmpp/xmppstanzaparser.h"
     35 
     36 namespace buzz {
     37 
     38 class XmppLoginTask;
     39 class XmppEngine;
     40 class XmppIqEntry;
     41 class SaslHandler;
     42 class SaslMechanism;
     43 
     44 //! The XMPP connection engine.
     45 //! This engine implements the client side of the 'core' XMPP protocol.
     46 //! To use it, register an XmppOutputHandler to handle socket output
     47 //! and pass socket input to HandleInput.  Then application code can
     48 //! set up the connection with a user, password, and other settings,
     49 //! and then call Connect() to initiate the connection.
     50 //! An application can listen for events and receive stanzas by
     51 //! registering an XmppStanzaHandler via AddStanzaHandler().
     52 class XmppEngineImpl : public XmppEngine {
     53  public:
     54   XmppEngineImpl();
     55   virtual ~XmppEngineImpl();
     56 
     57   // SOCKET INPUT AND OUTPUT ------------------------------------------------
     58 
     59   //! Registers the handler for socket output
     60   virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
     61 
     62   //! Provides socket input to the engine
     63   virtual XmppReturnStatus HandleInput(const char* bytes, size_t len);
     64 
     65   //! Advises the engine that the socket has closed
     66   virtual XmppReturnStatus ConnectionClosed(int subcode);
     67 
     68   // SESSION SETUP ---------------------------------------------------------
     69 
     70   //! Indicates the (bare) JID for the user to use.
     71   virtual XmppReturnStatus SetUser(const Jid& jid);
     72 
     73   //! Get the login (bare) JID.
     74   virtual const Jid& GetUser();
     75 
     76   //! Indicates the autentication to use.  Takes ownership of the object.
     77   virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler);
     78 
     79   //! Sets whether TLS will be used within the connection (default true).
     80   virtual XmppReturnStatus SetTls(TlsOptions use_tls);
     81 
     82   //! Sets an alternate domain from which we allows TLS certificates.
     83   //! This is for use in the case where a we want to allow a proxy to
     84   //! serve up its own certificate rather than one owned by the underlying
     85   //! domain.
     86   virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname,
     87                                         const std::string& proxy_domain);
     88 
     89   //! Gets whether TLS will be used within the connection.
     90   virtual TlsOptions GetTls();
     91 
     92   //! Sets the request resource name, if any (optional).
     93   //! Note that the resource name may be overridden by the server; after
     94   //! binding, the actual resource name is available as part of FullJid().
     95   virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
     96 
     97   //! Gets the request resource name.
     98   virtual const std::string& GetRequestedResource();
     99 
    100   //! Sets language
    101   virtual void SetLanguage(const std::string& lang) {
    102     lang_ = lang;
    103   }
    104 
    105   // SESSION MANAGEMENT ---------------------------------------------------
    106 
    107   //! Set callback for state changes.
    108   virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler);
    109 
    110   //! Initiates the XMPP connection.
    111   //! After supplying connection settings, call this once to initiate,
    112   //! (optionally) encrypt, authenticate, and bind the connection.
    113   virtual XmppReturnStatus Connect();
    114 
    115   //! The current engine state.
    116   virtual State GetState() { return state_; }
    117 
    118   //! Returns true if the connection is encrypted (under TLS)
    119   virtual bool IsEncrypted() { return encrypted_; }
    120 
    121   //! The error code.
    122   //! Consult this after XmppOutputHandler.OnClose().
    123   virtual Error GetError(int *subcode) {
    124      if (subcode) {
    125        *subcode = subcode_;
    126      }
    127      return error_code_;
    128   }
    129 
    130   //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
    131   //! Notice the stanza returned is owned by the XmppEngine and
    132   //! is deleted when the engine is destroyed.
    133   virtual const XmlElement* GetStreamError() { return stream_error_.get(); }
    134 
    135   //! Closes down the connection.
    136   //! Sends CloseConnection to output, and disconnects and registered
    137   //! session handlers.  After Disconnect completes, it is guaranteed
    138   //! that no further callbacks will be made.
    139   virtual XmppReturnStatus Disconnect();
    140 
    141   // APPLICATION USE -------------------------------------------------------
    142 
    143   //! Adds a listener for session events.
    144   //! Stanza delivery is chained to session handlers; the first to
    145   //! return 'true' is the last to get each stanza.
    146   virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler,
    147                                             XmppEngine::HandlerLevel level);
    148 
    149   //! Removes a listener for session events.
    150   virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
    151 
    152   //! Sends a stanza to the server.
    153   virtual XmppReturnStatus SendStanza(const XmlElement* stanza);
    154 
    155   //! Sends raw text to the server
    156   virtual XmppReturnStatus SendRaw(const std::string& text);
    157 
    158   //! Sends an iq to the server, and registers a callback for the result.
    159   //! Returns the cookie passed to the result handler.
    160   virtual XmppReturnStatus SendIq(const XmlElement* stanza,
    161                                   XmppIqHandler* iq_handler,
    162                                   XmppIqCookie* cookie);
    163 
    164   //! Unregisters an iq callback handler given its cookie.
    165   //! No callback will come to this handler after it's unregistered.
    166   virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
    167                                       XmppIqHandler** iq_handler);
    168 
    169   //! Forms and sends an error in response to the given stanza.
    170   //! Swaps to and from, sets type to "error", and adds error information
    171   //! based on the passed code.  Text is optional and may be STR_EMPTY.
    172   virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal,
    173                                            XmppStanzaError code,
    174                                            const std::string& text);
    175 
    176   //! The fullly bound JID.
    177   //! This JID is only valid after binding has succeeded.  If the value
    178   //! is JID_NULL, the binding has not succeeded.
    179   virtual const Jid& FullJid() { return bound_jid_; }
    180 
    181   //! The next unused iq id for this connection.
    182   //! Call this when building iq stanzas, to ensure that each iq
    183   //! gets its own unique id.
    184   virtual std::string NextId();
    185 
    186  private:
    187   friend class XmppLoginTask;
    188   friend class XmppIqEntry;
    189 
    190   void IncomingStanza(const XmlElement *stanza);
    191   void IncomingStart(const XmlElement *stanza);
    192   void IncomingEnd(bool isError);
    193 
    194   void InternalSendStart(const std::string& domainName);
    195   void InternalSendStanza(const XmlElement* stanza);
    196   std::string ChooseBestSaslMechanism(
    197       const std::vector<std::string>& mechanisms, bool encrypted);
    198   SaslMechanism* GetSaslMechanism(const std::string& name);
    199   void SignalBound(const Jid& fullJid);
    200   void SignalStreamError(const XmlElement* streamError);
    201   void SignalError(Error errorCode, int subCode);
    202   bool HasError();
    203   void DeleteIqCookies();
    204   bool HandleIqResponse(const XmlElement* element);
    205   void StartTls(const std::string& domain);
    206   void RaiseReset() { raised_reset_ = true; }
    207 
    208   class StanzaParseHandler : public XmppStanzaParseHandler {
    209    public:
    210     StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {}
    211     virtual ~StanzaParseHandler() {}
    212 
    213     virtual void StartStream(const XmlElement* stream) {
    214       outer_->IncomingStart(stream);
    215     }
    216     virtual void Stanza(const XmlElement* stanza) {
    217       outer_->IncomingStanza(stanza);
    218     }
    219     virtual void EndStream() {
    220       outer_->IncomingEnd(false);
    221     }
    222     virtual void XmlError() {
    223       outer_->IncomingEnd(true);
    224     }
    225 
    226    private:
    227     XmppEngineImpl* const outer_;
    228   };
    229 
    230   class EnterExit {
    231    public:
    232     EnterExit(XmppEngineImpl* engine);
    233     ~EnterExit();
    234    private:
    235     XmppEngineImpl* engine_;
    236     State state_;
    237   };
    238 
    239   friend class StanzaParseHandler;
    240   friend class EnterExit;
    241 
    242   StanzaParseHandler stanza_parse_handler_;
    243   XmppStanzaParser stanza_parser_;
    244 
    245   // state
    246   int engine_entered_;
    247   Jid user_jid_;
    248   std::string password_;
    249   std::string requested_resource_;
    250   TlsOptions tls_option_;
    251   std::string tls_server_hostname_;
    252   std::string tls_server_domain_;
    253   talk_base::scoped_ptr<XmppLoginTask> login_task_;
    254   std::string lang_;
    255 
    256   int next_id_;
    257   Jid bound_jid_;
    258   State state_;
    259   bool encrypted_;
    260   Error error_code_;
    261   int subcode_;
    262   talk_base::scoped_ptr<XmlElement> stream_error_;
    263   bool raised_reset_;
    264   XmppOutputHandler* output_handler_;
    265   XmppSessionHandler* session_handler_;
    266 
    267   XmlnsStack xmlns_stack_;
    268 
    269   typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector;
    270   talk_base::scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
    271 
    272   typedef std::vector<XmppIqEntry*> IqEntryVector;
    273   talk_base::scoped_ptr<IqEntryVector> iq_entries_;
    274 
    275   talk_base::scoped_ptr<SaslHandler> sasl_handler_;
    276 
    277   talk_base::scoped_ptr<std::stringstream> output_;
    278 };
    279 
    280 }  // namespace buzz
    281 
    282 #endif  // TALK_XMPP_XMPPENGINEIMPL_H_
    283