/* Copyright (c) 2009, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TORRENT_UTP_STREAM_HPP_INCLUDED #define TORRENT_UTP_STREAM_HPP_INCLUDED #include "libtorrent/connection_queue.hpp" #include "libtorrent/proxy_base.hpp" #include "libtorrent/udp_socket.hpp" #include "libtorrent/io.hpp" #include "libtorrent/packet_buffer.hpp" #include "libtorrent/error_code.hpp" #include #include #include #define CCONTROL_TARGET 100 namespace libtorrent { struct utp_socket_manager; // some MTU and protocol header sizes constants enum { TORRENT_IPV4_HEADER = 20, TORRENT_IPV6_HEADER = 40, TORRENT_UDP_HEADER = 8, TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address TORRENT_ETHERNET_MTU = 1500, TORRENT_TEREDO_MTU = 1280, TORRENT_INET_MIN_MTU = 576, TORRENT_INET_MAX_MTU = 0xffff }; // the point of the bif_endian_int is two-fold // one purpuse is to not have any alignment requirements // so that any byffer received from the network can be cast // to it and read as an integer of various sizes without // triggering a bus error. The other purpose is to convert // from network byte order to host byte order when read and // written, to offer a convenient interface to both interpreting // and writing network packets template struct big_endian_int { big_endian_int& operator=(T v) { char* p = m_storage; detail::write_impl(v, p); return *this; } operator T() const { const char* p = m_storage; return detail::read_impl(p, detail::type()); } private: char m_storage[sizeof(T)]; }; typedef big_endian_int be_uint64; typedef big_endian_int be_uint32; typedef big_endian_int be_uint16; typedef big_endian_int be_int64; typedef big_endian_int be_int32; typedef big_endian_int be_int16; /* uTP header from BEP 29 0 4 8 16 24 32 +-------+-------+---------------+---------------+---------------+ | type | ver | extension | connection_id | +-------+-------+---------------+---------------+---------------+ | timestamp_microseconds | +---------------+---------------+---------------+---------------+ | timestamp_difference_microseconds | +---------------+---------------+---------------+---------------+ | wnd_size | +---------------+---------------+---------------+---------------+ | seq_nr | ack_nr | +---------------+---------------+---------------+---------------+ */ enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES }; struct utp_header { unsigned char type_ver; unsigned char extension; be_uint16 connection_id; be_uint32 timestamp_microseconds; be_uint32 timestamp_difference_microseconds; be_uint32 wnd_size; be_uint16 seq_nr; be_uint16 ack_nr; int get_type() const { return type_ver >> 4; } int get_version() const { return type_ver & 0xf; } }; struct utp_socket_impl; utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id , boost::uint16_t send_id, void* userdata , utp_socket_manager* sm); void detach_utp_impl(utp_socket_impl* s); void delete_utp_impl(utp_socket_impl* s); bool should_delete(utp_socket_impl* s); void tick_utp_impl(utp_socket_impl* s, ptime const& now); void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu); bool utp_incoming_packet(utp_socket_impl* s, char const* p , int size, udp::endpoint const& ep, ptime receive_time); bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id); udp::endpoint utp_remote_endpoint(utp_socket_impl* s); boost::uint16_t utp_receive_id(utp_socket_impl* s); int utp_socket_state(utp_socket_impl const* s); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING int socket_impl_size(); #endif // this is the user-level stream interface to utp sockets. // the reason why it's split up in a utp_stream class and // an implementation class is because the socket state has // to be able to out-live the user level socket. For instance // when sending data on a stream and then closing it, the // state holding the send buffer has to be kept around until // it has been flushed, which may be longer than the client // will keep the utp_stream object around for. // for more details, see utp_socket_impl, which is analogous // to the kernel state for a socket. It's defined in utp_stream.cpp class TORRENT_EXPORT utp_stream { public: typedef stream_socket::endpoint_type endpoint_type; typedef stream_socket::protocol_type protocol_type; explicit utp_stream(asio::io_service& io_service); ~utp_stream(); // used for incoming connections void set_impl(utp_socket_impl* s); utp_socket_impl* get_impl(); #ifndef BOOST_NO_EXCEPTIONS template void io_control(IO_Control_Command& ioc) {} #endif template void io_control(IO_Control_Command& ioc, error_code& ec) {} #ifndef BOOST_NO_EXCEPTIONS void bind(endpoint_type const& endpoint) {} #endif void bind(endpoint_type const& endpoint, error_code& ec); #ifndef BOOST_NO_EXCEPTIONS template void set_option(SettableSocketOption const& opt) {} #endif template error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; } void close(); void close(error_code const& ec) { close(); } bool is_open() const { return m_open; } int read_buffer_size() const; static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill); static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill); static void on_connect(void* self, error_code const& ec, bool kill); typedef void(*handler_t)(void*, size_t, error_code const&, bool); typedef void(*connect_handler_t)(void*, error_code const&, bool); void add_read_buffer(void* buf, size_t len); void set_read_handler(handler_t h); void add_write_buffer(void const* buf, size_t len); void set_write_handler(handler_t h); size_t read_some(bool clear_buffers); int send_delay() const; void do_connect(tcp::endpoint const& ep, connect_handler_t h); endpoint_type local_endpoint() const { error_code ec; return local_endpoint(ec); } endpoint_type local_endpoint(error_code& ec) const; endpoint_type remote_endpoint() const { error_code ec; return remote_endpoint(ec); } endpoint_type remote_endpoint(error_code& ec) const; std::size_t available() const; std::size_t available(error_code& ec) const { return available(); } asio::io_service& io_service() { return m_io_service; } template void async_connect(endpoint_type const& endpoint, Handler const& handler) { if (!endpoint.address().is_v4()) { error_code ec = asio::error::operation_not_supported; m_io_service.post(boost::bind(handler, asio::error::operation_not_supported, 0)); return; } if (m_impl == 0) { m_io_service.post(boost::bind(handler, asio::error::not_connected, 0)); return; } m_connect_handler = handler; do_connect(endpoint, &utp_stream::on_connect); } template void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) { if (m_impl == 0) { m_io_service.post(boost::bind(handler, asio::error::not_connected, 0)); return; } TORRENT_ASSERT(!m_read_handler); if (m_read_handler) { m_io_service.post(boost::bind(handler, asio::error::operation_not_supported, 0)); return; } for (typename Mutable_Buffers::const_iterator i = buffers.begin() , end(buffers.end()); i != end; ++i) { TORRENT_ASSERT(buffer_size(*i) > 0); using asio::buffer_cast; using asio::buffer_size; add_read_buffer(buffer_cast(*i), buffer_size(*i)); } m_read_handler = handler; set_read_handler(&utp_stream::on_read); } void do_async_connect(endpoint_type const& ep , boost::function const& handler); template void open(Protocol const& p, error_code& ec) { m_open = true; } template void open(Protocol const& p) { m_open = true; } template std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) { TORRENT_ASSERT(!m_read_handler); if (m_impl == 0) { ec = asio::error::not_connected; return 0; } if (read_buffer_size() == 0) { ec = asio::error::would_block; return 0; } #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS size_t buf_size = 0; #endif for (typename Mutable_Buffers::const_iterator i = buffers.begin() , end(buffers.end()); i != end; ++i) { using asio::buffer_cast; using asio::buffer_size; add_read_buffer(buffer_cast(*i), buffer_size(*i)); #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS buf_size += buffer_size(*i); #endif } std::size_t ret = read_some(true); TORRENT_ASSERT(ret <= buf_size); TORRENT_ASSERT(ret > 0); return ret; } template std::size_t write_some(Const_Buffers const& buffers, error_code& ec) { // TODO: implement return 0; } template void async_write_some(Const_Buffers const& buffers, Handler const& handler) { if (m_impl == 0) { m_io_service.post(boost::bind(handler, asio::error::not_connected, 0)); return; } TORRENT_ASSERT(!m_write_handler); if (m_write_handler) { m_io_service.post(boost::bind(handler, asio::error::operation_not_supported, 0)); return; } for (typename Const_Buffers::const_iterator i = buffers.begin() , end(buffers.end()); i != end; ++i) { TORRENT_ASSERT(buffer_size(*i) > 0); using asio::buffer_cast; using asio::buffer_size; add_write_buffer((void*)buffer_cast(*i), buffer_size(*i)); } m_write_handler = handler; set_write_handler(&utp_stream::on_write); } //private: void cancel_handlers(error_code const&); boost::function1 m_connect_handler; boost::function2 m_read_handler; boost::function2 m_write_handler; asio::io_service& m_io_service; utp_socket_impl* m_impl; bool m_open; }; } #endif