1 /*
2  * Copyright (c) 2007-2019 by Jakob Schröter <js@camaya.net>
3  * This file is part of the gloox library. http://camaya.net/gloox
4  *
5  * This software is distributed under a license. The full license
6  * agreement can be found in the file LICENSE in this distribution.
7  * This software may not be copied, modified, sold or distributed
8  * other than expressed in the named license agreement.
9  *
10  * This software is distributed without any warranty.
11  */
12 
13 #ifndef CONNECTIONBOSH_H__
14 #define CONNECTIONBOSH_H__
15 
16 #include "gloox.h"
17 #include "connectionbase.h"
18 #include "logsink.h"
19 #include "taghandler.h"
20 #include "parser.h"
21 
22 #include <string>
23 #include <list>
24 #include <ctime>
25 
26 namespace gloox
27 {
28 
29   /**
30    * @brief This is an implementation of a BOSH (HTTP binding) connection.
31    *
32    * Usage:
33    *
34    * @code
35    * Client *c = new Client( ... );
36    * c->setConnectionImpl( new ConnectionBOSH( c,
37    *                                new ConnectionTCPClient( c->logInstance(), httpServer, httpPort ),
38    *                                c->logInstance(), boshHost, xmpphost, xmppPort ) );
39    * @endcode
40    *
41    * Make sure to pass the BOSH connection manager's host/port to the transport connection
42    * (ConnectionTCPClient in this case), and the XMPP server's host and port to the BOSH connection.
43    * You must also pass to BOSH the address of the BOSH server you are dealing with, this is used
44    * in the HTTP Host header.
45    *
46    * In the case of using ConnectionBOSH through a HTTP proxy, supply httpServer and httpPort as
47    * those of the proxy. In all cases, boshHost should be set to the hostname (not IP address) of
48    * the server running the BOSH connection manager.
49    *
50    * The reason why ConnectionBOSH doesn't manage its own ConnectionTCPClient is that it allows it
51    * to be used with other transports (like chained SOCKS5/HTTP proxies, or ConnectionTLS
52    * for HTTPS).
53    *
54    * @note To avoid problems, you should disable TLS in gloox by calling
55    * ClientBase::setTls( TLSDisabled ).
56    *
57    * Sample configurations for different servers can be found in the bosh_example.cpp file included
58    * with gloox in the @b src/examples/ directory.
59    *
60    * @author Matthew Wild <mwild1@gmail.com>
61    * @author Jakob Schröter <js@camaya.net>
62    * @since 1.0
63    */
64   class GLOOX_API ConnectionBOSH : public ConnectionBase, ConnectionDataHandler, TagHandler
65   {
66     public:
67       /**
68        * Constructs a new ConnectionBOSH object.
69        * @param connection A transport connection. It should be configured to connect to
70        * the BOSH connection manager's (or a HTTP proxy's) host and port, @b not to the XMPP host.
71        * ConnectionBOSH will own the transport connection and delete it in its destructor.
72        * @param logInstance The log target. Obtain it from ClientBase::logInstance().
73        * @param boshHost The hostname of the BOSH connection manager
74        * @param xmppServer A server to connect to. This is the XMPP server's address, @b not the
75        * connection manager's.
76        * @param xmppPort The port to connect to. This is the XMPP server's port, @b not the connection
77        * manager's.
78        * @note To properly use this object, you have to set a ConnectionDataHandler using
79        * registerConnectionDataHandler(). This is not necessary if this object is
80        * part of a 'connection chain', e.g. with ConnectionSOCKS5Proxy.
81        */
82       ConnectionBOSH( ConnectionBase* connection, const LogSink& logInstance, const std::string& boshHost,
83                       const std::string& xmppServer, int xmppPort = 5222 );
84 
85       /**
86        * Constructs a new ConnectionBOSH object.
87        * @param cdh An ConnectionDataHandler-derived object that will handle incoming data.
88        * @param connection A transport connection. It should be configured to connect to
89        * the connection manager's (or proxy's) host and port, @b not to the XMPP host. ConnectionBOSH
90        * will own the transport connection and delete it in its destructor.
91        * @param logInstance The log target. Obtain it from ClientBase::logInstance().
92        * @param boshHost The hostname of the BOSH connection manager (not any intermediate proxy)
93        * @param xmppServer A server to connect to. This is the XMPP server's address, @b not the connection
94        * manager's.
95        * @param xmppPort The port to connect to. This is the XMPP server's port, @b not the connection
96        * manager's.
97        */
98       ConnectionBOSH( ConnectionDataHandler* cdh, ConnectionBase* connection,
99                       const LogSink& logInstance, const std::string& boshHost,
100                       const std::string& xmppServer, int xmppPort = 5222 );
101 
102       /**
103        * Virtual destructor
104        */
105       virtual ~ConnectionBOSH();
106 
107       /**
108        * The supported connection modes. Usually auto-detected.
109        */
110       enum ConnMode
111       {
112         ModeLegacyHTTP,             /**< HTTP 1.0 connections, closed after receiving a response */
113         ModePersistentHTTP,         /**< HTTP 1.1 connections, re-used after receiving a response */
114         ModePipelining              /**< HTTP Pipelining (implies HTTP 1.1) a single connection is used */
115       };
116 
117       /**
118        * Sets the XMPP server to proxy to.
119        * @param xmppHost The XMPP server hostname (IP address).
120        * @param xmppPort The XMPP server port.
121        */
122       void setServer( const std::string& xmppHost, unsigned short xmppPort = 5222 )
123         { m_server = xmppHost; m_port = xmppPort; }
124 
125       /**
126        * Sets the path on the connection manager to request
127        * @param path The path, the default is "/http-bind/", which is the default for
128        * many connection managers.
129        */
setPath(const std::string & path)130       void setPath( const std::string& path ) { m_path = path; }
131 
132       /**
133        * Sets the connection mode
134        * @param mode The connection mode, @sa ConnMode
135        * @note In the case that a mode is selected that the connection manager
136        * or proxy does not support, gloox will fall back to using HTTP/1.0 connections,
137        * which should work with any server.
138        */
setMode(ConnMode mode)139       void setMode( ConnMode mode ) { m_connMode = mode; }
140 
141       // reimplemented from ConnectionBase
142       virtual ConnectionError connect();
143 
144       // reimplemented from ConnectionBase
145       virtual ConnectionError recv( int timeout = -1 );
146 
147       // reimplemented from ConnectionBase
148       virtual bool send( const std::string& data );
149 
150       // reimplemented from ConnectionBase
151       virtual ConnectionError receive();
152 
153       // reimplemented from ConnectionBase
154       virtual void disconnect();
155 
156       // reimplemented from ConnectionBase
157       virtual void cleanup();
158 
159       // reimplemented from ConnectionBase
160       virtual void getStatistics( long int& totalIn, long int& totalOut );
161 
162       // reimplemented from ConnectionDataHandler
163       virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data );
164 
165       // reimplemented from ConnectionDataHandler
166       virtual void handleConnect( const ConnectionBase* connection );
167 
168       // reimplemented from ConnectionDataHandler
169       virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason );
170 
171       // reimplemented from ConnectionDataHandler
172       virtual ConnectionBase* newInstance() const;
173 
174       // reimplemented from TagHandler
175       virtual void handleTag( Tag* tag );
176 
177     private:
178       ConnectionBOSH& operator=( const ConnectionBOSH& );
179       void initInstance( ConnectionBase* connection, const std::string& xmppServer, const int xmppPort );
180       bool sendRequest( const std::string& xml );
181       bool sendXML();
182       const std::string getHTTPField( const std::string& field );
183       ConnectionBase* getConnection();
184       ConnectionBase* activateConnection();
185       void putConnection();
186 
187       //ConnectionBase *m_connection;
188       const LogSink& m_logInstance;
189 
190       Parser m_parser;   // Used for parsing XML section of responses
191       std::string m_boshHost;   // The hostname of the BOSH connection manager
192       std::string m_boshedHost;   // The hostname of the BOSH connection manager + : + port
193       std::string m_path;   // The path part of the URL that we need to request
194 
195       // BOSH parameters
196       unsigned long m_rid;
197       std::string m_sid;
198 
199       bool m_initialStreamSent;
200       int m_openRequests;
201       int m_maxOpenRequests;
202       int m_wait;
203       int m_hold;
204 
205       bool m_streamRestart;   // Set to true if we are waiting for an acknowledgement of a stream restart
206 
207       time_t m_lastRequestTime;
208       unsigned long m_minTimePerRequest;
209 
210       std::string m_buffer;   // Buffer of received data
211       std::string m_bufferHeader;   // HTTP header of data currently in buffer // FIXME doens't need to be member
212       std::string::size_type m_bufferContentLength;   // Length of the data in the current response
213 
214       std::string m_sendBuffer;   // Data waiting to be sent
215 
216       typedef std::list<ConnectionBase*> ConnectionList;
217       ConnectionList m_activeConnections;
218       ConnectionList m_connectionPool;
219       ConnMode m_connMode;
220 
221   };
222 
223 }
224 
225 #endif // CONNECTIONBOSH_H__
226