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: ~XmppOutputHandler()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: ~XmppSessionHandler()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: ~XmppStanzaHandler()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: ~XmppIqHandler()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(); ~XmppEngine()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