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_XMPPENGINE_H_
12 #define THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINE_H_
13 
14 // also part of the API
15 #include "third_party/libjingle_xmpp/xmllite/qname.h"
16 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
17 #include "third_party/libjingle_xmpp/xmpp/jid.h"
18 
19 
20 namespace jingle_xmpp {
21 
22 class XmppEngine;
23 class SaslHandler;
24 typedef void * XmppIqCookie;
25 
26 //! XMPP stanza error codes.
27 //! Used in XmppEngine.SendStanzaError().
28 enum XmppStanzaError {
29   XSE_BAD_REQUEST,
30   XSE_CONFLICT,
31   XSE_FEATURE_NOT_IMPLEMENTED,
32   XSE_FORBIDDEN,
33   XSE_GONE,
34   XSE_INTERNAL_SERVER_ERROR,
35   XSE_ITEM_NOT_FOUND,
36   XSE_JID_MALFORMED,
37   XSE_NOT_ACCEPTABLE,
38   XSE_NOT_ALLOWED,
39   XSE_PAYMENT_REQUIRED,
40   XSE_RECIPIENT_UNAVAILABLE,
41   XSE_REDIRECT,
42   XSE_REGISTRATION_REQUIRED,
43   XSE_SERVER_NOT_FOUND,
44   XSE_SERVER_TIMEOUT,
45   XSE_RESOURCE_CONSTRAINT,
46   XSE_SERVICE_UNAVAILABLE,
47   XSE_SUBSCRIPTION_REQUIRED,
48   XSE_UNDEFINED_CONDITION,
49   XSE_UNEXPECTED_REQUEST,
50 };
51 
52 // XmppReturnStatus
53 //    This is used by API functions to synchronously return status.
54 enum XmppReturnStatus {
55   XMPP_RETURN_OK,
56   XMPP_RETURN_BADARGUMENT,
57   XMPP_RETURN_BADSTATE,
58   XMPP_RETURN_PENDING,
59   XMPP_RETURN_UNEXPECTED,
60   XMPP_RETURN_NOTYETIMPLEMENTED,
61 };
62 
63 // TlsOptions
64 //    This is used by API to identify TLS setting.
65 enum TlsOptions {
66   TLS_DISABLED,
67   TLS_ENABLED,
68   TLS_REQUIRED
69 };
70 
71 //! Callback for socket output for an XmppEngine connection.
72 //! Register via XmppEngine.SetOutputHandler.  An XmppEngine
73 //! can call back to this handler while it is processing
74 //! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
75 class XmppOutputHandler {
76 public:
~XmppOutputHandler()77   virtual ~XmppOutputHandler() {}
78 
79   //! Deliver the specified bytes to the XMPP socket.
80   virtual void WriteOutput(const char * bytes, size_t len) = 0;
81 
82   //! Initiate TLS encryption on the socket.
83   //! The implementation must verify that the SSL
84   //! certificate matches the given domainname.
85   virtual void StartTls(const std::string & domainname) = 0;
86 
87   //! Called when engine wants the connecton closed.
88   virtual void CloseConnection() = 0;
89 };
90 
91 //! Callback to deliver engine state change notifications
92 //! to the object managing the engine.
93 class XmppSessionHandler {
94 public:
~XmppSessionHandler()95   virtual ~XmppSessionHandler() {}
96   //! Called when engine changes state. Argument is new state.
97   virtual void OnStateChange(int state) = 0;
98 };
99 
100 //! Callback to deliver stanzas to an Xmpp application module.
101 //! Register via XmppEngine.SetDefaultSessionHandler or via
102 //! XmppEngine.AddSessionHAndler.
103 class XmppStanzaHandler {
104 public:
~XmppStanzaHandler()105   virtual ~XmppStanzaHandler() {}
106   //! Process the given stanza.
107   //! The handler must return true if it has handled the stanza.
108   //! A false return value causes the stanza to be passed on to
109   //! the next registered handler.
110   virtual bool HandleStanza(const XmlElement * stanza) = 0;
111 };
112 
113 //! Callback to deliver iq responses (results and errors).
114 //! Register while sending an iq via XmppEngine.SendIq.
115 //! Iq responses are routed to matching XmppIqHandlers in preference
116 //! to sending to any registered SessionHandlers.
117 class XmppIqHandler {
118 public:
~XmppIqHandler()119   virtual ~XmppIqHandler() {}
120   //! Called to handle the iq response.
121   //! The response may be either a result or an error, and will have
122   //! an 'id' that matches the request and a 'from' that matches the
123   //! 'to' of the request.  Called no more than once; once this is
124   //! called, the handler is automatically unregistered.
125   virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
126 };
127 
128 //! The XMPP connection engine.
129 //! This engine implements the client side of the 'core' XMPP protocol.
130 //! To use it, register an XmppOutputHandler to handle socket output
131 //! and pass socket input to HandleInput.  Then application code can
132 //! set up the connection with a user, password, and other settings,
133 //! and then call Connect() to initiate the connection.
134 //! An application can listen for events and receive stanzas by
135 //! registering an XmppStanzaHandler via AddStanzaHandler().
136 class XmppEngine {
137 public:
138   static XmppEngine * Create();
~XmppEngine()139   virtual ~XmppEngine() {}
140 
141   //! Error codes. See GetError().
142   enum Error {
143     ERROR_NONE = 0,         //!< No error
144     ERROR_XML,              //!< Malformed XML or encoding error
145     ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
146     ERROR_VERSION,          //!< XMPP version error
147     ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
148     ERROR_TLS,              //!< TLS could not be negotiated
149     ERROR_AUTH,             //!< Authentication could not be negotiated
150     ERROR_BIND,             //!< Resource or session binding could not be negotiated
151     ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
152     ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
153     ERROR_SOCKET,           //!< Socket error
154     ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
155     ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
156   };
157 
158   //! States.  See GetState().
159   enum State {
160     STATE_NONE = 0,        //!< Nonexistent state
161     STATE_START,           //!< Initial state.
162     STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
163     STATE_OPEN,            //!< Authenticated and bound.
164     STATE_CLOSED,          //!< Session closed, possibly due to error.
165   };
166 
167   // SOCKET INPUT AND OUTPUT ------------------------------------------------
168 
169   //! Registers the handler for socket output
170   virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
171 
172   //! Provides socket input to the engine
173   virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
174 
175   //! Advises the engine that the socket has closed
176   virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
177 
178   // SESSION SETUP ---------------------------------------------------------
179 
180   //! Indicates the (bare) JID for the user to use.
181   virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
182 
183   //! Get the login (bare) JID.
184   virtual const Jid & GetUser() = 0;
185 
186   //! Provides different methods for credentials for login.
187   //! Takes ownership of this object; deletes when login is done
188   virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
189 
190   //! Sets whether TLS will be used within the connection (default true).
191   virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0;
192 
193   //! Sets an alternate domain from which we allows TLS certificates.
194   //! This is for use in the case where a we want to allow a proxy to
195   //! serve up its own certificate rather than one owned by the underlying
196   //! domain.
197   virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
198                                         const std::string & proxy_domain) = 0;
199 
200   //! Gets whether TLS will be used within the connection.
201   virtual TlsOptions GetTls() = 0;
202 
203   //! Sets the request resource name, if any (optional).
204   //! Note that the resource name may be overridden by the server; after
205   //! binding, the actual resource name is available as part of FullJid().
206   virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
207 
208   //! Gets the request resource name.
209   virtual const std::string & GetRequestedResource() = 0;
210 
211   //! Sets language
212   virtual void SetLanguage(const std::string & lang) = 0;
213 
214   // SESSION MANAGEMENT ---------------------------------------------------
215 
216   //! Set callback for state changes.
217   virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
218 
219   //! Initiates the XMPP connection.
220   //! After supplying connection settings, call this once to initiate,
221   //! (optionally) encrypt, authenticate, and bind the connection.
222   virtual XmppReturnStatus Connect() = 0;
223 
224   //! The current engine state.
225   virtual State GetState() = 0;
226 
227   //! Returns true if the connection is encrypted (under TLS)
228   virtual bool IsEncrypted() = 0;
229 
230   //! The error code.
231   //! Consult this after XmppOutputHandler.OnClose().
232   virtual Error GetError(int *subcode) = 0;
233 
234   //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
235   //! Notice the stanza returned is owned by the XmppEngine and
236   //! is deleted when the engine is destroyed.
237   virtual const XmlElement * GetStreamError() = 0;
238 
239   //! Closes down the connection.
240   //! Sends CloseConnection to output, and disconnects and registered
241   //! session handlers.  After Disconnect completes, it is guaranteed
242   //! that no further callbacks will be made.
243   virtual XmppReturnStatus Disconnect() = 0;
244 
245   // APPLICATION USE -------------------------------------------------------
246 
247   enum HandlerLevel {
248     HL_NONE = 0,
249     HL_PEEK,   //!< Sees messages before all other processing; cannot abort
250     HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
251     HL_SENDER, //!< Watches for a type of message from a specific sender
252     HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
253     HL_ALL,    //!< Watches all messages - gets last shot
254     HL_COUNT,  //!< Count of handler levels
255   };
256 
257   //! Adds a listener for session events.
258   //! Stanza delivery is chained to session handlers; the first to
259   //! return 'true' is the last to get each stanza.
260   virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
261 
262   //! Removes a listener for session events.
263   virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
264 
265   //! Sends a stanza to the server.
266   virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
267 
268   //! Sends raw text to the server
269   virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
270 
271   //! Sends an iq to the server, and registers a callback for the result.
272   //! Returns the cookie passed to the result handler.
273   virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
274                                   XmppIqHandler* iq_handler,
275                                   XmppIqCookie* cookie) = 0;
276 
277   //! Unregisters an iq callback handler given its cookie.
278   //! No callback will come to this handler after it's unregistered.
279   virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
280                                       XmppIqHandler** iq_handler) = 0;
281 
282 
283   //! Forms and sends an error in response to the given stanza.
284   //! Swaps to and from, sets type to "error", and adds error information
285   //! based on the passed code.  Text is optional and may be STR_EMPTY.
286   virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
287                                            XmppStanzaError code,
288                                            const std::string & text) = 0;
289 
290   //! The fullly bound JID.
291   //! This JID is only valid after binding has succeeded.  If the value
292   //! is JID_NULL, the binding has not succeeded.
293   virtual const Jid & FullJid() = 0;
294 
295   //! The next unused iq id for this connection.
296   //! Call this when building iq stanzas, to ensure that each iq
297   //! gets its own unique id.
298   virtual std::string NextId() = 0;
299 
300 };
301 
302 }
303 
304 
305 // Move these to a better location
306 
307 #define XMPP_FAILED(x)                      \
308   ( (x) == jingle_xmpp::XMPP_RETURN_OK ? false : true)   \
309 
310 
311 #define XMPP_SUCCEEDED(x)                   \
312   ( (x) == jingle_xmpp::XMPP_RETURN_OK ? true : false)   \
313 
314 #define IFR(x)                        \
315   do {                                \
316     xmpp_status = (x);                \
317     if (XMPP_FAILED(xmpp_status)) {   \
318       return xmpp_status;             \
319     }                                 \
320   } while (false)                     \
321 
322 
323 #define IFC(x)                        \
324   do {                                \
325     xmpp_status = (x);                \
326     if (XMPP_FAILED(xmpp_status)) {   \
327       goto Cleanup;                   \
328     }                                 \
329   } while (false)                     \
330 
331 
332 #endif  // THIRD_PARTY_LIBJINGLE_XMPP_XMPP_XMPPENGINE_H_
333