1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_ 12 #define WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_ 13 14 #include <sstream> 15 #include <vector> 16 #include "webrtc/libjingle/xmpp/xmppengine.h" 17 #include "webrtc/libjingle/xmpp/xmppstanzaparser.h" 18 19 namespace buzz { 20 21 class XmppLoginTask; 22 class XmppEngine; 23 class XmppIqEntry; 24 class SaslHandler; 25 class SaslMechanism; 26 27 //! The XMPP connection engine. 28 //! This engine implements the client side of the 'core' XMPP protocol. 29 //! To use it, register an XmppOutputHandler to handle socket output 30 //! and pass socket input to HandleInput. Then application code can 31 //! set up the connection with a user, password, and other settings, 32 //! and then call Connect() to initiate the connection. 33 //! An application can listen for events and receive stanzas by 34 //! registering an XmppStanzaHandler via AddStanzaHandler(). 35 class XmppEngineImpl : public XmppEngine { 36 public: 37 XmppEngineImpl(); 38 virtual ~XmppEngineImpl(); 39 40 // SOCKET INPUT AND OUTPUT ------------------------------------------------ 41 42 //! Registers the handler for socket output 43 virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh); 44 45 //! Provides socket input to the engine 46 virtual XmppReturnStatus HandleInput(const char* bytes, size_t len); 47 48 //! Advises the engine that the socket has closed 49 virtual XmppReturnStatus ConnectionClosed(int subcode); 50 51 // SESSION SETUP --------------------------------------------------------- 52 53 //! Indicates the (bare) JID for the user to use. 54 virtual XmppReturnStatus SetUser(const Jid& jid); 55 56 //! Get the login (bare) JID. 57 virtual const Jid& GetUser(); 58 59 //! Indicates the autentication to use. Takes ownership of the object. 60 virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler); 61 62 //! Sets whether TLS will be used within the connection (default true). 63 virtual XmppReturnStatus SetTls(TlsOptions use_tls); 64 65 //! Sets an alternate domain from which we allows TLS certificates. 66 //! This is for use in the case where a we want to allow a proxy to 67 //! serve up its own certificate rather than one owned by the underlying 68 //! domain. 69 virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname, 70 const std::string& proxy_domain); 71 72 //! Gets whether TLS will be used within the connection. 73 virtual TlsOptions GetTls(); 74 75 //! Sets the request resource name, if any (optional). 76 //! Note that the resource name may be overridden by the server; after 77 //! binding, the actual resource name is available as part of FullJid(). 78 virtual XmppReturnStatus SetRequestedResource(const std::string& resource); 79 80 //! Gets the request resource name. 81 virtual const std::string& GetRequestedResource(); 82 83 //! Sets language SetLanguage(const std::string & lang)84 virtual void SetLanguage(const std::string& lang) { 85 lang_ = lang; 86 } 87 88 // SESSION MANAGEMENT --------------------------------------------------- 89 90 //! Set callback for state changes. 91 virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler); 92 93 //! Initiates the XMPP connection. 94 //! After supplying connection settings, call this once to initiate, 95 //! (optionally) encrypt, authenticate, and bind the connection. 96 virtual XmppReturnStatus Connect(); 97 98 //! The current engine state. GetState()99 virtual State GetState() { return state_; } 100 101 //! Returns true if the connection is encrypted (under TLS) IsEncrypted()102 virtual bool IsEncrypted() { return encrypted_; } 103 104 //! The error code. 105 //! Consult this after XmppOutputHandler.OnClose(). GetError(int * subcode)106 virtual Error GetError(int *subcode) { 107 if (subcode) { 108 *subcode = subcode_; 109 } 110 return error_code_; 111 } 112 113 //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM. 114 //! Notice the stanza returned is owned by the XmppEngine and 115 //! is deleted when the engine is destroyed. GetStreamError()116 virtual const XmlElement* GetStreamError() { return stream_error_.get(); } 117 118 //! Closes down the connection. 119 //! Sends CloseConnection to output, and disconnects and registered 120 //! session handlers. After Disconnect completes, it is guaranteed 121 //! that no further callbacks will be made. 122 virtual XmppReturnStatus Disconnect(); 123 124 // APPLICATION USE ------------------------------------------------------- 125 126 //! Adds a listener for session events. 127 //! Stanza delivery is chained to session handlers; the first to 128 //! return 'true' is the last to get each stanza. 129 virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, 130 XmppEngine::HandlerLevel level); 131 132 //! Removes a listener for session events. 133 virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler); 134 135 //! Sends a stanza to the server. 136 virtual XmppReturnStatus SendStanza(const XmlElement* stanza); 137 138 //! Sends raw text to the server 139 virtual XmppReturnStatus SendRaw(const std::string& text); 140 141 //! Sends an iq to the server, and registers a callback for the result. 142 //! Returns the cookie passed to the result handler. 143 virtual XmppReturnStatus SendIq(const XmlElement* stanza, 144 XmppIqHandler* iq_handler, 145 XmppIqCookie* cookie); 146 147 //! Unregisters an iq callback handler given its cookie. 148 //! No callback will come to this handler after it's unregistered. 149 virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, 150 XmppIqHandler** iq_handler); 151 152 //! Forms and sends an error in response to the given stanza. 153 //! Swaps to and from, sets type to "error", and adds error information 154 //! based on the passed code. Text is optional and may be STR_EMPTY. 155 virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal, 156 XmppStanzaError code, 157 const std::string& text); 158 159 //! The fullly bound JID. 160 //! This JID is only valid after binding has succeeded. If the value 161 //! is JID_NULL, the binding has not succeeded. FullJid()162 virtual const Jid& FullJid() { return bound_jid_; } 163 164 //! The next unused iq id for this connection. 165 //! Call this when building iq stanzas, to ensure that each iq 166 //! gets its own unique id. 167 virtual std::string NextId(); 168 169 private: 170 friend class XmppLoginTask; 171 friend class XmppIqEntry; 172 173 void IncomingStanza(const XmlElement *stanza); 174 void IncomingStart(const XmlElement *stanza); 175 void IncomingEnd(bool isError); 176 177 void InternalSendStart(const std::string& domainName); 178 void InternalSendStanza(const XmlElement* stanza); 179 std::string ChooseBestSaslMechanism( 180 const std::vector<std::string>& mechanisms, bool encrypted); 181 SaslMechanism* GetSaslMechanism(const std::string& name); 182 void SignalBound(const Jid& fullJid); 183 void SignalStreamError(const XmlElement* streamError); 184 void SignalError(Error errorCode, int subCode); 185 bool HasError(); 186 void DeleteIqCookies(); 187 bool HandleIqResponse(const XmlElement* element); 188 void StartTls(const std::string& domain); RaiseReset()189 void RaiseReset() { raised_reset_ = true; } 190 191 class StanzaParseHandler : public XmppStanzaParseHandler { 192 public: StanzaParseHandler(XmppEngineImpl * outer)193 StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {} ~StanzaParseHandler()194 virtual ~StanzaParseHandler() {} 195 StartStream(const XmlElement * stream)196 virtual void StartStream(const XmlElement* stream) { 197 outer_->IncomingStart(stream); 198 } Stanza(const XmlElement * stanza)199 virtual void Stanza(const XmlElement* stanza) { 200 outer_->IncomingStanza(stanza); 201 } EndStream()202 virtual void EndStream() { 203 outer_->IncomingEnd(false); 204 } XmlError()205 virtual void XmlError() { 206 outer_->IncomingEnd(true); 207 } 208 209 private: 210 XmppEngineImpl* const outer_; 211 }; 212 213 class EnterExit { 214 public: 215 EnterExit(XmppEngineImpl* engine); 216 ~EnterExit(); 217 private: 218 XmppEngineImpl* engine_; 219 State state_; 220 }; 221 222 friend class StanzaParseHandler; 223 friend class EnterExit; 224 225 StanzaParseHandler stanza_parse_handler_; 226 XmppStanzaParser stanza_parser_; 227 228 // state 229 int engine_entered_; 230 Jid user_jid_; 231 std::string password_; 232 std::string requested_resource_; 233 TlsOptions tls_option_; 234 std::string tls_server_hostname_; 235 std::string tls_server_domain_; 236 rtc::scoped_ptr<XmppLoginTask> login_task_; 237 std::string lang_; 238 239 int next_id_; 240 Jid bound_jid_; 241 State state_; 242 bool encrypted_; 243 Error error_code_; 244 int subcode_; 245 rtc::scoped_ptr<XmlElement> stream_error_; 246 bool raised_reset_; 247 XmppOutputHandler* output_handler_; 248 XmppSessionHandler* session_handler_; 249 250 XmlnsStack xmlns_stack_; 251 252 typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector; 253 rtc::scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT]; 254 255 typedef std::vector<XmppIqEntry*> IqEntryVector; 256 rtc::scoped_ptr<IqEntryVector> iq_entries_; 257 258 rtc::scoped_ptr<SaslHandler> sasl_handler_; 259 260 rtc::scoped_ptr<std::stringstream> output_; 261 }; 262 263 } // namespace buzz 264 265 #endif // WEBRTC_LIBJINGLE_XMPP_XMPPENGINEIMPL_H_ 266