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
19namespace buzz {
20
21class XmppLoginTask;
22class XmppEngine;
23class XmppIqEntry;
24class SaslHandler;
25class 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().
35class 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
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.
99  virtual State GetState() { return state_; }
100
101  //! Returns true if the connection is encrypted (under TLS)
102  virtual bool IsEncrypted() { return encrypted_; }
103
104  //! The error code.
105  //! Consult this after XmppOutputHandler.OnClose().
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.
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.
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);
189  void RaiseReset() { raised_reset_ = true; }
190
191  class StanzaParseHandler : public XmppStanzaParseHandler {
192   public:
193    StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {}
194    virtual ~StanzaParseHandler() {}
195
196    virtual void StartStream(const XmlElement* stream) {
197      outer_->IncomingStart(stream);
198    }
199    virtual void Stanza(const XmlElement* stanza) {
200      outer_->IncomingStanza(stanza);
201    }
202    virtual void EndStream() {
203      outer_->IncomingEnd(false);
204    }
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