/* * libjingle * Copyright 2004--2005, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TALK_XMPP_XMPPENGINE_H_ #define TALK_XMPP_XMPPENGINE_H_ // also part of the API #include "webrtc/libjingle/xmllite/qname.h" #include "webrtc/libjingle/xmllite/xmlelement.h" #include "webrtc/libjingle/xmpp/jid.h" namespace buzz { class XmppEngine; class SaslHandler; typedef void * XmppIqCookie; //! XMPP stanza error codes. //! Used in XmppEngine.SendStanzaError(). enum XmppStanzaError { XSE_BAD_REQUEST, XSE_CONFLICT, XSE_FEATURE_NOT_IMPLEMENTED, XSE_FORBIDDEN, XSE_GONE, XSE_INTERNAL_SERVER_ERROR, XSE_ITEM_NOT_FOUND, XSE_JID_MALFORMED, XSE_NOT_ACCEPTABLE, XSE_NOT_ALLOWED, XSE_PAYMENT_REQUIRED, XSE_RECIPIENT_UNAVAILABLE, XSE_REDIRECT, XSE_REGISTRATION_REQUIRED, XSE_SERVER_NOT_FOUND, XSE_SERVER_TIMEOUT, XSE_RESOURCE_CONSTRAINT, XSE_SERVICE_UNAVAILABLE, XSE_SUBSCRIPTION_REQUIRED, XSE_UNDEFINED_CONDITION, XSE_UNEXPECTED_REQUEST, }; // XmppReturnStatus // This is used by API functions to synchronously return status. enum XmppReturnStatus { XMPP_RETURN_OK, XMPP_RETURN_BADARGUMENT, XMPP_RETURN_BADSTATE, XMPP_RETURN_PENDING, XMPP_RETURN_UNEXPECTED, XMPP_RETURN_NOTYETIMPLEMENTED, }; // TlsOptions // This is used by API to identify TLS setting. enum TlsOptions { TLS_DISABLED, TLS_ENABLED, TLS_REQUIRED }; //! Callback for socket output for an XmppEngine connection. //! Register via XmppEngine.SetOutputHandler. An XmppEngine //! can call back to this handler while it is processing //! Connect, SendStanza, SendIq, Disconnect, or HandleInput. class XmppOutputHandler { public: virtual ~XmppOutputHandler() {} //! Deliver the specified bytes to the XMPP socket. virtual void WriteOutput(const char * bytes, size_t len) = 0; //! Initiate TLS encryption on the socket. //! The implementation must verify that the SSL //! certificate matches the given domainname. virtual void StartTls(const std::string & domainname) = 0; //! Called when engine wants the connecton closed. virtual void CloseConnection() = 0; }; //! Callback to deliver engine state change notifications //! to the object managing the engine. class XmppSessionHandler { public: virtual ~XmppSessionHandler() {} //! Called when engine changes state. Argument is new state. virtual void OnStateChange(int state) = 0; }; //! Callback to deliver stanzas to an Xmpp application module. //! Register via XmppEngine.SetDefaultSessionHandler or via //! XmppEngine.AddSessionHAndler. class XmppStanzaHandler { public: virtual ~XmppStanzaHandler() {} //! Process the given stanza. //! The handler must return true if it has handled the stanza. //! A false return value causes the stanza to be passed on to //! the next registered handler. virtual bool HandleStanza(const XmlElement * stanza) = 0; }; //! Callback to deliver iq responses (results and errors). //! Register while sending an iq via XmppEngine.SendIq. //! Iq responses are routed to matching XmppIqHandlers in preference //! to sending to any registered SessionHandlers. class XmppIqHandler { public: virtual ~XmppIqHandler() {} //! Called to handle the iq response. //! The response may be either a result or an error, and will have //! an 'id' that matches the request and a 'from' that matches the //! 'to' of the request. Called no more than once; once this is //! called, the handler is automatically unregistered. virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0; }; //! The XMPP connection engine. //! This engine implements the client side of the 'core' XMPP protocol. //! To use it, register an XmppOutputHandler to handle socket output //! and pass socket input to HandleInput. Then application code can //! set up the connection with a user, password, and other settings, //! and then call Connect() to initiate the connection. //! An application can listen for events and receive stanzas by //! registering an XmppStanzaHandler via AddStanzaHandler(). class XmppEngine { public: static XmppEngine * Create(); virtual ~XmppEngine() {} //! Error codes. See GetError(). enum Error { ERROR_NONE = 0, //!< No error ERROR_XML, //!< Malformed XML or encoding error ERROR_STREAM, //!< XMPP stream error - see GetStreamError() ERROR_VERSION, //!< XMPP version error ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials) ERROR_TLS, //!< TLS could not be negotiated ERROR_AUTH, //!< Authentication could not be negotiated ERROR_BIND, //!< Resource or session binding could not be negotiated ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler. ERROR_DOCUMENT_CLOSED, //!< Closed by ERROR_SOCKET, //!< Socket error ERROR_NETWORK_TIMEOUT, //!< Some sort of timeout (eg., we never got the roster) ERROR_MISSING_USERNAME //!< User has a Google Account but no nickname }; //! States. See GetState(). enum State { STATE_NONE = 0, //!< Nonexistent state STATE_START, //!< Initial state. STATE_OPENING, //!< Exchanging stream headers, authenticating and so on. STATE_OPEN, //!< Authenticated and bound. STATE_CLOSED, //!< Session closed, possibly due to error. }; // SOCKET INPUT AND OUTPUT ------------------------------------------------ //! Registers the handler for socket output virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0; //! Provides socket input to the engine virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0; //! Advises the engine that the socket has closed virtual XmppReturnStatus ConnectionClosed(int subcode) = 0; // SESSION SETUP --------------------------------------------------------- //! Indicates the (bare) JID for the user to use. virtual XmppReturnStatus SetUser(const Jid & jid)= 0; //! Get the login (bare) JID. virtual const Jid & GetUser() = 0; //! Provides different methods for credentials for login. //! Takes ownership of this object; deletes when login is done virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0; //! Sets whether TLS will be used within the connection (default true). virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0; //! Sets an alternate domain from which we allows TLS certificates. //! This is for use in the case where a we want to allow a proxy to //! serve up its own certificate rather than one owned by the underlying //! domain. virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname, const std::string & proxy_domain) = 0; //! Gets whether TLS will be used within the connection. virtual TlsOptions GetTls() = 0; //! Sets the request resource name, if any (optional). //! Note that the resource name may be overridden by the server; after //! binding, the actual resource name is available as part of FullJid(). virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0; //! Gets the request resource name. virtual const std::string & GetRequestedResource() = 0; //! Sets language virtual void SetLanguage(const std::string & lang) = 0; // SESSION MANAGEMENT --------------------------------------------------- //! Set callback for state changes. virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0; //! Initiates the XMPP connection. //! After supplying connection settings, call this once to initiate, //! (optionally) encrypt, authenticate, and bind the connection. virtual XmppReturnStatus Connect() = 0; //! The current engine state. virtual State GetState() = 0; //! Returns true if the connection is encrypted (under TLS) virtual bool IsEncrypted() = 0; //! The error code. //! Consult this after XmppOutputHandler.OnClose(). virtual Error GetError(int *subcode) = 0; //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM. //! Notice the stanza returned is owned by the XmppEngine and //! is deleted when the engine is destroyed. virtual const XmlElement * GetStreamError() = 0; //! Closes down the connection. //! Sends CloseConnection to output, and disconnects and registered //! session handlers. After Disconnect completes, it is guaranteed //! that no further callbacks will be made. virtual XmppReturnStatus Disconnect() = 0; // APPLICATION USE ------------------------------------------------------- enum HandlerLevel { HL_NONE = 0, HL_PEEK, //!< Sees messages before all other processing; cannot abort HL_SINGLE, //!< Watches for a single message, e.g., by id and sender HL_SENDER, //!< Watches for a type of message from a specific sender HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs HL_ALL, //!< Watches all messages - gets last shot HL_COUNT, //!< Count of handler levels }; //! Adds a listener for session events. //! Stanza delivery is chained to session handlers; the first to //! return 'true' is the last to get each stanza. virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0; //! Removes a listener for session events. virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0; //! Sends a stanza to the server. virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0; //! Sends raw text to the server virtual XmppReturnStatus SendRaw(const std::string & text) = 0; //! Sends an iq to the server, and registers a callback for the result. //! Returns the cookie passed to the result handler. virtual XmppReturnStatus SendIq(const XmlElement* pelStanza, XmppIqHandler* iq_handler, XmppIqCookie* cookie) = 0; //! Unregisters an iq callback handler given its cookie. //! No callback will come to this handler after it's unregistered. virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, XmppIqHandler** iq_handler) = 0; //! Forms and sends an error in response to the given stanza. //! Swaps to and from, sets type to "error", and adds error information //! based on the passed code. Text is optional and may be STR_EMPTY. virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, XmppStanzaError code, const std::string & text) = 0; //! The fullly bound JID. //! This JID is only valid after binding has succeeded. If the value //! is JID_NULL, the binding has not succeeded. virtual const Jid & FullJid() = 0; //! The next unused iq id for this connection. //! Call this when building iq stanzas, to ensure that each iq //! gets its own unique id. virtual std::string NextId() = 0; }; } // Move these to a better location #define XMPP_FAILED(x) \ ( (x) == buzz::XMPP_RETURN_OK ? false : true) \ #define XMPP_SUCCEEDED(x) \ ( (x) == buzz::XMPP_RETURN_OK ? true : false) \ #define IFR(x) \ do { \ xmpp_status = (x); \ if (XMPP_FAILED(xmpp_status)) { \ return xmpp_status; \ } \ } while (false) \ #define IFC(x) \ do { \ xmpp_status = (x); \ if (XMPP_FAILED(xmpp_status)) { \ goto Cleanup; \ } \ } while (false) \ #endif // TALK_XMPP_XMPPENGINE_H_