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