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_XMPPENGINE_H_
     29 #define TALK_XMPP_XMPPENGINE_H_
     30 
     31 // also part of the API
     32 #include "webrtc/libjingle/xmllite/qname.h"
     33 #include "webrtc/libjingle/xmllite/xmlelement.h"
     34 #include "talk/xmpp/jid.h"
     35 
     36 
     37 namespace buzz {
     38 
     39 class XmppEngine;
     40 class SaslHandler;
     41 typedef void * XmppIqCookie;
     42 
     43 //! XMPP stanza error codes.
     44 //! Used in XmppEngine.SendStanzaError().
     45 enum XmppStanzaError {
     46   XSE_BAD_REQUEST,
     47   XSE_CONFLICT,
     48   XSE_FEATURE_NOT_IMPLEMENTED,
     49   XSE_FORBIDDEN,
     50   XSE_GONE,
     51   XSE_INTERNAL_SERVER_ERROR,
     52   XSE_ITEM_NOT_FOUND,
     53   XSE_JID_MALFORMED,
     54   XSE_NOT_ACCEPTABLE,
     55   XSE_NOT_ALLOWED,
     56   XSE_PAYMENT_REQUIRED,
     57   XSE_RECIPIENT_UNAVAILABLE,
     58   XSE_REDIRECT,
     59   XSE_REGISTRATION_REQUIRED,
     60   XSE_SERVER_NOT_FOUND,
     61   XSE_SERVER_TIMEOUT,
     62   XSE_RESOURCE_CONSTRAINT,
     63   XSE_SERVICE_UNAVAILABLE,
     64   XSE_SUBSCRIPTION_REQUIRED,
     65   XSE_UNDEFINED_CONDITION,
     66   XSE_UNEXPECTED_REQUEST,
     67 };
     68 
     69 // XmppReturnStatus
     70 //    This is used by API functions to synchronously return status.
     71 enum XmppReturnStatus {
     72   XMPP_RETURN_OK,
     73   XMPP_RETURN_BADARGUMENT,
     74   XMPP_RETURN_BADSTATE,
     75   XMPP_RETURN_PENDING,
     76   XMPP_RETURN_UNEXPECTED,
     77   XMPP_RETURN_NOTYETIMPLEMENTED,
     78 };
     79 
     80 // TlsOptions
     81 //    This is used by API to identify TLS setting.
     82 enum TlsOptions {
     83   TLS_DISABLED,
     84   TLS_ENABLED,
     85   TLS_REQUIRED
     86 };
     87 
     88 //! Callback for socket output for an XmppEngine connection.
     89 //! Register via XmppEngine.SetOutputHandler.  An XmppEngine
     90 //! can call back to this handler while it is processing
     91 //! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
     92 class XmppOutputHandler {
     93 public:
     94   virtual ~XmppOutputHandler() {}
     95 
     96   //! Deliver the specified bytes to the XMPP socket.
     97   virtual void WriteOutput(const char * bytes, size_t len) = 0;
     98 
     99   //! Initiate TLS encryption on the socket.
    100   //! The implementation must verify that the SSL
    101   //! certificate matches the given domainname.
    102   virtual void StartTls(const std::string & domainname) = 0;
    103 
    104   //! Called when engine wants the connecton closed.
    105   virtual void CloseConnection() = 0;
    106 };
    107 
    108 //! Callback to deliver engine state change notifications
    109 //! to the object managing the engine.
    110 class XmppSessionHandler {
    111 public:
    112   virtual ~XmppSessionHandler() {}
    113   //! Called when engine changes state. Argument is new state.
    114   virtual void OnStateChange(int state) = 0;
    115 };
    116 
    117 //! Callback to deliver stanzas to an Xmpp application module.
    118 //! Register via XmppEngine.SetDefaultSessionHandler or via
    119 //! XmppEngine.AddSessionHAndler.
    120 class XmppStanzaHandler {
    121 public:
    122   virtual ~XmppStanzaHandler() {}
    123   //! Process the given stanza.
    124   //! The handler must return true if it has handled the stanza.
    125   //! A false return value causes the stanza to be passed on to
    126   //! the next registered handler.
    127   virtual bool HandleStanza(const XmlElement * stanza) = 0;
    128 };
    129 
    130 //! Callback to deliver iq responses (results and errors).
    131 //! Register while sending an iq via XmppEngine.SendIq.
    132 //! Iq responses are routed to matching XmppIqHandlers in preference
    133 //! to sending to any registered SessionHandlers.
    134 class XmppIqHandler {
    135 public:
    136   virtual ~XmppIqHandler() {}
    137   //! Called to handle the iq response.
    138   //! The response may be either a result or an error, and will have
    139   //! an 'id' that matches the request and a 'from' that matches the
    140   //! 'to' of the request.  Called no more than once; once this is
    141   //! called, the handler is automatically unregistered.
    142   virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
    143 };
    144 
    145 //! The XMPP connection engine.
    146 //! This engine implements the client side of the 'core' XMPP protocol.
    147 //! To use it, register an XmppOutputHandler to handle socket output
    148 //! and pass socket input to HandleInput.  Then application code can
    149 //! set up the connection with a user, password, and other settings,
    150 //! and then call Connect() to initiate the connection.
    151 //! An application can listen for events and receive stanzas by
    152 //! registering an XmppStanzaHandler via AddStanzaHandler().
    153 class XmppEngine {
    154 public:
    155   static XmppEngine * Create();
    156   virtual ~XmppEngine() {}
    157 
    158   //! Error codes. See GetError().
    159   enum Error {
    160     ERROR_NONE = 0,         //!< No error
    161     ERROR_XML,              //!< Malformed XML or encoding error
    162     ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
    163     ERROR_VERSION,          //!< XMPP version error
    164     ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
    165     ERROR_TLS,              //!< TLS could not be negotiated
    166     ERROR_AUTH,             //!< Authentication could not be negotiated
    167     ERROR_BIND,             //!< Resource or session binding could not be negotiated
    168     ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
    169     ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
    170     ERROR_SOCKET,           //!< Socket error
    171     ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
    172     ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
    173   };
    174 
    175   //! States.  See GetState().
    176   enum State {
    177     STATE_NONE = 0,        //!< Nonexistent state
    178     STATE_START,           //!< Initial state.
    179     STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
    180     STATE_OPEN,            //!< Authenticated and bound.
    181     STATE_CLOSED,          //!< Session closed, possibly due to error.
    182   };
    183 
    184   // SOCKET INPUT AND OUTPUT ------------------------------------------------
    185 
    186   //! Registers the handler for socket output
    187   virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
    188 
    189   //! Provides socket input to the engine
    190   virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
    191 
    192   //! Advises the engine that the socket has closed
    193   virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
    194 
    195   // SESSION SETUP ---------------------------------------------------------
    196 
    197   //! Indicates the (bare) JID for the user to use.
    198   virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
    199 
    200   //! Get the login (bare) JID.
    201   virtual const Jid & GetUser() = 0;
    202 
    203   //! Provides different methods for credentials for login.
    204   //! Takes ownership of this object; deletes when login is done
    205   virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
    206 
    207   //! Sets whether TLS will be used within the connection (default true).
    208   virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0;
    209 
    210   //! Sets an alternate domain from which we allows TLS certificates.
    211   //! This is for use in the case where a we want to allow a proxy to
    212   //! serve up its own certificate rather than one owned by the underlying
    213   //! domain.
    214   virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
    215                                         const std::string & proxy_domain) = 0;
    216 
    217   //! Gets whether TLS will be used within the connection.
    218   virtual TlsOptions GetTls() = 0;
    219 
    220   //! Sets the request resource name, if any (optional).
    221   //! Note that the resource name may be overridden by the server; after
    222   //! binding, the actual resource name is available as part of FullJid().
    223   virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
    224 
    225   //! Gets the request resource name.
    226   virtual const std::string & GetRequestedResource() = 0;
    227 
    228   //! Sets language
    229   virtual void SetLanguage(const std::string & lang) = 0;
    230 
    231   // SESSION MANAGEMENT ---------------------------------------------------
    232 
    233   //! Set callback for state changes.
    234   virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
    235 
    236   //! Initiates the XMPP connection.
    237   //! After supplying connection settings, call this once to initiate,
    238   //! (optionally) encrypt, authenticate, and bind the connection.
    239   virtual XmppReturnStatus Connect() = 0;
    240 
    241   //! The current engine state.
    242   virtual State GetState() = 0;
    243 
    244   //! Returns true if the connection is encrypted (under TLS)
    245   virtual bool IsEncrypted() = 0;
    246 
    247   //! The error code.
    248   //! Consult this after XmppOutputHandler.OnClose().
    249   virtual Error GetError(int *subcode) = 0;
    250 
    251   //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
    252   //! Notice the stanza returned is owned by the XmppEngine and
    253   //! is deleted when the engine is destroyed.
    254   virtual const XmlElement * GetStreamError() = 0;
    255 
    256   //! Closes down the connection.
    257   //! Sends CloseConnection to output, and disconnects and registered
    258   //! session handlers.  After Disconnect completes, it is guaranteed
    259   //! that no further callbacks will be made.
    260   virtual XmppReturnStatus Disconnect() = 0;
    261 
    262   // APPLICATION USE -------------------------------------------------------
    263 
    264   enum HandlerLevel {
    265     HL_NONE = 0,
    266     HL_PEEK,   //!< Sees messages before all other processing; cannot abort
    267     HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
    268     HL_SENDER, //!< Watches for a type of message from a specific sender
    269     HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
    270     HL_ALL,    //!< Watches all messages - gets last shot
    271     HL_COUNT,  //!< Count of handler levels
    272   };
    273 
    274   //! Adds a listener for session events.
    275   //! Stanza delivery is chained to session handlers; the first to
    276   //! return 'true' is the last to get each stanza.
    277   virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
    278 
    279   //! Removes a listener for session events.
    280   virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
    281 
    282   //! Sends a stanza to the server.
    283   virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
    284 
    285   //! Sends raw text to the server
    286   virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
    287 
    288   //! Sends an iq to the server, and registers a callback for the result.
    289   //! Returns the cookie passed to the result handler.
    290   virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
    291                                   XmppIqHandler* iq_handler,
    292                                   XmppIqCookie* cookie) = 0;
    293 
    294   //! Unregisters an iq callback handler given its cookie.
    295   //! No callback will come to this handler after it's unregistered.
    296   virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
    297                                       XmppIqHandler** iq_handler) = 0;
    298 
    299 
    300   //! Forms and sends an error in response to the given stanza.
    301   //! Swaps to and from, sets type to "error", and adds error information
    302   //! based on the passed code.  Text is optional and may be STR_EMPTY.
    303   virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
    304                                            XmppStanzaError code,
    305                                            const std::string & text) = 0;
    306 
    307   //! The fullly bound JID.
    308   //! This JID is only valid after binding has succeeded.  If the value
    309   //! is JID_NULL, the binding has not succeeded.
    310   virtual const Jid & FullJid() = 0;
    311 
    312   //! The next unused iq id for this connection.
    313   //! Call this when building iq stanzas, to ensure that each iq
    314   //! gets its own unique id.
    315   virtual std::string NextId() = 0;
    316 
    317 };
    318 
    319 }
    320 
    321 
    322 // Move these to a better location
    323 
    324 #define XMPP_FAILED(x)                      \
    325   ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
    326 
    327 
    328 #define XMPP_SUCCEEDED(x)                   \
    329   ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
    330 
    331 #define IFR(x)                        \
    332   do {                                \
    333     xmpp_status = (x);                \
    334     if (XMPP_FAILED(xmpp_status)) {   \
    335       return xmpp_status;             \
    336     }                                 \
    337   } while (false)                     \
    338 
    339 
    340 #define IFC(x)                        \
    341   do {                                \
    342     xmpp_status = (x);                \
    343     if (XMPP_FAILED(xmpp_status)) {   \
    344       goto Cleanup;                   \
    345     }                                 \
    346   } while (false)                     \
    347 
    348 
    349 #endif  // TALK_XMPP_XMPPENGINE_H_
    350