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
36namespace buzz {
37
38class XmppLoginTask;
39class XmppEngine;
40class XmppIqEntry;
41class SaslHandler;
42class 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().
52class 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