1 /*
2 
3 Copyright (c) 2009-2018, Arvid Norberg
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #ifndef TORRENT_SOCKET_TYPE
34 #define TORRENT_SOCKET_TYPE
35 
36 #include "libtorrent/config.hpp"
37 #include "libtorrent/aux_/aligned_union.hpp"
38 #include "libtorrent/socket.hpp"
39 #include "libtorrent/socks5_stream.hpp"
40 #include "libtorrent/http_stream.hpp"
41 #include "libtorrent/i2p_stream.hpp"
42 #include "libtorrent/utp_stream.hpp"
43 #include "libtorrent/io_service.hpp"
44 #include "libtorrent/assert.hpp"
45 
46 #ifdef TORRENT_USE_OPENSSL
47 #include "libtorrent/ssl_stream.hpp"
48 #endif
49 
50 #include "libtorrent/debug.hpp"
51 
52 #if defined TORRENT_OS2 && defined ioc
53 #undef ioc
54 #endif
55 
56 #if TORRENT_USE_I2P
57 
58 #define TORRENT_SOCKTYPE_I2P_FORWARD(x) \
59 		case socket_type_int_impl<i2p_stream>::value: \
60 			get<i2p_stream>()->x; break;
61 
62 #define TORRENT_SOCKTYPE_I2P_FORWARD_RET(x, def) \
63 		case socket_type_int_impl<i2p_stream>::value: \
64 			return get<i2p_stream>()->x;
65 
66 #else // TORRENT_USE_I2P
67 
68 #define TORRENT_SOCKTYPE_I2P_FORWARD(x)
69 #define TORRENT_SOCKTYPE_I2P_FORWARD_RET(x, def)
70 
71 #endif
72 
73 #ifdef TORRENT_USE_OPENSSL
74 
75 #define TORRENT_SOCKTYPE_SSL_FORWARD(x) \
76 		case socket_type_int_impl<ssl_stream<tcp::socket>>::value: \
77 			get<ssl_stream<tcp::socket>>()->x; break; \
78 		case socket_type_int_impl<ssl_stream<socks5_stream>>::value: \
79 			get<ssl_stream<socks5_stream>>()->x; break; \
80 		case socket_type_int_impl<ssl_stream<http_stream>>::value: \
81 			get<ssl_stream<http_stream>>()->x; break; \
82 		case socket_type_int_impl<ssl_stream<utp_stream>>::value: \
83 			get<ssl_stream<utp_stream>>()->x; break;
84 
85 #define TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \
86 		case socket_type_int_impl<ssl_stream<tcp::socket>>::value: \
87 			return get<ssl_stream<tcp::socket>>()->x; \
88 		case socket_type_int_impl<ssl_stream<socks5_stream>>::value: \
89 			return get<ssl_stream<socks5_stream>>()->x; \
90 		case socket_type_int_impl<ssl_stream<http_stream>>::value: \
91 			return get<ssl_stream<http_stream>>()->x; \
92 		case socket_type_int_impl<ssl_stream<utp_stream>>::value: \
93 			return get<ssl_stream<utp_stream>>()->x;
94 
95 #else
96 
97 #define TORRENT_SOCKTYPE_SSL_FORWARD(x)
98 #define TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def)
99 
100 #endif
101 
102 #define TORRENT_SOCKTYPE_FORWARD(x) \
103 	switch (m_type) { \
104 		case socket_type_int_impl<tcp::socket>::value: \
105 			get<tcp::socket>()->x; break; \
106 		case socket_type_int_impl<socks5_stream>::value: \
107 			get<socks5_stream>()->x; break; \
108 		case socket_type_int_impl<http_stream>::value: \
109 			get<http_stream>()->x; break; \
110 		case socket_type_int_impl<utp_stream>::value: \
111 			get<utp_stream>()->x; break; \
112 		TORRENT_SOCKTYPE_I2P_FORWARD(x) \
113 		TORRENT_SOCKTYPE_SSL_FORWARD(x) \
114 		default: TORRENT_ASSERT_FAIL(); \
115 	}
116 
117 #define TORRENT_SOCKTYPE_FORWARD_RET(x, def) \
118 	switch (m_type) { \
119 		case socket_type_int_impl<tcp::socket>::value: \
120 			return get<tcp::socket>()->x; \
121 		case socket_type_int_impl<socks5_stream>::value: \
122 			return get<socks5_stream>()->x; \
123 		case socket_type_int_impl<http_stream>::value: \
124 			return get<http_stream>()->x; \
125 		case socket_type_int_impl<utp_stream>::value: \
126 			return get<utp_stream>()->x; \
127 		TORRENT_SOCKTYPE_I2P_FORWARD_RET(x, def) \
128 		TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \
129 		default: TORRENT_ASSERT_FAIL(); return def; \
130 	}
131 
132 namespace libtorrent {
133 namespace aux {
134 
135 	template <class S>
136 	struct socket_type_int_impl
137 	{ static constexpr int value = 0; };
138 
139 	template <>
140 	struct socket_type_int_impl<tcp::socket>
141 	{ static constexpr int value = 1; };
142 
143 	template <>
144 	struct socket_type_int_impl<socks5_stream>
145 	{ static constexpr int value = 2; };
146 
147 	template <>
148 	struct socket_type_int_impl<http_stream>
149 	{ static constexpr int value = 3; };
150 
151 	template <>
152 	struct socket_type_int_impl<utp_stream>
153 	{ static constexpr int value = 4; };
154 
155 #if TORRENT_USE_I2P
156 	template <>
157 	struct socket_type_int_impl<i2p_stream>
158 	{ static constexpr int value = 5; };
159 #endif
160 
161 #ifdef TORRENT_USE_OPENSSL
162 	template <>
163 	struct socket_type_int_impl<ssl_stream<tcp::socket>>
164 	{ static constexpr int value = 6; };
165 
166 	template <>
167 	struct socket_type_int_impl<ssl_stream<socks5_stream>>
168 	{ static constexpr int value = 7; };
169 
170 	template <>
171 	struct socket_type_int_impl<ssl_stream<http_stream>>
172 	{ static constexpr int value = 8; };
173 
174 	template <>
175 	struct socket_type_int_impl<ssl_stream<utp_stream>>
176 	{ static constexpr int value = 9; };
177 #endif
178 
179 	struct TORRENT_EXTRA_EXPORT socket_type
180 	{
181 		using endpoint_type = tcp::socket::endpoint_type;
182 		using protocol_type = tcp::socket::protocol_type;
183 
184 		using receive_buffer_size = tcp::socket::receive_buffer_size;
185 		using send_buffer_size = tcp::socket::send_buffer_size;
186 
187 #if BOOST_VERSION >= 106600
188 		using executor_type = tcp::socket::executor_type;
189 #endif
190 
socket_typelibtorrent::aux::socket_type191 		explicit socket_type(io_service& ios): m_io_service(ios), m_type(0) {}
192 		~socket_type();
193 
194 		io_service& get_io_service() const;
195 		bool is_open() const;
196 
197 		char const* type_name() const;
198 
199 #ifndef BOOST_NO_EXCEPTIONS
200 		void open(protocol_type const& p);
201 		void close();
202 		endpoint_type local_endpoint() const;
203 		endpoint_type remote_endpoint() const;
204 		void bind(endpoint_type const& endpoint);
205 		std::size_t available() const;
206 #endif
207 
208 		void open(protocol_type const& p, error_code& ec);
209 		void close(error_code& ec);
210 
211 		// this is only relevant for uTP connections
212 		void set_close_reason(close_reason_t code);
213 		close_reason_t get_close_reason();
214 
215 		endpoint_type local_endpoint(error_code& ec) const;
216 		endpoint_type remote_endpoint(error_code& ec) const;
217 		void bind(endpoint_type const& endpoint, error_code& ec);
218 		std::size_t available(error_code& ec) const;
219 		int type() const;
220 
221 
222 		template <class Mutable_Buffers>
read_somelibtorrent::aux::socket_type223 		std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
224 		{ TORRENT_SOCKTYPE_FORWARD_RET(read_some(buffers, ec), 0) }
225 
226 		template <class Mutable_Buffers, class Handler>
async_read_somelibtorrent::aux::socket_type227 		void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
228 		{ TORRENT_SOCKTYPE_FORWARD(async_read_some(buffers, handler)) }
229 
230 		template <class Const_Buffers>
write_somelibtorrent::aux::socket_type231 		std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
232 		{ TORRENT_SOCKTYPE_FORWARD_RET(write_some(buffers, ec), 0) }
233 
234 		template <class Const_Buffers, class Handler>
async_write_somelibtorrent::aux::socket_type235 		void async_write_some(Const_Buffers const& buffers, Handler const& handler)
236 		{ TORRENT_SOCKTYPE_FORWARD(async_write_some(buffers, handler)) }
237 
238 		template <class Handler>
async_connectlibtorrent::aux::socket_type239 		void async_connect(endpoint_type const& endpoint, Handler const& handler)
240 		{ TORRENT_SOCKTYPE_FORWARD(async_connect(endpoint, handler)) }
241 
242 #ifndef BOOST_NO_EXCEPTIONS
243 		template <class IO_Control_Command>
io_controllibtorrent::aux::socket_type244 		void io_control(IO_Control_Command& ioc)
245 		{ TORRENT_SOCKTYPE_FORWARD(io_control(ioc)) }
246 
247 		template <class Mutable_Buffers>
read_somelibtorrent::aux::socket_type248 		std::size_t read_some(Mutable_Buffers const& buffers)
249 		{ TORRENT_SOCKTYPE_FORWARD_RET(read_some(buffers), 0) }
250 #endif
251 
252 		template <class IO_Control_Command>
io_controllibtorrent::aux::socket_type253 		void io_control(IO_Control_Command& ioc, error_code& ec)
254 		{ TORRENT_SOCKTYPE_FORWARD(io_control(ioc, ec)) }
255 
256 #ifndef BOOST_NO_EXCEPTIONS
257 		template <class SettableSocketOption>
set_optionlibtorrent::aux::socket_type258 		void set_option(SettableSocketOption const& opt)
259 		{ TORRENT_SOCKTYPE_FORWARD(set_option(opt)) }
260 #endif
261 
262 		template <class SettableSocketOption>
set_optionlibtorrent::aux::socket_type263 		error_code set_option(SettableSocketOption const& opt, error_code& ec)
264 		{ TORRENT_SOCKTYPE_FORWARD_RET(set_option(opt, ec), ec) }
265 
non_blockinglibtorrent::aux::socket_type266 		void non_blocking(bool b, error_code& ec)
267 		{ TORRENT_SOCKTYPE_FORWARD(non_blocking(b, ec)) }
268 
269 #ifndef BOOST_NO_EXCEPTIONS
non_blockinglibtorrent::aux::socket_type270 		void non_blocking(bool b)
271 		{ TORRENT_SOCKTYPE_FORWARD(non_blocking(b)) }
272 #endif
273 
274 #ifndef BOOST_NO_EXCEPTIONS
275 		template <class GettableSocketOption>
get_optionlibtorrent::aux::socket_type276 		void get_option(GettableSocketOption& opt)
277 		{ TORRENT_SOCKTYPE_FORWARD(get_option(opt)) }
278 #endif
279 
280 		template <class GettableSocketOption>
get_optionlibtorrent::aux::socket_type281 		error_code get_option(GettableSocketOption& opt, error_code& ec)
282 		{ TORRENT_SOCKTYPE_FORWARD_RET(get_option(opt, ec), ec) }
283 
284 		template <class S>
instantiatelibtorrent::aux::socket_type285 		void instantiate(io_service& ios, void* userdata = nullptr)
286 		{
287 			TORRENT_UNUSED(ios);
288 			TORRENT_ASSERT(&ios == &m_io_service);
289 			construct(socket_type_int_impl<S>::value, userdata);
290 		}
291 
getlibtorrent::aux::socket_type292 		template <class S> S* get()
293 		{
294 			if (m_type != socket_type_int_impl<S>::value) return nullptr;
295 			return reinterpret_cast<S*>(&m_data);
296 		}
297 
getlibtorrent::aux::socket_type298 		template <class S> S const* get() const
299 		{
300 			if (m_type != socket_type_int_impl<S>::value) return nullptr;
301 			return reinterpret_cast<S const*>(&m_data);
302 		}
303 
304 		// explicitly disallow assignment, to silence msvc warning
305 		socket_type& operator=(socket_type const&) = delete;
306 
307 	private:
308 
309 		void destruct();
310 		void construct(int type, void* userdata);
311 
312 		io_service& m_io_service;
313 		int m_type;
314 
315 		aux::aligned_union<1
316 			, tcp::socket
317 			, socks5_stream
318 			, http_stream
319 			, utp_stream
320 #if TORRENT_USE_I2P
321 			, i2p_stream
322 #endif
323 #ifdef TORRENT_USE_OPENSSL
324 			, ssl_stream<tcp::socket>
325 			, ssl_stream<socks5_stream>
326 			, ssl_stream<http_stream>
327 			, ssl_stream<utp_stream>
328 #endif
329 		>::type m_data;
330 	};
331 
332 	// returns true if this socket is an SSL socket
333 	bool is_ssl(socket_type const& s);
334 
335 	// returns true if this is a uTP socket
336 	bool is_utp(socket_type const& s);
337 
338 #if TORRENT_USE_I2P
339 	// returns true if this is an i2p socket
340 	bool is_i2p(socket_type const& s);
341 #endif
342 
343 	// assuming the socket_type s is an ssl socket, make sure it
344 	// verifies the hostname in its SSL handshake
345 	void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec);
346 
347 	// properly shuts down SSL sockets. holder keeps s alive
348 	void async_shutdown(socket_type& s, std::shared_ptr<void> holder);
349 }
350 }
351 
352 #endif
353