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