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