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