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