merged back the asio development branch
This commit is contained in:
parent
410af930a7
commit
41810b1166
4
AUTHORS
4
AUTHORS
|
@ -1,8 +1,10 @@
|
||||||
|
|
||||||
Written by Arvid Norberg. Copyright (c) 2003-2005
|
Written by Arvid Norberg. Copyright (c) 2003-2006
|
||||||
|
|
||||||
Contributions by Magnus Jonsson, Daniel Wallin and Cory Nelson
|
Contributions by Magnus Jonsson, Daniel Wallin and Cory Nelson
|
||||||
|
|
||||||
|
Lots of testing, suggestions and contributions by Massaroddel.
|
||||||
|
|
||||||
Big thanks to Michael Wojciechowski and Peter Koeleman for making the
|
Big thanks to Michael Wojciechowski and Peter Koeleman for making the
|
||||||
autotools scripts.
|
autotools scripts.
|
||||||
|
|
||||||
|
|
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
* improved the piece picker performance and made it possible to download
|
||||||
|
popular pieces in sequence to improve disk performance.
|
||||||
|
* added the possibility to control upload and download limits per peer.
|
||||||
|
* fixed problem with re-requesting skipped pieces when peer was sending pieces
|
||||||
|
out of fifo-order.
|
||||||
|
* added support for http seeding (the GetRight protocol)
|
||||||
|
* renamed identifiers called 'id' in the public interface to support linking
|
||||||
|
with Objective.C++
|
||||||
|
* changed the extensions protocol to use the new one, which is also
|
||||||
|
implemented by uTorrent.
|
||||||
|
* factorized the peer_connection and added web_peer_connection which is
|
||||||
|
able to download from http-sources. (currently only for single file torrents).
|
||||||
|
* converted the network code to use asio
|
||||||
* made libtorrent build in vc7 (patches from Allen Zhao)
|
* made libtorrent build in vc7 (patches from Allen Zhao)
|
||||||
* fixed bug caused when binding outgoing connections to a non-local interface.
|
* fixed bug caused when binding outgoing connections to a non-local interface.
|
||||||
* add_torrent() will now throw if called while the session object is
|
* add_torrent() will now throw if called while the session object is
|
||||||
|
|
16
Jamfile
16
Jamfile
|
@ -23,6 +23,7 @@ project torrent
|
||||||
: requirements
|
: requirements
|
||||||
|
|
||||||
<include>./include
|
<include>./include
|
||||||
|
<include>./asio/include
|
||||||
<include>./zlib
|
<include>./zlib
|
||||||
<include>$(BOOST_ROOT)
|
<include>$(BOOST_ROOT)
|
||||||
<variant>release:<define>NDEBUG
|
<variant>release:<define>NDEBUG
|
||||||
|
@ -33,8 +34,19 @@ project torrent
|
||||||
<library>/boost/filesystem//boost_filesystem/<link>static
|
<library>/boost/filesystem//boost_filesystem/<link>static
|
||||||
<library>/boost/date_time//boost_date_time/<link>static
|
<library>/boost/date_time//boost_date_time/<link>static
|
||||||
<threading>multi
|
<threading>multi
|
||||||
|
<toolset>msvc:<define>_WIN32_WINNT=0x0500
|
||||||
|
# WIN32 makes sure the win32 socket api is used
|
||||||
|
# instead of win16
|
||||||
|
<toolset>msvc:<define>WIN32
|
||||||
|
# without WIN32_LEAN_AND_MEAN there will be conflicts between
|
||||||
|
# winsock.h and winsock2.h
|
||||||
|
<toolset>msvc:<define>WIN32_LEAN_AND_MEAN
|
||||||
|
# these compiler settings just makes the compiler standard conforming
|
||||||
<toolset>msvc:<cxxflags>/Zc:wchar_t
|
<toolset>msvc:<cxxflags>/Zc:wchar_t
|
||||||
<toolset>msvc:<cxxflags>/Zc:forScope
|
<toolset>msvc:<cxxflags>/Zc:forScope
|
||||||
|
# this should be defined when libtorrent is built as
|
||||||
|
# a dll. It will make sure the functions and classes
|
||||||
|
# are exported (GCC 4 and msvc)
|
||||||
<link>shared:<define>TORRENT_BUILDING_SHARED
|
<link>shared:<define>TORRENT_BUILDING_SHARED
|
||||||
|
|
||||||
: usage-requirements
|
: usage-requirements
|
||||||
|
@ -50,17 +62,17 @@ project torrent
|
||||||
SOURCES =
|
SOURCES =
|
||||||
allocate_resources.cpp
|
allocate_resources.cpp
|
||||||
alert.cpp
|
alert.cpp
|
||||||
async_gethostbyname.cpp
|
|
||||||
entry.cpp
|
entry.cpp
|
||||||
escape_string.cpp
|
escape_string.cpp
|
||||||
file.cpp
|
file.cpp
|
||||||
identify_client.cpp
|
identify_client.cpp
|
||||||
ip_filter.cpp
|
ip_filter.cpp
|
||||||
peer_connection.cpp
|
peer_connection.cpp
|
||||||
|
bt_peer_connection.cpp
|
||||||
|
web_peer_connection.cpp
|
||||||
piece_picker.cpp
|
piece_picker.cpp
|
||||||
policy.cpp
|
policy.cpp
|
||||||
session.cpp
|
session.cpp
|
||||||
socket.cpp
|
|
||||||
stat.cpp
|
stat.cpp
|
||||||
storage.cpp
|
storage.cpp
|
||||||
torrent.cpp
|
torrent.cpp
|
||||||
|
|
153
Makefile.am
153
Makefile.am
|
@ -4,13 +4,162 @@ docs/extension_protocol.html docs/udp_tracker_protocol.rst \
|
||||||
docs/udp_tracker_protocol.html docs/client_test.rst docs/client_test.html \
|
docs/udp_tracker_protocol.html docs/client_test.rst docs/client_test.html \
|
||||||
docs/unicode_support.png docs/client_test.png docs/style.css Jamfile project-root.jam \
|
docs/unicode_support.png docs/client_test.png docs/style.css Jamfile project-root.jam \
|
||||||
m4/ac_cxx_namespaces.m4 m4/acx_pthread.m4 m4/ax_boost_date-time.m4 \
|
m4/ac_cxx_namespaces.m4 m4/acx_pthread.m4 m4/ax_boost_date-time.m4 \
|
||||||
m4/ax_boost_filesystem.m4 m4/ax_boost_thread.m4 src/file_win.cpp libtorrent.pc
|
m4/ax_boost_filesystem.m4 m4/ax_boost_thread.m4 src/file_win.cpp libtorrent.pc \
|
||||||
|
asio/COPYING \
|
||||||
|
asio/INSTALL \
|
||||||
|
asio/LICENSE_1_0.txt \
|
||||||
|
asio/Makefile.am \
|
||||||
|
asio/README \
|
||||||
|
asio/THANKS \
|
||||||
|
asio/TODO \
|
||||||
|
asio/autogen.sh \
|
||||||
|
asio/boostify.pl \
|
||||||
|
asio/configure.ac \
|
||||||
|
asio/include/Makefile.am \
|
||||||
|
asio/include/asio.hpp \
|
||||||
|
asio/include/asio/basic_datagram_socket.hpp \
|
||||||
|
asio/include/asio/basic_deadline_timer.hpp \
|
||||||
|
asio/include/asio/basic_io_object.hpp \
|
||||||
|
asio/include/asio/basic_io_service.hpp \
|
||||||
|
asio/include/asio/basic_locking_dispatcher.hpp \
|
||||||
|
asio/include/asio/basic_socket.hpp \
|
||||||
|
asio/include/asio/basic_socket_acceptor.hpp \
|
||||||
|
asio/include/asio/basic_stream_socket.hpp \
|
||||||
|
asio/include/asio/buffer.hpp \
|
||||||
|
asio/include/asio/buffered_read_stream.hpp \
|
||||||
|
asio/include/asio/buffered_read_stream_fwd.hpp \
|
||||||
|
asio/include/asio/buffered_stream.hpp \
|
||||||
|
asio/include/asio/buffered_stream_fwd.hpp \
|
||||||
|
asio/include/asio/buffered_write_stream.hpp \
|
||||||
|
asio/include/asio/buffered_write_stream_fwd.hpp \
|
||||||
|
asio/include/asio/completion_condition.hpp \
|
||||||
|
asio/include/asio/datagram_socket_service.hpp \
|
||||||
|
asio/include/asio/deadline_timer.hpp \
|
||||||
|
asio/include/asio/deadline_timer_service.hpp \
|
||||||
|
asio/include/asio/error.hpp \
|
||||||
|
asio/include/asio/error_handler.hpp \
|
||||||
|
asio/include/asio/handler_alloc_hook.hpp \
|
||||||
|
asio/include/asio/io_service.hpp \
|
||||||
|
asio/include/asio/is_read_buffered.hpp \
|
||||||
|
asio/include/asio/is_write_buffered.hpp \
|
||||||
|
asio/include/asio/locking_dispatcher.hpp \
|
||||||
|
asio/include/asio/placeholders.hpp \
|
||||||
|
asio/include/asio/read.hpp \
|
||||||
|
asio/include/asio/service_factory.hpp \
|
||||||
|
asio/include/asio/socket_acceptor_service.hpp \
|
||||||
|
asio/include/asio/socket_base.hpp \
|
||||||
|
asio/include/asio/ssl.hpp \
|
||||||
|
asio/include/asio/stream_socket_service.hpp \
|
||||||
|
asio/include/asio/system_exception.hpp \
|
||||||
|
asio/include/asio/thread.hpp \
|
||||||
|
asio/include/asio/time_traits.hpp \
|
||||||
|
asio/include/asio/write.hpp \
|
||||||
|
asio/include/asio/detail/bind_handler.hpp \
|
||||||
|
asio/include/asio/detail/buffer_resize_guard.hpp \
|
||||||
|
asio/include/asio/detail/buffered_stream_storage.hpp \
|
||||||
|
asio/include/asio/detail/call_stack.hpp \
|
||||||
|
asio/include/asio/detail/consuming_buffers.hpp \
|
||||||
|
asio/include/asio/detail/epoll_reactor.hpp \
|
||||||
|
asio/include/asio/detail/event.hpp \
|
||||||
|
asio/include/asio/detail/fd_set_adapter.hpp \
|
||||||
|
asio/include/asio/detail/handler_alloc_helpers.hpp \
|
||||||
|
asio/include/asio/detail/hash_map.hpp \
|
||||||
|
asio/include/asio/detail/io_control.hpp \
|
||||||
|
asio/include/asio/detail/kqueue_reactor.hpp \
|
||||||
|
asio/include/asio/detail/locking_dispatcher.hpp \
|
||||||
|
asio/include/asio/detail/mutex.hpp \
|
||||||
|
asio/include/asio/detail/noncopyable.hpp \
|
||||||
|
asio/include/asio/detail/null_event.hpp \
|
||||||
|
asio/include/asio/detail/null_mutex.hpp \
|
||||||
|
asio/include/asio/detail/null_signal_blocker.hpp \
|
||||||
|
asio/include/asio/detail/null_thread.hpp \
|
||||||
|
asio/include/asio/detail/null_tss_ptr.hpp \
|
||||||
|
asio/include/asio/detail/pipe_select_interrupter.hpp \
|
||||||
|
asio/include/asio/detail/pop_options.hpp \
|
||||||
|
asio/include/asio/detail/posix_event.hpp \
|
||||||
|
asio/include/asio/detail/posix_mutex.hpp \
|
||||||
|
asio/include/asio/detail/posix_signal_blocker.hpp \
|
||||||
|
asio/include/asio/detail/posix_thread.hpp \
|
||||||
|
asio/include/asio/detail/posix_tss_ptr.hpp \
|
||||||
|
asio/include/asio/detail/push_options.hpp \
|
||||||
|
asio/include/asio/detail/reactive_deadline_timer_service.hpp \
|
||||||
|
asio/include/asio/detail/reactive_socket_service.hpp \
|
||||||
|
asio/include/asio/detail/reactor_op_queue.hpp \
|
||||||
|
asio/include/asio/detail/reactor_timer_queue.hpp \
|
||||||
|
asio/include/asio/detail/scoped_lock.hpp \
|
||||||
|
asio/include/asio/detail/select_interrupter.hpp \
|
||||||
|
asio/include/asio/detail/select_reactor.hpp \
|
||||||
|
asio/include/asio/detail/service_registry.hpp \
|
||||||
|
asio/include/asio/detail/signal_blocker.hpp \
|
||||||
|
asio/include/asio/detail/signal_init.hpp \
|
||||||
|
asio/include/asio/detail/socket_holder.hpp \
|
||||||
|
asio/include/asio/detail/socket_ops.hpp \
|
||||||
|
asio/include/asio/detail/socket_option.hpp \
|
||||||
|
asio/include/asio/detail/socket_select_interrupter.hpp \
|
||||||
|
asio/include/asio/detail/socket_types.hpp \
|
||||||
|
asio/include/asio/detail/task_io_service.hpp \
|
||||||
|
asio/include/asio/detail/thread.hpp \
|
||||||
|
asio/include/asio/detail/tss_ptr.hpp \
|
||||||
|
asio/include/asio/detail/win_event.hpp \
|
||||||
|
asio/include/asio/detail/win_iocp_io_service.hpp \
|
||||||
|
asio/include/asio/detail/win_iocp_operation.hpp \
|
||||||
|
asio/include/asio/detail/win_iocp_socket_service.hpp \
|
||||||
|
asio/include/asio/detail/win_local_free_on_block_exit.hpp \
|
||||||
|
asio/include/asio/detail/win_mutex.hpp \
|
||||||
|
asio/include/asio/detail/win_signal_blocker.hpp \
|
||||||
|
asio/include/asio/detail/win_thread.hpp \
|
||||||
|
asio/include/asio/detail/win_tss_ptr.hpp \
|
||||||
|
asio/include/asio/detail/winsock_init.hpp \
|
||||||
|
asio/include/asio/detail/wrapped_handler.hpp \
|
||||||
|
asio/include/asio/impl/read.ipp \
|
||||||
|
asio/include/asio/impl/write.ipp \
|
||||||
|
asio/include/asio/ip/address.hpp \
|
||||||
|
asio/include/asio/ip/basic_endpoint.hpp \
|
||||||
|
asio/include/asio/ip/tcp.hpp \
|
||||||
|
asio/include/asio/ip/udp.hpp \
|
||||||
|
asio/include/asio/ipv4/address.hpp \
|
||||||
|
asio/include/asio/ipv4/basic_endpoint.hpp \
|
||||||
|
asio/include/asio/ipv4/basic_host_resolver.hpp \
|
||||||
|
asio/include/asio/ipv4/host.hpp \
|
||||||
|
asio/include/asio/ipv4/host_resolver.hpp \
|
||||||
|
asio/include/asio/ipv4/host_resolver_service.hpp \
|
||||||
|
asio/include/asio/ipv4/multicast.hpp \
|
||||||
|
asio/include/asio/ipv4/tcp.hpp \
|
||||||
|
asio/include/asio/ipv4/udp.hpp \
|
||||||
|
asio/include/asio/ipv4/detail/host_resolver_service.hpp \
|
||||||
|
asio/include/asio/ipv4/detail/socket_option.hpp \
|
||||||
|
asio/include/asio/ipv6/address.hpp \
|
||||||
|
asio/include/asio/ipv6/basic_endpoint.hpp \
|
||||||
|
asio/include/asio/ipv6/multicast.hpp \
|
||||||
|
asio/include/asio/ipv6/tcp.hpp \
|
||||||
|
asio/include/asio/ipv6/udp.hpp \
|
||||||
|
asio/include/asio/ipv6/detail/socket_option.hpp \
|
||||||
|
asio/include/asio/ssl/basic_context.hpp \
|
||||||
|
asio/include/asio/ssl/context.hpp \
|
||||||
|
asio/include/asio/ssl/context_base.hpp \
|
||||||
|
asio/include/asio/ssl/context_service.hpp \
|
||||||
|
asio/include/asio/ssl/stream.hpp \
|
||||||
|
asio/include/asio/ssl/stream_base.hpp \
|
||||||
|
asio/include/asio/ssl/stream_service.hpp \
|
||||||
|
asio/include/asio/ssl/detail/openssl_context_service.hpp \
|
||||||
|
asio/include/asio/ssl/detail/openssl_init.hpp \
|
||||||
|
asio/include/asio/ssl/detail/openssl_operation.hpp \
|
||||||
|
asio/include/asio/ssl/detail/openssl_stream_service.hpp \
|
||||||
|
asio/include/asio/ssl/detail/openssl_types.hpp
|
||||||
|
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libtorrent.pc
|
pkgconfig_DATA = libtorrent.pc
|
||||||
|
|
||||||
check: test
|
check: test
|
||||||
test/test_hasher && test/test_bencoding && test/test_ip_filter && echo "tests done, all OK"
|
test/test_hasher \
|
||||||
|
&& test/test_bencoding \
|
||||||
|
&& test/test_ip_filter \
|
||||||
|
&& test/test_piece_picker \
|
||||||
|
&& test/test_storage \
|
||||||
|
&& test/test_metadata_extension \
|
||||||
|
&& test/test_buffer \
|
||||||
|
&& echo && echo && echo " **** all tests passed ****" && echo && echo
|
||||||
|
|
||||||
deb:
|
deb:
|
||||||
dpkg-buildpackage -rfakeroot -us -uc
|
dpkg-buildpackage -rfakeroot -us -uc
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
AC_PREREQ(2.59)
|
AC_PREREQ(2.59)
|
||||||
|
|
||||||
AC_INIT(src/torrent.cpp)
|
AC_INIT(src/torrent.cpp)
|
||||||
AM_INIT_AUTOMAKE(libtorrent, 0.9.1)
|
AM_INIT_AUTOMAKE(libtorrent, 0.9.2)
|
||||||
|
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="generator" content="Docutils 0.3.9: http://docutils.sourceforge.net/" />
|
||||||
|
<title></title>
|
||||||
|
<meta name="author" content="Arvid Norberg, arvid@rasterbar.com Ludvig Strigeus, ludde@utorrent.com" />
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document">
|
||||||
|
<table class="docinfo" frame="void" rules="none">
|
||||||
|
<col class="docinfo-name" />
|
||||||
|
<col class="docinfo-content" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><th class="docinfo-name">Author:</th>
|
||||||
|
<td>Arvid Norberg, <a class="reference" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a>
|
||||||
|
Ludvig Strigeus, <a class="last reference" href="mailto:ludde@utorrent.com">ludde@utorrent.com</a></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="section" id="extension-protocol-for-bittorrent">
|
||||||
|
<h1><a name="extension-protocol-for-bittorrent">extension protocol for bittorrent</a></h1>
|
||||||
|
<p>The intention of this protocol is to provide a simple and thin transport
|
||||||
|
for extensions to the bittorrent protocol. Supporting this protocol makes
|
||||||
|
it easy to add new extensions without interfering with the standard
|
||||||
|
bittorrent protocol or clients that don't support this extension or the
|
||||||
|
one you want to add.</p>
|
||||||
|
<p>To advertise to other clients that you support, one bit from the reserved
|
||||||
|
bytes is used.</p>
|
||||||
|
<dl class="docutils">
|
||||||
|
<dt>Right now, two bits have known usages.</dt>
|
||||||
|
<dd><ul class="first last simple">
|
||||||
|
<li>[7] & 1 is used by Mainline for DHT support</li>
|
||||||
|
<li>[7] & 2 is used by XBT client for peer-exchange support</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<p>The bit selected for the extension protocol is bit 20 from the right (counting
|
||||||
|
starts at 0). So (reserved_byte[5] & 0x10) is the expression to use for checking
|
||||||
|
if the client supports extended messaging.</p>
|
||||||
|
<p>Once support for the protocol is established, the client is supposed to
|
||||||
|
support 1 new message:</p>
|
||||||
|
<table border="1" class="docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="86%" />
|
||||||
|
<col width="14%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head">name</th>
|
||||||
|
<th class="head">id</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">extended</span></tt></td>
|
||||||
|
<td>20</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>This message is sent as any other bittorrent message, with a 4 byte length
|
||||||
|
prefix and a single byte identifying the message (the single byte being 20
|
||||||
|
in this case). At the start of the payload of the message, is a single byte
|
||||||
|
message identifier. This identifier can refer to different extension messages
|
||||||
|
and only one ID is specified, 0. If the ID is 0, the message is a handshake
|
||||||
|
message which is described below. The layout of a general <tt class="docutils literal"><span class="pre">extended</span></tt> message
|
||||||
|
follows (including the message headers used by the bittorrent protocol):</p>
|
||||||
|
<table border="1" class="docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="15%" />
|
||||||
|
<col width="85%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head">size</th>
|
||||||
|
<th class="head">description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td>uint32_t</td>
|
||||||
|
<td>length prefix. Specifies the number of bytes for the
|
||||||
|
entire message. (Big endian)</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>uint8_t</td>
|
||||||
|
<td>bittorrent message ID, = 20</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>uint8_t</td>
|
||||||
|
<td>extended message ID. 0 = handshake, >0 = extended
|
||||||
|
message as specified by the handshake.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="section" id="handshake-message">
|
||||||
|
<h2><a name="handshake-message">handshake message</a></h2>
|
||||||
|
<p>The payload of the handshake message is a bencoded dictionary. All items
|
||||||
|
in the dictionary are optional. Any unknown names should be ignored
|
||||||
|
by the client. All parts of the dictionary are case sensitive.
|
||||||
|
This is the defined item in the dictionary:</p>
|
||||||
|
<table border="1" class="docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="11%" />
|
||||||
|
<col width="89%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head">name</th>
|
||||||
|
<th class="head">description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td>m</td>
|
||||||
|
<td>Dictionary of supported extension messages which maps
|
||||||
|
names of extensions to identification numbers of each
|
||||||
|
extension. The only requirement on the identification
|
||||||
|
numbers is that no extensions share the same. Setting
|
||||||
|
an extension number to zero means that the extension is
|
||||||
|
not supported/disabled. The client should ignore any
|
||||||
|
extension names it doesn't recognize.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>Here are two other items that an implementation may choose to support:</p>
|
||||||
|
<table border="1" class="docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="11%" />
|
||||||
|
<col width="89%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head">name</th>
|
||||||
|
<th class="head">description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td>p</td>
|
||||||
|
<td>Local TCP listen port. Allows each side to learn about
|
||||||
|
the TCP port number of the other side. Note that there is
|
||||||
|
no need for the receiving side of the connection to send
|
||||||
|
this extension message, since its port number is already
|
||||||
|
known.</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>v</td>
|
||||||
|
<td>Client name and version (as an utf-8 string).
|
||||||
|
This is a much more reliable way of identifying the
|
||||||
|
client than relying on the peer id encoding.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>The handshake dictionary could also include extended handshake
|
||||||
|
information, such as support for encrypted headers or anything
|
||||||
|
imaginable.</p>
|
||||||
|
<p>An example of what the payload of a handshake message could look like:</p>
|
||||||
|
<table border="1" class="docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="36%" />
|
||||||
|
<col width="64%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head" colspan="2">Dictionary</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">m</span></tt></td>
|
||||||
|
<td><table border="1" class="first last docutils">
|
||||||
|
<colgroup>
|
||||||
|
<col width="88%" />
|
||||||
|
<col width="12%" />
|
||||||
|
</colgroup>
|
||||||
|
<thead valign="bottom">
|
||||||
|
<tr><th class="head" colspan="2">Dictionary</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">LT_metadata</span></tt></td>
|
||||||
|
<td>1</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">µT_PEX</span></tt></td>
|
||||||
|
<td>2</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">p</span></tt></td>
|
||||||
|
<td>6881</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td><tt class="docutils literal"><span class="pre">v</span></tt></td>
|
||||||
|
<td>"µTorrent 1.2"</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>and in the encoded form:</p>
|
||||||
|
<p><tt class="docutils literal"><span class="pre">d1:md11:LT_metadatai1e6:µT_PEXi2ee1:pi6881e1:v13:\xc2\xb5Torrent</span> <span class="pre">1.2e</span></tt></p>
|
||||||
|
<p>To make sure the extension names do not collide by mistake, they should be
|
||||||
|
prefixed with the two (or one) character code that is used to identify the
|
||||||
|
client that introduced the extension. This applies for both the names of
|
||||||
|
extension messages, and for any additional information put inside the
|
||||||
|
top-level dictionary. All one and two byte identifiers are invalid to use
|
||||||
|
unless defined by this specification.</p>
|
||||||
|
<p>This message should be sent immediately after the standard bittorrent handshake
|
||||||
|
to any peer that supports this extension protocol. It is valid to send the
|
||||||
|
handshake message more than once during the lifetime of a connection,
|
||||||
|
the sending client should not be disconnected. An implementation may choose
|
||||||
|
to ignore the subsequent handshake messages (or parts of them).</p>
|
||||||
|
<p>Subsequent handshake messages can be used to enable/disable extensions
|
||||||
|
without restarting the connection. If a peer supports changing extensions
|
||||||
|
at run time, it should note that the <tt class="docutils literal"><span class="pre">m</span></tt> dictionary is additive.
|
||||||
|
It's enough that it contains the actual <em>CHANGES</em> to the extension list.
|
||||||
|
To disable the support for <tt class="docutils literal"><span class="pre">LT_metadata</span></tt> at run-time, without affecting
|
||||||
|
any other extensions, this message should be sent:
|
||||||
|
<tt class="docutils literal"><span class="pre">d11:LT_metadatai0ee</span></tt>.
|
||||||
|
As specified above, the value 0 is used to turn off an extension.</p>
|
||||||
|
<p>The extension IDs must be stored for every peer, becuase every peer may have
|
||||||
|
different IDs for the same extension.</p>
|
||||||
|
<p>This specification, deliberately, does not specify any extensions such as
|
||||||
|
peer-exchange or metadata exchange. This protocol is merely a transport
|
||||||
|
for the actual extensions to the bittorrent protocol and the extensions
|
||||||
|
named in the example above (such as <tt class="docutils literal"><span class="pre">p</span></tt>) are just examples of possible
|
||||||
|
extensions.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="rationale">
|
||||||
|
<h2><a name="rationale">rationale</a></h2>
|
||||||
|
<p>The reason why the extension messages' IDs would be defined in the handshake
|
||||||
|
is to avoid having a global registry somewhere, where ID's are assigned
|
||||||
|
global identifiers. Now the extensions have unique names.</p>
|
||||||
|
<p>If the client supporting the extensions can decide which numbers the messages
|
||||||
|
it receives will have, it means they are constants within that client. i.e.
|
||||||
|
they can be used in <tt class="docutils literal"><span class="pre">switch</span></tt> statements. It's easy for the other end to
|
||||||
|
store an array with the ID's we expect for each message and use that for
|
||||||
|
lookups each time it sends an extension message.</p>
|
||||||
|
<p>The reason for having a dictionary instead of having an array (using
|
||||||
|
implicitly assigned index numbers to the extensions) is that if a client
|
||||||
|
want to disable some extensions, the ID numbers would change, and it wouldn't
|
||||||
|
be able to use constants (and hence, not use them in a <tt class="docutils literal"><span class="pre">switch</span></tt>). If the
|
||||||
|
messages IDs would map directly to bittorrent message IDs, It would also make
|
||||||
|
it possible to map extensions in the handshake to existing extensions with
|
||||||
|
fixed message IDs.</p>
|
||||||
|
<p>The reasoning behind having a single byte as extended message identifier is
|
||||||
|
to follow the the bittorrent spec. with its single byte message identifiers.
|
||||||
|
It is also considered to be enough. It won't limit the total number of
|
||||||
|
extensions, only the number of extensions used simultaneously.</p>
|
||||||
|
<p>The reason for using single byte identifiers for the standardized handshake
|
||||||
|
identifiers is 1) The mainline DHT uses single byte identifiers. 2) Saves
|
||||||
|
bandwidth. The only advantage of longer messages is that it makes the
|
||||||
|
protocol more readable for a human, but the BT protocol wasn't designed to
|
||||||
|
be a human readable protocol, so why bother.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,179 @@
|
||||||
|
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||||
|
Ludvig Strigeus, ludde@utorrent.com
|
||||||
|
|
||||||
|
extension protocol for bittorrent
|
||||||
|
=================================
|
||||||
|
|
||||||
|
The intention of this protocol is to provide a simple and thin transport
|
||||||
|
for extensions to the bittorrent protocol. Supporting this protocol makes
|
||||||
|
it easy to add new extensions without interfering with the standard
|
||||||
|
bittorrent protocol or clients that don't support this extension or the
|
||||||
|
one you want to add.
|
||||||
|
|
||||||
|
To advertise to other clients that you support, one bit from the reserved
|
||||||
|
bytes is used.
|
||||||
|
|
||||||
|
Right now, two bits have known usages.
|
||||||
|
* [7] & 1 is used by Mainline for DHT support
|
||||||
|
* [7] & 2 is used by XBT client for peer-exchange support
|
||||||
|
|
||||||
|
The bit selected for the extension protocol is bit 20 from the right (counting
|
||||||
|
starts at 0). So (reserved_byte[5] & 0x10) is the expression to use for checking
|
||||||
|
if the client supports extended messaging.
|
||||||
|
|
||||||
|
Once support for the protocol is established, the client is supposed to
|
||||||
|
support 1 new message:
|
||||||
|
|
||||||
|
+------------------------+----+
|
||||||
|
|name | id |
|
||||||
|
+========================+====+
|
||||||
|
|``extended`` | 20 |
|
||||||
|
+------------------------+----+
|
||||||
|
|
||||||
|
This message is sent as any other bittorrent message, with a 4 byte length
|
||||||
|
prefix and a single byte identifying the message (the single byte being 20
|
||||||
|
in this case). At the start of the payload of the message, is a single byte
|
||||||
|
message identifier. This identifier can refer to different extension messages
|
||||||
|
and only one ID is specified, 0. If the ID is 0, the message is a handshake
|
||||||
|
message which is described below. The layout of a general ``extended`` message
|
||||||
|
follows (including the message headers used by the bittorrent protocol):
|
||||||
|
|
||||||
|
+----------+---------------------------------------------------------+
|
||||||
|
| size | description |
|
||||||
|
+==========+=========================================================+
|
||||||
|
| uint32_t | length prefix. Specifies the number of bytes for the |
|
||||||
|
| | entire message. (Big endian) |
|
||||||
|
+----------+---------------------------------------------------------+
|
||||||
|
| uint8_t | bittorrent message ID, = 20 |
|
||||||
|
+----------+---------------------------------------------------------+
|
||||||
|
| uint8_t | extended message ID. 0 = handshake, >0 = extended |
|
||||||
|
| | message as specified by the handshake. |
|
||||||
|
+----------+---------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
handshake message
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The payload of the handshake message is a bencoded dictionary. All items
|
||||||
|
in the dictionary are optional. Any unknown names should be ignored
|
||||||
|
by the client. All parts of the dictionary are case sensitive.
|
||||||
|
This is the defined item in the dictionary:
|
||||||
|
|
||||||
|
+-------+-----------------------------------------------------------+
|
||||||
|
| name | description |
|
||||||
|
+=======+===========================================================+
|
||||||
|
| m | Dictionary of supported extension messages which maps |
|
||||||
|
| | names of extensions to identification numbers of each |
|
||||||
|
| | extension. The only requirement on the identification |
|
||||||
|
| | numbers is that no extensions share the same. Setting |
|
||||||
|
| | an extension number to zero means that the extension is |
|
||||||
|
| | not supported/disabled. The client should ignore any |
|
||||||
|
| | extension names it doesn't recognize. |
|
||||||
|
+-------+-----------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Here are two other items that an implementation may choose to support:
|
||||||
|
|
||||||
|
+-------+-----------------------------------------------------------+
|
||||||
|
| name | description |
|
||||||
|
+=======+===========================================================+
|
||||||
|
| p | Local TCP listen port. Allows each side to learn about |
|
||||||
|
| | the TCP port number of the other side. Note that there is |
|
||||||
|
| | no need for the receiving side of the connection to send |
|
||||||
|
| | this extension message, since its port number is already |
|
||||||
|
| | known. |
|
||||||
|
+-------+-----------------------------------------------------------+
|
||||||
|
| v | Client name and version (as an utf-8 string). |
|
||||||
|
| | This is a much more reliable way of identifying the |
|
||||||
|
| | client than relying on the peer id encoding. |
|
||||||
|
+-------+-----------------------------------------------------------+
|
||||||
|
|
||||||
|
The handshake dictionary could also include extended handshake
|
||||||
|
information, such as support for encrypted headers or anything
|
||||||
|
imaginable.
|
||||||
|
|
||||||
|
An example of what the payload of a handshake message could look like:
|
||||||
|
|
||||||
|
+------------------------------------------------------+
|
||||||
|
| Dictionary |
|
||||||
|
+===================+==================================+
|
||||||
|
| ``m`` | +--------------------------+ |
|
||||||
|
| | | Dictionary | |
|
||||||
|
| | +======================+===+ |
|
||||||
|
| | | ``LT_metadata`` | 1 | |
|
||||||
|
| | +----------------------+---+ |
|
||||||
|
| | | ``µT_PEX`` | 2 | |
|
||||||
|
| | +----------------------+---+ |
|
||||||
|
| | |
|
||||||
|
+-------------------+----------------------------------+
|
||||||
|
| ``p`` | 6881 |
|
||||||
|
+-------------------+----------------------------------+
|
||||||
|
| ``v`` | "µTorrent 1.2" |
|
||||||
|
+-------------------+----------------------------------+
|
||||||
|
|
||||||
|
and in the encoded form:
|
||||||
|
|
||||||
|
``d1:md11:LT_metadatai1e6:µT_PEXi2ee1:pi6881e1:v13:\xc2\xb5Torrent 1.2e``
|
||||||
|
|
||||||
|
To make sure the extension names do not collide by mistake, they should be
|
||||||
|
prefixed with the two (or one) character code that is used to identify the
|
||||||
|
client that introduced the extension. This applies for both the names of
|
||||||
|
extension messages, and for any additional information put inside the
|
||||||
|
top-level dictionary. All one and two byte identifiers are invalid to use
|
||||||
|
unless defined by this specification.
|
||||||
|
|
||||||
|
This message should be sent immediately after the standard bittorrent handshake
|
||||||
|
to any peer that supports this extension protocol. It is valid to send the
|
||||||
|
handshake message more than once during the lifetime of a connection,
|
||||||
|
the sending client should not be disconnected. An implementation may choose
|
||||||
|
to ignore the subsequent handshake messages (or parts of them).
|
||||||
|
|
||||||
|
Subsequent handshake messages can be used to enable/disable extensions
|
||||||
|
without restarting the connection. If a peer supports changing extensions
|
||||||
|
at run time, it should note that the ``m`` dictionary is additive.
|
||||||
|
It's enough that it contains the actual *CHANGES* to the extension list.
|
||||||
|
To disable the support for ``LT_metadata`` at run-time, without affecting
|
||||||
|
any other extensions, this message should be sent:
|
||||||
|
``d11:LT_metadatai0ee``.
|
||||||
|
As specified above, the value 0 is used to turn off an extension.
|
||||||
|
|
||||||
|
The extension IDs must be stored for every peer, becuase every peer may have
|
||||||
|
different IDs for the same extension.
|
||||||
|
|
||||||
|
This specification, deliberately, does not specify any extensions such as
|
||||||
|
peer-exchange or metadata exchange. This protocol is merely a transport
|
||||||
|
for the actual extensions to the bittorrent protocol and the extensions
|
||||||
|
named in the example above (such as ``p``) are just examples of possible
|
||||||
|
extensions.
|
||||||
|
|
||||||
|
rationale
|
||||||
|
---------
|
||||||
|
|
||||||
|
The reason why the extension messages' IDs would be defined in the handshake
|
||||||
|
is to avoid having a global registry somewhere, where ID's are assigned
|
||||||
|
global identifiers. Now the extensions have unique names.
|
||||||
|
|
||||||
|
If the client supporting the extensions can decide which numbers the messages
|
||||||
|
it receives will have, it means they are constants within that client. i.e.
|
||||||
|
they can be used in ``switch`` statements. It's easy for the other end to
|
||||||
|
store an array with the ID's we expect for each message and use that for
|
||||||
|
lookups each time it sends an extension message.
|
||||||
|
|
||||||
|
The reason for having a dictionary instead of having an array (using
|
||||||
|
implicitly assigned index numbers to the extensions) is that if a client
|
||||||
|
want to disable some extensions, the ID numbers would change, and it wouldn't
|
||||||
|
be able to use constants (and hence, not use them in a ``switch``). If the
|
||||||
|
messages IDs would map directly to bittorrent message IDs, It would also make
|
||||||
|
it possible to map extensions in the handshake to existing extensions with
|
||||||
|
fixed message IDs.
|
||||||
|
|
||||||
|
The reasoning behind having a single byte as extended message identifier is
|
||||||
|
to follow the the bittorrent spec. with its single byte message identifiers.
|
||||||
|
It is also considered to be enough. It won't limit the total number of
|
||||||
|
extensions, only the number of extensions used simultaneously.
|
||||||
|
|
||||||
|
The reason for using single byte identifiers for the standardized handshake
|
||||||
|
identifiers is 1) The mainline DHT uses single byte identifiers. 2) Saves
|
||||||
|
bandwidth. The only advantage of longer messages is that it makes the
|
||||||
|
protocol more readable for a human, but the BT protocol wasn't designed to
|
||||||
|
be a human readable protocol, so why bother.
|
1143
docs/manual.html
1143
docs/manual.html
File diff suppressed because it is too large
Load Diff
307
docs/manual.rst
307
docs/manual.rst
|
@ -30,6 +30,7 @@ following features:
|
||||||
* serves multiple torrents on a single port and a single thread
|
* serves multiple torrents on a single port and a single thread
|
||||||
* supports http proxies and proxy authentication
|
* supports http proxies and proxy authentication
|
||||||
* gzipped tracker-responses
|
* gzipped tracker-responses
|
||||||
|
* `HTTP seeding`_, as `specified by Michael Burford of GetRight`__.
|
||||||
* piece picking on block-level like in Azureus_ (as opposed to piece-level).
|
* piece picking on block-level like in Azureus_ (as opposed to piece-level).
|
||||||
This means it can download parts of the same piece from different peers.
|
This means it can download parts of the same piece from different peers.
|
||||||
It will also prefer to download whole pieces from single peers if the
|
It will also prefer to download whole pieces from single peers if the
|
||||||
|
@ -64,13 +65,19 @@ following features:
|
||||||
* ip filter
|
* ip filter
|
||||||
|
|
||||||
__ http://home.elp.rr.com/tur/multitracker-spec.txt
|
__ http://home.elp.rr.com/tur/multitracker-spec.txt
|
||||||
|
__ http://www.getright.com/seedtorrent.html
|
||||||
.. _Azureus: http://azureus.sourceforge.net
|
.. _Azureus: http://azureus.sourceforge.net
|
||||||
__ extension_protocol.html
|
__ extension_protocol.html
|
||||||
__ udp_tracker_protocol.html
|
__ udp_tracker_protocol.html
|
||||||
|
|
||||||
|
|
||||||
libtorrent is portable at least among Windows, MacOS X and other UNIX-systems. It uses Boost.Thread,
|
libtorrent is portable at least among Windows, MacOS X and other UNIX-systems.
|
||||||
Boost.Filesystem, Boost.Date_time and various other boost libraries as well as zlib.
|
It uses Boost.Thread, Boost.Filesystem, Boost.Date_time and various other
|
||||||
|
boost libraries as well as zlib_ (shipped) and asio_ (shipped). At least version
|
||||||
|
1.33.1 of boost is required.
|
||||||
|
|
||||||
|
.. _zlib: http://www.zlib.org
|
||||||
|
.. _asio: http://asio.sf.net
|
||||||
|
|
||||||
libtorrent has been successfully compiled and tested on:
|
libtorrent has been successfully compiled and tested on:
|
||||||
|
|
||||||
|
@ -255,6 +262,10 @@ The ``Jamfile`` has the following build variants:
|
||||||
* ``debug_log`` - debug version with standard logging
|
* ``debug_log`` - debug version with standard logging
|
||||||
* ``debug_vlog`` - debug version with verbose logging
|
* ``debug_vlog`` - debug version with verbose logging
|
||||||
|
|
||||||
|
When building the example client on windows, you need to build with
|
||||||
|
``link=static`` otherwise you may get unresolved external symbols for some
|
||||||
|
boost.program-options symbols.
|
||||||
|
|
||||||
|
|
||||||
building with autotools
|
building with autotools
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -983,6 +994,7 @@ The ``torrent_info`` has the following synopsis::
|
||||||
void set_hash(int index, sha1_hash const& h);
|
void set_hash(int index, sha1_hash const& h);
|
||||||
void add_tracker(std::string const& url, int tier = 0);
|
void add_tracker(std::string const& url, int tier = 0);
|
||||||
void add_file(boost::filesystem::path file, size_type size);
|
void add_file(boost::filesystem::path file, size_type size);
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||||
typedef std::vector<file_entry>::const_reverse_iterator
|
typedef std::vector<file_entry>::const_reverse_iterator
|
||||||
|
@ -996,8 +1008,15 @@ The ``torrent_info`` has the following synopsis::
|
||||||
int num_files() const;
|
int num_files() const;
|
||||||
file_entry const& file_at(int index) const;
|
file_entry const& file_at(int index) const;
|
||||||
|
|
||||||
|
std::vector<file_slice> map_block(int piece, size_type offset
|
||||||
|
, int size) const;
|
||||||
|
peer_request map_file(int file_index, size_type file_offset
|
||||||
|
, int size) const;
|
||||||
|
|
||||||
std::vector<announce_entry> const& trackers() const;
|
std::vector<announce_entry> const& trackers() const;
|
||||||
|
|
||||||
|
std::vector<std::string> const& url_seeds() const;
|
||||||
|
|
||||||
size_type total_size() const;
|
size_type total_size() const;
|
||||||
size_type piece_length() const;
|
size_type piece_length() const;
|
||||||
int num_pieces() const;
|
int num_pieces() const;
|
||||||
|
@ -1138,6 +1157,81 @@ If you need index-access to files you can use the ``num_files()`` and ``file_at(
|
||||||
to access files using indices.
|
to access files using indices.
|
||||||
|
|
||||||
|
|
||||||
|
map_block()
|
||||||
|
-----------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
std::vector<file_slice> map_block(int piece, size_type offset
|
||||||
|
, int size) const;
|
||||||
|
|
||||||
|
This function will map a piece index, a byte offset within that piece and
|
||||||
|
a size (in bytes) into the corresponding files with offsets where that data
|
||||||
|
for that piece is supposed to be stored.
|
||||||
|
|
||||||
|
The file slice struct looks like this::
|
||||||
|
|
||||||
|
struct file_slice
|
||||||
|
{
|
||||||
|
int file_index;
|
||||||
|
size_type offset;
|
||||||
|
size_type size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
The ``file_index`` refers to the index of the file (in the torrent_info).
|
||||||
|
To get the path and filename, use ``file_at()`` and give the ``file_index``
|
||||||
|
as argument. The ``offset`` is the byte offset in the file where the range
|
||||||
|
starts, and ``size`` is the number of bytes this range is. The size + offset
|
||||||
|
will never be greater than the file size.
|
||||||
|
|
||||||
|
|
||||||
|
map_file()
|
||||||
|
----------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
peer_request map_file(int file_index, size_type file_offset
|
||||||
|
, int size) const;
|
||||||
|
|
||||||
|
This function will map a range in a specific file into a range in the torrent.
|
||||||
|
The ``file_offset`` parameter is the offset in the file, given in bytes, where
|
||||||
|
0 is the start of the file.
|
||||||
|
The ``peer_request`` structure looks like this::
|
||||||
|
|
||||||
|
struct peer_request
|
||||||
|
{
|
||||||
|
int piece;
|
||||||
|
int start;
|
||||||
|
int length;
|
||||||
|
bool operator==(peer_request const& r) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
``piece`` is the index of the piece in which the range starts.
|
||||||
|
``start`` is the offset within that piece where the range starts.
|
||||||
|
``length`` is the size of the range, in bytes.
|
||||||
|
|
||||||
|
The input range is assumed to be valid within the torrent. ``file_offset``
|
||||||
|
+ ``size`` is not allowed to be greater than the file size. ``file_index``
|
||||||
|
must refer to a valid file, i.e. it cannot be >= ``num_files()``.
|
||||||
|
|
||||||
|
|
||||||
|
url_seeds()
|
||||||
|
-----------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
std::vector<std::string> const& url_seeds() const;
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
|
If there are any url-seeds in this torrent, ``url_seeds()`` will return a
|
||||||
|
vector of those urls. If you're creating a torrent file, ``add_url_seed()``
|
||||||
|
adds one url to the list of url-seeds. Currently, the only transport protocol
|
||||||
|
supported for the url is http.
|
||||||
|
|
||||||
|
See `HTTP seeding`_ for more information.
|
||||||
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -1202,6 +1296,8 @@ hash_for_piece() info_hash()
|
||||||
``hash_for_piece()`` takes a piece-index and returns the 20-bytes sha1-hash for that
|
``hash_for_piece()`` takes a piece-index and returns the 20-bytes sha1-hash for that
|
||||||
piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of the
|
piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of the
|
||||||
torrent file. For more information on the ``sha1_hash``, see the big_number_ class.
|
torrent file. For more information on the ``sha1_hash``, see the big_number_ class.
|
||||||
|
``info_hash()`` will only return a valid hash if the torrent_info was read from a
|
||||||
|
``.torrent`` file or if an ``entry`` was created from it (through ``create_torrent``).
|
||||||
|
|
||||||
|
|
||||||
name() comment() creation_date() creator()
|
name() comment() creation_date() creator()
|
||||||
|
@ -1250,7 +1346,7 @@ Its declaration looks like this::
|
||||||
entry write_resume_data() const;
|
entry write_resume_data() const;
|
||||||
std::vector<char> const& metadata() const;
|
std::vector<char> const& metadata() const;
|
||||||
void force_reannounce() const;
|
void force_reannounce() const;
|
||||||
void connect_peer(address const& adr) const;
|
void connect_peer(asio::ipv4::tcp::endpoint const& adr) const;
|
||||||
|
|
||||||
void set_tracker_login(std::string const& username
|
void set_tracker_login(std::string const& username
|
||||||
, std::string const& password) const;
|
, std::string const& password) const;
|
||||||
|
@ -1258,11 +1354,17 @@ Its declaration looks like this::
|
||||||
std::vector<announce_entry> const& trackers() const;
|
std::vector<announce_entry> const& trackers() const;
|
||||||
void replace_trackers(std::vector<announce_entry> const&);
|
void replace_trackers(std::vector<announce_entry> const&);
|
||||||
|
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
void set_ratio(float ratio) const;
|
void set_ratio(float ratio) const;
|
||||||
void set_max_uploads(int max_uploads) const;
|
void set_max_uploads(int max_uploads) const;
|
||||||
void set_max_connections(int max_connections) const;
|
void set_max_connections(int max_connections) const;
|
||||||
void set_upload_limit(int limit) const;
|
void set_upload_limit(int limit) const;
|
||||||
void set_download_limit(int limit) const;
|
void set_download_limit(int limit) const;
|
||||||
|
|
||||||
|
void set_peer_upload_limit(asio::ipv4::tcp::endpoint ip, int limit) const;
|
||||||
|
void set_peer_download_limit(asio::ipv4::tcp::endpoint ip, int limit) const;
|
||||||
|
|
||||||
void use_interface(char const* net_interface) const;
|
void use_interface(char const* net_interface) const;
|
||||||
|
|
||||||
void pause() const;
|
void pause() const;
|
||||||
|
@ -1336,7 +1438,7 @@ connect_peer()
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
void connect_peer(address const& adr) const;
|
void connect_peer(asio::ipv4::tcp::endpoint const& adr) const;
|
||||||
|
|
||||||
``connect_peer()`` is a way to manually connect to peers that one believe is a part of the
|
``connect_peer()`` is a way to manually connect to peers that one believe is a part of the
|
||||||
torrent. If the peer does not respond, or is not a member of this torrent, it will simply
|
torrent. If the peer does not respond, or is not a member of this torrent, it will simply
|
||||||
|
@ -1377,6 +1479,16 @@ Note that setting a higher limit on a torrent then the global limit (``session::
|
||||||
will not override the global rate limit. The torrent can never upload more than the global rate
|
will not override the global rate limit. The torrent can never upload more than the global rate
|
||||||
limit.
|
limit.
|
||||||
|
|
||||||
|
set_peer_upload_limit() set_peer_download_limit()
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void set_peer_upload_limit(asio::ipv4::tcp::endpoint ip, int limit) const;
|
||||||
|
void set_peer_download_limit(asio::ipv4::tcp::endpoint ip, int limit) const;
|
||||||
|
|
||||||
|
Works like ``set_upload_limit`` and ``set_download_limit`` respectively, but controls individual
|
||||||
|
peer instead of the whole torrent.
|
||||||
|
|
||||||
pause() resume() is_paused()
|
pause() resume() is_paused()
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@ -1445,6 +1557,21 @@ replace it. If you want an immediate effect, you have to call
|
||||||
`force_reannounce()`_.
|
`force_reannounce()`_.
|
||||||
|
|
||||||
|
|
||||||
|
add_url_seed()
|
||||||
|
--------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
|
``add_url_seed()`` adds another url to the torrent's list of url seeds. If the
|
||||||
|
given url already exists in that list, the call has no effect. The torrent
|
||||||
|
will connect to the server and try to download pieces from it, unless it's
|
||||||
|
paused, queued, checking or seeding.
|
||||||
|
|
||||||
|
See `HTTP seeding`_ for more information.
|
||||||
|
|
||||||
|
|
||||||
use_interface()
|
use_interface()
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -1649,6 +1776,7 @@ It contains the following fields::
|
||||||
size_type total_payload_upload;
|
size_type total_payload_upload;
|
||||||
|
|
||||||
size_type total_failed_bytes;
|
size_type total_failed_bytes;
|
||||||
|
size_type total_redundant_bytes;
|
||||||
|
|
||||||
float download_rate;
|
float download_rate;
|
||||||
float upload_rate;
|
float upload_rate;
|
||||||
|
@ -1662,6 +1790,8 @@ It contains the following fields::
|
||||||
int num_incomplete;
|
int num_incomplete;
|
||||||
|
|
||||||
const std::vector<bool>* pieces;
|
const std::vector<bool>* pieces;
|
||||||
|
int num_pieces;
|
||||||
|
|
||||||
size_type total_done;
|
size_type total_done;
|
||||||
size_type total_wanted_done;
|
size_type total_wanted_done;
|
||||||
size_type total_wanted;
|
size_type total_wanted;
|
||||||
|
@ -1727,10 +1857,24 @@ data), these counters ignore any protocol overhead.
|
||||||
has failed the piece hash test. In other words, this is just how much crap that
|
has failed the piece hash test. In other words, this is just how much crap that
|
||||||
has been downloaded.
|
has been downloaded.
|
||||||
|
|
||||||
|
``total_redundant_bytes`` is the number of bytes that has been downloaded even
|
||||||
|
though that data already was downloaded. The reason for this is that in some
|
||||||
|
situations the same data can be downloaded by mistake. When libtorrent sends
|
||||||
|
requests to a peer, and the peer doesn't send a response within a certain
|
||||||
|
timeout, libtorrent will re-request that block. Another situation when
|
||||||
|
libtorrent will re-request blocks is when the requests it sends out are not
|
||||||
|
replyed in FIFO-order (it will re-request blocks that are skipped by an out of
|
||||||
|
order block). This is supposed to be as low as possible.
|
||||||
|
|
||||||
``pieces`` is the bitmask that represents which pieces we have (set to true) and
|
``pieces`` is the bitmask that represents which pieces we have (set to true) and
|
||||||
the pieces we don't have. It's a pointer and may be set to 0 if the torrent isn't
|
the pieces we don't have. It's a pointer and may be set to 0 if the torrent isn't
|
||||||
downloading or seeding.
|
downloading or seeding.
|
||||||
|
|
||||||
|
``num_pieces`` is the number of pieces that has been downloaded. It is equivalent
|
||||||
|
to: ``std::accumulate(pieces->begin(), pieces->end())``. So you don't have to
|
||||||
|
count yourself. This can be used to see if anything has updated since last time
|
||||||
|
if you want to keep a graph of the pieces up to date.
|
||||||
|
|
||||||
``download_rate`` and ``upload_rate`` are the total rates for all peers for this
|
``download_rate`` and ``upload_rate`` are the total rates for all peers for this
|
||||||
torrent. These will usually have better precision than summing the rates from
|
torrent. These will usually have better precision than summing the rates from
|
||||||
all peers. The rates are given as the number of bytes per second. The
|
all peers. The rates are given as the number of bytes per second. The
|
||||||
|
@ -1793,22 +1937,23 @@ It contains the following fields::
|
||||||
remote_choked = 0x8,
|
remote_choked = 0x8,
|
||||||
supports_extensions = 0x10,
|
supports_extensions = 0x10,
|
||||||
local_connection = 0x20,
|
local_connection = 0x20,
|
||||||
connecting = 0x40,
|
handshake = 0x40,
|
||||||
queued = 0x80
|
connecting = 0x80,
|
||||||
|
queued = 0x100
|
||||||
};
|
};
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
address ip;
|
asio::ipv4::tcp::endpoint ip;
|
||||||
float up_speed;
|
float up_speed;
|
||||||
float down_speed;
|
float down_speed;
|
||||||
float payload_up_speed;
|
float payload_up_speed;
|
||||||
float payload_down_speed;
|
float payload_down_speed;
|
||||||
size_type total_download;
|
size_type total_download;
|
||||||
size_type total_upload;
|
size_type total_upload;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
std::vector<bool> pieces;
|
std::vector<bool> pieces;
|
||||||
bool seed;
|
bool seed;
|
||||||
int upload_limit;
|
int upload_limit;
|
||||||
int upload_ceiling;
|
int download_limit;
|
||||||
|
|
||||||
size_type load_balancing;
|
size_type load_balancing;
|
||||||
|
|
||||||
|
@ -1819,6 +1964,15 @@ It contains the following fields::
|
||||||
int downloading_block_index;
|
int downloading_block_index;
|
||||||
int downloading_progress;
|
int downloading_progress;
|
||||||
int downloading_total;
|
int downloading_total;
|
||||||
|
|
||||||
|
std::string client;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
standard_bittorrent = 0,
|
||||||
|
web_seed = 1
|
||||||
|
};
|
||||||
|
int connection_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
The ``flags`` attribute tells you in which state the peer is. It is set to
|
The ``flags`` attribute tells you in which state the peer is. It is set to
|
||||||
|
@ -1838,10 +1992,14 @@ any combination of the enums above. The following table describes each flag:
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
| ``local_connection`` | The connection was initiated by us, the peer has a |
|
| ``local_connection`` | The connection was initiated by us, the peer has a |
|
||||||
| | listen port open, and that port is the same as in the |
|
| | listen port open, and that port is the same as in the |
|
||||||
| | address_ of this peer. If this flag is not set, this |
|
| | address of this peer. If this flag is not set, this |
|
||||||
| | peer connection was opened by this peer connecting to |
|
| | peer connection was opened by this peer connecting to |
|
||||||
| | us. |
|
| | us. |
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
|
| ``handshake`` | The connection is opened, and waiting for the |
|
||||||
|
| | handshake. Until the handshake is done, the peer |
|
||||||
|
| | cannot be identified. |
|
||||||
|
+-------------------------+-------------------------------------------------------+
|
||||||
| ``connecting`` | The connection is in a half-open state (i.e. it is |
|
| ``connecting`` | The connection is in a half-open state (i.e. it is |
|
||||||
| | being connected). |
|
| | being connected). |
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
|
@ -1852,8 +2010,10 @@ any combination of the enums above. The following table describes each flag:
|
||||||
|
|
||||||
__ extension_protocol.html
|
__ extension_protocol.html
|
||||||
|
|
||||||
The ``ip`` field is the IP-address to this peer. Its type is a wrapper around the
|
The ``ip`` field is the IP-address to this peer. The type is an asio endpoint. For
|
||||||
actual address and the port number. See address_ class.
|
more info, see the asio_ documentation.
|
||||||
|
|
||||||
|
.. _asio: http://asio.sf.net
|
||||||
|
|
||||||
``up_speed`` and ``down_speed`` contains the current upload and download speed
|
``up_speed`` and ``down_speed`` contains the current upload and download speed
|
||||||
we have to and from this peer (including any protocol messages). The transfer rates
|
we have to and from this peer (including any protocol messages). The transfer rates
|
||||||
|
@ -1864,7 +2024,7 @@ These figures are updated aproximately once every second.
|
||||||
from and uploaded to this peer. These numbers do not include the protocol chatter, but only
|
from and uploaded to this peer. These numbers do not include the protocol chatter, but only
|
||||||
the payload data.
|
the payload data.
|
||||||
|
|
||||||
``id`` is the peer's id as used in the bit torrent protocol. This id can be used to
|
``pid`` is the peer's id as used in the bit torrent protocol. This id can be used to
|
||||||
extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer
|
extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer
|
||||||
is using. See identify_client()_
|
is using. See identify_client()_
|
||||||
|
|
||||||
|
@ -1878,9 +2038,8 @@ or if the peer miss that piece (set to false).
|
||||||
peer every second. It may be -1 if there's no limit. The upload limits of all peers
|
peer every second. It may be -1 if there's no limit. The upload limits of all peers
|
||||||
should sum up to the upload limit set by ``session::set_upload_limit``.
|
should sum up to the upload limit set by ``session::set_upload_limit``.
|
||||||
|
|
||||||
``upload_ceiling`` is the current maximum allowed upload rate given the cownload
|
``download_limit`` is the number of bytes per second this peer is allowed to
|
||||||
rate and share ratio. If the global upload rate is inlimited, the ``upload_limit``
|
receive. -1 means it's unlimited.
|
||||||
for every peer will be the same as their ``upload_ceiling``.
|
|
||||||
|
|
||||||
``load_balancing`` is a measurment of the balancing of free download (that we get)
|
``load_balancing`` is a measurment of the balancing of free download (that we get)
|
||||||
and free upload that we give. Every peer gets a certain amount of free upload, but
|
and free upload that we give. Every peer gets a certain amount of free upload, but
|
||||||
|
@ -1903,44 +2062,14 @@ block (or sub-piece) that is being downloaded. ``downloading_progress`` is the n
|
||||||
of bytes of this block we have received from the peer, and ``downloading_total`` is
|
of bytes of this block we have received from the peer, and ``downloading_total`` is
|
||||||
the total number of bytes in this block.
|
the total number of bytes in this block.
|
||||||
|
|
||||||
|
``client`` is a string describing the software at the other end of the connection.
|
||||||
|
In some cases this information is not available, then it will contain a string
|
||||||
|
that may give away something about which software is running in the other end.
|
||||||
|
In the case of a web seed, the server type and version will be a part of this
|
||||||
|
string.
|
||||||
|
|
||||||
|
``connection_type`` can currently be one of ``standard_bittorrent`` or
|
||||||
address
|
``web_seed``. These are currently the only implemented protocols.
|
||||||
=======
|
|
||||||
|
|
||||||
The ``address`` class represents a name of a network endpoint (usually referred to as
|
|
||||||
IP-address) and a port number. This is the same thing as a ``sockaddr_in`` would contain.
|
|
||||||
Its declaration looks like this::
|
|
||||||
|
|
||||||
class address
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
address();
|
|
||||||
address(unsigned char a
|
|
||||||
, unsigned char b
|
|
||||||
, unsigned char c
|
|
||||||
, unsigned char d
|
|
||||||
, unsigned short port);
|
|
||||||
address(unsigned int addr, unsigned short port);
|
|
||||||
address(const std::string& addr, unsigned short port);
|
|
||||||
address(const address& a);
|
|
||||||
~address();
|
|
||||||
|
|
||||||
std::string as_string() const;
|
|
||||||
unsigned int ip() const;
|
|
||||||
unsigned short port() const;
|
|
||||||
|
|
||||||
bool operator<(const address& a) const;
|
|
||||||
bool operator!=(const address& a) const;
|
|
||||||
bool operator==(const address& a) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
It is less-than comparable to make it possible to use it as a key in a map. ``as_string()`` may block
|
|
||||||
while it does the DNS lookup, it returns a string that points to the address represented by the object.
|
|
||||||
|
|
||||||
``ip()`` will return the 32-bit ip-address as an integer. ``port()`` returns the port number.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
http_settings
|
http_settings
|
||||||
=============
|
=============
|
||||||
|
@ -1960,7 +2089,8 @@ that will be sent to the tracker. The user-agent is a good way to identify your
|
||||||
std::string proxy_login;
|
std::string proxy_login;
|
||||||
std::string proxy_password;
|
std::string proxy_password;
|
||||||
std::string user_agent;
|
std::string user_agent;
|
||||||
int tracker_timeout;
|
int tracker_completion_timeout;
|
||||||
|
int tracker_receive_timeout;
|
||||||
int tracker_maximum_response_length;
|
int tracker_maximum_response_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1978,10 +2108,18 @@ empty, the http proxy will be tried to be used without authentication.
|
||||||
``user_agent`` this is the client identification to the tracker. It will
|
``user_agent`` this is the client identification to the tracker. It will
|
||||||
be followed by the string "(libtorrent)" to identify that this library
|
be followed by the string "(libtorrent)" to identify that this library
|
||||||
is being used. This should be set to your client's name and version number.
|
is being used. This should be set to your client's name and version number.
|
||||||
|
This name will not only be used when making HTTP requests, but also when
|
||||||
|
sending extended headers to peers that support that extension.
|
||||||
|
|
||||||
``tracker_timeout`` is the number of seconds the tracker connection will
|
``tracker_completion_timeout`` is the number of seconds the tracker
|
||||||
wait until it considers the tracker to have timed-out. Default value is 10
|
connection will wait from when it sent the request until it considers the
|
||||||
seconds.
|
tracker to have timed-out. Default value is 60 seconds.
|
||||||
|
|
||||||
|
``tracker_receive_timeout`` is the number of seconds to wait to receive
|
||||||
|
any data from the tracker. If no data is received for this number of
|
||||||
|
seconds, the tracker will be considered as having timed out. If a tracker
|
||||||
|
is down, this is the kind of timeout that will occur. The default value
|
||||||
|
is 20 seconds.
|
||||||
|
|
||||||
``tracker_maximum_response_length`` is the maximum number of bytes in a
|
``tracker_maximum_response_length`` is the maximum number of bytes in a
|
||||||
tracker response. If a response size passes this number it will be rejected
|
tracker response. If a response size passes this number it will be rejected
|
||||||
|
@ -1998,6 +2136,8 @@ ip_filter
|
||||||
The ``ip_filter`` class is a set of rules that uniquely categorizes all
|
The ``ip_filter`` class is a set of rules that uniquely categorizes all
|
||||||
ip addresses as allowed or disallowed. The default constructor creates
|
ip addresses as allowed or disallowed. The default constructor creates
|
||||||
a single rule that allowes all addresses (0.0.0.0 - 255.255.255.255).
|
a single rule that allowes all addresses (0.0.0.0 - 255.255.255.255).
|
||||||
|
The ``address`` type here is ``asio::ipv4::address``. It can also be
|
||||||
|
accessed as ``libtorrent::address``.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -2112,8 +2252,9 @@ This class creates sha1-hashes. Its declaration looks like this::
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
hasher();
|
hasher();
|
||||||
|
hasher(char const* data, unsigned int len);
|
||||||
|
|
||||||
void update(const char* data, unsigned int len);
|
void update(char const* data, unsigned int len);
|
||||||
sha1_hash final();
|
sha1_hash final();
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
@ -2125,6 +2266,9 @@ create the hash in memory. You can feed the hasher parts of it at a time. When
|
||||||
You have fed the hasher with all the data, you call ``final()`` and it
|
You have fed the hasher with all the data, you call ``final()`` and it
|
||||||
will return the sha1-hash of the data.
|
will return the sha1-hash of the data.
|
||||||
|
|
||||||
|
The constructor that takes a ``char const*`` and an integer will construct the
|
||||||
|
sha1 context and feed it the data passed in.
|
||||||
|
|
||||||
If you want to reuse the hasher object once you have created a hash, you have to
|
If you want to reuse the hasher object once you have created a hash, you have to
|
||||||
call ``reset()`` to reinitialize it.
|
call ``reset()`` to reinitialize it.
|
||||||
|
|
||||||
|
@ -2147,7 +2291,7 @@ This is the class declaration::
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
char id[2];
|
char name[2];
|
||||||
char major_version;
|
char major_version;
|
||||||
char minor_version;
|
char minor_version;
|
||||||
char revision_version;
|
char revision_version;
|
||||||
|
@ -2458,6 +2602,25 @@ the tracker. It is generated with severity level ``warning``.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
url_seed_alert
|
||||||
|
--------------
|
||||||
|
|
||||||
|
This alert is generated when a HTTP seed name lookup fails. This alert is
|
||||||
|
generated as severity level ``warning``.
|
||||||
|
|
||||||
|
It contains ``url`` to the HTTP seed that failed along with an error message.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
struct url_seed_alert: alert
|
||||||
|
{
|
||||||
|
url_seed_alert(std::string const& h, const std::string& msg);
|
||||||
|
virtual std::auto_ptr<alert> clone() const;
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hash_failed_alert
|
hash_failed_alert
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -2493,12 +2656,12 @@ to the torrent that this peer was a member of.
|
||||||
struct peer_ban_alert: alert
|
struct peer_ban_alert: alert
|
||||||
{
|
{
|
||||||
peer_ban_alert(
|
peer_ban_alert(
|
||||||
address const& pip
|
asio::ipv4::tcp::endpoint const& pip
|
||||||
, torrent_handle h
|
, torrent_handle h
|
||||||
, const std::string& msg);
|
, const std::string& msg);
|
||||||
|
|
||||||
virtual std::auto_ptr<alert> clone() const;
|
virtual std::auto_ptr<alert> clone() const;
|
||||||
address ip;
|
asio::ipv4::tcp::endpoint ip;
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2515,12 +2678,12 @@ is generated as severity level ``debug``.
|
||||||
struct peer_error_alert: alert
|
struct peer_error_alert: alert
|
||||||
{
|
{
|
||||||
peer_error_alert(
|
peer_error_alert(
|
||||||
address const& pip
|
asio::ipv4::tcp::endpoint const& pip
|
||||||
, peer_id const& pid
|
, peer_id const& pid
|
||||||
, const std::string& msg);
|
, const std::string& msg);
|
||||||
|
|
||||||
virtual std::auto_ptr<alert> clone() const;
|
virtual std::auto_ptr<alert> clone() const;
|
||||||
address ip;
|
asio::ipv4::tcp::endpoint ip;
|
||||||
peer_id id;
|
peer_id id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2540,13 +2703,13 @@ is a handle to the torrent the peer is a member of. ``
|
||||||
invalid_request_alert(
|
invalid_request_alert(
|
||||||
peer_request const& r
|
peer_request const& r
|
||||||
, torrent_handle const& h
|
, torrent_handle const& h
|
||||||
, address const& send
|
, asio::ipv4::tcp::endpoint const& send
|
||||||
, peer_id const& pid
|
, peer_id const& pid
|
||||||
, std::string const& msg);
|
, std::string const& msg);
|
||||||
|
|
||||||
virtual std::auto_ptr<alert> clone() const;
|
virtual std::auto_ptr<alert> clone() const;
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
address ip;
|
asio::ipv4::tcp::endpoint ip;
|
||||||
peer_request request;
|
peer_request request;
|
||||||
peer_id id;
|
peer_id id;
|
||||||
};
|
};
|
||||||
|
@ -3292,6 +3455,20 @@ Don't have metadata:
|
||||||
| | | doesn't have any metadata. |
|
| | | doesn't have any metadata. |
|
||||||
+-----------+---------------+----------------------------------------+
|
+-----------+---------------+----------------------------------------+
|
||||||
|
|
||||||
|
HTTP seeding
|
||||||
|
------------
|
||||||
|
|
||||||
|
The HTTP seed extension implements `this specification`__.
|
||||||
|
|
||||||
|
The libtorrent implementation assumes that, if the URL ends with a slash
|
||||||
|
('/'), the filename should be appended to it in order to request pieces from
|
||||||
|
that file. The way this works is that if the torrent is a single-file torrent,
|
||||||
|
only that filename is appended. If the torrent is a multi-file torrent, the
|
||||||
|
torrent's name '/' the file name is appended. This is the same directory
|
||||||
|
structure that libtorrent will download torrents into.
|
||||||
|
|
||||||
|
__ http://www.getright.com/seedtorrent.html
|
||||||
|
|
||||||
|
|
||||||
filename checks
|
filename checks
|
||||||
===============
|
===============
|
||||||
|
|
|
@ -14,5 +14,5 @@ make_torrent_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
simple_client_SOURCES = simple_client.cpp
|
simple_client_SOURCES = simple_client.cpp
|
||||||
simple_client_LDADD = $(top_builddir)/src/libtorrent.la
|
simple_client_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
|
|
||||||
AM_CXXFLAGS=-ftemplate-depth-50 -I$(top_srcdir)/include @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
AM_CXXFLAGS=-ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/asio/include @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
||||||
AM_LDFLAGS= ${LDLAGS} -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
AM_LDFLAGS= ${LDLAGS} -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
||||||
|
|
|
@ -226,11 +226,11 @@ std::string progress_bar(float progress, int width, char const* code = "33")
|
||||||
return std::string(bar.begin(), bar.end());
|
return std::string(bar.begin(), bar.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* peer_index(libtorrent::address addr, std::vector<libtorrent::peer_info> const& peers)
|
char const* peer_index(libtorrent::tcp::endpoint addr, std::vector<libtorrent::peer_info> const& peers)
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
|
std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
|
||||||
, peers.end(), boost::bind(std::equal_to<address>()
|
, peers.end(), boost::bind(std::equal_to<libtorrent::tcp::endpoint>()
|
||||||
, bind(&peer_info::ip, _1), addr));
|
, bind(&peer_info::ip, _1), addr));
|
||||||
if (i == peers.end()) return "+";
|
if (i == peers.end()) return "+";
|
||||||
|
|
||||||
|
@ -274,7 +274,11 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
||||||
out << progress_bar(0.f, 15);
|
out << progress_bar(0.f, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->flags & peer_info::connecting)
|
if (i->flags & peer_info::handshake)
|
||||||
|
{
|
||||||
|
out << esc("31") << " waiting for handshake" << esc("0") << "\n";
|
||||||
|
}
|
||||||
|
else if (i->flags & peer_info::connecting)
|
||||||
{
|
{
|
||||||
out << esc("31") << " connecting to peer" << esc("0") << "\n";
|
out << esc("31") << " connecting to peer" << esc("0") << "\n";
|
||||||
}
|
}
|
||||||
|
@ -284,7 +288,7 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out << " " << identify_client(i->id) << "\n";
|
out << " " << i->client << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -569,9 +573,9 @@ int main(int ac, char* av[])
|
||||||
int a, b, c, d;
|
int a, b, c, d;
|
||||||
char dummy;
|
char dummy;
|
||||||
in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
|
in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
|
||||||
address start(a, b, c, d, 0);
|
address start((a << 24) + (b << 16) + (c << 8) + d);
|
||||||
in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
|
in >> a >> dummy >> b >> dummy >> c >> dummy >> d >> dummy;
|
||||||
address last(a, b, c, d, 0);
|
address last((a << 24) + (b << 16) + (c << 8) + d);
|
||||||
int flags;
|
int flags;
|
||||||
in >> flags;
|
in >> flags;
|
||||||
if (flags <= 127) flags = ip_filter::blocked;
|
if (flags <= 127) flags = ip_filter::blocked;
|
||||||
|
@ -681,6 +685,7 @@ int main(int ac, char* av[])
|
||||||
// loop through the alert queue to see if anything has happened.
|
// loop through the alert queue to see if anything has happened.
|
||||||
std::auto_ptr<alert> a;
|
std::auto_ptr<alert> a;
|
||||||
a = ses.pop_alert();
|
a = ses.pop_alert();
|
||||||
|
std::string now = to_simple_string(second_clock::universal_time());
|
||||||
while (a.get())
|
while (a.get())
|
||||||
{
|
{
|
||||||
if (torrent_finished_alert* p = dynamic_cast<torrent_finished_alert*>(a.get()))
|
if (torrent_finished_alert* p = dynamic_cast<torrent_finished_alert*>(a.get()))
|
||||||
|
@ -693,20 +698,22 @@ int main(int ac, char* av[])
|
||||||
// all finished downloades are
|
// all finished downloades are
|
||||||
// moved into this directory
|
// moved into this directory
|
||||||
//p->handle.move_storage("finished");
|
//p->handle.move_storage("finished");
|
||||||
events.push_back(
|
events.push_back(now + ": "
|
||||||
p->handle.get_torrent_info().name() + ": " + a->msg());
|
+ p->handle.get_torrent_info().name() + ": " + a->msg());
|
||||||
}
|
}
|
||||||
else if (peer_error_alert* p = dynamic_cast<peer_error_alert*>(a.get()))
|
else if (peer_error_alert* p = dynamic_cast<peer_error_alert*>(a.get()))
|
||||||
{
|
{
|
||||||
events.push_back(identify_client(p->id) + ": " + a->msg());
|
events.push_back(now + ": " + identify_client(p->pid)
|
||||||
|
+ ": " + a->msg());
|
||||||
}
|
}
|
||||||
else if (invalid_request_alert* p = dynamic_cast<invalid_request_alert*>(a.get()))
|
else if (invalid_request_alert* p = dynamic_cast<invalid_request_alert*>(a.get()))
|
||||||
{
|
{
|
||||||
events.push_back(identify_client(p->id) + ": " + a->msg());
|
events.push_back(now + ": " + identify_client(p->pid)
|
||||||
|
+ ": " + a->msg());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
events.push_back(a->msg());
|
events.push_back(now + ": " + a->msg());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.size() >= 10) events.pop_front();
|
if (events.size() >= 10) events.pop_front();
|
||||||
|
|
|
@ -73,9 +73,12 @@ int main(int argc, char* argv[])
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
using namespace boost::filesystem;
|
using namespace boost::filesystem;
|
||||||
|
|
||||||
|
path::default_name_check(no_check);
|
||||||
|
|
||||||
if (argc != 4)
|
if (argc != 4)
|
||||||
{
|
{
|
||||||
std::cerr << "usage: make_torrent <output torrent-file> <announce url> <file or directory to create torrent from>\n";
|
std::cerr << "usage: make_torrent <output torrent-file> "
|
||||||
|
"<announce url> <file or directory to create torrent from>\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
pkginclude_HEADERS = libtorrent/alert.hpp \
|
pkginclude_HEADERS = libtorrent/alert.hpp \
|
||||||
libtorrent/alert_types.hpp \
|
libtorrent/alert_types.hpp \
|
||||||
libtorrent/allocate_resources.hpp \
|
libtorrent/allocate_resources.hpp \
|
||||||
libtorrent/async_gethostbyname.hpp \
|
|
||||||
libtorrent/bencode.hpp \
|
libtorrent/bencode.hpp \
|
||||||
libtorrent/buffer.hpp \
|
libtorrent/buffer.hpp \
|
||||||
libtorrent/config.hpp \
|
libtorrent/config.hpp \
|
||||||
|
@ -19,6 +18,8 @@ libtorrent/io.hpp \
|
||||||
libtorrent/ip_filter.hpp \
|
libtorrent/ip_filter.hpp \
|
||||||
libtorrent/peer.hpp \
|
libtorrent/peer.hpp \
|
||||||
libtorrent/peer_connection.hpp \
|
libtorrent/peer_connection.hpp \
|
||||||
|
libtorrent/bt_peer_connection.hpp \
|
||||||
|
libtorrent/web_peer_connection.hpp \
|
||||||
libtorrent/peer_id.hpp \
|
libtorrent/peer_id.hpp \
|
||||||
libtorrent/peer_info.hpp \
|
libtorrent/peer_info.hpp \
|
||||||
libtorrent/peer_request.hpp \
|
libtorrent/peer_request.hpp \
|
||||||
|
@ -27,6 +28,7 @@ libtorrent/piece_picker.hpp \
|
||||||
libtorrent/policy.hpp \
|
libtorrent/policy.hpp \
|
||||||
libtorrent/resource_request.hpp \
|
libtorrent/resource_request.hpp \
|
||||||
libtorrent/session.hpp \
|
libtorrent/session.hpp \
|
||||||
|
libtorrent/session_settings.hpp \
|
||||||
libtorrent/size_type.hpp \
|
libtorrent/size_type.hpp \
|
||||||
libtorrent/socket.hpp \
|
libtorrent/socket.hpp \
|
||||||
libtorrent/stat.hpp \
|
libtorrent/stat.hpp \
|
||||||
|
|
|
@ -57,6 +57,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
|
#define TORRENT_MAX_ALERT_TYPES 10
|
||||||
|
|
||||||
namespace libtorrent {
|
namespace libtorrent {
|
||||||
|
|
||||||
class TORRENT_EXPORT alert
|
class TORRENT_EXPORT alert
|
||||||
|
@ -112,13 +114,13 @@ namespace libtorrent {
|
||||||
|
|
||||||
template<
|
template<
|
||||||
class Handler
|
class Handler
|
||||||
, BOOST_PP_ENUM_PARAMS(5, class T)
|
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)
|
||||||
>
|
>
|
||||||
void handle_alert_dispatch(
|
void handle_alert_dispatch(
|
||||||
const std::auto_ptr<alert>& alert_
|
const std::auto_ptr<alert>& alert_
|
||||||
, const Handler& handler
|
, const Handler& handler
|
||||||
, const std::type_info& typeid_
|
, const std::type_info& typeid_
|
||||||
, BOOST_PP_ENUM_BINARY_PARAMS(5, T, *p))
|
, BOOST_PP_ENUM_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
|
||||||
{
|
{
|
||||||
if (typeid_ == typeid(T0))
|
if (typeid_ == typeid(T0))
|
||||||
handler(*static_cast<T0*>(alert_.get()));
|
handler(*static_cast<T0*>(alert_.get()));
|
||||||
|
@ -127,7 +129,7 @@ namespace libtorrent {
|
||||||
alert_
|
alert_
|
||||||
, handler
|
, handler
|
||||||
, typeid_
|
, typeid_
|
||||||
, BOOST_PP_ENUM_SHIFTED_PARAMS(5, p), (void_*)0
|
, BOOST_PP_ENUM_SHIFTED_PARAMS(TORRENT_MAX_ALERT_TYPES, p), (void_*)0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +138,7 @@ namespace libtorrent {
|
||||||
const std::auto_ptr<alert>& alert_
|
const std::auto_ptr<alert>& alert_
|
||||||
, const Handler& handler
|
, const Handler& handler
|
||||||
, const std::type_info& typeid_
|
, const std::type_info& typeid_
|
||||||
, BOOST_PP_ENUM_PARAMS(5, void_* BOOST_PP_INTERCEPT))
|
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
|
||||||
{
|
{
|
||||||
throw unhandled_alert();
|
throw unhandled_alert();
|
||||||
}
|
}
|
||||||
|
@ -144,7 +146,7 @@ namespace libtorrent {
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<
|
template<
|
||||||
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(5, class T, detail::void_)
|
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(TORRENT_MAX_ALERT_TYPES, class T, detail::void_)
|
||||||
>
|
>
|
||||||
struct TORRENT_EXPORT handle_alert
|
struct TORRENT_EXPORT handle_alert
|
||||||
{
|
{
|
||||||
|
@ -159,7 +161,7 @@ namespace libtorrent {
|
||||||
alert_
|
alert_
|
||||||
, handler
|
, handler
|
||||||
, typeid(*alert_)
|
, typeid(*alert_)
|
||||||
, BOOST_PP_ENUM(5, ALERT_POINTER_TYPE, _)
|
, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _)
|
||||||
);
|
);
|
||||||
|
|
||||||
#undef ALERT_POINTER_TYPE
|
#undef ALERT_POINTER_TYPE
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace libtorrent
|
||||||
|
|
||||||
struct TORRENT_EXPORT peer_ban_alert: alert
|
struct TORRENT_EXPORT peer_ban_alert: alert
|
||||||
{
|
{
|
||||||
peer_ban_alert(address const& pip, torrent_handle h, std::string const& msg)
|
peer_ban_alert(tcp::endpoint const& pip, torrent_handle h, std::string const& msg)
|
||||||
: alert(alert::info, msg)
|
: alert(alert::info, msg)
|
||||||
, ip(pip)
|
, ip(pip)
|
||||||
, handle(h)
|
, handle(h)
|
||||||
|
@ -133,30 +133,30 @@ namespace libtorrent
|
||||||
virtual std::auto_ptr<alert> clone() const
|
virtual std::auto_ptr<alert> clone() const
|
||||||
{ return std::auto_ptr<alert>(new peer_ban_alert(*this)); }
|
{ return std::auto_ptr<alert>(new peer_ban_alert(*this)); }
|
||||||
|
|
||||||
address ip;
|
tcp::endpoint ip;
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT peer_error_alert: alert
|
struct TORRENT_EXPORT peer_error_alert: alert
|
||||||
{
|
{
|
||||||
peer_error_alert(address const& pip, peer_id const& pid, std::string const& msg)
|
peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg)
|
||||||
: alert(alert::debug, msg)
|
: alert(alert::debug, msg)
|
||||||
, ip(pip)
|
, ip(pip)
|
||||||
, id(pid)
|
, pid(pid_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual std::auto_ptr<alert> clone() const
|
virtual std::auto_ptr<alert> clone() const
|
||||||
{ return std::auto_ptr<alert>(new peer_error_alert(*this)); }
|
{ return std::auto_ptr<alert>(new peer_error_alert(*this)); }
|
||||||
|
|
||||||
address ip;
|
tcp::endpoint ip;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT chat_message_alert: alert
|
struct TORRENT_EXPORT chat_message_alert: alert
|
||||||
{
|
{
|
||||||
chat_message_alert(
|
chat_message_alert(
|
||||||
const torrent_handle& h
|
const torrent_handle& h
|
||||||
, const address& sender
|
, const tcp::endpoint& sender
|
||||||
, const std::string& msg)
|
, const std::string& msg)
|
||||||
: alert(alert::critical, msg)
|
: alert(alert::critical, msg)
|
||||||
, handle(h)
|
, handle(h)
|
||||||
|
@ -167,7 +167,7 @@ namespace libtorrent
|
||||||
{ return std::auto_ptr<alert>(new chat_message_alert(*this)); }
|
{ return std::auto_ptr<alert>(new chat_message_alert(*this)); }
|
||||||
|
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
address ip;
|
tcp::endpoint ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT invalid_request_alert: alert
|
struct TORRENT_EXPORT invalid_request_alert: alert
|
||||||
|
@ -175,23 +175,23 @@ namespace libtorrent
|
||||||
invalid_request_alert(
|
invalid_request_alert(
|
||||||
peer_request const& r
|
peer_request const& r
|
||||||
, torrent_handle const& h
|
, torrent_handle const& h
|
||||||
, address const& sender
|
, tcp::endpoint const& sender
|
||||||
, peer_id const& pid
|
, peer_id const& pid_
|
||||||
, std::string const& msg)
|
, std::string const& msg)
|
||||||
: alert(alert::debug, msg)
|
: alert(alert::debug, msg)
|
||||||
, handle(h)
|
, handle(h)
|
||||||
, ip(sender)
|
, ip(sender)
|
||||||
, request(r)
|
, request(r)
|
||||||
, id(pid)
|
, pid(pid_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual std::auto_ptr<alert> clone() const
|
virtual std::auto_ptr<alert> clone() const
|
||||||
{ return std::auto_ptr<alert>(new invalid_request_alert(*this)); }
|
{ return std::auto_ptr<alert>(new invalid_request_alert(*this)); }
|
||||||
|
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
address ip;
|
tcp::endpoint ip;
|
||||||
peer_request request;
|
peer_request request;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT torrent_finished_alert: alert
|
struct TORRENT_EXPORT torrent_finished_alert: alert
|
||||||
|
@ -209,6 +209,21 @@ namespace libtorrent
|
||||||
torrent_handle handle;
|
torrent_handle handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TORRENT_EXPORT url_seed_alert: alert
|
||||||
|
{
|
||||||
|
url_seed_alert(
|
||||||
|
const std::string& url_
|
||||||
|
, const std::string& msg)
|
||||||
|
: alert(alert::warning, msg)
|
||||||
|
, url(url_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual std::auto_ptr<alert> clone() const
|
||||||
|
{ return std::auto_ptr<alert>(new url_seed_alert(*this)); }
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT file_error_alert: alert
|
struct TORRENT_EXPORT file_error_alert: alert
|
||||||
{
|
{
|
||||||
file_error_alert(
|
file_error_alert(
|
||||||
|
|
|
@ -44,7 +44,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
class socket;
|
|
||||||
class peer_connection;
|
class peer_connection;
|
||||||
class torrent;
|
class torrent;
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ namespace libtorrent
|
||||||
/*
|
/*
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
int resources
|
int resources
|
||||||
, std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> >& connections
|
, std::map<boost::shared_ptr<socket>, boost::intrusive_ptr<peer_connection> >& connections
|
||||||
, resource_request peer_connection::* res);
|
, resource_request peer_connection::* res);
|
||||||
*/
|
*/
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
|
@ -69,7 +68,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
int resources
|
int resources
|
||||||
, std::map<address, peer_connection*>& connections
|
, std::map<tcp::endpoint, peer_connection*>& connections
|
||||||
, resource_request peer_connection::* res);
|
, resource_request peer_connection::* res);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003, 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_BT_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
#define TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "libtorrent/debug.hpp"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/smart_ptr.hpp>
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
#include <boost/array.hpp>
|
||||||
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
|
#include "libtorrent/peer_connection.hpp"
|
||||||
|
#include "libtorrent/socket.hpp"
|
||||||
|
#include "libtorrent/peer_id.hpp"
|
||||||
|
#include "libtorrent/storage.hpp"
|
||||||
|
#include "libtorrent/stat.hpp"
|
||||||
|
#include "libtorrent/alert.hpp"
|
||||||
|
#include "libtorrent/torrent_handle.hpp"
|
||||||
|
#include "libtorrent/torrent.hpp"
|
||||||
|
#include "libtorrent/allocate_resources.hpp"
|
||||||
|
#include "libtorrent/peer_request.hpp"
|
||||||
|
#include "libtorrent/piece_block_progress.hpp"
|
||||||
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
class torrent;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct session_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TORRENT_EXPORT bt_peer_connection
|
||||||
|
: public peer_connection
|
||||||
|
{
|
||||||
|
friend class invariant_access;
|
||||||
|
public:
|
||||||
|
|
||||||
|
// this is the constructor where the we are the active part.
|
||||||
|
// The peer_conenction should handshake and verify that the
|
||||||
|
// other end has the correct id
|
||||||
|
bt_peer_connection(
|
||||||
|
detail::session_impl& ses
|
||||||
|
, boost::weak_ptr<torrent> t
|
||||||
|
, boost::shared_ptr<stream_socket> s
|
||||||
|
, tcp::endpoint const& remote);
|
||||||
|
|
||||||
|
// with this constructor we have been contacted and we still don't
|
||||||
|
// know which torrent the connection belongs to
|
||||||
|
bt_peer_connection(
|
||||||
|
detail::session_impl& ses
|
||||||
|
, boost::shared_ptr<stream_socket> s);
|
||||||
|
|
||||||
|
~bt_peer_connection();
|
||||||
|
|
||||||
|
// called from the main loop when this connection has any
|
||||||
|
// work to do.
|
||||||
|
|
||||||
|
void on_sent(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
void on_receive(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
virtual void get_peer_info(peer_info& p) const;
|
||||||
|
|
||||||
|
bool support_extensions() const { return m_supports_extensions; }
|
||||||
|
|
||||||
|
bool supports_extension(extension_index ex) const
|
||||||
|
{ return m_extension_messages[ex] > 0; }
|
||||||
|
|
||||||
|
bool has_metadata() const;
|
||||||
|
|
||||||
|
// the message handlers are called
|
||||||
|
// each time a recv() returns some new
|
||||||
|
// data, the last time it will be called
|
||||||
|
// is when the entire packet has been
|
||||||
|
// received, then it will no longer
|
||||||
|
// be called. i.e. most handlers need
|
||||||
|
// to check how much of the packet they
|
||||||
|
// have received before any processing
|
||||||
|
void on_keepalive();
|
||||||
|
void on_choke(int received);
|
||||||
|
void on_unchoke(int received);
|
||||||
|
void on_interested(int received);
|
||||||
|
void on_not_interested(int received);
|
||||||
|
void on_have(int received);
|
||||||
|
void on_bitfield(int received);
|
||||||
|
void on_request(int received);
|
||||||
|
void on_piece(int received);
|
||||||
|
void on_cancel(int received);
|
||||||
|
void on_dht_port(int received);
|
||||||
|
|
||||||
|
void on_extended(int received);
|
||||||
|
|
||||||
|
void on_extended_handshake();
|
||||||
|
void on_chat();
|
||||||
|
void on_metadata();
|
||||||
|
void on_peer_exchange();
|
||||||
|
|
||||||
|
typedef void (bt_peer_connection::*message_handler)(int received);
|
||||||
|
|
||||||
|
// the following functions appends messages
|
||||||
|
// to the send buffer
|
||||||
|
void write_choke();
|
||||||
|
void write_unchoke();
|
||||||
|
void write_interested();
|
||||||
|
void write_not_interested();
|
||||||
|
void write_request(peer_request const& r);
|
||||||
|
void write_cancel(peer_request const& r);
|
||||||
|
void write_bitfield(std::vector<bool> const& bitfield);
|
||||||
|
void write_have(int index);
|
||||||
|
void write_piece(peer_request const& r);
|
||||||
|
void write_handshake();
|
||||||
|
void write_extensions();
|
||||||
|
void write_chat_message(const std::string& msg);
|
||||||
|
void write_metadata(std::pair<int, int> req);
|
||||||
|
void write_metadata_request(std::pair<int, int> req);
|
||||||
|
void write_keepalive();
|
||||||
|
void write_dht_port(int listen_port);
|
||||||
|
void on_connected() {}
|
||||||
|
void on_tick();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void check_invariant() const;
|
||||||
|
boost::posix_time::ptime m_last_choke;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool dispatch_message(int received);
|
||||||
|
// returns the block currently being
|
||||||
|
// downloaded. And the progress of that
|
||||||
|
// block. If the peer isn't downloading
|
||||||
|
// a piece for the moment, the boost::optional
|
||||||
|
// will be invalid.
|
||||||
|
boost::optional<piece_block_progress> downloading_piece_progress() const;
|
||||||
|
|
||||||
|
// if we don't have all metadata
|
||||||
|
// this function will request a part of it
|
||||||
|
// from this peer
|
||||||
|
void request_metadata();
|
||||||
|
|
||||||
|
enum state
|
||||||
|
{
|
||||||
|
read_protocol_length = 0,
|
||||||
|
read_protocol_string,
|
||||||
|
read_info_hash,
|
||||||
|
read_peer_id,
|
||||||
|
|
||||||
|
read_packet_size,
|
||||||
|
read_packet
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string m_client_version;
|
||||||
|
|
||||||
|
state m_state;
|
||||||
|
|
||||||
|
// the timeout in seconds
|
||||||
|
int m_timeout;
|
||||||
|
|
||||||
|
enum message_type
|
||||||
|
{
|
||||||
|
// standard messages
|
||||||
|
msg_choke = 0,
|
||||||
|
msg_unchoke,
|
||||||
|
msg_interested,
|
||||||
|
msg_not_interested,
|
||||||
|
msg_have,
|
||||||
|
msg_bitfield,
|
||||||
|
msg_request,
|
||||||
|
msg_piece,
|
||||||
|
msg_cancel,
|
||||||
|
msg_dht_port,
|
||||||
|
// extension protocol message
|
||||||
|
msg_extended = 20,
|
||||||
|
|
||||||
|
num_supported_messages
|
||||||
|
};
|
||||||
|
|
||||||
|
static const message_handler m_message_handler[num_supported_messages];
|
||||||
|
|
||||||
|
// this is a queue of ranges that describes
|
||||||
|
// where in the send buffer actual payload
|
||||||
|
// data is located. This is currently
|
||||||
|
// only used to be able to gather statistics
|
||||||
|
// seperately on payload and protocol data.
|
||||||
|
struct range
|
||||||
|
{
|
||||||
|
range(int s, int l)
|
||||||
|
: start(s)
|
||||||
|
, length(l)
|
||||||
|
{
|
||||||
|
assert(s >= 0);
|
||||||
|
assert(l > 0);
|
||||||
|
}
|
||||||
|
int start;
|
||||||
|
int length;
|
||||||
|
};
|
||||||
|
static bool range_below_zero(const range& r)
|
||||||
|
{ return r.start < 0; }
|
||||||
|
std::deque<range> m_payloads;
|
||||||
|
|
||||||
|
// this is set to true if the handshake from
|
||||||
|
// the peer indicated that it supports the
|
||||||
|
// extension protocol
|
||||||
|
bool m_supports_extensions;
|
||||||
|
bool m_supports_dht_port;
|
||||||
|
|
||||||
|
static const char* extension_names[num_supported_extensions];
|
||||||
|
// contains the indices of the extension messages for each extension
|
||||||
|
// supported by the other end. A value of <= 0 means that the extension
|
||||||
|
// is not supported.
|
||||||
|
int m_extension_messages[num_supported_extensions];
|
||||||
|
|
||||||
|
// this is set to the current time each time we get a
|
||||||
|
// "I don't have metadata" message.
|
||||||
|
boost::posix_time::ptime m_no_metadata;
|
||||||
|
|
||||||
|
// this is set to the time when we last sent
|
||||||
|
// a request for metadata to this peer
|
||||||
|
boost::posix_time::ptime m_metadata_request;
|
||||||
|
|
||||||
|
// this is set to true when we send a metadata
|
||||||
|
// request to this peer, and reset to false when
|
||||||
|
// we receive a reply to our request.
|
||||||
|
bool m_waiting_metadata_request;
|
||||||
|
|
||||||
|
// if we're waiting for a metadata request
|
||||||
|
// this was the request we sent
|
||||||
|
std::pair<int, int> m_last_metadata_request;
|
||||||
|
|
||||||
|
// the number of bytes of metadata we have received
|
||||||
|
// so far from this per, only counting the current
|
||||||
|
// request. Any previously finished requests
|
||||||
|
// that have been forwarded to the torrent object
|
||||||
|
// do not count.
|
||||||
|
int m_metadata_progress;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool m_in_constructor;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
|
@ -49,6 +49,14 @@ public:
|
||||||
, end(end)
|
, end(end)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
char operator[](int index) const
|
||||||
|
{
|
||||||
|
assert(begin + index < end);
|
||||||
|
return begin[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int left() const { assert(end > begin); return end - begin; }
|
||||||
|
|
||||||
char* begin;
|
char* begin;
|
||||||
char* end;
|
char* end;
|
||||||
};
|
};
|
||||||
|
@ -60,6 +68,14 @@ public:
|
||||||
, end(end)
|
, end(end)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
char operator[](int index) const
|
||||||
|
{
|
||||||
|
assert(begin + index < end);
|
||||||
|
return begin[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int left() const { assert(end > begin); return end - begin; }
|
||||||
|
|
||||||
char const* begin;
|
char const* begin;
|
||||||
char const* end;
|
char const* end;
|
||||||
};
|
};
|
||||||
|
@ -69,7 +85,7 @@ public:
|
||||||
buffer(std::size_t n = 0);
|
buffer(std::size_t n = 0);
|
||||||
~buffer();
|
~buffer();
|
||||||
|
|
||||||
interval allocate(std::size_t n);
|
interval allocate(std::size_t n);
|
||||||
void insert(char const* first, char const* last);
|
void insert(char const* first, char const* last);
|
||||||
void erase(std::size_t n);
|
void erase(std::size_t n);
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
@ -94,7 +110,7 @@ private:
|
||||||
char* m_last;
|
char* m_last;
|
||||||
char* m_write_cursor;
|
char* m_write_cursor;
|
||||||
char* m_read_cursor;
|
char* m_read_cursor;
|
||||||
char* m_read_end;
|
char* m_read_end;
|
||||||
bool m_empty;
|
bool m_empty;
|
||||||
#ifdef TORRENT_BUFFER_DEBUG
|
#ifdef TORRENT_BUFFER_DEBUG
|
||||||
mutable std::vector<char> m_debug;
|
mutable std::vector<char> m_debug;
|
||||||
|
@ -230,27 +246,28 @@ inline void buffer::insert(char const* first, char const* last)
|
||||||
|
|
||||||
inline void buffer::erase(std::size_t n)
|
inline void buffer::erase(std::size_t n)
|
||||||
{
|
{
|
||||||
assert(!m_empty);
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
if (n == 0) return;
|
||||||
|
assert(!m_empty);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
int prev_size = size();
|
int prev_size = size();
|
||||||
#endif
|
#endif
|
||||||
assert(m_read_cursor <= m_read_end);
|
assert(m_read_cursor <= m_read_end);
|
||||||
m_read_cursor += n;
|
m_read_cursor += n;
|
||||||
if (m_read_cursor > m_read_end)
|
if (m_read_cursor > m_read_end)
|
||||||
{
|
{
|
||||||
m_read_cursor = m_first + (m_read_cursor - m_read_end);
|
m_read_cursor = m_first + (m_read_cursor - m_read_end);
|
||||||
assert(m_read_cursor <= m_write_cursor);
|
assert(m_read_cursor <= m_write_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_empty = m_read_cursor == m_write_cursor;
|
m_empty = m_read_cursor == m_write_cursor;
|
||||||
|
|
||||||
assert(prev_size - n == size());
|
assert(prev_size - n == size());
|
||||||
|
|
||||||
#ifdef TORRENT_BUFFER_DEBUG
|
#ifdef TORRENT_BUFFER_DEBUG
|
||||||
m_debug.erase(m_debug.begin(), m_debug.begin() + n);
|
m_debug.erase(m_debug.begin(), m_debug.begin() + n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ namespace libtorrent
|
||||||
m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
|
m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
|
||||||
log("\n\n\n*** starting log ***\n");
|
log("\n\n\n*** starting log ***\n");
|
||||||
}
|
}
|
||||||
virtual void log(const char* text) { assert(text); m_file << text; }
|
virtual void log(const char* text) { assert(text); m_file << text; m_file.flush(); }
|
||||||
|
|
||||||
boost::filesystem::ofstream m_file;
|
boost::filesystem::ofstream m_file;
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,6 +40,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
std::string TORRENT_EXPORT unescape_string(std::string const& s);
|
std::string TORRENT_EXPORT unescape_string(std::string const& s);
|
||||||
std::string TORRENT_EXPORT escape_string(const char* str, int len);
|
std::string TORRENT_EXPORT escape_string(const char* str, int len);
|
||||||
|
std::string TORRENT_EXPORT escape_path(const char* str, int len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED
|
#endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED
|
||||||
|
|
|
@ -114,7 +114,7 @@ namespace libtorrent
|
||||||
size_type write(const char*, size_type num_bytes);
|
size_type write(const char*, size_type num_bytes);
|
||||||
size_type read(char*, size_type num_bytes);
|
size_type read(char*, size_type num_bytes);
|
||||||
|
|
||||||
void seek(size_type pos, seek_mode m = begin);
|
size_type seek(size_type pos, seek_mode m = begin);
|
||||||
size_type tell();
|
size_type tell();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -55,14 +55,14 @@ namespace libtorrent
|
||||||
assert(revision >= 0);
|
assert(revision >= 0);
|
||||||
assert(tag >= 0);
|
assert(tag >= 0);
|
||||||
assert(std::strlen(id_string) == 2);
|
assert(std::strlen(id_string) == 2);
|
||||||
id[0] = id_string[0];
|
name[0] = id_string[0];
|
||||||
id[1] = id_string[1];
|
name[1] = id_string[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string() const
|
std::string to_string() const
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "-" << id[0] << id[1]
|
s << "-" << name[0] << name[1]
|
||||||
<< version_to_char(major_version)
|
<< version_to_char(major_version)
|
||||||
<< version_to_char(minor_version)
|
<< version_to_char(minor_version)
|
||||||
<< version_to_char(revision_version)
|
<< version_to_char(revision_version)
|
||||||
|
@ -70,7 +70,7 @@ namespace libtorrent
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
char id[2];
|
char name[2];
|
||||||
char major_version;
|
char major_version;
|
||||||
char minor_version;
|
char minor_version;
|
||||||
char revision_version;
|
char revision_version;
|
||||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
@ -56,19 +57,62 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/peer.hpp"
|
#include "libtorrent/peer.hpp"
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/async_gethostbyname.hpp"
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class http_parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
http_parser();
|
||||||
|
template <class T>
|
||||||
|
T header(char const* key) const;
|
||||||
|
std::string const& protocol() const { return m_protocol; }
|
||||||
|
int status_code() const { return m_status_code; }
|
||||||
|
std::string message() const { return m_server_message; }
|
||||||
|
buffer::const_interval get_body();
|
||||||
|
bool header_finished() const { return m_state == read_body; }
|
||||||
|
bool finished() const { return m_finished; }
|
||||||
|
boost::tuple<int, int> incoming(buffer::const_interval recv_buffer);
|
||||||
|
int body_start() const { return m_body_start_pos; }
|
||||||
|
private:
|
||||||
|
int m_recv_pos;
|
||||||
|
int m_status_code;
|
||||||
|
std::string m_protocol;
|
||||||
|
std::string m_server_message;
|
||||||
|
|
||||||
class TORRENT_EXPORT http_tracker_connection: public tracker_connection
|
int m_content_length;
|
||||||
|
enum { plain, gzip } m_content_encoding;
|
||||||
|
|
||||||
|
enum { read_status, read_header, read_body } m_state;
|
||||||
|
|
||||||
|
std::map<std::string, std::string> m_header;
|
||||||
|
buffer::const_interval m_recv_buffer;
|
||||||
|
int m_body_start_pos;
|
||||||
|
|
||||||
|
bool m_finished;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T http_parser::header(char const* key) const
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string>::const_iterator i
|
||||||
|
= m_header.find(key);
|
||||||
|
if (i == m_header.end()) return T();
|
||||||
|
return boost::lexical_cast<T>(i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TORRENT_EXPORT http_tracker_connection
|
||||||
|
: public tracker_connection
|
||||||
{
|
{
|
||||||
friend class tracker_manager;
|
friend class tracker_manager;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
http_tracker_connection(
|
http_tracker_connection(
|
||||||
tracker_manager& man
|
demuxer& d
|
||||||
|
, tracker_manager& man
|
||||||
, tracker_request const& req
|
, tracker_request const& req
|
||||||
, std::string const& hostname
|
, std::string const& hostname
|
||||||
, unsigned short port
|
, unsigned short port
|
||||||
|
@ -76,18 +120,29 @@ namespace libtorrent
|
||||||
, boost::weak_ptr<request_callback> c
|
, boost::weak_ptr<request_callback> c
|
||||||
, const http_settings& stn
|
, const http_settings& stn
|
||||||
, std::string const& password = "");
|
, std::string const& password = "");
|
||||||
virtual bool tick();
|
|
||||||
virtual bool send_finished() const
|
|
||||||
{ return m_send_buffer.empty(); }
|
|
||||||
virtual tracker_request const& tracker_req() const
|
virtual tracker_request const& tracker_req() const
|
||||||
{ return m_req; }
|
{ return m_req; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
boost::intrusive_ptr<http_tracker_connection> self()
|
||||||
|
{ return boost::intrusive_ptr<http_tracker_connection>(this); }
|
||||||
|
|
||||||
|
void on_response();
|
||||||
|
|
||||||
void init_send_buffer(
|
void init_send_buffer(
|
||||||
std::string const& hostname
|
std::string const& hostname
|
||||||
, std::string const& request);
|
, std::string const& request);
|
||||||
|
|
||||||
|
void name_lookup(asio::error const& error);
|
||||||
|
void connected(asio::error const& error);
|
||||||
|
void sent(asio::error const& error);
|
||||||
|
void receive(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
virtual void on_timeout();
|
||||||
|
|
||||||
void parse(const entry& e);
|
void parse(const entry& e);
|
||||||
peer_entry extract_peer_info(const entry& e);
|
peer_entry extract_peer_info(const entry& e);
|
||||||
|
|
||||||
|
@ -98,15 +153,14 @@ namespace libtorrent
|
||||||
int m_content_length;
|
int m_content_length;
|
||||||
std::string m_location;
|
std::string m_location;
|
||||||
|
|
||||||
dns_lookup m_name_lookup;
|
host_resolver m_name_lookup;
|
||||||
boost::shared_ptr<socket> m_socket;
|
host m_host;
|
||||||
|
int m_port;
|
||||||
|
boost::shared_ptr<stream_socket> m_socket;
|
||||||
int m_recv_pos;
|
int m_recv_pos;
|
||||||
std::vector<char> m_buffer;
|
std::vector<char> m_buffer;
|
||||||
std::string m_send_buffer;
|
std::string m_send_buffer;
|
||||||
|
|
||||||
// used for time outs
|
|
||||||
boost::posix_time::ptime m_request_time;
|
|
||||||
|
|
||||||
std::string m_server_message;
|
std::string m_server_message;
|
||||||
std::string m_server_protocol;
|
std::string m_server_protocol;
|
||||||
|
|
||||||
|
@ -117,8 +171,11 @@ namespace libtorrent
|
||||||
|
|
||||||
// server string in http-reply
|
// server string in http-reply
|
||||||
std::string m_server;
|
std::string m_server;
|
||||||
|
|
||||||
|
bool m_timed_out;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
|
#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
|
@ -30,17 +30,23 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IP_FILTER_HPP
|
#ifndef TORRENT_IP_FILTER_HPP
|
||||||
#define IP_FILTER_HPP
|
#define TORRENT_IP_FILTER_HPP
|
||||||
|
|
||||||
#include "libtorrent/socket.hpp"
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/socket.hpp"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
|
inline bool operator<=(address const& lhs
|
||||||
|
, address const& rhs)
|
||||||
|
{
|
||||||
|
return lhs < rhs || lhs == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
class TORRENT_EXPORT ip_filter
|
class TORRENT_EXPORT ip_filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -44,16 +44,16 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
std::string ip;
|
std::string ip;
|
||||||
int port;
|
int port;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
|
|
||||||
bool operator==(const peer_entry& p) const
|
bool operator==(const peer_entry& p) const
|
||||||
{
|
{
|
||||||
return id == p.id;
|
return pid == p.pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const peer_entry& p) const
|
bool operator<(const peer_entry& p) const
|
||||||
{
|
{
|
||||||
return id < p.id;
|
return pid < p.pid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/smart_ptr.hpp>
|
#include <boost/smart_ptr.hpp>
|
||||||
|
#include <boost/weak_ptr.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
@ -68,6 +69,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/peer_request.hpp"
|
#include "libtorrent/peer_request.hpp"
|
||||||
#include "libtorrent/piece_block_progress.hpp"
|
#include "libtorrent/piece_block_progress.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
|
||||||
// TODO: each time a block is 'taken over'
|
// TODO: each time a block is 'taken over'
|
||||||
// from another peer. That peer must be given
|
// from another peer. That peer must be given
|
||||||
|
@ -82,6 +84,9 @@ namespace libtorrent
|
||||||
struct session_impl;
|
struct session_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
|
||||||
|
TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
|
||||||
|
|
||||||
struct TORRENT_EXPORT protocol_error: std::runtime_error
|
struct TORRENT_EXPORT protocol_error: std::runtime_error
|
||||||
{
|
{
|
||||||
protocol_error(const std::string& msg): std::runtime_error(msg) {};
|
protocol_error(const std::string& msg): std::runtime_error(msg) {};
|
||||||
|
@ -89,27 +94,26 @@ namespace libtorrent
|
||||||
|
|
||||||
class TORRENT_EXPORT peer_connection
|
class TORRENT_EXPORT peer_connection
|
||||||
: public boost::noncopyable
|
: public boost::noncopyable
|
||||||
, public boost::enable_shared_from_this<peer_connection>
|
|
||||||
{
|
{
|
||||||
friend class invariant_access;
|
friend class invariant_access;
|
||||||
|
friend void intrusive_ptr_add_ref(peer_connection const*);
|
||||||
|
friend void intrusive_ptr_release(peer_connection const*);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// this is the constructor where the we are teh active part.
|
// this is the constructor where the we are the active part.
|
||||||
// The peer_conenction should handshake and verify that the
|
// The peer_conenction should handshake and verify that the
|
||||||
// other end has the correct id
|
// other end has the correct id
|
||||||
peer_connection(
|
peer_connection(
|
||||||
detail::session_impl& ses
|
detail::session_impl& ses
|
||||||
, selector& sel
|
, boost::weak_ptr<torrent> t
|
||||||
, torrent* t
|
, boost::shared_ptr<stream_socket> s
|
||||||
, boost::shared_ptr<libtorrent::socket> s
|
, tcp::endpoint const& remote);
|
||||||
, address const& remote);
|
|
||||||
|
|
||||||
// with this constructor we have been contacted and we still don't
|
// with this constructor we have been contacted and we still don't
|
||||||
// know which torrent the connection belongs to
|
// know which torrent the connection belongs to
|
||||||
peer_connection(
|
peer_connection(
|
||||||
detail::session_impl& ses
|
detail::session_impl& ses
|
||||||
, selector& sel
|
, boost::shared_ptr<stream_socket> s);
|
||||||
, boost::shared_ptr<libtorrent::socket> s);
|
|
||||||
|
|
||||||
// this function is called once the torrent associated
|
// this function is called once the torrent associated
|
||||||
// with this peer connection has retrieved the meta-
|
// with this peer connection has retrieved the meta-
|
||||||
|
@ -117,17 +121,15 @@ namespace libtorrent
|
||||||
// this is called from the constructor.
|
// this is called from the constructor.
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
~peer_connection();
|
void set_upload_limit(int limit);
|
||||||
|
void set_download_limit(int limit);
|
||||||
|
|
||||||
|
virtual ~peer_connection();
|
||||||
|
|
||||||
// this adds an announcement in the announcement queue
|
// this adds an announcement in the announcement queue
|
||||||
// it will let the peer know that we have the given piece
|
// it will let the peer know that we have the given piece
|
||||||
void announce_piece(int index);
|
void announce_piece(int index);
|
||||||
|
|
||||||
// called from the main loop when this connection has any
|
|
||||||
// work to do.
|
|
||||||
void send_data();
|
|
||||||
void receive_data();
|
|
||||||
|
|
||||||
// tells if this connection has data it want to send
|
// tells if this connection has data it want to send
|
||||||
// and has enough upload bandwidth quota left to send it.
|
// and has enough upload bandwidth quota left to send it.
|
||||||
bool can_write() const;
|
bool can_write() const;
|
||||||
|
@ -140,20 +142,14 @@ namespace libtorrent
|
||||||
// will send a keep-alive message to the peer
|
// will send a keep-alive message to the peer
|
||||||
void keep_alive();
|
void keep_alive();
|
||||||
|
|
||||||
const peer_id& id() const { return m_peer_id; }
|
peer_id const& pid() const { return m_peer_id; }
|
||||||
|
void set_pid(const peer_id& pid) { m_peer_id = pid; }
|
||||||
bool has_piece(int i) const;
|
bool has_piece(int i) const;
|
||||||
|
|
||||||
const std::deque<piece_block>& download_queue() const;
|
const std::deque<piece_block>& download_queue() const;
|
||||||
const std::deque<piece_block>& request_queue() const;
|
const std::deque<piece_block>& request_queue() const;
|
||||||
const std::deque<peer_request>& upload_queue() const;
|
const std::deque<peer_request>& upload_queue() const;
|
||||||
|
|
||||||
// returns the block currently being
|
|
||||||
// downloaded. And the progress of that
|
|
||||||
// block. If the peer isn't downloading
|
|
||||||
// a piece for the moment, the boost::optional
|
|
||||||
// will be invalid.
|
|
||||||
boost::optional<piece_block_progress> downloading_piece() const;
|
|
||||||
|
|
||||||
bool is_interesting() const { return m_interesting; }
|
bool is_interesting() const { return m_interesting; }
|
||||||
bool is_choked() const { return m_choked; }
|
bool is_choked() const { return m_choked; }
|
||||||
|
|
||||||
|
@ -164,21 +160,19 @@ namespace libtorrent
|
||||||
// may be zero if the connection is an incoming connection
|
// may be zero if the connection is an incoming connection
|
||||||
// and it hasn't received enough information to determine
|
// and it hasn't received enough information to determine
|
||||||
// which torrent it should be associated with
|
// which torrent it should be associated with
|
||||||
torrent* associated_torrent() const { return m_attached_to_torrent?m_torrent:0; }
|
boost::weak_ptr<torrent> associated_torrent() const
|
||||||
|
{ return m_torrent; }
|
||||||
bool verify_piece(const peer_request& p) const;
|
|
||||||
|
|
||||||
const stat& statistics() const { return m_statistics; }
|
const stat& statistics() const { return m_statistics; }
|
||||||
void add_stat(size_type downloaded, size_type uploaded);
|
void add_stat(size_type downloaded, size_type uploaded);
|
||||||
|
|
||||||
// is called once every second by the main loop
|
// is called once every second by the main loop
|
||||||
void second_tick();
|
void second_tick(float tick_interval);
|
||||||
|
|
||||||
boost::shared_ptr<libtorrent::socket> get_socket() const { return m_socket; }
|
boost::shared_ptr<stream_socket> get_socket() const { return m_socket; }
|
||||||
address const& remote() const { return m_remote; }
|
tcp::endpoint const& remote() const { return m_remote; }
|
||||||
|
|
||||||
const peer_id& get_peer_id() const { return m_peer_id; }
|
std::vector<bool> const& get_bitfield() const;
|
||||||
const std::vector<bool>& get_bitfield() const;
|
|
||||||
|
|
||||||
// this will cause this peer_connection to be disconnected.
|
// this will cause this peer_connection to be disconnected.
|
||||||
// what it does is that it puts a reference to it in
|
// what it does is that it puts a reference to it in
|
||||||
|
@ -190,7 +184,7 @@ namespace libtorrent
|
||||||
// this is called when the connection attempt has succeeded
|
// this is called when the connection attempt has succeeded
|
||||||
// and the peer_connection is supposed to set m_connecting
|
// and the peer_connection is supposed to set m_connecting
|
||||||
// to false, and stop monitor writability
|
// to false, and stop monitor writability
|
||||||
void connection_complete();
|
void on_connection_complete(asio::error const& e);
|
||||||
|
|
||||||
// returns true if this connection is still waiting to
|
// returns true if this connection is still waiting to
|
||||||
// finish the connection attempt
|
// finish the connection attempt
|
||||||
|
@ -206,20 +200,16 @@ namespace libtorrent
|
||||||
// the library isn't using up the limitation of half-open
|
// the library isn't using up the limitation of half-open
|
||||||
// tcp connections.
|
// tcp connections.
|
||||||
void connect();
|
void connect();
|
||||||
|
|
||||||
|
|
||||||
// This is called for every peer right after the upload
|
// This is called for every peer right after the upload
|
||||||
// bandwidth has been distributed among them
|
// bandwidth has been distributed among them
|
||||||
// It will reset the used bandwidth to 0 and
|
// It will reset the used bandwidth to 0.
|
||||||
// possibly add or remove the peer's socket
|
|
||||||
// from the socket monitor
|
|
||||||
void reset_upload_quota();
|
void reset_upload_quota();
|
||||||
|
|
||||||
// free upload.
|
// free upload.
|
||||||
size_type total_free_upload() const;
|
size_type total_free_upload() const;
|
||||||
void add_free_upload(size_type free_upload);
|
void add_free_upload(size_type free_upload);
|
||||||
|
|
||||||
|
|
||||||
// trust management.
|
// trust management.
|
||||||
void received_valid_data();
|
void received_valid_data();
|
||||||
void received_invalid_data();
|
void received_invalid_data();
|
||||||
|
@ -227,8 +217,6 @@ namespace libtorrent
|
||||||
|
|
||||||
size_type share_diff() const;
|
size_type share_diff() const;
|
||||||
|
|
||||||
bool support_extensions() const { return m_supports_extensions; }
|
|
||||||
|
|
||||||
// a connection is local if it was initiated by us.
|
// a connection is local if it was initiated by us.
|
||||||
// if it was an incoming connection, it is remote
|
// if it was an incoming connection, it is remote
|
||||||
bool is_local() const { return m_active; }
|
bool is_local() const { return m_active; }
|
||||||
|
@ -236,24 +224,12 @@ namespace libtorrent
|
||||||
void set_failed() { m_failed = true; }
|
void set_failed() { m_failed = true; }
|
||||||
bool failed() const { return m_failed; }
|
bool failed() const { return m_failed; }
|
||||||
|
|
||||||
|
int desired_queue_size() const { return m_desired_queue_size; }
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
boost::shared_ptr<logger> m_logger;
|
boost::shared_ptr<logger> m_logger;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum extension_index
|
|
||||||
{
|
|
||||||
extended_chat_message,
|
|
||||||
extended_metadata_message,
|
|
||||||
extended_peer_exchange_message,
|
|
||||||
extended_listen_port_message,
|
|
||||||
num_supported_extensions
|
|
||||||
};
|
|
||||||
|
|
||||||
bool supports_extension(extension_index ex) const
|
|
||||||
{ return m_extension_messages[ex] != -1; }
|
|
||||||
|
|
||||||
bool has_metadata() const;
|
|
||||||
|
|
||||||
// the message handlers are called
|
// the message handlers are called
|
||||||
// each time a recv() returns some new
|
// each time a recv() returns some new
|
||||||
// data, the last time it will be called
|
// data, the last time it will be called
|
||||||
|
@ -262,26 +238,18 @@ namespace libtorrent
|
||||||
// be called. i.e. most handlers need
|
// be called. i.e. most handlers need
|
||||||
// to check how much of the packet they
|
// to check how much of the packet they
|
||||||
// have received before any processing
|
// have received before any processing
|
||||||
void on_choke(int received);
|
void incoming_keepalive();
|
||||||
void on_unchoke(int received);
|
void incoming_choke();
|
||||||
void on_interested(int received);
|
void incoming_unchoke();
|
||||||
void on_not_interested(int received);
|
void incoming_interested();
|
||||||
void on_have(int received);
|
void incoming_not_interested();
|
||||||
void on_bitfield(int received);
|
void incoming_have(int piece_index);
|
||||||
void on_request(int received);
|
void incoming_bitfield(std::vector<bool> const& bitfield);
|
||||||
void on_piece(int received);
|
void incoming_request(peer_request const& r);
|
||||||
void on_cancel(int received);
|
void incoming_piece(peer_request const& p, char const* data);
|
||||||
void on_dht_port(int received);
|
void incoming_piece_fragment();
|
||||||
|
void incoming_cancel(peer_request const& r);
|
||||||
void on_extension_list(int received);
|
void incoming_dht_port(int listen_port);
|
||||||
void on_extended(int received);
|
|
||||||
|
|
||||||
void on_chat();
|
|
||||||
void on_metadata();
|
|
||||||
void on_peer_exchange();
|
|
||||||
void on_listen_port();
|
|
||||||
|
|
||||||
typedef void (peer_connection::*message_handler)(int received);
|
|
||||||
|
|
||||||
// the following functions appends messages
|
// the following functions appends messages
|
||||||
// to the send buffer
|
// to the send buffer
|
||||||
|
@ -289,15 +257,10 @@ namespace libtorrent
|
||||||
void send_unchoke();
|
void send_unchoke();
|
||||||
void send_interested();
|
void send_interested();
|
||||||
void send_not_interested();
|
void send_not_interested();
|
||||||
void send_request(piece_block block);
|
|
||||||
void send_cancel(piece_block block);
|
// adds a block to the request queue
|
||||||
void send_bitfield();
|
void add_request(piece_block const& b);
|
||||||
void send_have(int index);
|
void cancel_request(piece_block const& b);
|
||||||
void send_handshake();
|
|
||||||
void send_extensions();
|
|
||||||
void send_chat_message(const std::string& msg);
|
|
||||||
void send_metadata(std::pair<int, int> req);
|
|
||||||
void send_metadata_request(std::pair<int, int> req);
|
|
||||||
|
|
||||||
// how much bandwidth we're using, how much we want,
|
// how much bandwidth we're using, how much we want,
|
||||||
// and how much we are allowed to use.
|
// and how much we are allowed to use.
|
||||||
|
@ -309,59 +272,104 @@ namespace libtorrent
|
||||||
boost::posix_time::ptime m_last_choke;
|
boost::posix_time::ptime m_last_choke;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtual void get_peer_info(peer_info& p) const = 0;
|
||||||
|
|
||||||
|
// returns the block currently being
|
||||||
|
// downloaded. And the progress of that
|
||||||
|
// block. If the peer isn't downloading
|
||||||
|
// a piece for the moment, the boost::optional
|
||||||
|
// will be invalid.
|
||||||
|
virtual boost::optional<piece_block_progress>
|
||||||
|
downloading_piece_progress() const
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << "downloading_piece_progress() dispatched to the base class!\n";
|
||||||
|
#endif
|
||||||
|
return boost::optional<piece_block_progress>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void write_choke() = 0;
|
||||||
|
virtual void write_unchoke() = 0;
|
||||||
|
virtual void write_interested() = 0;
|
||||||
|
virtual void write_not_interested() = 0;
|
||||||
|
virtual void write_request(peer_request const& r) = 0;
|
||||||
|
virtual void write_cancel(peer_request const& r) = 0;
|
||||||
|
virtual void write_have(int index) = 0;
|
||||||
|
virtual void write_keepalive() = 0;
|
||||||
|
virtual void write_piece(peer_request const& r) = 0;
|
||||||
|
|
||||||
|
virtual void on_connected() = 0;
|
||||||
|
virtual void on_tick() {}
|
||||||
|
|
||||||
|
virtual void on_receive(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) = 0;
|
||||||
|
virtual void on_sent(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) = 0;
|
||||||
|
|
||||||
|
void send_buffer(char const* begin, char const* end);
|
||||||
|
buffer::interval allocate_send_buffer(int size);
|
||||||
|
int send_buffer_size() const
|
||||||
|
{
|
||||||
|
return (int)m_send_buffer[0].size()
|
||||||
|
+ (int)m_send_buffer[1].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer::const_interval receive_buffer() const
|
||||||
|
{
|
||||||
|
return buffer::const_interval(&m_recv_buffer[0]
|
||||||
|
, &m_recv_buffer[0] + m_recv_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cut_receive_buffer(int size, int packet_size);
|
||||||
|
|
||||||
|
void reset_recv_buffer(int packet_size);
|
||||||
|
int packet_size() const { return m_packet_size; }
|
||||||
|
|
||||||
|
bool packet_finished() const
|
||||||
|
{
|
||||||
|
assert(m_recv_pos <= m_packet_size);
|
||||||
|
return m_packet_size == m_recv_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_send();
|
||||||
|
void setup_receive();
|
||||||
|
|
||||||
|
void attach_to_torrent(sha1_hash const& ih);
|
||||||
|
|
||||||
|
bool verify_piece(peer_request const& p) const;
|
||||||
|
|
||||||
|
// statistics about upload and download speeds
|
||||||
|
// and total amount of uploads and downloads for
|
||||||
|
// this peer
|
||||||
|
stat m_statistics;
|
||||||
|
|
||||||
|
// a back reference to the session
|
||||||
|
// the peer belongs to.
|
||||||
|
detail::session_impl& m_ses;
|
||||||
|
|
||||||
|
boost::intrusive_ptr<peer_connection> self()
|
||||||
|
{ return boost::intrusive_ptr<peer_connection>(this); }
|
||||||
|
|
||||||
|
// called from the main loop when this connection has any
|
||||||
|
// work to do.
|
||||||
|
void on_send_data(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
void on_receive_data(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void fill_send_buffer();
|
||||||
void send_block_requests();
|
void send_block_requests();
|
||||||
bool dispatch_message(int received);
|
|
||||||
|
|
||||||
// if we don't have all metadata
|
|
||||||
// this function will request a part of it
|
|
||||||
// from this peer
|
|
||||||
void request_metadata();
|
|
||||||
|
|
||||||
// this is called each time this peer generates some
|
|
||||||
// data to be sent. It will add this socket to
|
|
||||||
// the writibility monitor in the selector.
|
|
||||||
void send_buffer_updated();
|
|
||||||
|
|
||||||
// is used during handshake
|
|
||||||
enum state
|
|
||||||
{
|
|
||||||
read_protocol_length = 0,
|
|
||||||
read_protocol_string,
|
|
||||||
read_info_hash,
|
|
||||||
read_peer_id,
|
|
||||||
|
|
||||||
read_packet_size,
|
|
||||||
read_packet
|
|
||||||
};
|
|
||||||
|
|
||||||
state m_state;
|
|
||||||
|
|
||||||
// the timeout in seconds
|
// the timeout in seconds
|
||||||
int m_timeout;
|
int m_timeout;
|
||||||
|
|
||||||
enum message_type
|
// the time when we last got a part of a
|
||||||
{
|
// piece packet from this peer
|
||||||
// standard messages
|
boost::posix_time::ptime m_last_piece;
|
||||||
msg_choke = 0,
|
|
||||||
msg_unchoke,
|
|
||||||
msg_interested,
|
|
||||||
msg_not_interested,
|
|
||||||
msg_have,
|
|
||||||
msg_bitfield,
|
|
||||||
msg_request,
|
|
||||||
msg_piece,
|
|
||||||
msg_cancel,
|
|
||||||
msg_dht_port,
|
|
||||||
// extension protocol message
|
|
||||||
msg_extension_list = 20,
|
|
||||||
msg_extended,
|
|
||||||
|
|
||||||
num_supported_messages
|
|
||||||
};
|
|
||||||
|
|
||||||
static const message_handler m_message_handler[num_supported_messages];
|
|
||||||
|
|
||||||
int m_packet_size;
|
int m_packet_size;
|
||||||
int m_recv_pos;
|
int m_recv_pos;
|
||||||
|
@ -369,73 +377,37 @@ namespace libtorrent
|
||||||
|
|
||||||
// this is the buffer where data that is
|
// this is the buffer where data that is
|
||||||
// to be sent is stored until it gets
|
// to be sent is stored until it gets
|
||||||
// consumed by send()
|
// consumed by send(). Since asio requires
|
||||||
// std::vector<char> m_send_buffer;
|
// the memory buffer that is given to async.
|
||||||
buffer m_send_buffer;
|
// operations to remain valid until the operation
|
||||||
|
// finishes, there has to be two buffers. While
|
||||||
// this is a queue of ranges that describes
|
// waiting for a async_write operation on one
|
||||||
// where in the send buffer actual payload
|
// buffer, the other is used to write data to
|
||||||
// data is located. This is currently
|
// be queued up.
|
||||||
// only used to be able to gather statistics
|
buffer m_send_buffer[2];
|
||||||
// seperately on payload and protocol data.
|
// the current send buffer is the one to write to.
|
||||||
struct range
|
// (m_current_send_buffer + 1) % 2 is the
|
||||||
{
|
// buffer we're currently waiting for.
|
||||||
range(int s, int l)
|
int m_current_send_buffer;
|
||||||
: start(s)
|
|
||||||
, length(l)
|
|
||||||
{
|
|
||||||
assert(s >= 0);
|
|
||||||
assert(l > 0);
|
|
||||||
}
|
|
||||||
int start;
|
|
||||||
int length;
|
|
||||||
};
|
|
||||||
static bool range_below_zero(const range& r)
|
|
||||||
{ return r.start < 0; }
|
|
||||||
std::deque<range> m_payloads;
|
|
||||||
|
|
||||||
// timeouts
|
// timeouts
|
||||||
boost::posix_time::ptime m_last_receive;
|
boost::posix_time::ptime m_last_receive;
|
||||||
boost::posix_time::ptime m_last_sent;
|
boost::posix_time::ptime m_last_sent;
|
||||||
|
|
||||||
// the selector is used to add and remove this
|
boost::shared_ptr<stream_socket> m_socket;
|
||||||
// peer's socket from the writability monitor list.
|
tcp::endpoint m_remote;
|
||||||
selector& m_selector;
|
|
||||||
boost::shared_ptr<libtorrent::socket> m_socket;
|
|
||||||
address m_remote;
|
|
||||||
|
|
||||||
// this is the torrent this connection is
|
// this is the torrent this connection is
|
||||||
// associated with. If the connection is an
|
// associated with. If the connection is an
|
||||||
// incoming conncetion, this is set to zero
|
// incoming conncetion, this is set to zero
|
||||||
// until the info_hash is received. Then it's
|
// until the info_hash is received. Then it's
|
||||||
// set to the torrent it belongs to.
|
// set to the torrent it belongs to.
|
||||||
torrent* m_torrent;
|
boost::weak_ptr<torrent> m_torrent;
|
||||||
|
|
||||||
// this is set to false until the peer_id
|
|
||||||
// is received from the other end. Or it is
|
|
||||||
// true from the start if the conenction
|
|
||||||
// was actively opened from our side.
|
|
||||||
bool m_attached_to_torrent;
|
|
||||||
|
|
||||||
// a back reference to the session
|
|
||||||
// the peer belongs to.
|
|
||||||
detail::session_impl& m_ses;
|
|
||||||
|
|
||||||
// is true if it was we that connected to the peer
|
// is true if it was we that connected to the peer
|
||||||
// and false if we got an incomming connection
|
// and false if we got an incomming connection
|
||||||
// could be considered: true = local, false = remote
|
// could be considered: true = local, false = remote
|
||||||
bool m_active;
|
bool m_active;
|
||||||
|
|
||||||
// this is true as long as this peer's
|
|
||||||
// socket is added to the selector to
|
|
||||||
// monitor writability. Each time we do
|
|
||||||
// something that generates data to be
|
|
||||||
// sent to this peer, we check this and
|
|
||||||
// if it's not added to the selector we
|
|
||||||
// add it. (this is done in send_buffer_updated())
|
|
||||||
bool m_writability_monitored;
|
|
||||||
bool m_readability_monitored;
|
|
||||||
|
|
||||||
// remote peer's id
|
// remote peer's id
|
||||||
peer_id m_peer_id;
|
peer_id m_peer_id;
|
||||||
|
|
||||||
|
@ -459,11 +431,6 @@ namespace libtorrent
|
||||||
// this peer
|
// this peer
|
||||||
bool m_failed;
|
bool m_failed;
|
||||||
|
|
||||||
// this is set to true if the handshake from
|
|
||||||
// the peer indicated that it supports the
|
|
||||||
// extension protocol
|
|
||||||
bool m_supports_extensions;
|
|
||||||
|
|
||||||
// the pieces the other end have
|
// the pieces the other end have
|
||||||
std::vector<bool> m_have_piece;
|
std::vector<bool> m_have_piece;
|
||||||
|
|
||||||
|
@ -477,11 +444,6 @@ namespace libtorrent
|
||||||
// from this peer
|
// from this peer
|
||||||
std::deque<peer_request> m_requests;
|
std::deque<peer_request> m_requests;
|
||||||
|
|
||||||
// a list of pieces that have become available
|
|
||||||
// and should be announced as available to
|
|
||||||
// the peer
|
|
||||||
std::vector<int> m_announce_queue;
|
|
||||||
|
|
||||||
// the blocks we have reserved in the piece
|
// the blocks we have reserved in the piece
|
||||||
// picker and will send to this peer.
|
// picker and will send to this peer.
|
||||||
std::deque<piece_block> m_request_queue;
|
std::deque<piece_block> m_request_queue;
|
||||||
|
@ -489,11 +451,10 @@ namespace libtorrent
|
||||||
// the queue of blocks we have requested
|
// the queue of blocks we have requested
|
||||||
// from this peer
|
// from this peer
|
||||||
std::deque<piece_block> m_download_queue;
|
std::deque<piece_block> m_download_queue;
|
||||||
|
|
||||||
// statistics about upload and download speeds
|
// the number of request we should queue up
|
||||||
// and total amount of uploads and downloads for
|
// at the remote end.
|
||||||
// this peer
|
int m_desired_queue_size;
|
||||||
stat m_statistics;
|
|
||||||
|
|
||||||
// the amount of data this peer has been given
|
// the amount of data this peer has been given
|
||||||
// as free upload. This is distributed from
|
// as free upload. This is distributed from
|
||||||
|
@ -511,8 +472,12 @@ namespace libtorrent
|
||||||
// considered a bad peer and will be banned.
|
// considered a bad peer and will be banned.
|
||||||
int m_trust_points;
|
int m_trust_points;
|
||||||
|
|
||||||
static const char* extension_names[num_supported_extensions];
|
// if this is true, this peer is assumed to handle all piece
|
||||||
int m_extension_messages[num_supported_extensions];
|
// requests in fifo order. All skipped blocks are re-requested
|
||||||
|
// immediately instead of having a looser requirement
|
||||||
|
// where blocks can be sent out of order. The default is to
|
||||||
|
// allow non-fifo order.
|
||||||
|
bool m_assume_fifo;
|
||||||
|
|
||||||
// the number of invalid piece-requests
|
// the number of invalid piece-requests
|
||||||
// we have got from this peer. If the request
|
// we have got from this peer. If the request
|
||||||
|
@ -523,10 +488,6 @@ namespace libtorrent
|
||||||
// by sending choke, unchoke.
|
// by sending choke, unchoke.
|
||||||
int m_num_invalid_requests;
|
int m_num_invalid_requests;
|
||||||
|
|
||||||
// the time when we last got a part of a
|
|
||||||
// piece packet from this peer
|
|
||||||
boost::posix_time::ptime m_last_piece;
|
|
||||||
|
|
||||||
// this is true if this connection has been added
|
// this is true if this connection has been added
|
||||||
// to the list of connections that will be closed.
|
// to the list of connections that will be closed.
|
||||||
bool m_disconnecting;
|
bool m_disconnecting;
|
||||||
|
@ -539,23 +500,6 @@ namespace libtorrent
|
||||||
// this peer the last time.
|
// this peer the last time.
|
||||||
boost::posix_time::ptime m_became_uninteresting;
|
boost::posix_time::ptime m_became_uninteresting;
|
||||||
|
|
||||||
// this is set to the current time each time we get a
|
|
||||||
// "I don't have metadata" message.
|
|
||||||
boost::posix_time::ptime m_no_metadata;
|
|
||||||
|
|
||||||
// this is set to the time when we last sent
|
|
||||||
// a request for metadata to this peer
|
|
||||||
boost::posix_time::ptime m_metadata_request;
|
|
||||||
|
|
||||||
// this is set to true when we send a metadata
|
|
||||||
// request to this peer, and reset to false when
|
|
||||||
// we receive a reply to our request.
|
|
||||||
bool m_waiting_metadata_request;
|
|
||||||
|
|
||||||
// if we're waiting for a metadata request
|
|
||||||
// this was the request we sent
|
|
||||||
std::pair<int, int> m_last_metadata_request;
|
|
||||||
|
|
||||||
// this is true until this socket has become
|
// this is true until this socket has become
|
||||||
// writable for the first time (i.e. the
|
// writable for the first time (i.e. the
|
||||||
// connection completed). While connecting
|
// connection completed). While connecting
|
||||||
|
@ -571,12 +515,24 @@ namespace libtorrent
|
||||||
// connections.
|
// connections.
|
||||||
bool m_queued;
|
bool m_queued;
|
||||||
|
|
||||||
// the number of bytes of metadata we have received
|
// these are true when there's a asynchronous write
|
||||||
// so far from this per, only counting the current
|
// or read operation running.
|
||||||
// request. Any previously finished requests
|
bool m_writing;
|
||||||
// that have been forwarded to the torrent object
|
// this is the number of bytes sent to the socket last
|
||||||
// do not count.
|
// time it was invoked. This is compared against the
|
||||||
int m_metadata_progress;
|
// bytes_transferred in the callback function that tells
|
||||||
|
// how much actually was sent. Then the quota can be
|
||||||
|
// corrected according to the actual number of bytes sent
|
||||||
|
int m_last_write_size;
|
||||||
|
bool m_reading;
|
||||||
|
int m_last_read_size;
|
||||||
|
// reference counter for intrusive_ptr
|
||||||
|
mutable int m_refs;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
public:
|
||||||
|
bool m_in_constructor;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,22 +52,23 @@ namespace libtorrent
|
||||||
remote_choked = 0x8,
|
remote_choked = 0x8,
|
||||||
supports_extensions = 0x10,
|
supports_extensions = 0x10,
|
||||||
local_connection = 0x20,
|
local_connection = 0x20,
|
||||||
connecting = 0x40,
|
handshake = 0x40,
|
||||||
queued = 0x80
|
connecting = 0x80,
|
||||||
|
queued = 0x100
|
||||||
};
|
};
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
address ip;
|
tcp::endpoint ip;
|
||||||
float up_speed;
|
float up_speed;
|
||||||
float down_speed;
|
float down_speed;
|
||||||
float payload_up_speed;
|
float payload_up_speed;
|
||||||
float payload_down_speed;
|
float payload_down_speed;
|
||||||
size_type total_download;
|
size_type total_download;
|
||||||
size_type total_upload;
|
size_type total_upload;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
std::vector<bool> pieces;
|
std::vector<bool> pieces;
|
||||||
bool seed; // true if this is a seed
|
bool seed; // true if this is a seed
|
||||||
int upload_limit; // from peer_connection
|
int upload_limit;
|
||||||
int upload_ceiling; // from the global upload limiter
|
int download_limit;
|
||||||
|
|
||||||
size_type load_balancing;
|
size_type load_balancing;
|
||||||
|
|
||||||
|
@ -89,6 +90,15 @@ namespace libtorrent
|
||||||
int downloading_block_index;
|
int downloading_block_index;
|
||||||
int downloading_progress;
|
int downloading_progress;
|
||||||
int downloading_total;
|
int downloading_total;
|
||||||
|
|
||||||
|
std::string client;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
standard_bittorrent = 0,
|
||||||
|
web_seed = 1
|
||||||
|
};
|
||||||
|
int connection_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,13 +49,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
|
#include "libtorrent/session_settings.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
class torrent;
|
class torrent;
|
||||||
class address;
|
|
||||||
class peer_connection;
|
class peer_connection;
|
||||||
|
|
||||||
struct TORRENT_EXPORT piece_block
|
struct TORRENT_EXPORT piece_block
|
||||||
|
@ -93,7 +93,7 @@ namespace libtorrent
|
||||||
block_info(): num_downloads(0) {}
|
block_info(): num_downloads(0) {}
|
||||||
// the peer this block was requested or
|
// the peer this block was requested or
|
||||||
// downloaded from
|
// downloaded from
|
||||||
address peer;
|
tcp::endpoint peer;
|
||||||
// the number of times this block has been downloaded
|
// the number of times this block has been downloaded
|
||||||
int num_downloads;
|
int num_downloads;
|
||||||
};
|
};
|
||||||
|
@ -110,8 +110,11 @@ namespace libtorrent
|
||||||
block_info info[max_blocks_per_piece];
|
block_info info[max_blocks_per_piece];
|
||||||
};
|
};
|
||||||
|
|
||||||
piece_picker(int blocks_per_piece,
|
piece_picker(int blocks_per_piece
|
||||||
int total_num_blocks);
|
, int total_num_blocks
|
||||||
|
, int sequenced_download_threshold);
|
||||||
|
|
||||||
|
void set_sequenced_download_threshold(int sequenced_download_threshold);
|
||||||
|
|
||||||
// this is called before any other method is called
|
// this is called before any other method is called
|
||||||
// after the local files has been checked.
|
// after the local files has been checked.
|
||||||
|
@ -161,12 +164,12 @@ namespace libtorrent
|
||||||
// decides to download a piece, it must mark it as being downloaded
|
// decides to download a piece, it must mark it as being downloaded
|
||||||
// itself, by using the mark_as_downloading() member function.
|
// itself, by using the mark_as_downloading() member function.
|
||||||
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
||||||
// The last argument is the address of the peer that we'll download
|
// The last argument is the tcp::endpoint of the peer that we'll download
|
||||||
// from.
|
// from.
|
||||||
void pick_pieces(const std::vector<bool>& pieces
|
void pick_pieces(const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, int num_pieces, bool prefer_whole_pieces
|
, int num_pieces, bool prefer_whole_pieces
|
||||||
, address peer) const;
|
, tcp::endpoint peer) const;
|
||||||
|
|
||||||
// returns true if any client is currently downloading this
|
// returns true if any client is currently downloading this
|
||||||
// piece-block, or if it's queued for downloading by some client
|
// piece-block, or if it's queued for downloading by some client
|
||||||
|
@ -175,8 +178,8 @@ namespace libtorrent
|
||||||
bool is_finished(piece_block block) const;
|
bool is_finished(piece_block block) const;
|
||||||
|
|
||||||
// marks this piece-block as queued for downloading
|
// marks this piece-block as queued for downloading
|
||||||
void mark_as_downloading(piece_block block, const address& peer);
|
void mark_as_downloading(piece_block block, tcp::endpoint const& peer);
|
||||||
void mark_as_finished(piece_block block, const address& peer);
|
void mark_as_finished(piece_block block, tcp::endpoint const& peer);
|
||||||
|
|
||||||
// if a piece had a hash-failure, it must be restored and
|
// if a piece had a hash-failure, it must be restored and
|
||||||
// made available for redownloading
|
// made available for redownloading
|
||||||
|
@ -195,12 +198,12 @@ namespace libtorrent
|
||||||
// the hash-check yet
|
// the hash-check yet
|
||||||
int unverified_blocks() const;
|
int unverified_blocks() const;
|
||||||
|
|
||||||
void get_downloaders(std::vector<address>& d, int index) const;
|
void get_downloaders(std::vector<tcp::endpoint>& d, int index) const;
|
||||||
|
|
||||||
const std::vector<downloading_piece>& get_download_queue() const
|
const std::vector<downloading_piece>& get_download_queue() const
|
||||||
{ return m_downloads; }
|
{ return m_downloads; }
|
||||||
|
|
||||||
boost::optional<address> get_downloader(piece_block block) const;
|
boost::optional<tcp::endpoint> get_downloader(piece_block block) const;
|
||||||
|
|
||||||
// the number of filtered pieces we don't have
|
// the number of filtered pieces we don't have
|
||||||
int num_filtered() const { return m_num_filtered; }
|
int num_filtered() const { return m_num_filtered; }
|
||||||
|
@ -252,10 +255,20 @@ namespace libtorrent
|
||||||
|
|
||||||
enum { we_have_index = 0x3ffff };
|
enum { we_have_index = 0x3ffff };
|
||||||
|
|
||||||
bool operator!=(piece_pos p)
|
int priority(int limit) const
|
||||||
|
{
|
||||||
|
return peer_count >= (unsigned)limit ? limit : peer_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ordered(int limit) const
|
||||||
|
{
|
||||||
|
return peer_count >= (unsigned)limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(piece_pos p) const
|
||||||
{ return index != p.index || peer_count != p.peer_count; }
|
{ return index != p.index || peer_count != p.peer_count; }
|
||||||
|
|
||||||
bool operator==(piece_pos p)
|
bool operator==(piece_pos p) const
|
||||||
{ return index == p.index && peer_count == p.peer_count; }
|
{ return index == p.index && peer_count == p.peer_count; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -280,7 +293,7 @@ namespace libtorrent
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, address peer) const;
|
, tcp::endpoint peer) const;
|
||||||
|
|
||||||
|
|
||||||
// this vector contains all pieces we don't have.
|
// this vector contains all pieces we don't have.
|
||||||
|
@ -321,6 +334,10 @@ namespace libtorrent
|
||||||
|
|
||||||
// the number of pieces we have that also are filtered
|
// the number of pieces we have that also are filtered
|
||||||
int m_num_have_filtered;
|
int m_num_have_filtered;
|
||||||
|
|
||||||
|
// the required popularity of a piece in order to download
|
||||||
|
// it in sequence instead of random order.
|
||||||
|
int m_sequenced_download_threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int piece_picker::blocks_in_piece(int index) const
|
inline int piece_picker::blocks_in_piece(int index) const
|
||||||
|
|
|
@ -57,7 +57,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
class torrent;
|
class torrent;
|
||||||
class address;
|
|
||||||
class peer_connection;
|
class peer_connection;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -84,7 +83,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// this is called once for every peer we get from
|
// this is called once for every peer we get from
|
||||||
// the tracker
|
// the tracker
|
||||||
void peer_from_tracker(const address& remote, const peer_id& id);
|
void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid);
|
||||||
|
|
||||||
// called when an incoming connection is accepted
|
// called when an incoming connection is accepted
|
||||||
// return false if the connection closed
|
// return false if the connection closed
|
||||||
|
@ -131,7 +130,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
enum connection_type { not_connectable,connectable };
|
enum connection_type { not_connectable,connectable };
|
||||||
|
|
||||||
peer(const address& ip, connection_type t);
|
peer(const tcp::endpoint& ip, connection_type t);
|
||||||
|
|
||||||
size_type total_download() const;
|
size_type total_download() const;
|
||||||
size_type total_upload() const;
|
size_type total_upload() const;
|
||||||
|
@ -140,7 +139,7 @@ namespace libtorrent
|
||||||
// if it was a remote (incoming) connection, type is
|
// if it was a remote (incoming) connection, type is
|
||||||
// set thereafter. If it was a peer we got from the
|
// set thereafter. If it was a peer we got from the
|
||||||
// tracker, type is set to local_connection.
|
// tracker, type is set to local_connection.
|
||||||
address id;
|
tcp::endpoint ip;
|
||||||
connection_type type;
|
connection_type type;
|
||||||
|
|
||||||
// the time when this peer was optimistically unchoked
|
// the time when this peer was optimistically unchoked
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright (c) 2003, Magnus Jonsson
|
Copyright (c) 2003, Magnus Jonsson, Arvid Norberg
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -60,7 +60,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
assert(given <= max);
|
assert(given <= max);
|
||||||
assert(given >= min);
|
assert(given >= min);
|
||||||
assert(given >= used);
|
// TODO: TEMP!
|
||||||
|
// assert(given >= used);
|
||||||
return given - used;
|
return given - used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
@ -69,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/piece_block_progress.hpp"
|
#include "libtorrent/piece_block_progress.hpp"
|
||||||
#include "libtorrent/ip_filter.hpp"
|
#include "libtorrent/ip_filter.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/session_settings.hpp"
|
||||||
|
|
||||||
#if !defined(NDEBUG) && defined(_MSC_VER)
|
#if !defined(NDEBUG) && defined(_MSC_VER)
|
||||||
# include <float.h>
|
# include <float.h>
|
||||||
|
@ -77,9 +79,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
class torrent;
|
class torrent;
|
||||||
|
|
||||||
|
enum extension_index
|
||||||
|
{
|
||||||
|
extended_handshake,
|
||||||
|
extended_chat_message,
|
||||||
|
extended_metadata_message,
|
||||||
|
extended_peer_exchange_message,
|
||||||
|
num_supported_extensions
|
||||||
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
// workaround for microsofts
|
// workaround for microsofts
|
||||||
|
@ -123,7 +133,7 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<int> piece_map;
|
std::vector<int> piece_map;
|
||||||
std::vector<piece_picker::downloading_piece> unfinished_pieces;
|
std::vector<piece_picker::downloading_piece> unfinished_pieces;
|
||||||
std::vector<address> peers;
|
std::vector<tcp::endpoint> peers;
|
||||||
entry resume_data;
|
entry resume_data;
|
||||||
|
|
||||||
// this is true if this torrent is being processed (checked)
|
// this is true if this torrent is being processed (checked)
|
||||||
|
@ -170,12 +180,10 @@ namespace libtorrent
|
||||||
struct session_impl: boost::noncopyable
|
struct session_impl: boost::noncopyable
|
||||||
{
|
{
|
||||||
friend class invariant_access;
|
friend class invariant_access;
|
||||||
// TODO: maybe this should be changed to a sorted vector
|
typedef std::map<boost::shared_ptr<stream_socket>, boost::intrusive_ptr<peer_connection> >
|
||||||
// using lower_bound?
|
|
||||||
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> >
|
|
||||||
connection_map;
|
connection_map;
|
||||||
typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
|
typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
|
||||||
typedef std::deque<boost::shared_ptr<peer_connection> >
|
typedef std::deque<boost::intrusive_ptr<peer_connection> >
|
||||||
connection_queue;
|
connection_queue;
|
||||||
|
|
||||||
session_impl(
|
session_impl(
|
||||||
|
@ -187,10 +195,16 @@ namespace libtorrent
|
||||||
|
|
||||||
void open_listen_port();
|
void open_listen_port();
|
||||||
|
|
||||||
|
void async_accept();
|
||||||
|
void on_incoming_connection(boost::shared_ptr<stream_socket> const& s
|
||||||
|
, boost::weak_ptr<socket_acceptor> const& as, asio::error const& e);
|
||||||
|
|
||||||
// must be locked to access the data
|
// must be locked to access the data
|
||||||
// in this struct
|
// in this struct
|
||||||
mutable boost::mutex m_mutex;
|
typedef boost::recursive_mutex mutex_t;
|
||||||
torrent* find_torrent(const sha1_hash& info_hash);
|
mutable mutex_t m_mutex;
|
||||||
|
|
||||||
|
boost::weak_ptr<torrent> find_torrent(const sha1_hash& info_hash);
|
||||||
peer_id const& get_peer_id() const { return m_peer_id; }
|
peer_id const& get_peer_id() const { return m_peer_id; }
|
||||||
|
|
||||||
tracker_manager m_tracker_manager;
|
tracker_manager m_tracker_manager;
|
||||||
|
@ -201,15 +215,11 @@ namespace libtorrent
|
||||||
// is reached.
|
// is reached.
|
||||||
void process_connection_queue();
|
void process_connection_queue();
|
||||||
|
|
||||||
void connection_failed(boost::shared_ptr<socket> const& s
|
void close_connection(boost::intrusive_ptr<peer_connection> const& p);
|
||||||
, address const& a, char const* message);
|
void connection_completed(boost::intrusive_ptr<peer_connection> const& p);
|
||||||
|
void connection_failed(boost::shared_ptr<stream_socket> const& s
|
||||||
|
, tcp::endpoint const& a, char const* message);
|
||||||
|
|
||||||
// this is where all active sockets are stored.
|
|
||||||
// the selector can sleep while there's no activity on
|
|
||||||
// them
|
|
||||||
selector m_selector;
|
|
||||||
|
|
||||||
|
|
||||||
// this maps sockets to their peer_connection
|
// this maps sockets to their peer_connection
|
||||||
// object. It is the complete list of all connected
|
// object. It is the complete list of all connected
|
||||||
// peers.
|
// peers.
|
||||||
|
@ -225,13 +235,7 @@ namespace libtorrent
|
||||||
// waiting for one slot in the half-open queue to open up.
|
// waiting for one slot in the half-open queue to open up.
|
||||||
connection_queue m_connection_queue;
|
connection_queue m_connection_queue;
|
||||||
|
|
||||||
// this is a list of iterators into the m_connections map
|
// filters incoming connections
|
||||||
// that should be disconnected as soon as possible.
|
|
||||||
// It is used to delay disconnections to avoid troubles
|
|
||||||
// in loops that iterate over them.
|
|
||||||
std::vector<boost::shared_ptr<peer_connection> > m_disconnect_peer;
|
|
||||||
|
|
||||||
// filters incomming connections
|
|
||||||
ip_filter m_ip_filter;
|
ip_filter m_ip_filter;
|
||||||
|
|
||||||
// the peer id that is generated at the start of the session
|
// the peer id that is generated at the start of the session
|
||||||
|
@ -250,18 +254,24 @@ namespace libtorrent
|
||||||
// if the ip is set to zero, it means
|
// if the ip is set to zero, it means
|
||||||
// that we should let the os decide which
|
// that we should let the os decide which
|
||||||
// interface to listen on
|
// interface to listen on
|
||||||
address m_listen_interface;
|
tcp::endpoint m_listen_interface;
|
||||||
|
|
||||||
boost::shared_ptr<socket> m_listen_socket;
|
// this is where all active sockets are stored.
|
||||||
|
// the selector can sleep while there's no activity on
|
||||||
|
// them
|
||||||
|
demuxer m_selector;
|
||||||
|
|
||||||
|
boost::shared_ptr<socket_acceptor> m_listen_socket;
|
||||||
|
|
||||||
// the entries in this array maps the
|
// the entries in this array maps the
|
||||||
// extension index (as specified in peer_connection)
|
// extension index (as specified in peer_connection)
|
||||||
bool m_extension_enabled[peer_connection::num_supported_extensions];
|
bool m_extension_enabled[num_supported_extensions];
|
||||||
|
|
||||||
bool extensions_enabled() const;
|
bool extensions_enabled() const;
|
||||||
|
|
||||||
// the settings for the client
|
// the settings for the client
|
||||||
http_settings m_settings;
|
session_settings m_settings;
|
||||||
|
http_settings m_http_settings;
|
||||||
|
|
||||||
// set to true when the session object
|
// set to true when the session object
|
||||||
// is being destructed and the thread
|
// is being destructed and the thread
|
||||||
|
@ -293,8 +303,11 @@ namespace libtorrent
|
||||||
|
|
||||||
// does the actual disconnections
|
// does the actual disconnections
|
||||||
// that are queued up in m_disconnect_peer
|
// that are queued up in m_disconnect_peer
|
||||||
void purge_connections();
|
void second_tick(asio::error const& e);
|
||||||
|
boost::posix_time::ptime m_last_tick;
|
||||||
|
|
||||||
|
// the timer used to fire the second_tick
|
||||||
|
deadline_timer m_timer;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void check_invariant(const char *place = 0);
|
void check_invariant(const char *place = 0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -330,7 +343,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
session(fingerprint const& print = fingerprint("LT", 0, 9, 1, 0));
|
session(fingerprint const& print = fingerprint("LT", 0, 9, 2, 0));
|
||||||
session(
|
session(
|
||||||
fingerprint const& print
|
fingerprint const& print
|
||||||
, std::pair<int, int> listen_port_range
|
, std::pair<int, int> listen_port_range
|
||||||
|
@ -348,7 +361,7 @@ namespace libtorrent
|
||||||
, bool compact_mode = true
|
, bool compact_mode = true
|
||||||
, int block_size = 16 * 1024);
|
, int block_size = 16 * 1024);
|
||||||
|
|
||||||
// TODO: depricated, this is for backwards compatibility only
|
// TODO: deprecated, this is for backwards compatibility only
|
||||||
torrent_handle add_torrent(
|
torrent_handle add_torrent(
|
||||||
entry const& e
|
entry const& e
|
||||||
, boost::filesystem::path const& save_path
|
, boost::filesystem::path const& save_path
|
||||||
|
@ -370,11 +383,11 @@ namespace libtorrent
|
||||||
|
|
||||||
session_status status() const;
|
session_status status() const;
|
||||||
|
|
||||||
void enable_extension(peer_connection::extension_index i);
|
void enable_extension(extension_index i);
|
||||||
void disable_extensions();
|
void disable_extensions();
|
||||||
|
|
||||||
void set_ip_filter(ip_filter const& f);
|
void set_ip_filter(ip_filter const& f);
|
||||||
void set_peer_id(peer_id const& id);
|
void set_peer_id(peer_id const& pid);
|
||||||
void set_key(int key);
|
void set_key(int key);
|
||||||
|
|
||||||
bool is_listening() const;
|
bool is_listening() const;
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003, 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_SESSION_SETTINGS_HPP_INCLUDED
|
||||||
|
#define TORRENT_SESSION_SETTINGS_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TORRENT_EXPORT session_settings
|
||||||
|
{
|
||||||
|
session_settings()
|
||||||
|
: piece_timeout(120)
|
||||||
|
, request_queue_time(3.f)
|
||||||
|
, sequenced_download_threshold(7)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// the number of seconds from a request is sent until
|
||||||
|
// it times out if no piece response is returned.
|
||||||
|
int piece_timeout;
|
||||||
|
|
||||||
|
// the length of the request queue given in the number
|
||||||
|
// of seconds it should take for the other end to send
|
||||||
|
// all the pieces. i.e. the actual number of requests
|
||||||
|
// depends on the download rate and this number.
|
||||||
|
float request_queue_time;
|
||||||
|
|
||||||
|
// this is the limit on how popular a piece has to be
|
||||||
|
// (popular == inverse of rarity) to be downloaded
|
||||||
|
// in sequence instead of in random (rarest first) order.
|
||||||
|
// it can be used to tweak disk performance in settings
|
||||||
|
// where the random download property is less necessary.
|
||||||
|
// for example, if the threshold is 7, all pieces which 7
|
||||||
|
// or more peers have, will be downloaded in index order.
|
||||||
|
int sequenced_download_threshold;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -37,268 +37,54 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma warning(push, 1)
|
#pragma warning(push, 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
// if building as Objective C++, asio's template
|
||||||
#include <boost/function.hpp>
|
// parameters Protocol has to be renamed to avoid
|
||||||
#include <boost/noncopyable.hpp>
|
// colliding with keywords
|
||||||
#include <boost/cstdint.hpp>
|
|
||||||
#include <boost/thread/thread.hpp>
|
#ifdef __OBJC__
|
||||||
|
#define Protocol Protocol_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <asio.hpp>
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#undef Protocol
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <exception>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "libtorrent/config.hpp"
|
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
namespace asio = boost::asio;
|
||||||
|
|
||||||
class TORRENT_EXPORT network_error : public std::exception
|
using boost::asio::ipv4::tcp;
|
||||||
{
|
using boost::asio::ipv4::address;
|
||||||
public:
|
using boost::asio::stream_socket;
|
||||||
network_error(int error_code): m_error_code(error_code) {}
|
using boost::asio::datagram_socket;
|
||||||
virtual const char* what() const throw();
|
using boost::asio::socket_acceptor;
|
||||||
int error_code() const
|
using boost::asio::demuxer;
|
||||||
{ return m_error_code; }
|
using boost::asio::ipv4::host_resolver;
|
||||||
private:
|
using boost::asio::async_write;
|
||||||
int m_error_code;
|
using boost::asio::ipv4::host;
|
||||||
};
|
using boost::asio::deadline_timer;
|
||||||
|
*/
|
||||||
|
namespace asio = ::asio;
|
||||||
|
|
||||||
class socket;
|
using asio::ipv4::tcp;
|
||||||
|
using asio::ipv4::udp;
|
||||||
class TORRENT_EXPORT address
|
typedef asio::ipv4::tcp::socket stream_socket;
|
||||||
{
|
using asio::ipv4::address;
|
||||||
friend class socket;
|
typedef asio::ipv4::udp::socket datagram_socket;
|
||||||
public:
|
typedef asio::ipv4::tcp::acceptor socket_acceptor;
|
||||||
address();
|
typedef asio::io_service demuxer;
|
||||||
address(
|
using asio::ipv4::host_resolver;
|
||||||
unsigned char a
|
using asio::ipv4::host;
|
||||||
, unsigned char b
|
|
||||||
, unsigned char c
|
|
||||||
, unsigned char d
|
|
||||||
, unsigned short port);
|
|
||||||
|
|
||||||
address(unsigned int addr, unsigned short port);
|
|
||||||
|
|
||||||
address(const char* addr, unsigned short port);
|
|
||||||
address(const address& a);
|
|
||||||
~address();
|
|
||||||
|
|
||||||
std::string as_string() const;
|
|
||||||
unsigned int ip() const { return m_ip; }
|
|
||||||
|
|
||||||
bool operator<=(const address& a) const
|
|
||||||
{ if (ip() == a.ip()) return port <= a.port; else return ip() <= a.ip(); }
|
|
||||||
bool operator<(const address& a) const
|
|
||||||
{ if (ip() == a.ip()) return port < a.port; else return ip() < a.ip(); }
|
|
||||||
bool operator!=(const address& a) const
|
|
||||||
{ return ip() != a.ip() || port != a.port; }
|
|
||||||
bool operator==(const address& a) const
|
|
||||||
{ return ip() == a.ip() && port == a.port; }
|
|
||||||
|
|
||||||
unsigned short port;
|
|
||||||
|
|
||||||
BOOST_STATIC_CONSTANT(unsigned short, any_port = 0);
|
|
||||||
BOOST_STATIC_CONSTANT(unsigned int, any_addr = 0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
unsigned int m_ip;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TORRENT_EXPORT socket: public boost::noncopyable
|
|
||||||
{
|
|
||||||
friend class address;
|
|
||||||
friend class selector;
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum type
|
|
||||||
{
|
|
||||||
tcp = 0,
|
|
||||||
udp
|
|
||||||
};
|
|
||||||
|
|
||||||
socket(type t, bool blocking = true, unsigned short receive_port = 0);
|
|
||||||
virtual ~socket();
|
|
||||||
|
|
||||||
void connect(
|
|
||||||
const address& addr
|
|
||||||
, address const& bind_to
|
|
||||||
= address(address::any_addr, address::any_port));
|
|
||||||
void close();
|
|
||||||
|
|
||||||
void set_blocking(bool blocking);
|
|
||||||
bool is_blocking() { return m_blocking; }
|
|
||||||
|
|
||||||
const address& sender() const { assert(m_sender != address()); return m_sender; }
|
|
||||||
address name() const;
|
|
||||||
|
|
||||||
void listen(libtorrent::address const& iface, int queue);
|
|
||||||
boost::shared_ptr<libtorrent::socket> accept();
|
|
||||||
|
|
||||||
template<class T> int send(const T& buffer);
|
|
||||||
template<class T> int send_to(const address& addr, const T& buffer);
|
|
||||||
template<class T> int receive(T& buf);
|
|
||||||
|
|
||||||
int send(const char* buffer, int size);
|
|
||||||
int send_to(const address& addr, const char* buffer, int size);
|
|
||||||
int receive(char* buffer, int size);
|
|
||||||
|
|
||||||
void set_receive_bufsize(int size);
|
|
||||||
void set_send_bufsize(int size);
|
|
||||||
|
|
||||||
bool is_readable() const;
|
|
||||||
bool is_writable() const;
|
|
||||||
bool has_error() const;
|
|
||||||
|
|
||||||
enum error_code
|
|
||||||
{
|
|
||||||
netdown,
|
|
||||||
fault,
|
|
||||||
access,
|
|
||||||
address_in_use,
|
|
||||||
address_not_available,
|
|
||||||
in_progress,
|
|
||||||
interrupted,
|
|
||||||
invalid,
|
|
||||||
net_reset,
|
|
||||||
not_connected,
|
|
||||||
no_buffers,
|
|
||||||
operation_not_supported,
|
|
||||||
not_socket,
|
|
||||||
shutdown,
|
|
||||||
would_block,
|
|
||||||
connection_reset,
|
|
||||||
timed_out,
|
|
||||||
connection_aborted,
|
|
||||||
message_size,
|
|
||||||
not_ready,
|
|
||||||
no_support,
|
|
||||||
connection_refused,
|
|
||||||
is_connected,
|
|
||||||
net_unreachable,
|
|
||||||
not_initialized,
|
|
||||||
host_not_found,
|
|
||||||
unknown_error
|
|
||||||
};
|
|
||||||
|
|
||||||
error_code last_error() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
socket(int sock, const address& sender, bool blocking);
|
|
||||||
|
|
||||||
int m_socket;
|
|
||||||
address m_sender;
|
|
||||||
bool m_blocking;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
bool m_connected; // indicates that this socket has been connected
|
|
||||||
type m_type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
inline int socket::send(const T& buf)
|
|
||||||
{
|
|
||||||
return send(reinterpret_cast<const char*>(&buf), sizeof(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
inline int socket::send_to(const address& addr, const T& buf)
|
|
||||||
{
|
|
||||||
return send_to(addr, reinterpret_cast<const unsigned char*>(&buf), sizeof(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
inline int socket::receive(T& buf)
|
|
||||||
{
|
|
||||||
return receive(reinterpret_cast<char*>(&buf), sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// timeout is given in microseconds
|
|
||||||
// modified is cleared and filled with the sockets that is ready for reading or writing
|
|
||||||
// or have had an error
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TORRENT_EXPORT selector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
void monitor_readability(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
assert(std::find(m_readable.begin(), m_readable.end(), s) == m_readable.end());
|
|
||||||
m_readable.push_back(s);
|
|
||||||
}
|
|
||||||
void monitor_writability(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
assert(std::find(m_writable.begin(), m_writable.end(), s) == m_writable.end());
|
|
||||||
m_writable.push_back(s);
|
|
||||||
}
|
|
||||||
void monitor_errors(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
assert(std::find(m_error.begin(), m_error.end(), s) == m_error.end());
|
|
||||||
m_error.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(boost::shared_ptr<socket> s);
|
|
||||||
|
|
||||||
void remove_writable(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
m_writable.erase(std::find(m_writable.begin(), m_writable.end(), s));
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_readable(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
m_readable.erase(std::find(m_readable.begin(), m_readable.end(), s));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_writability_monitored(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
return std::find(m_writable.begin(), m_writable.end(), s)
|
|
||||||
!= m_writable.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_readability_monitored(boost::shared_ptr<socket> s)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
return std::find(m_readable.begin(), m_readable.end(), s)
|
|
||||||
!= m_readable.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait(int timeout
|
|
||||||
, std::vector<boost::shared_ptr<socket> >& readable
|
|
||||||
, std::vector<boost::shared_ptr<socket> >& writable
|
|
||||||
, std::vector<boost::shared_ptr<socket> >& error);
|
|
||||||
|
|
||||||
int count_read_monitors() const
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
return (int)m_readable.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
mutable boost::mutex m_mutex;
|
|
||||||
std::vector<boost::shared_ptr<socket> > m_readable;
|
|
||||||
std::vector<boost::shared_ptr<socket> > m_writable;
|
|
||||||
std::vector<boost::shared_ptr<socket> > m_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
using asio::async_write;
|
||||||
|
using asio::deadline_timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_SOCKET_HPP_INCLUDED
|
#endif // TORRENT_SOCKET_HPP_INCLUDED
|
||||||
|
|
|
@ -112,7 +112,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// should be called once every second
|
// should be called once every second
|
||||||
void second_tick();
|
void second_tick(float tick_interval);
|
||||||
|
|
||||||
float upload_rate() const { return m_mean_upload_rate; }
|
float upload_rate() const { return m_mean_upload_rate; }
|
||||||
float download_rate() const { return m_mean_download_rate; }
|
float download_rate() const { return m_mean_download_rate; }
|
||||||
|
@ -152,11 +152,11 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// history of download/upload speeds a few seconds back
|
// history of download/upload speeds a few seconds back
|
||||||
int m_download_rate_history[history];
|
float m_download_rate_history[history];
|
||||||
int m_upload_rate_history[history];
|
float m_upload_rate_history[history];
|
||||||
|
|
||||||
int m_download_payload_rate_history[history];
|
float m_download_payload_rate_history[history];
|
||||||
int m_upload_payload_rate_history[history];
|
float m_upload_payload_rate_history[history];
|
||||||
|
|
||||||
// the accumulators we are adding the downloads/uploads
|
// the accumulators we are adding the downloads/uploads
|
||||||
// to this second. This only counts the actual payload
|
// to this second. This only counts the actual payload
|
||||||
|
|
|
@ -130,8 +130,9 @@ namespace libtorrent
|
||||||
~piece_manager();
|
~piece_manager();
|
||||||
|
|
||||||
bool check_fastresume(detail::piece_checker_data& d
|
bool check_fastresume(detail::piece_checker_data& d
|
||||||
, std::vector<bool>& pieces, bool compact_mode);
|
, std::vector<bool>& pieces, int& num_pieces, bool compact_mode);
|
||||||
std::pair<bool, float> check_files(std::vector<bool>& pieces);
|
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
||||||
|
, int& num_pieces);
|
||||||
|
|
||||||
void release_files();
|
void release_files();
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/resource_request.hpp"
|
#include "libtorrent/resource_request.hpp"
|
||||||
#include "libtorrent/piece_picker.hpp"
|
#include "libtorrent/piece_picker.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
#include "libtorrent/escape_string.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -74,10 +75,6 @@ namespace libtorrent
|
||||||
|
|
||||||
class piece_manager;
|
class piece_manager;
|
||||||
|
|
||||||
std::string escape_string(const char* str, int len);
|
|
||||||
std::string unescape_string(std::string const& s);
|
|
||||||
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
struct session_impl;
|
struct session_impl;
|
||||||
|
@ -101,9 +98,10 @@ namespace libtorrent
|
||||||
, detail::checker_impl& checker
|
, detail::checker_impl& checker
|
||||||
, torrent_info const& tf
|
, torrent_info const& tf
|
||||||
, boost::filesystem::path const& save_path
|
, boost::filesystem::path const& save_path
|
||||||
, address const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, bool compact_mode
|
||||||
, int block_size);
|
, int block_size
|
||||||
|
, session_settings const& s);
|
||||||
|
|
||||||
// used with metadata-less torrents
|
// used with metadata-less torrents
|
||||||
// (the metadata is downloaded from the peers)
|
// (the metadata is downloaded from the peers)
|
||||||
|
@ -113,9 +111,10 @@ namespace libtorrent
|
||||||
, char const* tracker_url
|
, char const* tracker_url
|
||||||
, sha1_hash const& info_hash
|
, sha1_hash const& info_hash
|
||||||
, boost::filesystem::path const& save_path
|
, boost::filesystem::path const& save_path
|
||||||
, address const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, bool compact_mode
|
, bool compact_mode
|
||||||
, int block_size);
|
, int block_size
|
||||||
|
, session_settings const& s);
|
||||||
|
|
||||||
~torrent();
|
~torrent();
|
||||||
|
|
||||||
|
@ -138,7 +137,7 @@ namespace libtorrent
|
||||||
// caclulate the upload/download and number
|
// caclulate the upload/download and number
|
||||||
// of connections this torrent needs. And prepare
|
// of connections this torrent needs. And prepare
|
||||||
// it for being used by allocate_resources.
|
// it for being used by allocate_resources.
|
||||||
void second_tick(stat& accumulator);
|
void second_tick(stat& accumulator, float tick_interval);
|
||||||
|
|
||||||
// debug purpose only
|
// debug purpose only
|
||||||
void print(std::ostream& os) const;
|
void print(std::ostream& os) const;
|
||||||
|
@ -165,19 +164,15 @@ namespace libtorrent
|
||||||
bool is_piece_filtered(int index) const;
|
bool is_piece_filtered(int index) const;
|
||||||
void filtered_pieces(std::vector<bool>& bitmask) const;
|
void filtered_pieces(std::vector<bool>& bitmask) const;
|
||||||
|
|
||||||
// idea from Arvid and MooPolice
|
|
||||||
// todo refactoring and improving the function body
|
|
||||||
// marks the file with the given index as filtered
|
|
||||||
// it will not be downloaded
|
|
||||||
void filter_file(int index, bool filter);
|
|
||||||
void filter_files(std::vector<bool> const& files);
|
void filter_files(std::vector<bool> const& files);
|
||||||
|
|
||||||
|
|
||||||
torrent_status status() const;
|
torrent_status status() const;
|
||||||
|
|
||||||
void use_interface(const char* net_interface);
|
void use_interface(const char* net_interface);
|
||||||
address const& get_interface() const { return m_net_interface; }
|
tcp::endpoint const& get_interface() const { return m_net_interface; }
|
||||||
peer_connection& connect_to_peer(const address& a);
|
|
||||||
|
void connect_to_url_seed(std::string const& url);
|
||||||
|
peer_connection& connect_to_peer(tcp::endpoint const& a);
|
||||||
|
|
||||||
void set_ratio(float ratio)
|
void set_ratio(float ratio)
|
||||||
{ assert(ratio >= 0.0f); m_ratio = ratio; }
|
{ assert(ratio >= 0.0f); m_ratio = ratio; }
|
||||||
|
@ -187,6 +182,14 @@ namespace libtorrent
|
||||||
|
|
||||||
// --------------------------------------------
|
// --------------------------------------------
|
||||||
// PEER MANAGEMENT
|
// PEER MANAGEMENT
|
||||||
|
|
||||||
|
// add or remove a url that will be attempted for
|
||||||
|
// finding the file(s) in this torrent.
|
||||||
|
void add_url_seed(std::string const& url)
|
||||||
|
{ m_web_seeds.insert(url); }
|
||||||
|
|
||||||
|
void remove_url_seed(std::string const& url)
|
||||||
|
{ m_web_seeds.erase(url); }
|
||||||
|
|
||||||
// used by peer_connection to attach itself to a torrent
|
// used by peer_connection to attach itself to a torrent
|
||||||
// since incoming connections don't know what torrent
|
// since incoming connections don't know what torrent
|
||||||
|
@ -196,10 +199,9 @@ namespace libtorrent
|
||||||
// this will remove the peer and make sure all
|
// this will remove the peer and make sure all
|
||||||
// the pieces it had have their reference counter
|
// the pieces it had have their reference counter
|
||||||
// decreased in the piece_picker
|
// decreased in the piece_picker
|
||||||
// called from the peer_connection destructor
|
|
||||||
void remove_peer(peer_connection* p);
|
void remove_peer(peer_connection* p);
|
||||||
|
|
||||||
peer_connection* connection_for(const address& a)
|
peer_connection* connection_for(tcp::endpoint const& a)
|
||||||
{
|
{
|
||||||
peer_iterator i = m_connections.find(a);
|
peer_iterator i = m_connections.find(a);
|
||||||
if (i == m_connections.end()) return 0;
|
if (i == m_connections.end()) return 0;
|
||||||
|
@ -210,8 +212,8 @@ namespace libtorrent
|
||||||
int num_peers() const { return (int)m_connections.size(); }
|
int num_peers() const { return (int)m_connections.size(); }
|
||||||
int num_seeds() const;
|
int num_seeds() const;
|
||||||
|
|
||||||
typedef std::map<address, peer_connection*>::iterator peer_iterator;
|
typedef std::map<tcp::endpoint, peer_connection*>::iterator peer_iterator;
|
||||||
typedef std::map<address, peer_connection*>::const_iterator const_peer_iterator;
|
typedef std::map<tcp::endpoint, peer_connection*>::const_iterator const_peer_iterator;
|
||||||
|
|
||||||
const_peer_iterator begin() const { return m_connections.begin(); }
|
const_peer_iterator begin() const { return m_connections.begin(); }
|
||||||
const_peer_iterator end() const { return m_connections.end(); }
|
const_peer_iterator end() const { return m_connections.end(); }
|
||||||
|
@ -264,9 +266,9 @@ namespace libtorrent
|
||||||
// the tracker
|
// the tracker
|
||||||
void set_tracker_login(std::string const& name, std::string const& pw);
|
void set_tracker_login(std::string const& name, std::string const& pw);
|
||||||
|
|
||||||
// the address of the tracker that we managed to
|
// the tcp::endpoint of the tracker that we managed to
|
||||||
// announce ourself at the last time we tried to announce
|
// announce ourself at the last time we tried to announce
|
||||||
const address& current_tracker() const;
|
const tcp::endpoint& current_tracker() const;
|
||||||
|
|
||||||
// --------------------------------------------
|
// --------------------------------------------
|
||||||
// PIECE MANAGEMENT
|
// PIECE MANAGEMENT
|
||||||
|
@ -300,7 +302,7 @@ namespace libtorrent
|
||||||
m_picker->dec_refcount(index);
|
m_picker->dec_refcount(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
int block_size() const { return m_block_size; }
|
int block_size() const { assert(m_block_size > 0); return m_block_size; }
|
||||||
|
|
||||||
// this will tell all peers that we just got his piece
|
// this will tell all peers that we just got his piece
|
||||||
// and also let the piece picker know that we have this piece
|
// and also let the piece picker know that we have this piece
|
||||||
|
@ -313,6 +315,10 @@ namespace libtorrent
|
||||||
// the download. It will post an event, disconnect
|
// the download. It will post an event, disconnect
|
||||||
// all seeds and let the tracker know we're finished.
|
// all seeds and let the tracker know we're finished.
|
||||||
void completed();
|
void completed();
|
||||||
|
|
||||||
|
// this is the asio callback that is called when a name
|
||||||
|
// lookup for a web seed is completed.
|
||||||
|
void on_name_lookup(asio::error const& e, int port, std::string url, host h);
|
||||||
|
|
||||||
// this is called when the torrent has finished. i.e.
|
// this is called when the torrent has finished. i.e.
|
||||||
// all the pieces we have not filtered have been downloaded.
|
// all the pieces we have not filtered have been downloaded.
|
||||||
|
@ -326,6 +332,8 @@ namespace libtorrent
|
||||||
// each time a piece has failed the hash
|
// each time a piece has failed the hash
|
||||||
// test
|
// test
|
||||||
void piece_failed(int index);
|
void piece_failed(int index);
|
||||||
|
void received_redundant_data(int num_bytes)
|
||||||
|
{ assert(num_bytes > 0); m_total_redundant_bytes += num_bytes; }
|
||||||
|
|
||||||
float priority() const
|
float priority() const
|
||||||
{ return m_priority; }
|
{ return m_priority; }
|
||||||
|
@ -384,6 +392,9 @@ namespace libtorrent
|
||||||
resource_request m_uploads_quota;
|
resource_request m_uploads_quota;
|
||||||
resource_request m_connections_quota;
|
resource_request m_connections_quota;
|
||||||
|
|
||||||
|
void set_peer_upload_limit(tcp::endpoint ip, int limit);
|
||||||
|
void set_peer_download_limit(tcp::endpoint ip, int limit);
|
||||||
|
|
||||||
void set_upload_limit(int limit);
|
void set_upload_limit(int limit);
|
||||||
void set_download_limit(int limit);
|
void set_download_limit(int limit);
|
||||||
void set_max_uploads(int limit);
|
void set_max_uploads(int limit);
|
||||||
|
@ -454,15 +465,25 @@ namespace libtorrent
|
||||||
// is optional and may be -1.
|
// is optional and may be -1.
|
||||||
int m_complete;
|
int m_complete;
|
||||||
int m_incomplete;
|
int m_incomplete;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
public:
|
public:
|
||||||
#endif
|
#endif
|
||||||
std::map<address, peer_connection*> m_connections;
|
std::map<tcp::endpoint, peer_connection*> m_connections;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The list of web seeds in this torrent. Seeds
|
||||||
|
// with fatal errors are removed from the set
|
||||||
|
std::set<std::string> m_web_seeds;
|
||||||
|
// The set of url seeds that are currently having
|
||||||
|
// their hostnames resolved.
|
||||||
|
std::map<std::string, host> m_resolving_web_seeds;
|
||||||
|
|
||||||
|
// used to resolve the names of web seeds
|
||||||
|
host_resolver m_host_resolver;
|
||||||
|
|
||||||
// this is the upload and download statistics for the whole torrent.
|
// this is the upload and download statistics for the whole torrent.
|
||||||
// it's updated from all its peers once every second.
|
// it's updated from all its peers once every second.
|
||||||
libtorrent::stat m_stat;
|
libtorrent::stat m_stat;
|
||||||
|
@ -518,13 +539,14 @@ namespace libtorrent
|
||||||
// the number of bytes that has been
|
// the number of bytes that has been
|
||||||
// downloaded that failed the hash-test
|
// downloaded that failed the hash-test
|
||||||
size_type m_total_failed_bytes;
|
size_type m_total_failed_bytes;
|
||||||
|
size_type m_total_redundant_bytes;
|
||||||
|
|
||||||
std::string m_username;
|
std::string m_username;
|
||||||
std::string m_password;
|
std::string m_password;
|
||||||
|
|
||||||
// the network interface all outgoing connections
|
// the network interface all outgoing connections
|
||||||
// are opened through
|
// are opened through
|
||||||
address m_net_interface;
|
tcp::endpoint m_net_interface;
|
||||||
|
|
||||||
// the max number of bytes this torrent
|
// the max number of bytes this torrent
|
||||||
// can upload per second
|
// can upload per second
|
||||||
|
@ -569,6 +591,15 @@ namespace libtorrent
|
||||||
// them from altering the piece-picker before it
|
// them from altering the piece-picker before it
|
||||||
// has been initialized with files_checked().
|
// has been initialized with files_checked().
|
||||||
bool m_connections_initialized;
|
bool m_connections_initialized;
|
||||||
|
|
||||||
|
session_settings const& m_settings;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// this is the amount downloaded when this torrent
|
||||||
|
// is started. i.e.
|
||||||
|
// total_done - m_initial_done <= total_payload_download
|
||||||
|
size_type m_initial_done;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline boost::posix_time::ptime torrent::next_announce() const
|
inline boost::posix_time::ptime torrent::next_announce() const
|
||||||
|
|
|
@ -81,6 +81,8 @@ namespace libtorrent
|
||||||
, total_upload(0)
|
, total_upload(0)
|
||||||
, total_payload_download(0)
|
, total_payload_download(0)
|
||||||
, total_payload_upload(0)
|
, total_payload_upload(0)
|
||||||
|
, total_failed_bytes(0)
|
||||||
|
, total_redundant_bytes(0)
|
||||||
, download_rate(0)
|
, download_rate(0)
|
||||||
, upload_rate(0)
|
, upload_rate(0)
|
||||||
, download_payload_rate(0)
|
, download_payload_rate(0)
|
||||||
|
@ -89,6 +91,7 @@ namespace libtorrent
|
||||||
, num_complete(-1)
|
, num_complete(-1)
|
||||||
, num_incomplete(-1)
|
, num_incomplete(-1)
|
||||||
, pieces(0)
|
, pieces(0)
|
||||||
|
, num_pieces(0)
|
||||||
, total_done(0)
|
, total_done(0)
|
||||||
, total_wanted_done(0)
|
, total_wanted_done(0)
|
||||||
, total_wanted(0)
|
, total_wanted(0)
|
||||||
|
@ -130,6 +133,10 @@ namespace libtorrent
|
||||||
// has failed their hash test
|
// has failed their hash test
|
||||||
size_type total_failed_bytes;
|
size_type total_failed_bytes;
|
||||||
|
|
||||||
|
// the number of payload bytes that
|
||||||
|
// has been received redundantly.
|
||||||
|
size_type total_redundant_bytes;
|
||||||
|
|
||||||
// current transfer rate
|
// current transfer rate
|
||||||
// payload plus protocol
|
// payload plus protocol
|
||||||
float download_rate;
|
float download_rate;
|
||||||
|
@ -153,6 +160,11 @@ namespace libtorrent
|
||||||
int num_incomplete;
|
int num_incomplete;
|
||||||
|
|
||||||
const std::vector<bool>* pieces;
|
const std::vector<bool>* pieces;
|
||||||
|
|
||||||
|
// this is the number of pieces the client has
|
||||||
|
// downloaded. it is equal to:
|
||||||
|
// std::accumulate(pieces->begin(), pieces->end());
|
||||||
|
int num_pieces;
|
||||||
|
|
||||||
// the number of bytes of the file we have
|
// the number of bytes of the file we have
|
||||||
// including pieces that may have been filtered
|
// including pieces that may have been filtered
|
||||||
|
@ -196,7 +208,7 @@ namespace libtorrent
|
||||||
int blocks_in_piece;
|
int blocks_in_piece;
|
||||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||||
address peer[max_blocks_per_piece];
|
tcp::endpoint peer[max_blocks_per_piece];
|
||||||
int num_downloads[max_blocks_per_piece];
|
int num_downloads[max_blocks_per_piece];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,13 +221,15 @@ namespace libtorrent
|
||||||
torrent_handle(): m_ses(0), m_chk(0) {}
|
torrent_handle(): m_ses(0), m_chk(0) {}
|
||||||
|
|
||||||
void get_peer_info(std::vector<peer_info>& v) const;
|
void get_peer_info(std::vector<peer_info>& v) const;
|
||||||
bool send_chat_message(address ip, std::string message) const;
|
bool send_chat_message(tcp::endpoint ip, std::string message) const;
|
||||||
torrent_status status() const;
|
torrent_status status() const;
|
||||||
void get_download_queue(std::vector<partial_piece_info>& queue) const;
|
void get_download_queue(std::vector<partial_piece_info>& queue) const;
|
||||||
|
|
||||||
std::vector<announce_entry> const& trackers() const;
|
std::vector<announce_entry> const& trackers() const;
|
||||||
void replace_trackers(std::vector<announce_entry> const&) const;
|
void replace_trackers(std::vector<announce_entry> const&) const;
|
||||||
|
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
bool has_metadata() const;
|
bool has_metadata() const;
|
||||||
const torrent_info& get_torrent_info() const;
|
const torrent_info& get_torrent_info() const;
|
||||||
bool is_valid() const;
|
bool is_valid() const;
|
||||||
|
@ -225,7 +239,6 @@ namespace libtorrent
|
||||||
void pause() const;
|
void pause() const;
|
||||||
void resume() const;
|
void resume() const;
|
||||||
|
|
||||||
|
|
||||||
// marks the piece with the given index as filtered
|
// marks the piece with the given index as filtered
|
||||||
// it will not be downloaded
|
// it will not be downloaded
|
||||||
void filter_piece(int index, bool filter) const;
|
void filter_piece(int index, bool filter) const;
|
||||||
|
@ -233,8 +246,6 @@ namespace libtorrent
|
||||||
bool is_piece_filtered(int index) const;
|
bool is_piece_filtered(int index) const;
|
||||||
std::vector<bool> filtered_pieces() const;
|
std::vector<bool> filtered_pieces() const;
|
||||||
|
|
||||||
//idea from Arvid and MooPolice
|
|
||||||
//todo refactoring and improving the function body
|
|
||||||
// marks the file with the given index as filtered
|
// marks the file with the given index as filtered
|
||||||
// it will not be downloaded
|
// it will not be downloaded
|
||||||
void filter_file(int index, bool filter) const;
|
void filter_file(int index, bool filter) const;
|
||||||
|
@ -247,7 +258,7 @@ namespace libtorrent
|
||||||
entry write_resume_data() const;
|
entry write_resume_data() const;
|
||||||
|
|
||||||
// kind of similar to get_torrent_info() but this
|
// kind of similar to get_torrent_info() but this
|
||||||
// is low level, returning the exact info-part of
|
// is lower level, returning the exact info-part of
|
||||||
// the .torrent file. When hashed, this buffer
|
// the .torrent file. When hashed, this buffer
|
||||||
// will produce the info hash. The reference is valid
|
// will produce the info hash. The reference is valid
|
||||||
// only as long as the torrent is running.
|
// only as long as the torrent is running.
|
||||||
|
@ -270,8 +281,11 @@ namespace libtorrent
|
||||||
void set_upload_limit(int limit) const;
|
void set_upload_limit(int limit) const;
|
||||||
void set_download_limit(int limit) const;
|
void set_download_limit(int limit) const;
|
||||||
|
|
||||||
|
void set_peer_upload_limit(tcp::endpoint ip, int limit) const;
|
||||||
|
void set_peer_download_limit(tcp::endpoint ip, int limit) const;
|
||||||
|
|
||||||
// manually connect a peer
|
// manually connect a peer
|
||||||
void connect_peer(address const& adr) const;
|
void connect_peer(tcp::endpoint const& adr) const;
|
||||||
|
|
||||||
// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
|
// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
|
||||||
// the ratio is uploaded / downloaded. less than 1 is not allowed
|
// the ratio is uploaded / downloaded. less than 1 is not allowed
|
||||||
|
|
|
@ -54,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/size_type.hpp"
|
#include "libtorrent/size_type.hpp"
|
||||||
|
#include "libtorrent/peer_request.hpp"
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
|
@ -65,6 +66,13 @@ namespace libtorrent
|
||||||
size_type size;
|
size_type size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TORRENT_EXPORT file_slice
|
||||||
|
{
|
||||||
|
int file_index;
|
||||||
|
size_type offset;
|
||||||
|
size_type size;
|
||||||
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT announce_entry
|
struct TORRENT_EXPORT announce_entry
|
||||||
{
|
{
|
||||||
announce_entry(std::string const& u): url(u), tier(0) {}
|
announce_entry(std::string const& u): url(u), tier(0) {}
|
||||||
|
@ -77,11 +85,6 @@ namespace libtorrent
|
||||||
virtual const char* what() const throw() { return "invalid torrent file"; }
|
virtual const char* what() const throw() { return "invalid torrent file"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: add a check to see if filenames are accepted on the
|
|
||||||
// current platform.
|
|
||||||
// also add a filename converter function that will transform
|
|
||||||
// invalid filenames to valid filenames on the current platform
|
|
||||||
|
|
||||||
class TORRENT_EXPORT torrent_info
|
class TORRENT_EXPORT torrent_info
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -99,6 +102,12 @@ namespace libtorrent
|
||||||
void set_hash(int index, sha1_hash const& h);
|
void set_hash(int index, sha1_hash const& h);
|
||||||
void add_tracker(std::string const& url, int tier = 0);
|
void add_tracker(std::string const& url, int tier = 0);
|
||||||
void add_file(boost::filesystem::path file, size_type size);
|
void add_file(boost::filesystem::path file, size_type size);
|
||||||
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
|
std::vector<file_slice> map_block(int piece, size_type offset, int size) const;
|
||||||
|
peer_request map_file(int file, size_type offset, int size) const;
|
||||||
|
|
||||||
|
std::vector<std::string> const& url_seeds() const { return m_url_seeds; }
|
||||||
|
|
||||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
||||||
|
@ -153,6 +162,8 @@ namespace libtorrent
|
||||||
// the urls to the trackers
|
// the urls to the trackers
|
||||||
std::vector<announce_entry> m_urls;
|
std::vector<announce_entry> m_urls;
|
||||||
|
|
||||||
|
std::vector<std::string> m_url_seeds;
|
||||||
|
|
||||||
// the length of one piece
|
// the length of one piece
|
||||||
// if this is 0, the torrent_info is
|
// if this is 0, the torrent_info is
|
||||||
// in an uninitialized state
|
// in an uninitialized state
|
||||||
|
@ -168,7 +179,7 @@ namespace libtorrent
|
||||||
size_type m_total_size;
|
size_type m_total_size;
|
||||||
|
|
||||||
// the hash that identifies this torrent
|
// the hash that identifies this torrent
|
||||||
// it is mutable because it's calculated
|
// is mutable because it's calculated
|
||||||
// lazily
|
// lazily
|
||||||
mutable sha1_hash m_info_hash;
|
mutable sha1_hash m_info_hash;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/weak_ptr.hpp>
|
#include <boost/weak_ptr.hpp>
|
||||||
|
#include <boost/intrusive_ptr.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
@ -62,8 +66,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
struct request_callback;
|
struct request_callback;
|
||||||
class tracker_manager;
|
class tracker_manager;
|
||||||
|
struct timeout_handler;
|
||||||
// address parse_url(std::string const& url);
|
struct tracker_connection;
|
||||||
|
|
||||||
// encodes a string using the base64 scheme
|
// encodes a string using the base64 scheme
|
||||||
TORRENT_EXPORT std::string base64encode(const std::string& s);
|
TORRENT_EXPORT std::string base64encode(const std::string& s);
|
||||||
|
@ -71,6 +75,9 @@ namespace libtorrent
|
||||||
// returns -1 if gzip header is invalid or the header size in bytes
|
// returns -1 if gzip header is invalid or the header size in bytes
|
||||||
TORRENT_EXPORT int gzip_header(const char* buf, int size);
|
TORRENT_EXPORT int gzip_header(const char* buf, int size);
|
||||||
|
|
||||||
|
TORRENT_EXPORT boost::tuple<std::string, std::string, int, std::string>
|
||||||
|
parse_url_components(std::string url);
|
||||||
|
|
||||||
struct TORRENT_EXPORT tracker_request
|
struct TORRENT_EXPORT tracker_request
|
||||||
{
|
{
|
||||||
tracker_request()
|
tracker_request()
|
||||||
|
@ -95,7 +102,7 @@ namespace libtorrent
|
||||||
};
|
};
|
||||||
|
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
peer_id id;
|
peer_id pid;
|
||||||
size_type downloaded;
|
size_type downloaded;
|
||||||
size_type uploaded;
|
size_type uploaded;
|
||||||
size_type left;
|
size_type left;
|
||||||
|
@ -125,7 +132,7 @@ namespace libtorrent
|
||||||
, int response_code
|
, int response_code
|
||||||
, const std::string& description) = 0;
|
, const std::string& description) = 0;
|
||||||
|
|
||||||
address m_tracker_address;
|
tcp::endpoint m_tracker_address;
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
virtual void debug_log(const std::string& line) = 0;
|
virtual void debug_log(const std::string& line) = 0;
|
||||||
|
@ -140,23 +147,71 @@ namespace libtorrent
|
||||||
, request_callback* requester
|
, request_callback* requester
|
||||||
, int maximum_tracker_response_length);
|
, int maximum_tracker_response_length);
|
||||||
|
|
||||||
struct TORRENT_EXPORT tracker_connection: boost::noncopyable
|
TORRENT_EXPORT void intrusive_ptr_add_ref(timeout_handler const*);
|
||||||
{
|
TORRENT_EXPORT void intrusive_ptr_release(timeout_handler const*);
|
||||||
tracker_connection(boost::weak_ptr<request_callback> r)
|
|
||||||
: m_requester(r)
|
struct TORRENT_EXPORT timeout_handler
|
||||||
{}
|
: boost::noncopyable
|
||||||
|
{
|
||||||
|
friend void intrusive_ptr_add_ref(timeout_handler const*);
|
||||||
|
friend void intrusive_ptr_release(timeout_handler const*);
|
||||||
|
|
||||||
|
timeout_handler(demuxer& d);
|
||||||
|
|
||||||
|
void set_timeout(int completion_timeout, int read_timeout);
|
||||||
|
void restart_read_timeout();
|
||||||
|
void cancel();
|
||||||
|
|
||||||
|
virtual void on_timeout() = 0;
|
||||||
|
virtual ~timeout_handler() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void timeout_callback(asio::error const&);
|
||||||
|
|
||||||
|
boost::intrusive_ptr<timeout_handler> self()
|
||||||
|
{ return boost::intrusive_ptr<timeout_handler>(this); }
|
||||||
|
|
||||||
|
demuxer& m_demuxer;
|
||||||
|
// used for timeouts
|
||||||
|
// this is set when the request has been sent
|
||||||
|
boost::posix_time::ptime m_start_time;
|
||||||
|
// this is set every time something is received
|
||||||
|
boost::posix_time::ptime m_read_time;
|
||||||
|
// the asio async operation
|
||||||
|
asio::deadline_timer m_timeout;
|
||||||
|
|
||||||
|
int m_completion_timeout;
|
||||||
|
int m_read_timeout;
|
||||||
|
|
||||||
|
typedef boost::mutex mutex_t;
|
||||||
|
mutable mutex_t m_mutex;
|
||||||
|
mutable int m_refs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TORRENT_EXPORT tracker_connection
|
||||||
|
: timeout_handler
|
||||||
|
{
|
||||||
|
tracker_connection(tracker_manager& man
|
||||||
|
, tracker_request req
|
||||||
|
, demuxer& d
|
||||||
|
, boost::weak_ptr<request_callback> r);
|
||||||
|
|
||||||
virtual bool tick() = 0;
|
|
||||||
virtual bool send_finished() const = 0;
|
|
||||||
bool has_requester() const { return !m_requester.expired(); }
|
|
||||||
request_callback& requester();
|
request_callback& requester();
|
||||||
virtual ~tracker_connection() {}
|
virtual ~tracker_connection() {}
|
||||||
virtual tracker_request const& tracker_req() const = 0;
|
|
||||||
|
tracker_request const& tracker_req() const { return m_req; }
|
||||||
|
bool has_requester() const { return !m_requester.expired(); }
|
||||||
|
|
||||||
|
void fail(int code, char const* msg);
|
||||||
|
void fail_timeout();
|
||||||
|
void close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
boost::weak_ptr<request_callback> m_requester;
|
boost::weak_ptr<request_callback> m_requester;
|
||||||
|
private:
|
||||||
|
tracker_manager& m_man;
|
||||||
|
const tracker_request m_req;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TORRENT_EXPORT tracker_manager: boost::noncopyable
|
class TORRENT_EXPORT tracker_manager: boost::noncopyable
|
||||||
|
@ -165,19 +220,23 @@ namespace libtorrent
|
||||||
|
|
||||||
tracker_manager(const http_settings& s)
|
tracker_manager(const http_settings& s)
|
||||||
: m_settings(s) {}
|
: m_settings(s) {}
|
||||||
|
|
||||||
void tick();
|
|
||||||
void queue_request(
|
void queue_request(
|
||||||
tracker_request r
|
demuxer& d
|
||||||
|
, tracker_request r
|
||||||
, std::string const& auth
|
, std::string const& auth
|
||||||
, boost::weak_ptr<request_callback> c
|
, boost::weak_ptr<request_callback> c
|
||||||
= boost::weak_ptr<request_callback>());
|
= boost::weak_ptr<request_callback>());
|
||||||
void abort_all_requests();
|
void abort_all_requests();
|
||||||
bool send_finished() const;
|
|
||||||
|
|
||||||
|
void remove_request(tracker_connection const*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef std::list<boost::shared_ptr<tracker_connection> >
|
typedef boost::recursive_mutex mutex_t;
|
||||||
|
mutex_t m_mutex;
|
||||||
|
|
||||||
|
typedef std::list<boost::intrusive_ptr<tracker_connection> >
|
||||||
tracker_connections_t;
|
tracker_connections_t;
|
||||||
tracker_connections_t m_connections;
|
tracker_connections_t m_connections;
|
||||||
const http_settings& m_settings;
|
const http_settings& m_settings;
|
||||||
|
|
|
@ -56,7 +56,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/peer.hpp"
|
#include "libtorrent/peer.hpp"
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/async_gethostbyname.hpp"
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
|
@ -67,45 +66,55 @@ namespace libtorrent
|
||||||
public:
|
public:
|
||||||
|
|
||||||
udp_tracker_connection(
|
udp_tracker_connection(
|
||||||
tracker_request const& req
|
demuxer& d
|
||||||
|
, tracker_manager& man
|
||||||
|
, tracker_request const& req
|
||||||
, std::string const& hostname
|
, std::string const& hostname
|
||||||
, unsigned short port
|
, unsigned short port
|
||||||
, boost::weak_ptr<request_callback> c
|
, boost::weak_ptr<request_callback> c
|
||||||
, const http_settings& stn);
|
, const http_settings& stn);
|
||||||
|
|
||||||
virtual bool tick();
|
|
||||||
virtual bool send_finished() const;
|
|
||||||
virtual tracker_request const& tracker_req() const
|
|
||||||
{ return m_request; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum action_t
|
enum action_t
|
||||||
{
|
{
|
||||||
connect,
|
action_connect,
|
||||||
announce,
|
action_announce,
|
||||||
scrape,
|
action_scrape,
|
||||||
error
|
action_error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boost::intrusive_ptr<udp_tracker_connection> self()
|
||||||
|
{ return boost::intrusive_ptr<udp_tracker_connection>(this); }
|
||||||
|
|
||||||
|
void name_lookup(asio::error const& error);
|
||||||
|
void timeout(asio::error const& error);
|
||||||
|
|
||||||
void send_udp_connect();
|
void send_udp_connect();
|
||||||
|
void connect_response(asio::error const& error, std::size_t bytes_transferred);
|
||||||
|
|
||||||
void send_udp_announce();
|
void send_udp_announce();
|
||||||
|
void announce_response(asio::error const& error, std::size_t bytes_transferred);
|
||||||
|
|
||||||
void send_udp_scrape();
|
void send_udp_scrape();
|
||||||
bool parse_connect_response(const char* buf, int ret);
|
void scrape_response(asio::error const& error, std::size_t bytes_transferred);
|
||||||
bool parse_announce_response(const char* buf, int ret);
|
|
||||||
bool parse_scrape_response(const char* buf, int ret);
|
|
||||||
|
|
||||||
dns_lookup m_name_lookup;
|
virtual void on_timeout();
|
||||||
boost::shared_ptr<socket> m_socket;
|
|
||||||
|
|
||||||
// used for time outs
|
tracker_manager& m_man;
|
||||||
boost::posix_time::ptime m_request_time;
|
|
||||||
|
host_resolver m_name_lookup;
|
||||||
|
host m_host;
|
||||||
|
int m_port;
|
||||||
|
boost::shared_ptr<datagram_socket> m_socket;
|
||||||
|
udp::endpoint m_target;
|
||||||
|
udp::endpoint m_sender;
|
||||||
|
|
||||||
tracker_request m_request;
|
|
||||||
int m_transaction_id;
|
int m_transaction_id;
|
||||||
boost::int64_t m_connection_id;
|
boost::int64_t m_connection_id;
|
||||||
const http_settings& m_settings;
|
const http_settings& m_settings;
|
||||||
int m_attempts;
|
int m_attempts;
|
||||||
|
std::vector<char> m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef TORRENT_VERSION_HPP_INCLUDED
|
#ifndef TORRENT_VERSION_HPP_INCLUDED
|
||||||
#define TORRENT_VERSION_HPP_INCLUDED
|
#define TORRENT_VERSION_HPP_INCLUDED
|
||||||
|
|
||||||
#define LIBTORRENT_VERSION "0.9.0.0"
|
#define LIBTORRENT_VERSION "0.9.2.0"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003, 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_WEB_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
#define TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "libtorrent/debug.hpp"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/smart_ptr.hpp>
|
||||||
|
#include <boost/weak_ptr.hpp>
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
#include <boost/array.hpp>
|
||||||
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
|
#include "libtorrent/peer_connection.hpp"
|
||||||
|
#include "libtorrent/socket.hpp"
|
||||||
|
#include "libtorrent/peer_id.hpp"
|
||||||
|
#include "libtorrent/storage.hpp"
|
||||||
|
#include "libtorrent/stat.hpp"
|
||||||
|
#include "libtorrent/alert.hpp"
|
||||||
|
#include "libtorrent/torrent_handle.hpp"
|
||||||
|
#include "libtorrent/torrent.hpp"
|
||||||
|
#include "libtorrent/allocate_resources.hpp"
|
||||||
|
#include "libtorrent/peer_request.hpp"
|
||||||
|
#include "libtorrent/piece_block_progress.hpp"
|
||||||
|
#include "libtorrent/config.hpp"
|
||||||
|
// parse_url
|
||||||
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
|
// http_parser
|
||||||
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
class torrent;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
struct session_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TORRENT_EXPORT web_peer_connection
|
||||||
|
: public peer_connection
|
||||||
|
{
|
||||||
|
friend class invariant_access;
|
||||||
|
public:
|
||||||
|
|
||||||
|
// this is the constructor where the we are the active part.
|
||||||
|
// The peer_conenction should handshake and verify that the
|
||||||
|
// other end has the correct id
|
||||||
|
web_peer_connection(
|
||||||
|
detail::session_impl& ses
|
||||||
|
, boost::weak_ptr<torrent> t
|
||||||
|
, boost::shared_ptr<stream_socket> s
|
||||||
|
, tcp::endpoint const& remote
|
||||||
|
, std::string const& url);
|
||||||
|
|
||||||
|
~web_peer_connection();
|
||||||
|
|
||||||
|
// called from the main loop when this connection has any
|
||||||
|
// work to do.
|
||||||
|
void on_sent(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
void on_receive(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
std::string const& url() const { return m_url; }
|
||||||
|
|
||||||
|
virtual void get_peer_info(peer_info& p) const;
|
||||||
|
|
||||||
|
// the following functions appends messages
|
||||||
|
// to the send buffer
|
||||||
|
void write_choke() {}
|
||||||
|
void write_unchoke() {}
|
||||||
|
void write_interested() {}
|
||||||
|
void write_not_interested() {}
|
||||||
|
void write_request(peer_request const& r);
|
||||||
|
void write_cancel(peer_request const& r) {}
|
||||||
|
void write_have(int index) {}
|
||||||
|
void write_piece(peer_request const& r) {}
|
||||||
|
void write_keepalive() {}
|
||||||
|
void on_connected();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void check_invariant() const;
|
||||||
|
boost::posix_time::ptime m_last_choke;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// returns the block currently being
|
||||||
|
// downloaded. And the progress of that
|
||||||
|
// block. If the peer isn't downloading
|
||||||
|
// a piece for the moment, the boost::optional
|
||||||
|
// will be invalid.
|
||||||
|
boost::optional<piece_block_progress> downloading_piece_progress() const;
|
||||||
|
|
||||||
|
// this has one entry per bittorrent request
|
||||||
|
std::deque<peer_request> m_requests;
|
||||||
|
// this has one entry per http-request
|
||||||
|
// (might be more than the bt requests)
|
||||||
|
std::deque<int> m_file_requests;
|
||||||
|
|
||||||
|
std::string m_server_string;
|
||||||
|
http_parser m_parser;
|
||||||
|
std::string m_host;
|
||||||
|
int m_port;
|
||||||
|
std::string m_path;
|
||||||
|
std::string m_url;
|
||||||
|
|
||||||
|
// the first request will contain a little bit more data
|
||||||
|
// than subsequent ones, things that aren't critical are left
|
||||||
|
// out to save bandwidth.
|
||||||
|
bool m_first_request;
|
||||||
|
|
||||||
|
// this is used for intermediate storage of pieces
|
||||||
|
// that is received in more than on HTTP responses
|
||||||
|
std::vector<char> m_piece;
|
||||||
|
// the mapping of the data in the m_piece buffer
|
||||||
|
peer_request m_intermediate_piece;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
lib_LTLIBRARIES = libtorrent.la
|
lib_LTLIBRARIES = libtorrent.la
|
||||||
|
|
||||||
libtorrent_la_SOURCES = allocate_resources.cpp async_gethostbyname.cpp \
|
libtorrent_la_SOURCES = allocate_resources.cpp \
|
||||||
entry.cpp escape_string.cpp \
|
entry.cpp escape_string.cpp \
|
||||||
peer_connection.cpp piece_picker.cpp policy.cpp \
|
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
|
||||||
session.cpp sha1.cpp socket.cpp stat.cpp \
|
piece_picker.cpp policy.cpp session.cpp sha1.cpp stat.cpp \
|
||||||
storage.cpp torrent.cpp torrent_handle.cpp \
|
storage.cpp torrent.cpp torrent_handle.cpp \
|
||||||
torrent_info.cpp tracker_manager.cpp \
|
torrent_info.cpp tracker_manager.cpp \
|
||||||
http_tracker_connection.cpp udp_tracker_connection.cpp \
|
http_tracker_connection.cpp udp_tracker_connection.cpp \
|
||||||
|
@ -13,7 +13,6 @@ noinst_HEADERS = \
|
||||||
$(top_srcdir)/include/libtorrent/alert.hpp \
|
$(top_srcdir)/include/libtorrent/alert.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/alert_types.hpp \
|
$(top_srcdir)/include/libtorrent/alert_types.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/allocate_resources.hpp \
|
$(top_srcdir)/include/libtorrent/allocate_resources.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/async_gethostbyname.hpp \
|
|
||||||
$(top_srcdir)/include/libtorrent/bencode.hpp \
|
$(top_srcdir)/include/libtorrent/bencode.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/buffer.hpp \
|
$(top_srcdir)/include/libtorrent/buffer.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/debug.hpp \
|
$(top_srcdir)/include/libtorrent/debug.hpp \
|
||||||
|
@ -30,6 +29,8 @@ $(top_srcdir)/include/libtorrent/io.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/ip_filter.hpp \
|
$(top_srcdir)/include/libtorrent/ip_filter.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/peer.hpp \
|
$(top_srcdir)/include/libtorrent/peer.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/peer_connection.hpp \
|
$(top_srcdir)/include/libtorrent/peer_connection.hpp \
|
||||||
|
$(top_srcdir)/include/libtorrent/bt_peer_connection.hpp \
|
||||||
|
$(top_srcdir)/include/libtorrent/web_peer_connection.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/peer_id.hpp \
|
$(top_srcdir)/include/libtorrent/peer_id.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/peer_info.hpp \
|
$(top_srcdir)/include/libtorrent/peer_info.hpp \
|
||||||
$(top_srcdir)/include/libtorrent/peer_request.hpp \
|
$(top_srcdir)/include/libtorrent/peer_request.hpp \
|
||||||
|
@ -54,5 +55,5 @@ $(top_srcdir)/include/libtorrent/version.hpp
|
||||||
libtorrent_la_LDFLAGS = $(LDFLAGS) -version-info 1:0:1
|
libtorrent_la_LDFLAGS = $(LDFLAGS) -version-info 1:0:1
|
||||||
libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
||||||
|
|
||||||
AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/asio/include @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
||||||
AM_LDFLAGS= $(LDFLAGS) -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
AM_LDFLAGS= $(LDFLAGS) -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
||||||
|
|
|
@ -69,10 +69,12 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
assert(a >= 0);
|
assert(a >= 0);
|
||||||
assert(b >= 0);
|
assert(b >= 0);
|
||||||
|
assert(a <= resource_request::inf);
|
||||||
|
assert(b <= resource_request::inf);
|
||||||
assert(resource_request::inf + resource_request::inf < 0);
|
assert(resource_request::inf + resource_request::inf < 0);
|
||||||
|
|
||||||
int sum = a + b;
|
int sum = a + b;
|
||||||
if(sum < 0)
|
if (sum < 0)
|
||||||
sum = resource_request::inf;
|
sum = resource_request::inf;
|
||||||
|
|
||||||
assert(sum >= a && sum >= b);
|
assert(sum >= a && sum >= b);
|
||||||
|
@ -121,7 +123,6 @@ namespace libtorrent
|
||||||
assert(m_resources >= 0);
|
assert(m_resources >= 0);
|
||||||
for (It i = m_start, end(m_end); i != end; ++i)
|
for (It i = m_start, end(m_end); i != end; ++i)
|
||||||
{
|
{
|
||||||
assert(((*i).*m_res).used >= 0);
|
|
||||||
assert(((*i).*m_res).max >= 0);
|
assert(((*i).*m_res).max >= 0);
|
||||||
assert(((*i).*m_res).given >= 0);
|
assert(((*i).*m_res).given >= 0);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +166,7 @@ namespace libtorrent
|
||||||
, res);
|
, res);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(resources == resource_request::inf)
|
if (resources == resource_request::inf)
|
||||||
{
|
{
|
||||||
// No competition for resources.
|
// No competition for resources.
|
||||||
// Just give everyone what they want.
|
// Just give everyone what they want.
|
||||||
|
@ -224,15 +225,18 @@ namespace libtorrent
|
||||||
for (It i = start; i != end && resources_to_distribute > 0; ++i)
|
for (It i = start; i != end && resources_to_distribute > 0; ++i)
|
||||||
{
|
{
|
||||||
resource_request& r = (*i).*res;
|
resource_request& r = (*i).*res;
|
||||||
if(r.given == r.max) continue;
|
if (r.given == r.max) continue;
|
||||||
|
|
||||||
assert(r.given < r.max);
|
assert(r.given < r.max);
|
||||||
|
|
||||||
size_type used = (size_type)r.used + 1;
|
size_type used = (size_type)r.used + 1;
|
||||||
|
if (used < 1) used = 1;
|
||||||
size_type to_give = used * kNumer / kDenom;
|
size_type to_give = used * kNumer / kDenom;
|
||||||
if(to_give > resource_request::inf)
|
if(to_give > resource_request::inf)
|
||||||
to_give = resource_request::inf;
|
to_give = resource_request::inf;
|
||||||
|
assert(to_give >= 0);
|
||||||
resources_to_distribute -= give(r, (int)to_give);
|
resources_to_distribute -= give(r, (int)to_give);
|
||||||
|
assert(resources_to_distribute >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(resources_to_distribute >= 0);
|
assert(resources_to_distribute >= 0);
|
||||||
|
@ -240,13 +244,14 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
peer_connection& pick_peer(
|
peer_connection& pick_peer(
|
||||||
std::pair<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> > const& p)
|
std::pair<boost::shared_ptr<stream_socket>
|
||||||
|
, boost::intrusive_ptr<peer_connection> > const& p)
|
||||||
{
|
{
|
||||||
return *p.second;
|
return *p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
peer_connection& pick_peer2(
|
peer_connection& pick_peer2(
|
||||||
std::pair<address, peer_connection*> const& p)
|
std::pair<tcp::endpoint, peer_connection*> const& p)
|
||||||
{
|
{
|
||||||
return *p.second;
|
return *p.second;
|
||||||
}
|
}
|
||||||
|
@ -262,11 +267,11 @@ namespace libtorrent
|
||||||
/*
|
/*
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
int resources
|
int resources
|
||||||
, std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> >& c
|
, std::map<boost::shared_ptr<socket>, boost::intrusive_ptr<peer_connection> >& c
|
||||||
, resource_request peer_connection::* res)
|
, resource_request peer_connection::* res)
|
||||||
{
|
{
|
||||||
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> >::iterator orig_iter;
|
typedef std::map<boost::shared_ptr<socket>, boost::intrusive_ptr<peer_connection> >::iterator orig_iter;
|
||||||
typedef std::pair<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> > in_param;
|
typedef std::pair<boost::shared_ptr<socket>, boost::intrusive_ptr<peer_connection> > in_param;
|
||||||
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
|
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
|
||||||
|
|
||||||
allocate_resources_impl(
|
allocate_resources_impl(
|
||||||
|
@ -297,7 +302,7 @@ namespace libtorrent
|
||||||
|
|
||||||
struct iterator_wrapper2
|
struct iterator_wrapper2
|
||||||
{
|
{
|
||||||
typedef std::map<address, peer_connection*>::iterator orig_iter;
|
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
|
||||||
|
|
||||||
orig_iter iter;
|
orig_iter iter;
|
||||||
|
|
||||||
|
@ -326,7 +331,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
int resources
|
int resources
|
||||||
, std::map<address, peer_connection*>& c
|
, std::map<tcp::endpoint, peer_connection*>& c
|
||||||
, resource_request peer_connection::* res)
|
, resource_request peer_connection::* res)
|
||||||
{
|
{
|
||||||
allocate_resources_impl(
|
allocate_resources_impl(
|
||||||
|
@ -356,11 +361,11 @@ namespace libtorrent
|
||||||
|
|
||||||
void allocate_resources(
|
void allocate_resources(
|
||||||
int resources
|
int resources
|
||||||
, std::map<address, peer_connection*>& c
|
, std::map<tcp::endpoint, peer_connection*>& c
|
||||||
, resource_request peer_connection::* res)
|
, resource_request peer_connection::* res)
|
||||||
{
|
{
|
||||||
typedef std::map<address, peer_connection*>::iterator orig_iter;
|
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
|
||||||
typedef std::pair<address, peer_connection*> in_param;
|
typedef std::pair<tcp::endpoint, peer_connection*> in_param;
|
||||||
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
|
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
|
||||||
|
|
||||||
allocate_resources_impl(
|
allocate_resources_impl(
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -62,7 +62,7 @@ namespace
|
||||||
std::pair<std::string
|
std::pair<std::string
|
||||||
, libtorrent::entry> const& e) const
|
, libtorrent::entry> const& e) const
|
||||||
{
|
{
|
||||||
return e.first == m_str;
|
return m_str && e.first == m_str;
|
||||||
}
|
}
|
||||||
char const* m_str;
|
char const* m_str;
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,4 +115,34 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return ret.str();
|
return ret.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string escape_path(const char* str, int len)
|
||||||
|
{
|
||||||
|
assert(str != 0);
|
||||||
|
assert(len >= 0);
|
||||||
|
static const char unreserved_chars[] = "/-_.!~*()"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
"0123456789";
|
||||||
|
|
||||||
|
std::stringstream ret;
|
||||||
|
ret << std::hex << std::setfill('0');
|
||||||
|
for (int i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
if (std::count(
|
||||||
|
unreserved_chars
|
||||||
|
, unreserved_chars+sizeof(unreserved_chars)-1
|
||||||
|
, *str))
|
||||||
|
{
|
||||||
|
ret << *str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret << '%'
|
||||||
|
<< std::setw(2)
|
||||||
|
<< (int)static_cast<unsigned char>(*str);
|
||||||
|
}
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
return ret.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/file.cpp
12
src/file.cpp
|
@ -167,7 +167,11 @@ namespace libtorrent
|
||||||
m_fd = ::open(
|
m_fd = ::open(
|
||||||
utf8_native(path.native_file_string()).c_str()
|
utf8_native(path.native_file_string()).c_str()
|
||||||
, map_open_mode(mode)
|
, map_open_mode(mode)
|
||||||
|
#ifdef _WIN32
|
||||||
, S_IREAD | S_IWRITE);
|
, S_IREAD | S_IWRITE);
|
||||||
|
#else
|
||||||
|
, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if (m_fd == -1)
|
if (m_fd == -1)
|
||||||
{
|
{
|
||||||
|
@ -218,7 +222,7 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(size_type offset, int m)
|
size_type seek(size_type offset, int m)
|
||||||
{
|
{
|
||||||
assert(m_open_mode);
|
assert(m_open_mode);
|
||||||
assert(m_fd != -1);
|
assert(m_fd != -1);
|
||||||
|
@ -242,7 +246,7 @@ namespace libtorrent
|
||||||
<< " seekdir: " << seekdir;
|
<< " seekdir: " << seekdir;
|
||||||
throw file_error(msg.str());
|
throw file_error(msg.str());
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type tell()
|
size_type tell()
|
||||||
|
@ -291,9 +295,9 @@ namespace libtorrent
|
||||||
return m_impl->read(buf, num_bytes);
|
return m_impl->read(buf, num_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::seek(size_type pos, file::seek_mode m)
|
size_type file::seek(size_type pos, file::seek_mode m)
|
||||||
{
|
{
|
||||||
m_impl->seek(pos, m.m_val);
|
return m_impl->seek(pos, m.m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type file::tell()
|
size_type file::tell()
|
||||||
|
|
|
@ -233,7 +233,7 @@ namespace libtorrent
|
||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(size_type pos, seek_mode from_where)
|
size_type seek(size_type pos, seek_mode from_where)
|
||||||
{
|
{
|
||||||
assert(pos >= 0 || from_where != seek_begin);
|
assert(pos >= 0 || from_where != seek_begin);
|
||||||
assert(pos <= 0 || from_where != seek_end);
|
assert(pos <= 0 || from_where != seek_end);
|
||||||
|
@ -333,9 +333,9 @@ namespace libtorrent
|
||||||
return m_impl->read(buffer, num_bytes);
|
return m_impl->read(buffer, num_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::seek(size_type pos, seek_mode m)
|
size_type file::seek(size_type pos, seek_mode m)
|
||||||
{
|
{
|
||||||
m_impl->seek(pos,impl::seek_mode(m.m_val));
|
return m_impl->seek(pos,impl::seek_mode(m.m_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type file::tell()
|
size_type file::tell()
|
||||||
|
|
|
@ -38,16 +38,25 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/http_tracker_connection.hpp"
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
#include "libtorrent/udp_tracker_connection.hpp"
|
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
#include "libtorrent/async_gethostbyname.hpp"
|
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
using boost::bind;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -77,9 +86,152 @@ using namespace boost::posix_time;
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
http_parser::http_parser()
|
||||||
|
: m_recv_pos(0)
|
||||||
|
, m_status_code(-1)
|
||||||
|
, m_content_length(-1)
|
||||||
|
, m_content_encoding(plain)
|
||||||
|
, m_state(read_status)
|
||||||
|
, m_recv_buffer(0, 0)
|
||||||
|
, m_body_start_pos(0)
|
||||||
|
, m_finished(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
boost::tuple<int, int> http_parser::incoming(buffer::const_interval recv_buffer)
|
||||||
|
{
|
||||||
|
m_recv_buffer = recv_buffer;
|
||||||
|
boost::tuple<int, int> ret(0, 0);
|
||||||
|
|
||||||
|
char const* pos = recv_buffer.begin + m_recv_pos;
|
||||||
|
if (m_state == read_status)
|
||||||
|
{
|
||||||
|
assert(!m_finished);
|
||||||
|
char const* newline = std::find(pos, recv_buffer.end, '\n');
|
||||||
|
// if we don't have a full line yet, wait.
|
||||||
|
if (newline == recv_buffer.end) return ret;
|
||||||
|
|
||||||
|
if (newline == pos)
|
||||||
|
throw std::runtime_error("unexpected newline in HTTP response");
|
||||||
|
|
||||||
|
std::istringstream line(std::string(pos, newline - 1));
|
||||||
|
++newline;
|
||||||
|
int incoming = (int)std::distance(pos, newline);
|
||||||
|
m_recv_pos += incoming;
|
||||||
|
boost::get<1>(ret) += incoming;
|
||||||
|
pos = newline;
|
||||||
|
|
||||||
|
line >> m_protocol;
|
||||||
|
if (m_protocol.substr(0, 5) != "HTTP/")
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown protocol in HTTP response: "
|
||||||
|
+ m_protocol);
|
||||||
|
}
|
||||||
|
line >> m_status_code;
|
||||||
|
std::getline(line, m_server_message);
|
||||||
|
m_state = read_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == read_header)
|
||||||
|
{
|
||||||
|
assert(!m_finished);
|
||||||
|
char const* newline = std::find(pos, recv_buffer.end, '\n');
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (newline != recv_buffer.end && m_state == read_header)
|
||||||
|
{
|
||||||
|
if (newline == pos)
|
||||||
|
throw std::runtime_error("unexpected newline in HTTP response");
|
||||||
|
|
||||||
|
line.assign(pos, newline - 1);
|
||||||
|
m_recv_pos += newline - pos;
|
||||||
|
boost::get<1>(ret) += newline - pos;
|
||||||
|
pos = newline;
|
||||||
|
|
||||||
|
std::string::size_type separator = line.find(": ");
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
++m_recv_pos;
|
||||||
|
boost::get<1>(ret) += 1;
|
||||||
|
|
||||||
|
m_state = read_body;
|
||||||
|
m_body_start_pos = m_recv_pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = line.substr(0, separator);
|
||||||
|
std::string value = line.substr(separator + 2, std::string::npos);
|
||||||
|
m_header.insert(std::make_pair(name, value));
|
||||||
|
|
||||||
|
if (name == "Content-Length")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_content_length = boost::lexical_cast<int>(value);
|
||||||
|
}
|
||||||
|
catch(boost::bad_lexical_cast&) {}
|
||||||
|
}
|
||||||
|
else if (name == "Content-Encoding")
|
||||||
|
{
|
||||||
|
if (value == "gzip" || value == "x-gzip")
|
||||||
|
{
|
||||||
|
m_content_encoding = gzip;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string error_str = "unknown content encoding in response: \"";
|
||||||
|
error_str += value;
|
||||||
|
error_str += "\"";
|
||||||
|
throw std::runtime_error(error_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: make sure we don't step outside of the buffer
|
||||||
|
++pos;
|
||||||
|
++m_recv_pos;
|
||||||
|
assert(m_recv_pos <= (int)recv_buffer.left());
|
||||||
|
newline = std::find(pos, recv_buffer.end, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == read_body)
|
||||||
|
{
|
||||||
|
int incoming = recv_buffer.end - pos;
|
||||||
|
if (m_recv_pos - m_body_start_pos + incoming > m_content_length
|
||||||
|
&& m_content_length >= 0)
|
||||||
|
incoming = m_content_length - m_recv_pos + m_body_start_pos;
|
||||||
|
|
||||||
|
assert(incoming >= 0);
|
||||||
|
m_recv_pos += incoming;
|
||||||
|
boost::get<0>(ret) += incoming;
|
||||||
|
|
||||||
|
if (m_content_length >= 0
|
||||||
|
&& m_recv_pos - m_body_start_pos >= m_content_length)
|
||||||
|
{
|
||||||
|
m_finished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer::const_interval http_parser::get_body()
|
||||||
|
{
|
||||||
|
char const* body_begin = m_recv_buffer.begin + m_body_start_pos;
|
||||||
|
char const* body_end = m_recv_buffer.begin + m_recv_pos;
|
||||||
|
|
||||||
|
m_recv_pos = 0;
|
||||||
|
m_body_start_pos = 0;
|
||||||
|
m_status_code = -1;
|
||||||
|
m_content_length = -1;
|
||||||
|
m_finished = false;
|
||||||
|
m_state = read_status;
|
||||||
|
m_header.clear();
|
||||||
|
|
||||||
|
return buffer::const_interval(body_begin, body_end);
|
||||||
|
}
|
||||||
|
|
||||||
http_tracker_connection::http_tracker_connection(
|
http_tracker_connection::http_tracker_connection(
|
||||||
tracker_manager& man
|
demuxer& d
|
||||||
|
, tracker_manager& man
|
||||||
, tracker_request const& req
|
, tracker_request const& req
|
||||||
, std::string const& hostname
|
, std::string const& hostname
|
||||||
, unsigned short port
|
, unsigned short port
|
||||||
|
@ -87,20 +239,21 @@ namespace libtorrent
|
||||||
, boost::weak_ptr<request_callback> c
|
, boost::weak_ptr<request_callback> c
|
||||||
, const http_settings& stn
|
, const http_settings& stn
|
||||||
, std::string const& auth)
|
, std::string const& auth)
|
||||||
: tracker_connection(c)
|
: tracker_connection(man, req, d, c)
|
||||||
, m_man(man)
|
, m_man(man)
|
||||||
, m_state(read_status)
|
, m_state(read_status)
|
||||||
, m_content_encoding(plain)
|
, m_content_encoding(plain)
|
||||||
, m_content_length(0)
|
, m_content_length(0)
|
||||||
|
, m_name_lookup(d)
|
||||||
|
, m_port(port)
|
||||||
, m_recv_pos(0)
|
, m_recv_pos(0)
|
||||||
, m_request_time(second_clock::universal_time())
|
, m_buffer(http_buffer_size)
|
||||||
, m_settings(stn)
|
, m_settings(stn)
|
||||||
, m_req(req)
|
|
||||||
, m_password(auth)
|
, m_password(auth)
|
||||||
, m_code(0)
|
, m_code(0)
|
||||||
|
, m_timed_out(false)
|
||||||
{
|
{
|
||||||
const std::string* connect_to_host;
|
const std::string* connect_to_host;
|
||||||
int connect_to_port = port;
|
|
||||||
bool using_proxy = false;
|
bool using_proxy = false;
|
||||||
|
|
||||||
m_send_buffer.assign("GET ");
|
m_send_buffer.assign("GET ");
|
||||||
|
@ -117,7 +270,7 @@ namespace libtorrent
|
||||||
m_send_buffer += ":";
|
m_send_buffer += ":";
|
||||||
m_send_buffer += boost::lexical_cast<std::string>(port);
|
m_send_buffer += boost::lexical_cast<std::string>(port);
|
||||||
}
|
}
|
||||||
connect_to_port = m_settings.proxy_port != 0
|
m_port = m_settings.proxy_port != 0
|
||||||
? m_settings.proxy_port : 80 ;
|
? m_settings.proxy_port : 80 ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -125,7 +278,7 @@ namespace libtorrent
|
||||||
connect_to_host = &hostname;
|
connect_to_host = &hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_req.kind == tracker_request::scrape_request)
|
if (tracker_req().kind == tracker_request::scrape_request)
|
||||||
{
|
{
|
||||||
// find and replace "announce" with "scrape"
|
// find and replace "announce" with "scrape"
|
||||||
// in request
|
// in request
|
||||||
|
@ -133,7 +286,7 @@ namespace libtorrent
|
||||||
std::size_t pos = request.find("announce");
|
std::size_t pos = request.find("announce");
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
throw std::runtime_error("scrape is not available on url: '"
|
throw std::runtime_error("scrape is not available on url: '"
|
||||||
+ m_req.url +"'");
|
+ tracker_req().url +"'");
|
||||||
request.replace(pos, 8, "scrape");
|
request.replace(pos, 8, "scrape");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,11 +304,11 @@ namespace libtorrent
|
||||||
m_send_buffer += escape_string(
|
m_send_buffer += escape_string(
|
||||||
reinterpret_cast<const char*>(req.info_hash.begin()), 20);
|
reinterpret_cast<const char*>(req.info_hash.begin()), 20);
|
||||||
|
|
||||||
if (m_req.kind == tracker_request::announce_request)
|
if (tracker_req().kind == tracker_request::announce_request)
|
||||||
{
|
{
|
||||||
m_send_buffer += "&peer_id=";
|
m_send_buffer += "&peer_id=";
|
||||||
m_send_buffer += escape_string(
|
m_send_buffer += escape_string(
|
||||||
reinterpret_cast<const char*>(req.id.begin()), 20);
|
reinterpret_cast<const char*>(req.pid.begin()), 20);
|
||||||
|
|
||||||
m_send_buffer += "&port=";
|
m_send_buffer += "&port=";
|
||||||
m_send_buffer += boost::lexical_cast<std::string>(req.listen_port);
|
m_send_buffer += boost::lexical_cast<std::string>(req.listen_port);
|
||||||
|
@ -191,7 +344,8 @@ namespace libtorrent
|
||||||
|
|
||||||
m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n"
|
m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n"
|
||||||
"User-Agent: ";
|
"User-Agent: ";
|
||||||
m_send_buffer += m_settings.user_agent;
|
m_send_buffer += escape_string(m_settings.user_agent.c_str()
|
||||||
|
, m_settings.user_agent.length());
|
||||||
m_send_buffer += " (libtorrent)\r\n"
|
m_send_buffer += " (libtorrent)\r\n"
|
||||||
"Host: ";
|
"Host: ";
|
||||||
m_send_buffer += hostname;
|
m_send_buffer += hostname;
|
||||||
|
@ -221,139 +375,147 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_name_lookup = dns_lookup(connect_to_host->c_str(), connect_to_port);
|
m_name_lookup.async_by_name(m_host, *connect_to_host
|
||||||
m_socket.reset(new socket(socket::tcp, false));
|
, bind(&http_tracker_connection::name_lookup, self(), _1));
|
||||||
|
set_timeout(m_settings.tracker_completion_timeout
|
||||||
|
, m_settings.tracker_receive_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if this connection is finished and should be removed from
|
void http_tracker_connection::on_timeout()
|
||||||
// the connections list.
|
|
||||||
bool http_tracker_connection::tick()
|
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
m_timed_out = true;
|
||||||
try
|
m_socket.reset();
|
||||||
|
m_name_lookup.cancel();
|
||||||
|
fail_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_tracker_connection::name_lookup(asio::error const& error) try
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (m_timed_out) return;
|
||||||
|
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
#endif
|
fail(-1, error.what());
|
||||||
|
return;
|
||||||
if (m_name_lookup.running())
|
}
|
||||||
{
|
|
||||||
if (!m_name_lookup.finished()) return false;
|
|
||||||
|
|
||||||
if (m_name_lookup.failed())
|
|
||||||
{
|
|
||||||
if (has_requester()) requester().tracker_request_error(
|
|
||||||
m_req, -1, m_name_lookup.error());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
address a(m_name_lookup.ip());
|
|
||||||
if (has_requester()) requester().m_tracker_address = a;
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
if (has_requester()) requester().debug_log("name lookup successful");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_socket->connect(a);
|
|
||||||
|
|
||||||
// clear the lookup entry so it will not be
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
// marked as running anymore
|
if (has_requester()) requester().debug_log("tracker name lookup successful");
|
||||||
m_name_lookup = dns_lookup();
|
#endif
|
||||||
}
|
restart_read_timeout();
|
||||||
|
m_socket.reset(new stream_socket(m_name_lookup.io_service()));
|
||||||
|
tcp::endpoint a(m_port, m_host.address(0));
|
||||||
|
if (has_requester()) requester().m_tracker_address = a;
|
||||||
|
m_socket->async_connect(a, bind(&http_tracker_connection::connected, self(), _1));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
fail(-1, e.what());
|
||||||
|
}
|
||||||
|
|
||||||
using namespace boost::posix_time;
|
void http_tracker_connection::connected(asio::error const& error) try
|
||||||
|
{
|
||||||
time_duration d = second_clock::universal_time() - m_request_time;
|
if (error == asio::error::operation_aborted) return;
|
||||||
if (d > seconds(m_settings.tracker_timeout) ||
|
if (m_timed_out) return;
|
||||||
(!has_requester() && d > seconds(m_settings.stop_tracker_timeout)))
|
if (error)
|
||||||
{
|
{
|
||||||
if (has_requester()) requester().tracker_request_timed_out(m_req);
|
fail(-1, error.what());
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (has_requester()) requester().debug_log("tracker connection tick");
|
if (has_requester()) requester().debug_log("tracker connection successful");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// if we have a send buffer and the socket is ready for writing
|
restart_read_timeout();
|
||||||
// send the buffer
|
async_write(*m_socket, asio::buffer(m_send_buffer.c_str()
|
||||||
if (!m_send_buffer.empty() && m_socket->is_writable())
|
, m_send_buffer.size()), bind(&http_tracker_connection::sent
|
||||||
|
, self(), _1));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
fail(-1, e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_tracker_connection::sent(asio::error const& error) try
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (m_timed_out) return;
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
int sent = m_socket->send(m_send_buffer.c_str(),(int)m_send_buffer.size());
|
fail(-1, error.what());
|
||||||
|
return;
|
||||||
if (sent == (int)m_send_buffer.size())
|
|
||||||
{
|
|
||||||
m_send_buffer.clear();
|
|
||||||
}
|
|
||||||
else if (sent > 0)
|
|
||||||
{
|
|
||||||
m_send_buffer.erase(
|
|
||||||
m_send_buffer.begin()
|
|
||||||
, m_send_buffer.begin() + sent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sent != 0)
|
|
||||||
m_request_time = second_clock::universal_time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_socket->has_error())
|
|
||||||
{
|
|
||||||
if (has_requester()) requester().tracker_request_error(
|
|
||||||
m_req, -1, "connection refused");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the socket isn't ready for reading, there's no point in continuing
|
|
||||||
// trying to read from it
|
|
||||||
if (!m_socket->is_readable()) return false;
|
|
||||||
m_request_time = second_clock::universal_time();
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (has_requester()) requester().debug_log("tracker connection socket readable");
|
if (has_requester()) requester().debug_log("tracker send data completed");
|
||||||
#endif
|
#endif
|
||||||
|
restart_read_timeout();
|
||||||
|
assert(m_buffer.size() - m_recv_pos > 0);
|
||||||
|
m_socket->async_read_some(asio::buffer(&m_buffer[m_recv_pos]
|
||||||
|
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
|
||||||
|
, self(), _1, _2));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
fail(-1, e.what());
|
||||||
|
}; // msvc 7.1 seems to require this semi-colon
|
||||||
|
|
||||||
|
|
||||||
|
void http_tracker_connection::receive(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) try
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (m_timed_out) return;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (error == asio::error::eof)
|
||||||
|
{
|
||||||
|
on_response();
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail(-1, error.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_read_timeout();
|
||||||
|
assert(bytes_transferred > 0);
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
if (has_requester()) requester().debug_log("tracker connection reading "
|
||||||
|
+ boost::lexical_cast<std::string>(bytes_transferred));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_recv_pos += bytes_transferred;
|
||||||
|
|
||||||
// if the receive buffer is full, expand it with http_buffer_size
|
// if the receive buffer is full, expand it with http_buffer_size
|
||||||
if ((int)m_buffer.size() == m_recv_pos)
|
if ((int)m_buffer.size() == m_recv_pos)
|
||||||
{
|
{
|
||||||
if ((int)m_buffer.size() > m_settings.tracker_maximum_response_length)
|
if ((int)m_buffer.size() >= m_settings.tracker_maximum_response_length)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(200, "too large tracker response");
|
||||||
{
|
return;
|
||||||
requester().tracker_request_error(m_req, 200
|
|
||||||
, "too large tracker response");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
assert(http_buffer_size > 0);
|
assert(http_buffer_size > 0);
|
||||||
m_buffer.resize(m_buffer.size() + http_buffer_size);
|
if ((int)m_buffer.size() + http_buffer_size
|
||||||
|
> m_settings.tracker_maximum_response_length)
|
||||||
|
m_buffer.resize(m_settings.tracker_maximum_response_length);
|
||||||
|
else
|
||||||
|
m_buffer.resize(m_buffer.size() + http_buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
assert(m_recv_pos >= 0);
|
|
||||||
assert(m_recv_pos < (int)m_buffer.size());
|
|
||||||
int received = m_socket->receive(&m_buffer[m_recv_pos], (int)m_buffer.size() - m_recv_pos);
|
|
||||||
|
|
||||||
assert(received <= (int)m_buffer.size() - m_recv_pos);
|
|
||||||
|
|
||||||
if (received > 0) m_recv_pos += received;
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
if (has_requester()) requester().debug_log("received: " + boost::lexical_cast<std::string>(m_recv_pos));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_state == read_status)
|
if (m_state == read_status)
|
||||||
{
|
{
|
||||||
if (received <= 0)
|
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
{
|
|
||||||
requester().tracker_request_error(m_req, -1
|
|
||||||
, "invalid tracker response, connection closed");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char>::iterator end = m_buffer.begin()+m_recv_pos;
|
std::vector<char>::iterator end = m_buffer.begin()+m_recv_pos;
|
||||||
std::vector<char>::iterator newline = std::find(m_buffer.begin(), end, '\n');
|
std::vector<char>::iterator newline = std::find(m_buffer.begin(), end, '\n');
|
||||||
// if we don't have a full line yet, wait.
|
// if we don't have a full line yet, wait.
|
||||||
if (newline == end) return false;
|
if (newline == end) return;
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (has_requester()) requester().debug_log(std::string(m_buffer.begin(), newline));
|
if (has_requester()) requester().debug_log(std::string(m_buffer.begin(), newline));
|
||||||
|
@ -369,8 +531,8 @@ namespace libtorrent
|
||||||
if (m_server_protocol.substr(0, 5) != "HTTP/")
|
if (m_server_protocol.substr(0, 5) != "HTTP/")
|
||||||
{
|
{
|
||||||
std::string error_msg = "unknown protocol in response: " + m_server_protocol;
|
std::string error_msg = "unknown protocol in response: " + m_server_protocol;
|
||||||
if (has_requester()) requester().tracker_request_error(m_req, -1, error_msg.c_str());
|
fail(-1, error_msg.c_str());
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
line >> m_code;
|
line >> m_code;
|
||||||
std::getline(line, m_server_message);
|
std::getline(line, m_server_message);
|
||||||
|
@ -379,16 +541,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_state == read_header)
|
if (m_state == read_header)
|
||||||
{
|
{
|
||||||
if (received <= 0)
|
std::vector<char>::iterator end = m_buffer.begin() + m_recv_pos;
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
requester().tracker_request_error(m_req, -1
|
|
||||||
, "invalid tracker response, connection closed "
|
|
||||||
"while reading header");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char>::iterator end = m_buffer.begin()+m_recv_pos;
|
|
||||||
std::vector<char>::iterator newline
|
std::vector<char>::iterator newline
|
||||||
= std::find(m_buffer.begin(), end, '\n');
|
= std::find(m_buffer.begin(), end, '\n');
|
||||||
std::string line;
|
std::string line;
|
||||||
|
@ -410,31 +563,19 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
catch(boost::bad_lexical_cast&)
|
catch(boost::bad_lexical_cast&)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, "invalid content-length in tracker response");
|
||||||
{
|
return;
|
||||||
requester().tracker_request_error(m_req, -1,
|
|
||||||
"invalid content-length in tracker response");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (m_content_length > m_settings.tracker_maximum_response_length)
|
if (m_content_length > m_settings.tracker_maximum_response_length)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, "content-length is greater than maximum response length");
|
||||||
{
|
return;
|
||||||
requester().tracker_request_error(m_req, -1
|
|
||||||
, "content-length is greater than maximum response length");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_content_length < minimum_tracker_response_length && m_code == 200)
|
if (m_content_length < minimum_tracker_response_length && m_code == 200)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, "content-length is smaller than minimum response length");
|
||||||
{
|
return;
|
||||||
requester().tracker_request_error(m_req, -1
|
|
||||||
, "content-length is smaller than minimum response length");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (line.substr(0, 18) == "Content-Encoding: ")
|
else if (line.substr(0, 18) == "Content-Encoding: ")
|
||||||
|
@ -448,10 +589,8 @@ namespace libtorrent
|
||||||
std::string error_str = "unknown content encoding in response: \"";
|
std::string error_str = "unknown content encoding in response: \"";
|
||||||
error_str += line.substr(18, line.length() - 18 - 2);
|
error_str += line.substr(18, line.length() - 18 - 2);
|
||||||
error_str += "\"";
|
error_str += "\"";
|
||||||
if (has_requester())
|
fail(-1, error_str.c_str());
|
||||||
requester().tracker_request_error(m_req, -1
|
return;
|
||||||
, error_str.c_str());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (line.substr(0, 10) == "Location: ")
|
else if (line.substr(0, 10) == "Location: ")
|
||||||
|
@ -475,23 +614,24 @@ namespace libtorrent
|
||||||
std::string error_str = "got redirection response (";
|
std::string error_str = "got redirection response (";
|
||||||
error_str += boost::lexical_cast<std::string>(m_code);
|
error_str += boost::lexical_cast<std::string>(m_code);
|
||||||
error_str += ") without 'Location' header";
|
error_str += ") without 'Location' header";
|
||||||
if (has_requester())
|
fail(-1, error_str.c_str());
|
||||||
requester().tracker_request_error(m_req
|
return;
|
||||||
, m_code, error_str.c_str());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (has_requester()) requester().debug_log("Redirecting to \"" + m_location + "\"");
|
if (has_requester()) requester().debug_log("Redirecting to \"" + m_location + "\"");
|
||||||
#endif
|
#endif
|
||||||
|
tracker_request req = tracker_req();
|
||||||
std::string::size_type i = m_location.find('?');
|
std::string::size_type i = m_location.find('?');
|
||||||
if (i == std::string::npos)
|
if (i == std::string::npos)
|
||||||
m_req.url = m_location;
|
req.url = m_location;
|
||||||
else
|
else
|
||||||
m_req.url.assign(m_location.begin(), m_location.begin() + i);
|
req.url.assign(m_location.begin(), m_location.begin() + i);
|
||||||
|
|
||||||
m_man.queue_request(m_req, m_password, m_requester);
|
m_man.queue_request(m_socket->io_service(), req
|
||||||
return true;
|
, m_password, m_requester);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,54 +648,69 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_state == read_body)
|
if (m_state == read_body)
|
||||||
{
|
{
|
||||||
if (m_recv_pos == m_content_length || received <= 0)
|
if (m_recv_pos == m_content_length)
|
||||||
{
|
{
|
||||||
// GZIP
|
on_response();
|
||||||
if (m_content_encoding == gzip)
|
close();
|
||||||
{
|
return;
|
||||||
boost::shared_ptr<request_callback> r = m_requester.lock();
|
|
||||||
if (!r) return true;
|
|
||||||
if (inflate_gzip(m_buffer, m_req, r.get(),
|
|
||||||
m_settings.tracker_maximum_response_length))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle tracker response
|
|
||||||
try
|
|
||||||
{
|
|
||||||
entry e = bdecode(m_buffer.begin(), m_buffer.end());
|
|
||||||
parse(e);
|
|
||||||
}
|
|
||||||
catch (std::exception&)
|
|
||||||
{
|
|
||||||
std::string error_str(m_buffer.begin(), m_buffer.end());
|
|
||||||
if (has_requester()) requester().tracker_request_error(m_req, m_code, error_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else if (m_recv_pos > m_content_length && m_content_length > 0)
|
else if (m_recv_pos > m_content_length && m_content_length > 0)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, "invalid tracker response (body > content_length)");
|
||||||
{
|
return;
|
||||||
requester().tracker_request_error(m_req, -1
|
|
||||||
, "invalid tracker response (body > content_length)");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
assert(m_buffer.size() - m_recv_pos > 0);
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
m_socket->async_read_some(asio::buffer(&m_buffer[m_recv_pos]
|
||||||
}
|
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
|
||||||
catch (std::exception&)
|
, self(), _1, _2));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
fail(-1, e.what());
|
||||||
|
};
|
||||||
|
|
||||||
|
void http_tracker_connection::on_response()
|
||||||
|
{
|
||||||
|
// GZIP
|
||||||
|
if (m_content_encoding == gzip)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
boost::shared_ptr<request_callback> r = m_requester.lock();
|
||||||
requester().debug_log(std::string(m_buffer.begin(), m_buffer.end()));
|
|
||||||
throw;
|
if (!r)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inflate_gzip(m_buffer, m_req, r.get(),
|
||||||
|
m_settings.tracker_maximum_response_length))
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// handle tracker response
|
||||||
|
try
|
||||||
|
{
|
||||||
|
entry e = bdecode(m_buffer.begin(), m_buffer.end());
|
||||||
|
parse(e);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::string error_str(e.what());
|
||||||
|
error_str += ": ";
|
||||||
|
error_str.append(m_buffer.begin(), m_buffer.end());
|
||||||
|
fail(m_code, error_str.c_str());
|
||||||
|
}
|
||||||
|
#ifndef NDEBUG
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
peer_entry http_tracker_connection::extract_peer_info(const entry& info)
|
peer_entry http_tracker_connection::extract_peer_info(const entry& info)
|
||||||
|
@ -568,12 +723,12 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (i->string().length() != 20)
|
if (i->string().length() != 20)
|
||||||
throw std::runtime_error("invalid response from tracker");
|
throw std::runtime_error("invalid response from tracker");
|
||||||
std::copy(i->string().begin(), i->string().end(), ret.id.begin());
|
std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if there's no peer_id, just initialize it to a bunch of zeroes
|
// if there's no peer_id, just initialize it to a bunch of zeroes
|
||||||
std::fill_n(ret.id.begin(), 20, 0);
|
std::fill_n(ret.pid.begin(), 20, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract ip
|
// extract ip
|
||||||
|
@ -600,8 +755,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
entry const& failure = e["failure reason"];
|
entry const& failure = e["failure reason"];
|
||||||
|
|
||||||
if (has_requester()) requester().tracker_request_error(
|
fail(m_code, failure.string().c_str());
|
||||||
m_req, m_code, failure.string().c_str());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (type_error const&) {}
|
catch (type_error const&) {}
|
||||||
|
@ -616,10 +770,10 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<peer_entry> peer_list;
|
std::vector<peer_entry> peer_list;
|
||||||
|
|
||||||
if (m_req.kind == tracker_request::scrape_request)
|
if (tracker_req().kind == tracker_request::scrape_request)
|
||||||
{
|
{
|
||||||
std::string ih;
|
std::string ih;
|
||||||
std::copy(m_req.info_hash.begin(), m_req.info_hash.end()
|
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
|
||||||
, std::back_inserter(ih));
|
, std::back_inserter(ih));
|
||||||
entry scrape_data = e["files"][ih];
|
entry scrape_data = e["files"][ih];
|
||||||
int complete = scrape_data["complete"].integer();
|
int complete = scrape_data["complete"].integer();
|
||||||
|
@ -640,7 +794,7 @@ namespace libtorrent
|
||||||
if (std::distance(i, peers.end()) < 6) break;
|
if (std::distance(i, peers.end()) < 6) break;
|
||||||
|
|
||||||
peer_entry p;
|
peer_entry p;
|
||||||
p.id.clear();
|
p.pid.clear();
|
||||||
std::stringstream ip_str;
|
std::stringstream ip_str;
|
||||||
ip_str << (int)detail::read_uint8(i) << ".";
|
ip_str << (int)detail::read_uint8(i) << ".";
|
||||||
ip_str << (int)detail::read_uint8(i) << ".";
|
ip_str << (int)detail::read_uint8(i) << ".";
|
||||||
|
@ -661,7 +815,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for optional crape info
|
// look for optional scrape info
|
||||||
int complete = -1;
|
int complete = -1;
|
||||||
int incomplete = -1;
|
int incomplete = -1;
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ namespace
|
||||||
|| id[7] != '-')
|
|| id[7] != '-')
|
||||||
return boost::optional<fingerprint>();
|
return boost::optional<fingerprint>();
|
||||||
|
|
||||||
ret.id[0] = id[1];
|
ret.name[0] = id[1];
|
||||||
ret.id[1] = id[2];
|
ret.name[1] = id[2];
|
||||||
ret.major_version = decode_digit(id[3]);
|
ret.major_version = decode_digit(id[3]);
|
||||||
ret.minor_version = decode_digit(id[4]);
|
ret.minor_version = decode_digit(id[4]);
|
||||||
ret.revision_version = decode_digit(id[5]);
|
ret.revision_version = decode_digit(id[5]);
|
||||||
|
@ -108,8 +108,8 @@ namespace
|
||||||
ret.revision_version = id[3];
|
ret.revision_version = id[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.id[0] = id[0];
|
ret.name[0] = id[0];
|
||||||
ret.id[1] = 0;
|
ret.name[1] = 0;
|
||||||
|
|
||||||
ret.tag_version = 0;
|
ret.tag_version = 0;
|
||||||
return boost::optional<fingerprint>(ret);
|
return boost::optional<fingerprint>(ret);
|
||||||
|
@ -130,8 +130,8 @@ namespace
|
||||||
|
|
||||||
fingerprint ret("..", 0, 0, 0, 0);
|
fingerprint ret("..", 0, 0, 0, 0);
|
||||||
|
|
||||||
ret.id[0] = id[0];
|
ret.name[0] = id[0];
|
||||||
ret.id[1] = 0;
|
ret.name[1] = 0;
|
||||||
ret.major_version = decode_digit(id[1]);
|
ret.major_version = decode_digit(id[1]);
|
||||||
ret.minor_version = decode_digit(id[3]);
|
ret.minor_version = decode_digit(id[3]);
|
||||||
ret.revision_version = decode_digit(id[5]);
|
ret.revision_version = decode_digit(id[5]);
|
||||||
|
@ -166,6 +166,7 @@ namespace
|
||||||
, map_entry("SZ", "Shareaza")
|
, map_entry("SZ", "Shareaza")
|
||||||
, map_entry("T", "BitTornado")
|
, map_entry("T", "BitTornado")
|
||||||
, map_entry("TN", "Torrent.NET")
|
, map_entry("TN", "Torrent.NET")
|
||||||
|
, map_entry("TR", "Transmission")
|
||||||
, map_entry("TS", "TorrentStorm")
|
, map_entry("TS", "TorrentStorm")
|
||||||
, map_entry("U", "UPnP")
|
, map_entry("U", "UPnP")
|
||||||
, map_entry("UT", "MicroTorrent")
|
, map_entry("UT", "MicroTorrent")
|
||||||
|
@ -188,7 +189,7 @@ namespace
|
||||||
const int size = sizeof(name_map)/sizeof(name_map[0]);
|
const int size = sizeof(name_map)/sizeof(name_map[0]);
|
||||||
map_entry* i =
|
map_entry* i =
|
||||||
std::lower_bound(name_map, name_map + size
|
std::lower_bound(name_map, name_map + size
|
||||||
, map_entry(f.id, ""), &compare_first_string);
|
, map_entry(f.name, ""), &compare_first_string);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
for (int i = 1; i < size; ++i)
|
for (int i = 1; i < size; ++i)
|
||||||
|
@ -198,19 +199,19 @@ namespace
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
|
if (i < name_map + size && std::equal(f.name, f.name + 2, i->first))
|
||||||
identity << i->second;
|
identity << i->second;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
identity << f.id[0];
|
identity << f.name[0];
|
||||||
if (f.id[1] != 0) identity << f.id[1];
|
if (f.name[1] != 0) identity << f.name[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
identity << " " << (int)f.major_version
|
identity << " " << (int)f.major_version
|
||||||
<< "." << (int)f.minor_version
|
<< "." << (int)f.minor_version
|
||||||
<< "." << (int)f.revision_version;
|
<< "." << (int)f.revision_version;
|
||||||
|
|
||||||
if (f.id[1] != 0)
|
if (f.name[1] != 0)
|
||||||
identity << "." << (int)f.tag_version;
|
identity << "." << (int)f.tag_version;
|
||||||
|
|
||||||
return identity.str();
|
return identity.str();
|
||||||
|
|
|
@ -37,10 +37,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
ip_filter::ip_filter()
|
ip_filter::ip_filter()
|
||||||
{
|
{
|
||||||
// make the entire ip-range non-blocked
|
// make the entire ip-range non-blocked
|
||||||
m_access_list.insert(range(address(0,0,0,0,0), 0));
|
m_access_list.insert(range(address(0UL), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ip_filter::add_rule(address first, address last, int flags)
|
void ip_filter::add_rule(address first, address last, int flags)
|
||||||
|
@ -70,7 +71,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (i->start != first && first_access != flags)
|
if (i->start != first && first_access != flags)
|
||||||
{
|
{
|
||||||
i = m_access_list.insert(i, range(address(first.ip(), 0), flags));
|
i = m_access_list.insert(i, range(first, flags));
|
||||||
}
|
}
|
||||||
else if (i != m_access_list.begin() && prior(i)->access == flags)
|
else if (i != m_access_list.begin() && prior(i)->access == flags)
|
||||||
{
|
{
|
||||||
|
@ -100,16 +101,16 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else if (first_access != flags)
|
else if (first_access != flags)
|
||||||
{
|
{
|
||||||
m_access_list.insert(i, range(address(first.ip(), 0), flags));
|
m_access_list.insert(i, range(first, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((j != m_access_list.end() && j->start.ip() - 1 != last.ip())
|
if ((j != m_access_list.end() && j->start.to_ulong() - 1 != last.to_ulong())
|
||||||
|| (j == m_access_list.end() && last.ip() != 0xffffffff))
|
|| (j == m_access_list.end() && last.to_ulong() != 0xffffffff))
|
||||||
{
|
{
|
||||||
assert(j == m_access_list.end() || last.ip() < j->start.ip() - 1);
|
assert(j == m_access_list.end() || last.to_ulong() < j->start.to_ulong() - 1);
|
||||||
// std::cout << " -- last_access: " << last_access << "\n";
|
// std::cout << " -- last_access: " << last_access << "\n";
|
||||||
if (last_access != flags)
|
if (last_access != flags)
|
||||||
j = m_access_list.insert(j, range(address(last.ip() + 1, 0), last_access));
|
j = m_access_list.insert(j, range(address(last.to_ulong() + 1), last_access));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
|
if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
|
||||||
|
@ -138,14 +139,13 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
ip_range r;
|
ip_range r;
|
||||||
r.first = i->start;
|
r.first = i->start;
|
||||||
assert(r.first.port == 0);
|
|
||||||
r.flags = i->access;
|
r.flags = i->access;
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
if (i == end)
|
if (i == end)
|
||||||
r.last = address(0xffffffff, 0);
|
r.last = address(0xffffffff);
|
||||||
else
|
else
|
||||||
r.last = address(i->start.ip() - 1, 0);
|
r.last = address(i->start.to_ulong() - 1);
|
||||||
|
|
||||||
ret.push_back(r);
|
ret.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -45,12 +45,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks)
|
piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks
|
||||||
|
, int sequenced_download_threshold)
|
||||||
: m_piece_info(2)
|
: m_piece_info(2)
|
||||||
, m_downloading_piece_info(2)
|
, m_downloading_piece_info(2)
|
||||||
, m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
|
, m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
|
||||||
, m_num_filtered(0)
|
, m_num_filtered(0)
|
||||||
, m_num_have_filtered(0)
|
, m_num_have_filtered(0)
|
||||||
|
, m_sequenced_download_threshold(sequenced_download_threshold)
|
||||||
{
|
{
|
||||||
assert(blocks_per_piece > 0);
|
assert(blocks_per_piece > 0);
|
||||||
assert(total_num_blocks >= 0);
|
assert(total_num_blocks >= 0);
|
||||||
|
@ -104,12 +106,9 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// random shuffle the list
|
|
||||||
std::random_shuffle(piece_list.begin(), piece_list.end());
|
|
||||||
|
|
||||||
// add the pieces to the piece_picker
|
// add the pieces to the piece_picker
|
||||||
for (std::vector<int>::iterator i = piece_list.begin();
|
for (std::vector<int>::reverse_iterator i = piece_list.rbegin();
|
||||||
i != piece_list.end(); ++i)
|
i != piece_list.rend(); ++i)
|
||||||
{
|
{
|
||||||
int index = *i;
|
int index = *i;
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
|
@ -133,7 +132,7 @@ namespace libtorrent
|
||||||
for (std::vector<downloading_piece>::const_iterator i
|
for (std::vector<downloading_piece>::const_iterator i
|
||||||
= unfinished.begin(); i != unfinished.end(); ++i)
|
= unfinished.begin(); i != unfinished.end(); ++i)
|
||||||
{
|
{
|
||||||
address peer;
|
tcp::endpoint peer;
|
||||||
for (int j = 0; j < m_blocks_per_piece; ++j)
|
for (int j = 0; j < m_blocks_per_piece; ++j)
|
||||||
{
|
{
|
||||||
if (i->finished_blocks[j])
|
if (i->finished_blocks[j])
|
||||||
|
@ -146,6 +145,34 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_picker::set_sequenced_download_threshold(
|
||||||
|
int sequenced_download_threshold)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
integrity_check();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sequenced_download_threshold == m_sequenced_download_threshold)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int old_limit = m_sequenced_download_threshold;
|
||||||
|
m_sequenced_download_threshold = sequenced_download_threshold;
|
||||||
|
|
||||||
|
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
|
||||||
|
, end(m_piece_map.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (i->priority(old_limit) != i->priority(m_sequenced_download_threshold))
|
||||||
|
{
|
||||||
|
piece_pos& p = m_piece_map[i->index];
|
||||||
|
int prev_priority = i->priority(old_limit);
|
||||||
|
move(p.downloading, p.filtered, prev_priority, i->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef NDEBUG
|
||||||
|
integrity_check();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
void piece_picker::integrity_check(const torrent* t) const
|
void piece_picker::integrity_check(const torrent* t) const
|
||||||
|
@ -236,8 +263,8 @@ namespace libtorrent
|
||||||
assert(!t->have_piece(index));
|
assert(!t->have_piece(index));
|
||||||
|
|
||||||
const std::vector<std::vector<int> >& c_vec = pick_piece_info_vector(i->downloading, i->filtered);
|
const std::vector<std::vector<int> >& c_vec = pick_piece_info_vector(i->downloading, i->filtered);
|
||||||
assert(i->peer_count < c_vec.size());
|
assert(i->priority(m_sequenced_download_threshold) < (int)c_vec.size());
|
||||||
const std::vector<int>& vec = c_vec[i->peer_count];
|
const std::vector<int>& vec = c_vec[i->priority(m_sequenced_download_threshold)];
|
||||||
assert(i->index < vec.size());
|
assert(i->index < vec.size());
|
||||||
assert(vec[i->index] == index);
|
assert(vec[i->index] == index);
|
||||||
}
|
}
|
||||||
|
@ -302,80 +329,159 @@ namespace libtorrent
|
||||||
std::vector<std::vector<int> >& dst_vec = pick_piece_info_vector(
|
std::vector<std::vector<int> >& dst_vec = pick_piece_info_vector(
|
||||||
p.downloading, p.filtered);
|
p.downloading, p.filtered);
|
||||||
|
|
||||||
if (dst_vec.size() <= p.peer_count)
|
int priority = p.priority(m_sequenced_download_threshold);
|
||||||
dst_vec.resize(p.peer_count + 1);
|
if ((int)dst_vec.size() <= priority)
|
||||||
|
dst_vec.resize(priority + 1);
|
||||||
|
|
||||||
assert(dst_vec.size() > p.peer_count);
|
assert((int)dst_vec.size() > priority);
|
||||||
p.index = (int)dst_vec[p.peer_count].size();
|
|
||||||
dst_vec[p.peer_count].push_back(index);
|
if (p.ordered(m_sequenced_download_threshold))
|
||||||
|
{
|
||||||
|
// the piece should be inserted ordered, not randomly
|
||||||
|
std::vector<int>& v = dst_vec[priority];
|
||||||
|
std::vector<int>::iterator i = std::lower_bound(v.begin(), v.end()
|
||||||
|
, index, std::greater<int>());
|
||||||
|
p.index = i - v.begin();
|
||||||
|
v.insert(i, index);
|
||||||
|
i = v.begin() + p.index + 1;
|
||||||
|
for (;i != v.end(); ++i)
|
||||||
|
{
|
||||||
|
++m_piece_map[*i].index;
|
||||||
|
assert(v[m_piece_map[*i].index] == *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dst_vec[priority].size() < 2)
|
||||||
|
{
|
||||||
|
p.index = dst_vec[priority].size();
|
||||||
|
dst_vec[priority].push_back(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find a random position in the destination vector where we will place
|
||||||
|
// this entry.
|
||||||
|
int dst_index = rand() % dst_vec[priority].size();
|
||||||
|
|
||||||
|
// copy the entry at that position to the back
|
||||||
|
m_piece_map[dst_vec[priority][dst_index]].index
|
||||||
|
= dst_vec[priority].size();
|
||||||
|
dst_vec[priority].push_back(dst_vec[priority][dst_index]);
|
||||||
|
|
||||||
|
// and then replace the one at dst_index with the one we're moving.
|
||||||
|
// this procedure is to make sure there's no ordering when pieces
|
||||||
|
// are moved in sequenced order.
|
||||||
|
p.index = dst_index;
|
||||||
|
dst_vec[priority][p.index] = index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// will update the piece with the given properties (downloading, filtered, peer_count, elem_index)
|
// will update the piece with the given properties (downloading, filtered,
|
||||||
// to place it at the correct position in the vectors.
|
// priority, elem_index) to place it at the correct position in the
|
||||||
void piece_picker::move(bool downloading, bool filtered, int peer_count, int elem_index)
|
// vectors.
|
||||||
|
void piece_picker::move(bool downloading, bool filtered, int priority
|
||||||
|
, int elem_index)
|
||||||
{
|
{
|
||||||
assert(!filtered);
|
assert(!filtered);
|
||||||
assert(peer_count >= 0);
|
assert(priority >= 0);
|
||||||
assert(elem_index >= 0);
|
assert(elem_index >= 0);
|
||||||
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
|
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(
|
||||||
|
downloading, filtered));
|
||||||
|
|
||||||
assert((int)src_vec.size() > peer_count);
|
assert((int)src_vec.size() > priority);
|
||||||
assert((int)src_vec[peer_count].size() > elem_index);
|
assert((int)src_vec[priority].size() > elem_index);
|
||||||
|
|
||||||
int index = src_vec[peer_count][elem_index];
|
int index = src_vec[priority][elem_index];
|
||||||
// update the piece_map
|
// update the piece_map
|
||||||
piece_pos& p = m_piece_map[index];
|
piece_pos& p = m_piece_map[index];
|
||||||
|
int new_priority = p.priority(m_sequenced_download_threshold);
|
||||||
|
|
||||||
assert(p.downloading != downloading
|
assert(p.downloading != downloading
|
||||||
|| p.filtered != filtered
|
|| p.filtered != filtered
|
||||||
|| (int)p.peer_count != peer_count);
|
|| (int)new_priority != priority);
|
||||||
|
|
||||||
std::vector<std::vector<int> >& dst_vec(pick_piece_info_vector(p.downloading, p.filtered));
|
std::vector<std::vector<int> >& dst_vec(pick_piece_info_vector(
|
||||||
|
p.downloading, p.filtered));
|
||||||
|
|
||||||
if (dst_vec.size() <= p.peer_count)
|
if ((int)dst_vec.size() <= new_priority)
|
||||||
{
|
{
|
||||||
dst_vec.resize(p.peer_count+1);
|
dst_vec.resize(new_priority + 1);
|
||||||
assert(dst_vec.size() > p.peer_count);
|
assert((int)dst_vec.size() > new_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.index = (int)dst_vec[p.peer_count].size();
|
if (p.ordered(m_sequenced_download_threshold))
|
||||||
dst_vec[p.peer_count].push_back(index);
|
{
|
||||||
assert(p.index < dst_vec[p.peer_count].size());
|
// the piece should be inserted ordered, not randomly
|
||||||
assert(dst_vec[p.peer_count][p.index] == index);
|
std::vector<int>& v = dst_vec[new_priority];
|
||||||
|
|
||||||
|
std::vector<int>::iterator i = std::lower_bound(v.begin(), v.end()
|
||||||
|
, index, std::greater<int>());
|
||||||
|
p.index = i - v.begin();
|
||||||
|
v.insert(i, index);
|
||||||
|
i = v.begin() + p.index + 1;
|
||||||
|
for (;i != v.end(); ++i)
|
||||||
|
{
|
||||||
|
++m_piece_map[*i].index;
|
||||||
|
assert(v[m_piece_map[*i].index] == *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dst_vec[new_priority].size() < 2)
|
||||||
|
{
|
||||||
|
p.index = dst_vec[new_priority].size();
|
||||||
|
dst_vec[new_priority].push_back(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find a random position in the destination vector where we will place
|
||||||
|
// this entry.
|
||||||
|
int dst_index = rand() % dst_vec[new_priority].size();
|
||||||
|
|
||||||
|
// copy the entry at that position to the back
|
||||||
|
m_piece_map[dst_vec[new_priority][dst_index]].index
|
||||||
|
= dst_vec[new_priority].size();
|
||||||
|
dst_vec[new_priority].push_back(dst_vec[new_priority][dst_index]);
|
||||||
|
|
||||||
|
// and then replace the one at dst_index with the one we're moving.
|
||||||
|
// this procedure is to make sure there's no ordering when pieces
|
||||||
|
// are moved in sequenced order.
|
||||||
|
p.index = dst_index;
|
||||||
|
dst_vec[new_priority][p.index] = index;
|
||||||
|
}
|
||||||
|
assert(p.index < dst_vec[p.priority(m_sequenced_download_threshold)].size());
|
||||||
|
assert(dst_vec[p.priority(m_sequenced_download_threshold)][p.index] == index);
|
||||||
|
|
||||||
// this will remove elem from the source vector without
|
// this will remove elem from the source vector without
|
||||||
// preserving order, but the order is random any way
|
// preserving order, but the order is random anyway
|
||||||
int replace_index = src_vec[peer_count][elem_index] = src_vec[peer_count].back();
|
int replace_index = src_vec[priority][elem_index] = src_vec[priority].back();
|
||||||
if (index != replace_index)
|
if (index != replace_index)
|
||||||
{
|
{
|
||||||
// update the entry we moved from the back
|
// update the entry we moved from the back
|
||||||
m_piece_map[replace_index].index = elem_index;
|
m_piece_map[replace_index].index = elem_index;
|
||||||
|
|
||||||
assert((int)src_vec[peer_count].size() > elem_index);
|
assert((int)src_vec[priority].size() > elem_index);
|
||||||
assert((int)m_piece_map[replace_index].peer_count == peer_count);
|
assert((int)m_piece_map[replace_index].priority(m_sequenced_download_threshold) == priority);
|
||||||
assert((int)m_piece_map[replace_index].index == elem_index);
|
assert((int)m_piece_map[replace_index].index == elem_index);
|
||||||
assert(src_vec[peer_count][elem_index] == replace_index);
|
assert(src_vec[priority][elem_index] == replace_index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert((int)src_vec[peer_count].size() == elem_index+1);
|
assert((int)src_vec[priority].size() == elem_index+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
src_vec[peer_count].pop_back();
|
src_vec[priority].pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::remove(bool downloading, bool filtered, int peer_count, int elem_index)
|
void piece_picker::remove(bool downloading, bool filtered, int priority
|
||||||
|
, int elem_index)
|
||||||
{
|
{
|
||||||
assert(!filtered);
|
assert(!filtered);
|
||||||
assert(peer_count >= 0);
|
assert(priority >= 0);
|
||||||
assert(elem_index >= 0);
|
assert(elem_index >= 0);
|
||||||
|
|
||||||
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
|
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
|
||||||
|
|
||||||
assert((int)src_vec.size() > peer_count);
|
assert((int)src_vec.size() > priority);
|
||||||
assert((int)src_vec[peer_count].size() > elem_index);
|
assert((int)src_vec[priority].size() > elem_index);
|
||||||
|
|
||||||
int index = src_vec[peer_count][elem_index];
|
int index = src_vec[priority][elem_index];
|
||||||
|
|
||||||
if (downloading)
|
if (downloading)
|
||||||
{
|
{
|
||||||
|
@ -386,16 +492,30 @@ namespace libtorrent
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
m_downloads.erase(i);
|
m_downloads.erase(i);
|
||||||
}
|
}
|
||||||
m_piece_map[index].downloading = 0;
|
piece_pos& p = m_piece_map[index];
|
||||||
|
p.downloading = 0;
|
||||||
// this will remove elem from the vector without
|
if (p.ordered(m_sequenced_download_threshold))
|
||||||
// preserving order
|
{
|
||||||
index = src_vec[peer_count][elem_index] = src_vec[peer_count].back();
|
std::vector<int>& v = src_vec[priority];
|
||||||
// update the entry we moved from the back
|
std::vector<int>::iterator i = v.begin() + elem_index;
|
||||||
if ((int)src_vec[peer_count].size() > elem_index+1)
|
v.erase(i);
|
||||||
m_piece_map[index].index = elem_index;
|
i = v.begin() + elem_index;
|
||||||
src_vec[peer_count].pop_back();
|
for (; i != v.end(); ++i)
|
||||||
|
{
|
||||||
|
--m_piece_map[*i].index;
|
||||||
|
assert(v[m_piece_map[*i].index] == *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this will remove elem from the vector without
|
||||||
|
// preserving order
|
||||||
|
index = src_vec[priority][elem_index] = src_vec[priority].back();
|
||||||
|
// update the entry we moved from the back
|
||||||
|
if ((int)src_vec[priority].size() > elem_index+1)
|
||||||
|
m_piece_map[index].index = elem_index;
|
||||||
|
src_vec[priority].pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::restore_piece(int index)
|
void piece_picker::restore_piece(int index)
|
||||||
|
@ -415,7 +535,7 @@ namespace libtorrent
|
||||||
m_piece_map[index].downloading = 0;
|
m_piece_map[index].downloading = 0;
|
||||||
piece_pos& p = m_piece_map[index];
|
piece_pos& p = m_piece_map[index];
|
||||||
if (p.filtered) return;
|
if (p.filtered) return;
|
||||||
move(true, p.filtered, p.peer_count, p.index);
|
move(true, p.filtered, p.priority(m_sequenced_download_threshold), p.index);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// integrity_check();
|
// integrity_check();
|
||||||
|
@ -427,10 +547,10 @@ namespace libtorrent
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
assert(i < (int)m_piece_map.size());
|
assert(i < (int)m_piece_map.size());
|
||||||
|
|
||||||
int peer_count = m_piece_map[i].peer_count;
|
|
||||||
int index = m_piece_map[i].index;
|
int index = m_piece_map[i].index;
|
||||||
|
int prev_priority = m_piece_map[i].priority(m_sequenced_download_threshold);
|
||||||
|
|
||||||
assert(peer_count < 2048);
|
assert(m_piece_map[i].peer_count < 2048);
|
||||||
m_piece_map[i].peer_count++;
|
m_piece_map[i].peer_count++;
|
||||||
assert(m_piece_map[i].peer_count != 0);
|
assert(m_piece_map[i].peer_count != 0);
|
||||||
|
|
||||||
|
@ -438,9 +558,10 @@ namespace libtorrent
|
||||||
|
|
||||||
// if we have the piece or if it's filtered
|
// if we have the piece or if it's filtered
|
||||||
// we don't have to move any entries in the piece_info vector
|
// we don't have to move any entries in the piece_info vector
|
||||||
if (index == piece_pos::we_have_index || p.filtered) return;
|
if (index == piece_pos::we_have_index || p.filtered
|
||||||
|
|| p.priority(m_sequenced_download_threshold) == prev_priority) return;
|
||||||
|
|
||||||
move(p.downloading, p.filtered, peer_count, index);
|
move(p.downloading, p.filtered, prev_priority, index);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// integrity_check();
|
// integrity_check();
|
||||||
|
@ -457,18 +578,19 @@ namespace libtorrent
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
assert(i < (int)m_piece_map.size());
|
assert(i < (int)m_piece_map.size());
|
||||||
|
|
||||||
int peer_count = m_piece_map[i].peer_count;
|
int prev_priority = m_piece_map[i].priority(m_sequenced_download_threshold);
|
||||||
int index = m_piece_map[i].index;
|
int index = m_piece_map[i].index;
|
||||||
assert(peer_count > 0);
|
assert(m_piece_map[i].peer_count > 0);
|
||||||
|
|
||||||
if (m_piece_map[i].peer_count > 0)
|
if (m_piece_map[i].peer_count > 0)
|
||||||
m_piece_map[i].peer_count--;
|
m_piece_map[i].peer_count--;
|
||||||
|
|
||||||
piece_pos& p = m_piece_map[i];
|
piece_pos& p = m_piece_map[i];
|
||||||
|
|
||||||
if (index == piece_pos::we_have_index || p.filtered) return;
|
if (index == piece_pos::we_have_index || p.filtered
|
||||||
|
|| p.priority(m_sequenced_download_threshold) == prev_priority) return;
|
||||||
|
|
||||||
move(p.downloading, p.filtered, peer_count, index);
|
move(p.downloading, p.filtered, prev_priority, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is used to indicate that we succesfully have
|
// this is used to indicate that we succesfully have
|
||||||
|
@ -481,7 +603,7 @@ namespace libtorrent
|
||||||
assert(index < (int)m_piece_map.size());
|
assert(index < (int)m_piece_map.size());
|
||||||
|
|
||||||
int info_index = m_piece_map[index].index;
|
int info_index = m_piece_map[index].index;
|
||||||
int peer_count = m_piece_map[index].peer_count;
|
int priority = m_piece_map[index].priority(m_sequenced_download_threshold);
|
||||||
|
|
||||||
assert(m_piece_map[index].downloading == 1);
|
assert(m_piece_map[index].downloading == 1);
|
||||||
|
|
||||||
|
@ -494,7 +616,7 @@ namespace libtorrent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (info_index == piece_pos::we_have_index) return;
|
if (info_index == piece_pos::we_have_index) return;
|
||||||
remove(p.downloading, p.filtered, peer_count, info_index);
|
remove(p.downloading, p.filtered, priority, info_index);
|
||||||
p.index = piece_pos::we_have_index;
|
p.index = piece_pos::we_have_index;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
integrity_check();
|
integrity_check();
|
||||||
|
@ -517,7 +639,7 @@ namespace libtorrent
|
||||||
if (p.index != piece_pos::we_have_index)
|
if (p.index != piece_pos::we_have_index)
|
||||||
{
|
{
|
||||||
++m_num_filtered;
|
++m_num_filtered;
|
||||||
remove(p.downloading, false, p.peer_count, p.index);
|
remove(p.downloading, false, p.priority(m_sequenced_download_threshold), p.index);
|
||||||
assert(p.filtered == 1);
|
assert(p.filtered == 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -582,7 +704,7 @@ namespace libtorrent
|
||||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, address peer) const
|
, tcp::endpoint peer) const
|
||||||
{
|
{
|
||||||
assert(num_blocks > 0);
|
assert(num_blocks > 0);
|
||||||
assert(pieces.size() == m_piece_map.size());
|
assert(pieces.size() == m_piece_map.size());
|
||||||
|
@ -599,9 +721,13 @@ namespace libtorrent
|
||||||
assert(m_piece_info.begin() != m_piece_info.end());
|
assert(m_piece_info.begin() != m_piece_info.end());
|
||||||
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
|
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
|
||||||
// pieces that 0 other peers has.
|
// pieces that 0 other peers has.
|
||||||
std::vector<std::vector<int> >::const_iterator free = m_piece_info.begin()+1;
|
std::vector<std::vector<int> >::const_iterator free
|
||||||
assert(m_downloading_piece_info.begin() != m_downloading_piece_info.end());
|
= m_piece_info.begin() + 1;
|
||||||
std::vector<std::vector<int> >::const_iterator partial = m_downloading_piece_info.begin()+1;
|
assert(m_downloading_piece_info.begin()
|
||||||
|
!= m_downloading_piece_info.end());
|
||||||
|
|
||||||
|
std::vector<std::vector<int> >::const_iterator partial
|
||||||
|
= m_downloading_piece_info.begin() + 1;
|
||||||
|
|
||||||
std::vector<piece_block> backup_blocks;
|
std::vector<piece_block> backup_blocks;
|
||||||
|
|
||||||
|
@ -610,15 +736,18 @@ namespace libtorrent
|
||||||
// has filled the interesting_blocks with num_blocks
|
// has filled the interesting_blocks with num_blocks
|
||||||
// blocks.
|
// blocks.
|
||||||
|
|
||||||
// it iterates over two ranges simultaneously. The pieces that are partially downloaded
|
// it iterates over two ranges simultaneously. The pieces that are
|
||||||
// or partially requested, and the pieces that hasn't been requested at all.
|
// partially downloaded or partially requested, and the pieces that
|
||||||
// The default is to prioritize pieces that are partially requested/downloaded, so the
|
// hasn't been requested at all. The default is to prioritize pieces
|
||||||
// loop will first look for blocks among those pieces. And it will also take two steps
|
// that are partially requested/downloaded, so the loop will first
|
||||||
// in that range when iterating. This has the effect that partial pieces doesn't have to
|
// look for blocks among those pieces. And it will also take two steps
|
||||||
// be as rare as non-requested pieces in order to be prefered.
|
// in that range when iterating. This has the effect that partial pieces
|
||||||
|
// doesn't have to be as rare as non-requested pieces in order to be
|
||||||
// When prefer_whole_pieces is set (usually set when downloading from fast peers) the
|
// prefered.
|
||||||
// partial pieces will not be prioritized, but actually ignored as long as possible.
|
|
||||||
|
// When prefer_whole_pieces is set (usually set when downloading from
|
||||||
|
// fast peers) the partial pieces will not be prioritized, but actually
|
||||||
|
// ignored as long as possible.
|
||||||
|
|
||||||
while((free != m_piece_info.end())
|
while((free != m_piece_info.end())
|
||||||
|| (partial != m_downloading_piece_info.end()))
|
|| (partial != m_downloading_piece_info.end()))
|
||||||
|
@ -664,14 +793,14 @@ namespace libtorrent
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool exclusively_requested_from(piece_picker::downloading_piece const& p
|
bool exclusively_requested_from(piece_picker::downloading_piece const& p
|
||||||
, int num_blocks_in_piece, address peer)
|
, int num_blocks_in_piece, tcp::endpoint peer)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
{
|
{
|
||||||
if ((p.finished_blocks[j] == 1
|
if ((p.finished_blocks[j] == 1
|
||||||
|| p.requested_blocks[j] == 1)
|
|| p.requested_blocks[j] == 1)
|
||||||
&& p.info[j].peer != peer
|
&& p.info[j].peer != peer
|
||||||
&& p.info[j].peer != address())
|
&& p.info[j].peer != tcp::endpoint())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -715,7 +844,7 @@ namespace libtorrent
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, address peer) const
|
, tcp::endpoint peer) const
|
||||||
{
|
{
|
||||||
assert(num_blocks > 0);
|
assert(num_blocks > 0);
|
||||||
|
|
||||||
|
@ -730,7 +859,7 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(m_piece_map[*i].downloading == 1);
|
assert(m_piece_map[*i].downloading == 1);
|
||||||
|
|
||||||
// calculate the number of blocks in this
|
// calculate the number of blocks in this
|
||||||
// piece. It's always m_blocks_per_piece, except
|
// piece. It's always m_blocks_per_piece, except
|
||||||
// in the last piece.
|
// in the last piece.
|
||||||
int num_blocks_in_piece = blocks_in_piece(*i);
|
int num_blocks_in_piece = blocks_in_piece(*i);
|
||||||
|
@ -842,7 +971,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void piece_picker::mark_as_downloading(piece_block block, const address& peer)
|
void piece_picker::mark_as_downloading(piece_block block, const tcp::endpoint& peer)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// integrity_check();
|
// integrity_check();
|
||||||
|
@ -856,7 +985,7 @@ namespace libtorrent
|
||||||
if (p.downloading == 0)
|
if (p.downloading == 0)
|
||||||
{
|
{
|
||||||
p.downloading = 1;
|
p.downloading = 1;
|
||||||
move(false, p.filtered, p.peer_count, p.index);
|
move(false, p.filtered, p.priority(m_sequenced_download_threshold), p.index);
|
||||||
|
|
||||||
downloading_piece dp;
|
downloading_piece dp;
|
||||||
dp.index = block.piece_index;
|
dp.index = block.piece_index;
|
||||||
|
@ -878,7 +1007,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::mark_as_finished(piece_block block, const address& peer)
|
void piece_picker::mark_as_finished(piece_block block, const tcp::endpoint& peer)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// integrity_check();
|
// integrity_check();
|
||||||
|
@ -894,7 +1023,7 @@ namespace libtorrent
|
||||||
if (p.downloading == 0)
|
if (p.downloading == 0)
|
||||||
{
|
{
|
||||||
p.downloading = 1;
|
p.downloading = 1;
|
||||||
move(false, p.filtered, p.peer_count, p.index);
|
move(false, p.filtered, p.priority(m_sequenced_download_threshold), p.index);
|
||||||
|
|
||||||
downloading_piece dp;
|
downloading_piece dp;
|
||||||
dp.index = block.piece_index;
|
dp.index = block.piece_index;
|
||||||
|
@ -945,7 +1074,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
void piece_picker::get_downloaders(std::vector<address>& d, int index) const
|
void piece_picker::get_downloaders(std::vector<tcp::endpoint>& d, int index) const
|
||||||
{
|
{
|
||||||
assert(index >= 0 && index <= (int)m_piece_map.size());
|
assert(index >= 0 && index <= (int)m_piece_map.size());
|
||||||
std::vector<downloading_piece>::const_iterator i
|
std::vector<downloading_piece>::const_iterator i
|
||||||
|
@ -959,7 +1088,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<address> piece_picker::get_downloader(piece_block block) const
|
boost::optional<tcp::endpoint> piece_picker::get_downloader(piece_block block) const
|
||||||
{
|
{
|
||||||
std::vector<downloading_piece>::const_iterator i = std::find_if(
|
std::vector<downloading_piece>::const_iterator i = std::find_if(
|
||||||
m_downloads.begin()
|
m_downloads.begin()
|
||||||
|
@ -967,16 +1096,16 @@ namespace libtorrent
|
||||||
, has_index(block.piece_index));
|
, has_index(block.piece_index));
|
||||||
|
|
||||||
if (i == m_downloads.end())
|
if (i == m_downloads.end())
|
||||||
return boost::optional<address>();
|
return boost::optional<tcp::endpoint>();
|
||||||
|
|
||||||
assert(block.block_index < max_blocks_per_piece);
|
assert(block.block_index < max_blocks_per_piece);
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
|
|
||||||
if (i->requested_blocks[block.block_index] == false
|
if (i->requested_blocks[block.block_index] == false
|
||||||
|| i->finished_blocks[block.block_index] == true)
|
|| i->finished_blocks[block.block_index] == true)
|
||||||
return boost::optional<address>();
|
return boost::optional<tcp::endpoint>();
|
||||||
|
|
||||||
return boost::optional<address>(i->info[block.block_index].peer);
|
return boost::optional<tcp::endpoint>(i->info[block.block_index].peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::abort_download(piece_block block)
|
void piece_picker::abort_download(piece_block block)
|
||||||
|
@ -1003,7 +1132,12 @@ namespace libtorrent
|
||||||
if (i->finished_blocks[block.block_index]) return;
|
if (i->finished_blocks[block.block_index]) return;
|
||||||
|
|
||||||
assert(block.block_index < blocks_in_piece(block.piece_index));
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
||||||
assert(i->requested_blocks[block.block_index] == 1);
|
#ifndef NDEBUG
|
||||||
|
if (i->requested_blocks[block.block_index] != 1)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// clear this block as being downloaded
|
// clear this block as being downloaded
|
||||||
i->requested_blocks[block.block_index] = 0;
|
i->requested_blocks[block.block_index] = 0;
|
||||||
|
@ -1015,7 +1149,7 @@ namespace libtorrent
|
||||||
m_downloads.erase(i);
|
m_downloads.erase(i);
|
||||||
m_piece_map[block.piece_index].downloading = 0;
|
m_piece_map[block.piece_index].downloading = 0;
|
||||||
piece_pos& p = m_piece_map[block.piece_index];
|
piece_pos& p = m_piece_map[block.piece_index];
|
||||||
move(true, p.filtered, p.peer_count, p.index);
|
move(true, p.filtered, p.priority(m_sequenced_download_threshold), p.index);
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// integrity_check();
|
// integrity_check();
|
||||||
|
|
132
src/policy.cpp
132
src/policy.cpp
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "libtorrent/web_peer_connection.hpp"
|
||||||
#include "libtorrent/policy.hpp"
|
#include "libtorrent/policy.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
|
@ -72,26 +73,8 @@ namespace
|
||||||
, peer_connection& c
|
, peer_connection& c
|
||||||
, std::vector<peer_connection*> ignore = std::vector<peer_connection*>())
|
, std::vector<peer_connection*> ignore = std::vector<peer_connection*>())
|
||||||
{
|
{
|
||||||
// this will make the number of requests linearly dependent
|
int num_requests = c.desired_queue_size()
|
||||||
// on the rate in which we download from the peer.
|
- (int)c.download_queue().size()
|
||||||
// we want the queue to represent:
|
|
||||||
// TODO: make this constant user-settable
|
|
||||||
const int queue_time = 3; // seconds
|
|
||||||
// (if the latency is more than this, the download will stall)
|
|
||||||
// so, the queue size is 5 * down_rate / 16 kiB (16 kB is the size of each request)
|
|
||||||
// the minimum request size is 2 and the maximum is 48
|
|
||||||
// the block size doesn't have to be 16. So we first query the torrent for it
|
|
||||||
const int block_size = t.block_size();
|
|
||||||
assert(block_size > 0);
|
|
||||||
|
|
||||||
int desired_queue_size = static_cast<int>(queue_time
|
|
||||||
* c.statistics().download_rate() / block_size);
|
|
||||||
if (desired_queue_size > max_request_queue) desired_queue_size = max_request_queue;
|
|
||||||
if (desired_queue_size < min_request_queue) desired_queue_size = min_request_queue;
|
|
||||||
|
|
||||||
assert(desired_queue_size >= min_request_queue);
|
|
||||||
|
|
||||||
int num_requests = desired_queue_size - (int)c.download_queue().size()
|
|
||||||
- (int)c.request_queue().size();
|
- (int)c.request_queue().size();
|
||||||
|
|
||||||
// if our request queue is already full, we
|
// if our request queue is already full, we
|
||||||
|
@ -117,7 +100,9 @@ namespace
|
||||||
// the number of blocks we want, but it will try to make the picked
|
// the number of blocks we want, but it will try to make the picked
|
||||||
// blocks be from whole pieces, possibly by returning more blocks
|
// blocks be from whole pieces, possibly by returning more blocks
|
||||||
// than we requested.
|
// than we requested.
|
||||||
assert(c.remote() == c.get_socket()->sender());
|
#ifndef NDEBUG
|
||||||
|
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||||
|
#endif
|
||||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||||
, num_requests, prefer_whole_pieces, c.remote());
|
, num_requests, prefer_whole_pieces, c.remote());
|
||||||
|
|
||||||
|
@ -141,7 +126,7 @@ namespace
|
||||||
// ok, we found a piece that's not being downloaded
|
// ok, we found a piece that's not being downloaded
|
||||||
// by somebody else. request it from this peer
|
// by somebody else. request it from this peer
|
||||||
// and return
|
// and return
|
||||||
c.send_request(*i);
|
c.add_request(*i);
|
||||||
num_requests--;
|
num_requests--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +202,8 @@ namespace
|
||||||
|
|
||||||
assert(common_block != peer->download_queue().rend());
|
assert(common_block != peer->download_queue().rend());
|
||||||
piece_block block = *common_block;
|
piece_block block = *common_block;
|
||||||
peer->send_cancel(block);
|
peer->cancel_request(block);
|
||||||
c.send_request(block);
|
c.add_request(block);
|
||||||
|
|
||||||
// the one we interrupted may need to request a new piece
|
// the one we interrupted may need to request a new piece
|
||||||
// make sure it doesn't take over a block from the peer
|
// make sure it doesn't take over a block from the peer
|
||||||
|
@ -308,14 +293,14 @@ namespace
|
||||||
|
|
||||||
struct match_peer_ip
|
struct match_peer_ip
|
||||||
{
|
{
|
||||||
match_peer_ip(const address& id)
|
match_peer_ip(const tcp::endpoint& ip)
|
||||||
: m_id(id)
|
: m_ip(ip)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator()(const policy::peer& p) const
|
bool operator()(const policy::peer& p) const
|
||||||
{ return p.id.ip() == m_id.ip(); }
|
{ return p.ip.address() == m_ip.address(); }
|
||||||
|
|
||||||
address m_id;
|
tcp::endpoint m_ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct match_peer_connection
|
struct match_peer_connection
|
||||||
|
@ -837,10 +822,18 @@ namespace libtorrent
|
||||||
, m_peers.end()
|
, m_peers.end()
|
||||||
, match_peer_connection(c));
|
, match_peer_connection(c));
|
||||||
|
|
||||||
assert(i != m_peers.end());
|
if (i == m_peers.end())
|
||||||
|
{
|
||||||
|
// this is probably a http seed
|
||||||
|
if (web_peer_connection const* p = dynamic_cast<web_peer_connection const*>(&c))
|
||||||
|
{
|
||||||
|
m_torrent->remove_url_seed(p->url());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
i->type = peer::not_connectable;
|
i->type = peer::not_connectable;
|
||||||
i->id.port = address::any_port;
|
i->ip.port(0);
|
||||||
i->banned = true;
|
i->banned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,7 +843,7 @@ namespace libtorrent
|
||||||
/*
|
/*
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// avoid the invariant check to fail
|
// avoid the invariant check to fail
|
||||||
peer p(address("0.0.0.0", 0), peer::not_connectable);
|
peer p(tcp::endpoint("0.0.0.0", 0), peer::not_connectable);
|
||||||
p.connection = &c;
|
p.connection = &c;
|
||||||
m_peers.push_back(p);
|
m_peers.push_back(p);
|
||||||
#endif
|
#endif
|
||||||
|
@ -868,15 +861,17 @@ namespace libtorrent
|
||||||
|
|
||||||
// TODO: only allow _one_ connection to use this
|
// TODO: only allow _one_ connection to use this
|
||||||
// override at a time
|
// override at a time
|
||||||
assert(c.remote() == c.get_socket()->sender());
|
#ifndef NDEBUG
|
||||||
|
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||||
|
#endif
|
||||||
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
|
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
|
||||||
&& c.remote().ip() != m_torrent->current_tracker().ip())
|
&& c.remote().address() != m_torrent->current_tracker().address())
|
||||||
{
|
{
|
||||||
throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
|
throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (c.remote().ip() == m_torrent->current_tracker().ip())
|
if (c.remote().address() == m_torrent->current_tracker().address())
|
||||||
{
|
{
|
||||||
m_torrent->debug_log("overriding connection limit for tracker NAT-check");
|
m_torrent->debug_log("overriding connection limit for tracker NAT-check");
|
||||||
}
|
}
|
||||||
|
@ -894,8 +889,9 @@ namespace libtorrent
|
||||||
|
|
||||||
// we don't have ny info about this peer.
|
// we don't have ny info about this peer.
|
||||||
// add a new entry
|
// add a new entry
|
||||||
|
#ifndef NDEBUG
|
||||||
assert(c.remote() == c.get_socket()->sender());
|
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||||
|
#endif
|
||||||
peer p(c.remote(), peer::not_connectable);
|
peer p(c.remote(), peer::not_connectable);
|
||||||
m_peers.push_back(p);
|
m_peers.push_back(p);
|
||||||
i = m_peers.end()-1;
|
i = m_peers.end()-1;
|
||||||
|
@ -905,7 +901,7 @@ namespace libtorrent
|
||||||
if (i->connection != 0)
|
if (i->connection != 0)
|
||||||
throw protocol_error("duplicate connection, closing");
|
throw protocol_error("duplicate connection, closing");
|
||||||
if (i->banned)
|
if (i->banned)
|
||||||
throw protocol_error("ip address banned, closing");
|
throw protocol_error("ip tcp::endpoint banned, closing");
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(i->connection == 0);
|
assert(i->connection == 0);
|
||||||
|
@ -918,12 +914,12 @@ namespace libtorrent
|
||||||
m_last_optimistic_disconnect = second_clock::universal_time();
|
m_last_optimistic_disconnect = second_clock::universal_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
void policy::peer_from_tracker(const address& remote, const peer_id& id)
|
void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
// just ignore the obviously invalid entries from the tracker
|
// just ignore the obviously invalid entries from the tracker
|
||||||
if(remote.ip() == 0 || remote.port == 0)
|
if(remote.address().to_ulong() == 0 || remote.port() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -956,7 +952,7 @@ namespace libtorrent
|
||||||
// in case we got the ip from a remote connection, port is
|
// in case we got the ip from a remote connection, port is
|
||||||
// not known, so save it. Client may also have changed port
|
// not known, so save it. Client may also have changed port
|
||||||
// for some reason.
|
// for some reason.
|
||||||
i->id = remote;
|
i->ip = remote;
|
||||||
|
|
||||||
if (i->connection)
|
if (i->connection)
|
||||||
{
|
{
|
||||||
|
@ -965,11 +961,11 @@ namespace libtorrent
|
||||||
// it again.
|
// it again.
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
m_torrent->debug_log("already connected to peer: " + remote.as_string() + ":"
|
m_torrent->debug_log("already connected to peer: " + remote.address().to_string() + ":"
|
||||||
+ boost::lexical_cast<std::string>(remote.port));
|
+ boost::lexical_cast<std::string>(remote.port()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(i->connection->associated_torrent() == m_torrent);
|
assert(i->connection->associated_torrent().lock().get() == m_torrent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -990,20 +986,12 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch(network_error& e)
|
catch(std::exception& e)
|
||||||
{
|
{
|
||||||
if (m_torrent->alerts().should_post(alert::debug))
|
if (m_torrent->alerts().should_post(alert::debug))
|
||||||
{
|
{
|
||||||
m_torrent->alerts().post_alert(
|
m_torrent->alerts().post_alert(
|
||||||
peer_error_alert(remote, id, e.what()));
|
peer_error_alert(remote, pid, e.what()));
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(protocol_error& e)
|
|
||||||
{
|
|
||||||
if (m_torrent->alerts().should_post(alert::debug))
|
|
||||||
{
|
|
||||||
m_torrent->alerts().post_alert(
|
|
||||||
peer_error_alert(remote, id, e.what()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1174,7 +1162,7 @@ namespace libtorrent
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assert(!p->connection);
|
assert(!p->connection);
|
||||||
p->connection = &m_torrent->connect_to_peer(p->id);
|
p->connection = &m_torrent->connect_to_peer(p->ip);
|
||||||
assert(p->connection);
|
assert(p->connection);
|
||||||
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
|
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
|
||||||
p->prev_amount_download = 0;
|
p->prev_amount_download = 0;
|
||||||
|
@ -1184,14 +1172,8 @@ namespace libtorrent
|
||||||
second_clock::universal_time();
|
second_clock::universal_time();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (network_error& e)
|
catch (std::exception& e)
|
||||||
{
|
{}
|
||||||
// TODO: This path needs testing!
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
|
||||||
std::string msg = e.what();
|
|
||||||
(*p->connection->m_logger) << "*** CONNECTION FAILED '" << msg << "'\n";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,11 +1191,11 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is called whenever a peer connection is closed
|
// this is called whenever a peer connection is closed
|
||||||
void policy::connection_closed(const peer_connection& c)
|
void policy::connection_closed(const peer_connection& c) try
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
assert(c.is_disconnecting());
|
// assert(c.is_disconnecting());
|
||||||
bool unchoked = false;
|
bool unchoked = false;
|
||||||
|
|
||||||
std::vector<peer>::iterator i = std::find_if(
|
std::vector<peer>::iterator i = std::find_if(
|
||||||
|
@ -1234,7 +1216,7 @@ namespace libtorrent
|
||||||
if (c.failed())
|
if (c.failed())
|
||||||
{
|
{
|
||||||
i->type = peer::not_connectable;
|
i->type = peer::not_connectable;
|
||||||
i->id.port = address::any_port;
|
i->ip.port(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the share ratio is 0 (infinite), the
|
// if the share ratio is 0 (infinite), the
|
||||||
|
@ -1242,7 +1224,7 @@ namespace libtorrent
|
||||||
// because it isn't necessary.
|
// because it isn't necessary.
|
||||||
if (m_torrent->ratio() != 0.f)
|
if (m_torrent->ratio() != 0.f)
|
||||||
{
|
{
|
||||||
assert(i->connection->associated_torrent() == m_torrent);
|
assert(i->connection->associated_torrent().lock().get() == m_torrent);
|
||||||
assert(i->connection->share_diff() < std::numeric_limits<size_type>::max());
|
assert(i->connection->share_diff() < std::numeric_limits<size_type>::max());
|
||||||
m_available_free_upload += i->connection->share_diff();
|
m_available_free_upload += i->connection->share_diff();
|
||||||
}
|
}
|
||||||
|
@ -1260,6 +1242,13 @@ namespace libtorrent
|
||||||
else unchoke_one_peer();
|
else unchoke_one_peer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::string err = e.what();
|
||||||
|
#endif
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void policy::peer_is_interesting(peer_connection& c)
|
void policy::peer_is_interesting(peer_connection& c)
|
||||||
{
|
{
|
||||||
|
@ -1274,7 +1263,9 @@ namespace libtorrent
|
||||||
bool policy::has_connection(const peer_connection* c)
|
bool policy::has_connection(const peer_connection* c)
|
||||||
{
|
{
|
||||||
assert(c);
|
assert(c);
|
||||||
assert(c->remote() == c->get_socket()->sender());
|
#ifndef NDEBUG
|
||||||
|
assert(c->remote() == c->get_socket()->remote_endpoint());
|
||||||
|
#endif
|
||||||
return std::find_if(
|
return std::find_if(
|
||||||
m_peers.begin()
|
m_peers.begin()
|
||||||
, m_peers.end()
|
, m_peers.end()
|
||||||
|
@ -1309,6 +1300,9 @@ namespace libtorrent
|
||||||
i != m_torrent->end(); ++i)
|
i != m_torrent->end(); ++i)
|
||||||
{
|
{
|
||||||
if (i->second->is_disconnecting()) continue;
|
if (i->second->is_disconnecting()) continue;
|
||||||
|
// ignore web_peer_connections since they are not managed
|
||||||
|
// by the policy class
|
||||||
|
if (dynamic_cast<web_peer_connection*>(i->second)) continue;
|
||||||
++num_torrent_peers;
|
++num_torrent_peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1332,8 +1326,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
policy::peer::peer(const address& pid, peer::connection_type t)
|
policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t)
|
||||||
: id(pid)
|
: ip(ip_)
|
||||||
, type(t)
|
, type(t)
|
||||||
, last_optimistically_unchoked(
|
, last_optimistically_unchoked(
|
||||||
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||||
|
|
1077
src/session.cpp
1077
src/session.cpp
File diff suppressed because it is too large
Load Diff
12
src/stat.cpp
12
src/stat.cpp
|
@ -47,7 +47,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
void libtorrent::stat::second_tick()
|
void libtorrent::stat::second_tick(float tick_interval)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -59,10 +59,12 @@ void libtorrent::stat::second_tick()
|
||||||
m_upload_payload_rate_history[i + 1] = m_upload_payload_rate_history[i];
|
m_upload_payload_rate_history[i + 1] = m_upload_payload_rate_history[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_download_rate_history[0] = m_downloaded_payload + m_downloaded_protocol;
|
m_download_rate_history[0] = (m_downloaded_payload + m_downloaded_protocol)
|
||||||
m_upload_rate_history[0] = m_uploaded_payload + m_uploaded_protocol;
|
/ tick_interval;
|
||||||
m_download_payload_rate_history[0] = m_downloaded_payload;
|
m_upload_rate_history[0] = (m_uploaded_payload + m_uploaded_protocol)
|
||||||
m_upload_payload_rate_history[0] = m_uploaded_payload;
|
/ tick_interval;
|
||||||
|
m_download_payload_rate_history[0] = m_downloaded_payload / tick_interval;
|
||||||
|
m_upload_payload_rate_history[0] = m_uploaded_payload / tick_interval;
|
||||||
|
|
||||||
m_downloaded_payload = 0;
|
m_downloaded_payload = 0;
|
||||||
m_uploaded_payload = 0;
|
m_uploaded_payload = 0;
|
||||||
|
|
135
src/storage.cpp
135
src/storage.cpp
|
@ -232,9 +232,9 @@ namespace
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
struct file_entry
|
struct lru_file_entry
|
||||||
{
|
{
|
||||||
file_entry(boost::shared_ptr<file> const& f)
|
lru_file_entry(boost::shared_ptr<file> const& f)
|
||||||
: file_ptr(f)
|
: file_ptr(f)
|
||||||
, last_use(pt::second_clock::universal_time()) {}
|
, last_use(pt::second_clock::universal_time()) {}
|
||||||
mutable boost::shared_ptr<file> file_ptr;
|
mutable boost::shared_ptr<file> file_ptr;
|
||||||
|
@ -257,7 +257,7 @@ namespace
|
||||||
path_view::iterator i = pt.find(p);
|
path_view::iterator i = pt.find(p);
|
||||||
if (i != pt.end())
|
if (i != pt.end())
|
||||||
{
|
{
|
||||||
file_entry e = *i;
|
lru_file_entry e = *i;
|
||||||
e.last_use = pt::second_clock::universal_time();
|
e.last_use = pt::second_clock::universal_time();
|
||||||
|
|
||||||
// if you hit this assert, you probably have more than one
|
// if you hit this assert, you probably have more than one
|
||||||
|
@ -294,7 +294,7 @@ namespace
|
||||||
*/ assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
|
*/ assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use));
|
||||||
lt.erase(i);
|
lt.erase(i);
|
||||||
}
|
}
|
||||||
file_entry e(boost::shared_ptr<file>(new file(p, m)));
|
lru_file_entry e(boost::shared_ptr<file>(new file(p, m)));
|
||||||
e.mode = m;
|
e.mode = m;
|
||||||
e.key = st;
|
e.key = st;
|
||||||
e.file_path = p;
|
e.file_path = p;
|
||||||
|
@ -334,13 +334,13 @@ namespace
|
||||||
int m_size;
|
int m_size;
|
||||||
|
|
||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
file_entry, indexed_by<
|
lru_file_entry, indexed_by<
|
||||||
ordered_unique<member<file_entry, path
|
ordered_unique<member<lru_file_entry, path
|
||||||
, &file_entry::file_path> >
|
, &lru_file_entry::file_path> >
|
||||||
, ordered_non_unique<member<file_entry, pt::ptime
|
, ordered_non_unique<member<lru_file_entry, pt::ptime
|
||||||
, &file_entry::last_use> >
|
, &lru_file_entry::last_use> >
|
||||||
, ordered_non_unique<member<file_entry, void*
|
, ordered_non_unique<member<lru_file_entry, void*
|
||||||
, &file_entry::key> >
|
, &lru_file_entry::key> >
|
||||||
>
|
>
|
||||||
> file_set;
|
> file_set;
|
||||||
|
|
||||||
|
@ -620,6 +620,12 @@ namespace libtorrent
|
||||||
|
|
||||||
slot_lock lock(*m_pimpl, slot);
|
slot_lock lock(*m_pimpl, slot);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::vector<file_slice> slices
|
||||||
|
= m_pimpl->info.map_block(slot, offset, size);
|
||||||
|
assert(!slices.empty());
|
||||||
|
#endif
|
||||||
|
|
||||||
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
||||||
|
|
||||||
// find the file iterator and file offset
|
// find the file iterator and file offset
|
||||||
|
@ -642,8 +648,10 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(file_offset < file_iter->size);
|
assert(file_offset < file_iter->size);
|
||||||
|
|
||||||
in->seek(file_offset);
|
assert(slices[0].offset == file_offset);
|
||||||
if (in->tell() != file_offset)
|
|
||||||
|
size_type new_pos = in->seek(file_offset);
|
||||||
|
if (new_pos != file_offset)
|
||||||
{
|
{
|
||||||
// the file was not big enough
|
// the file was not big enough
|
||||||
throw file_error("slot has no storage");
|
throw file_error("slot has no storage");
|
||||||
|
@ -665,12 +673,24 @@ namespace libtorrent
|
||||||
size_type result = left_to_read;
|
size_type result = left_to_read;
|
||||||
int buf_pos = 0;
|
int buf_pos = 0;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int counter = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
while (left_to_read > 0)
|
while (left_to_read > 0)
|
||||||
{
|
{
|
||||||
int read_bytes = left_to_read;
|
int read_bytes = left_to_read;
|
||||||
if (file_offset + read_bytes > file_iter->size)
|
if (file_offset + read_bytes > file_iter->size)
|
||||||
read_bytes = static_cast<int>(file_iter->size - file_offset);
|
read_bytes = static_cast<int>(file_iter->size - file_offset);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(int(slices.size()) > counter);
|
||||||
|
size_type slice_size = slices[counter].size;
|
||||||
|
assert(slice_size == read_bytes);
|
||||||
|
assert(m_pimpl->info.file_at(slices[counter].file_index).path
|
||||||
|
== file_iter->path);
|
||||||
|
#endif
|
||||||
|
|
||||||
size_type actual_read = in->read(buf + buf_pos, read_bytes);
|
size_type actual_read = in->read(buf + buf_pos, read_bytes);
|
||||||
|
|
||||||
if (read_bytes != actual_read)
|
if (read_bytes != actual_read)
|
||||||
|
@ -687,6 +707,9 @@ namespace libtorrent
|
||||||
if (left_to_read > 0)
|
if (left_to_read > 0)
|
||||||
{
|
{
|
||||||
++file_iter;
|
++file_iter;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
++counter;
|
||||||
|
#endif
|
||||||
path path = m_pimpl->save_path / file_iter->path;
|
path path = m_pimpl->save_path / file_iter->path;
|
||||||
|
|
||||||
file_offset = 0;
|
file_offset = 0;
|
||||||
|
@ -714,6 +737,12 @@ namespace libtorrent
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
|
|
||||||
slot_lock lock(*m_pimpl, slot);
|
slot_lock lock(*m_pimpl, slot);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::vector<file_slice> slices
|
||||||
|
= m_pimpl->info.map_block(slot, offset, size);
|
||||||
|
assert(!slices.empty());
|
||||||
|
#endif
|
||||||
|
|
||||||
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
size_type start = slot * (size_type)m_pimpl->info.piece_length() + offset;
|
||||||
|
|
||||||
|
@ -737,9 +766,9 @@ namespace libtorrent
|
||||||
, p, file::out | file::in);
|
, p, file::out | file::in);
|
||||||
|
|
||||||
assert(file_offset < file_iter->size);
|
assert(file_offset < file_iter->size);
|
||||||
|
assert(slices[0].offset == file_offset);
|
||||||
|
|
||||||
out->seek(file_offset);
|
size_type pos = out->seek(file_offset);
|
||||||
size_type pos = out->tell();
|
|
||||||
|
|
||||||
if (pos != file_offset)
|
if (pos != file_offset)
|
||||||
{
|
{
|
||||||
|
@ -757,7 +786,9 @@ namespace libtorrent
|
||||||
assert(left_to_write >= 0);
|
assert(left_to_write >= 0);
|
||||||
|
|
||||||
int buf_pos = 0;
|
int buf_pos = 0;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int counter = 0;
|
||||||
|
#endif
|
||||||
while (left_to_write > 0)
|
while (left_to_write > 0)
|
||||||
{
|
{
|
||||||
int write_bytes = left_to_write;
|
int write_bytes = left_to_write;
|
||||||
|
@ -767,6 +798,11 @@ namespace libtorrent
|
||||||
write_bytes = static_cast<int>(file_iter->size - file_offset);
|
write_bytes = static_cast<int>(file_iter->size - file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(int(slices.size()) > counter);
|
||||||
|
assert(slices[counter].size == write_bytes);
|
||||||
|
assert(m_pimpl->info.file_at(slices[counter].file_index).path
|
||||||
|
== file_iter->path);
|
||||||
|
|
||||||
assert(buf_pos >= 0);
|
assert(buf_pos >= 0);
|
||||||
assert(write_bytes >= 0);
|
assert(write_bytes >= 0);
|
||||||
size_type written = out->write(buf + buf_pos, write_bytes);
|
size_type written = out->write(buf + buf_pos, write_bytes);
|
||||||
|
@ -786,6 +822,9 @@ namespace libtorrent
|
||||||
|
|
||||||
if (left_to_write > 0)
|
if (left_to_write > 0)
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
++counter;
|
||||||
|
#endif
|
||||||
++file_iter;
|
++file_iter;
|
||||||
|
|
||||||
assert(file_iter != m_pimpl->info.end_files());
|
assert(file_iter != m_pimpl->info.end_files());
|
||||||
|
@ -818,10 +857,12 @@ namespace libtorrent
|
||||||
bool check_fastresume(
|
bool check_fastresume(
|
||||||
detail::piece_checker_data& d
|
detail::piece_checker_data& d
|
||||||
, std::vector<bool>& pieces
|
, std::vector<bool>& pieces
|
||||||
|
, int& num_pieces
|
||||||
, bool compact_mode);
|
, bool compact_mode);
|
||||||
|
|
||||||
std::pair<bool, float> check_files(
|
std::pair<bool, float> check_files(
|
||||||
std::vector<bool>& pieces);
|
std::vector<bool>& pieces
|
||||||
|
, int& num_pieces);
|
||||||
|
|
||||||
void release_files();
|
void release_files();
|
||||||
|
|
||||||
|
@ -868,6 +909,7 @@ namespace libtorrent
|
||||||
const std::vector<char>& piece_data
|
const std::vector<char>& piece_data
|
||||||
, int current_slot
|
, int current_slot
|
||||||
, std::vector<bool>& have_pieces
|
, std::vector<bool>& have_pieces
|
||||||
|
, int& num_pieces
|
||||||
, const std::multimap<sha1_hash, int>& hash_to_piece);
|
, const std::multimap<sha1_hash, int>& hash_to_piece);
|
||||||
|
|
||||||
int allocate_slot_for_piece(int piece_index);
|
int allocate_slot_for_piece(int piece_index);
|
||||||
|
@ -949,6 +991,12 @@ namespace libtorrent
|
||||||
// build the first time it is used (to save time if it
|
// build the first time it is used (to save time if it
|
||||||
// isn't needed)
|
// isn't needed)
|
||||||
std::multimap<sha1_hash, int> m_hash_to_piece;
|
std::multimap<sha1_hash, int> m_hash_to_piece;
|
||||||
|
|
||||||
|
// used as temporary piece data storage in allocate_slots
|
||||||
|
// it is a member in order to avoid allocating it on
|
||||||
|
// the heap every time a new slot is allocated. (This is quite
|
||||||
|
// frequent with high download speeds)
|
||||||
|
std::vector<char> m_scratch_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
piece_manager::impl::impl(
|
piece_manager::impl::impl(
|
||||||
|
@ -1156,6 +1204,7 @@ namespace libtorrent
|
||||||
const std::vector<char>& piece_data
|
const std::vector<char>& piece_data
|
||||||
, int current_slot
|
, int current_slot
|
||||||
, std::vector<bool>& have_pieces
|
, std::vector<bool>& have_pieces
|
||||||
|
, int& num_pieces
|
||||||
, const std::multimap<sha1_hash, int>& hash_to_piece)
|
, const std::multimap<sha1_hash, int>& hash_to_piece)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -1245,7 +1294,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
// this index is the only piece with this
|
// this index is the only piece with this
|
||||||
// hash. The previous slot we found with
|
// hash. The previous slot we found with
|
||||||
// this hash must be tha same piece. Mark
|
// this hash must be the same piece. Mark
|
||||||
// that piece as unassigned, since this slot
|
// that piece as unassigned, since this slot
|
||||||
// is the correct place for the piece.
|
// is the correct place for the piece.
|
||||||
m_slot_to_piece[other_slot] = unassigned;
|
m_slot_to_piece[other_slot] = unassigned;
|
||||||
|
@ -1254,12 +1303,19 @@ namespace libtorrent
|
||||||
assert(m_piece_to_slot[piece_index] != current_slot);
|
assert(m_piece_to_slot[piece_index] != current_slot);
|
||||||
assert(m_piece_to_slot[piece_index] >= 0);
|
assert(m_piece_to_slot[piece_index] >= 0);
|
||||||
m_piece_to_slot[piece_index] = has_no_slot;
|
m_piece_to_slot[piece_index] = has_no_slot;
|
||||||
|
#ifndef NDEBUG
|
||||||
have_pieces[piece_index] = false;
|
have_pieces[piece_index] = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(have_pieces[piece_index] == false);
|
assert(have_pieces[piece_index] == false);
|
||||||
assert(m_piece_to_slot[piece_index] == has_no_slot);
|
assert(m_piece_to_slot[piece_index] == has_no_slot);
|
||||||
have_pieces[piece_index] = true;
|
have_pieces[piece_index] = true;
|
||||||
|
|
||||||
return piece_index;
|
return piece_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,6 +1335,7 @@ namespace libtorrent
|
||||||
assert(have_pieces[free_piece] == false);
|
assert(have_pieces[free_piece] == false);
|
||||||
assert(m_piece_to_slot[free_piece] == has_no_slot);
|
assert(m_piece_to_slot[free_piece] == has_no_slot);
|
||||||
have_pieces[free_piece] = true;
|
have_pieces[free_piece] = true;
|
||||||
|
++num_pieces;
|
||||||
|
|
||||||
return free_piece;
|
return free_piece;
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1353,7 @@ namespace libtorrent
|
||||||
bool piece_manager::impl::check_fastresume(
|
bool piece_manager::impl::check_fastresume(
|
||||||
detail::piece_checker_data& data
|
detail::piece_checker_data& data
|
||||||
, std::vector<bool>& pieces
|
, std::vector<bool>& pieces
|
||||||
, bool compact_mode)
|
, int& num_pieces, bool compact_mode)
|
||||||
{
|
{
|
||||||
assert(m_info.piece_length() > 0);
|
assert(m_info.piece_length() > 0);
|
||||||
// synchronization ------------------------------------------------------
|
// synchronization ------------------------------------------------------
|
||||||
|
@ -1320,6 +1377,7 @@ namespace libtorrent
|
||||||
|
|
||||||
pieces.clear();
|
pieces.clear();
|
||||||
pieces.resize(m_info.num_pieces(), false);
|
pieces.resize(m_info.num_pieces(), false);
|
||||||
|
num_pieces = 0;
|
||||||
|
|
||||||
// if we have fast-resume info
|
// if we have fast-resume info
|
||||||
// use it instead of doing the actual checking
|
// use it instead of doing the actual checking
|
||||||
|
@ -1342,6 +1400,7 @@ namespace libtorrent
|
||||||
, piece_picker::has_index(found_piece))
|
, piece_picker::has_index(found_piece))
|
||||||
== data.unfinished_pieces.end())
|
== data.unfinished_pieces.end())
|
||||||
{
|
{
|
||||||
|
++num_pieces;
|
||||||
pieces[found_piece] = true;
|
pieces[found_piece] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1385,8 +1444,10 @@ namespace libtorrent
|
||||||
// file check is at. 0 is nothing done, and 1
|
// file check is at. 0 is nothing done, and 1
|
||||||
// is finished
|
// is finished
|
||||||
std::pair<bool, float> piece_manager::impl::check_files(
|
std::pair<bool, float> piece_manager::impl::check_files(
|
||||||
std::vector<bool>& pieces)
|
std::vector<bool>& pieces, int& num_pieces)
|
||||||
{
|
{
|
||||||
|
assert(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
|
|
||||||
if (m_state == state_allocating)
|
if (m_state == state_allocating)
|
||||||
{
|
{
|
||||||
if (m_compact_mode)
|
if (m_compact_mode)
|
||||||
|
@ -1395,17 +1456,18 @@ namespace libtorrent
|
||||||
return std::make_pair(true, 1.f);
|
return std::make_pair(true, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're not in compact mode, make sure the
|
|
||||||
// pieces are spread out and placed at their
|
|
||||||
// final position.
|
|
||||||
assert(!m_unallocated_slots.empty());
|
|
||||||
allocate_slots(1);
|
|
||||||
if (m_unallocated_slots.empty())
|
if (m_unallocated_slots.empty())
|
||||||
{
|
{
|
||||||
m_state = state_finished;
|
m_state = state_finished;
|
||||||
return std::make_pair(true, 1.f);
|
return std::make_pair(true, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're not in compact mode, make sure the
|
||||||
|
// pieces are spread out and placed at their
|
||||||
|
// final position.
|
||||||
|
assert(!m_unallocated_slots.empty());
|
||||||
|
allocate_slots(1);
|
||||||
|
|
||||||
return std::make_pair(false, 1.f - (float)m_unallocated_slots.size()
|
return std::make_pair(false, 1.f - (float)m_unallocated_slots.size()
|
||||||
/ (float)m_slot_to_piece.size());
|
/ (float)m_slot_to_piece.size());
|
||||||
}
|
}
|
||||||
|
@ -1462,8 +1524,10 @@ namespace libtorrent
|
||||||
m_piece_data
|
m_piece_data
|
||||||
, m_current_slot
|
, m_current_slot
|
||||||
, pieces
|
, pieces
|
||||||
|
, num_pieces
|
||||||
, m_hash_to_piece);
|
, m_hash_to_piece);
|
||||||
|
|
||||||
|
assert(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
assert(piece_index == unassigned || piece_index >= 0);
|
assert(piece_index == unassigned || piece_index >= 0);
|
||||||
|
|
||||||
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
|
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
|
||||||
|
@ -1712,23 +1776,27 @@ namespace libtorrent
|
||||||
std::vector<char>().swap(m_piece_data);
|
std::vector<char>().swap(m_piece_data);
|
||||||
std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
|
std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
|
||||||
m_state = state_allocating;
|
m_state = state_allocating;
|
||||||
|
assert(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
return std::make_pair(false, 1.f);
|
return std::make_pair(false, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
||||||
|
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info.num_pieces());
|
return std::make_pair(false, (float)m_current_slot / m_info.num_pieces());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool piece_manager::check_fastresume(
|
bool piece_manager::check_fastresume(
|
||||||
detail::piece_checker_data& d, std::vector<bool>& pieces
|
detail::piece_checker_data& d, std::vector<bool>& pieces
|
||||||
, bool compact_mode)
|
, int& num_pieces, bool compact_mode)
|
||||||
{
|
{
|
||||||
return m_pimpl->check_fastresume(d, pieces, compact_mode);
|
return m_pimpl->check_fastresume(d, pieces, num_pieces, compact_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, float> piece_manager::check_files(
|
std::pair<bool, float> piece_manager::check_files(
|
||||||
std::vector<bool>& pieces)
|
std::vector<bool>& pieces
|
||||||
|
, int& num_pieces)
|
||||||
{
|
{
|
||||||
return m_pimpl->check_files(pieces);
|
return m_pimpl->check_files(pieces, num_pieces);
|
||||||
}
|
}
|
||||||
|
|
||||||
int piece_manager::impl::allocate_slot_for_piece(int piece_index)
|
int piece_manager::impl::allocate_slot_for_piece(int piece_index)
|
||||||
|
@ -1888,9 +1956,9 @@ namespace libtorrent
|
||||||
// this object will syncronize the allocation with
|
// this object will syncronize the allocation with
|
||||||
// potential other threads
|
// potential other threads
|
||||||
allocation_syncronization sync_obj(
|
allocation_syncronization sync_obj(
|
||||||
m_allocating
|
m_allocating
|
||||||
, m_allocating_condition
|
, m_allocating_condition
|
||||||
, m_allocating_monitor);
|
, m_allocating_monitor);
|
||||||
|
|
||||||
// synchronization ------------------------------------------------------
|
// synchronization ------------------------------------------------------
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
@ -1902,7 +1970,8 @@ namespace libtorrent
|
||||||
|
|
||||||
const int piece_size = static_cast<int>(m_info.piece_length());
|
const int piece_size = static_cast<int>(m_info.piece_length());
|
||||||
|
|
||||||
std::vector<char> buffer(piece_size, 0);
|
std::vector<char>& buffer = m_scratch_buffer;
|
||||||
|
buffer.resize(piece_size);
|
||||||
|
|
||||||
for (int i = 0; i < num_slots && !m_unallocated_slots.empty(); ++i)
|
for (int i = 0; i < num_slots && !m_unallocated_slots.empty(); ++i)
|
||||||
{
|
{
|
||||||
|
|
576
src/torrent.cpp
576
src/torrent.cpp
File diff suppressed because it is too large
Load Diff
|
@ -54,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
|
#include "libtorrent/bt_peer_connection.hpp"
|
||||||
#include "libtorrent/torrent_info.hpp"
|
#include "libtorrent/torrent_info.hpp"
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
|
@ -71,6 +72,8 @@ namespace std
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using boost::bind;
|
using boost::bind;
|
||||||
|
using boost::mutex;
|
||||||
|
using libtorrent::detail::session_impl;
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -92,15 +95,15 @@ namespace libtorrent
|
||||||
|
|
||||||
if (chk)
|
if (chk)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(chk->m_mutex);
|
mutex::scoped_lock l(chk->m_mutex);
|
||||||
detail::piece_checker_data* d = chk->find_torrent(hash);
|
detail::piece_checker_data* d = chk->find_torrent(hash);
|
||||||
if (d != 0) return f(*d->torrent_ptr);
|
if (d != 0) return f(*d->torrent_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(ses->m_mutex);
|
||||||
torrent* t = ses->find_torrent(hash);
|
boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
|
||||||
if (t != 0) return f(*t);
|
if (t) return f(*t);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw invalid_handle();
|
throw invalid_handle();
|
||||||
|
@ -144,6 +147,24 @@ namespace libtorrent
|
||||||
, bind(&torrent::set_max_connections, _1, max_connections));
|
, bind(&torrent::set_max_connections, _1, max_connections));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
assert(limit >= -1);
|
||||||
|
|
||||||
|
call_member<void>(m_ses, m_chk, m_info_hash
|
||||||
|
, bind(&torrent::set_peer_upload_limit, _1, ip, limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
assert(limit >= -1);
|
||||||
|
|
||||||
|
call_member<void>(m_ses, m_chk, m_info_hash
|
||||||
|
, bind(&torrent::set_peer_download_limit, _1, ip, limit));
|
||||||
|
}
|
||||||
|
|
||||||
void torrent_handle::set_upload_limit(int limit) const
|
void torrent_handle::set_upload_limit(int limit) const
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -231,7 +252,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_chk)
|
if (m_chk)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
mutex::scoped_lock l(m_chk->m_mutex);
|
||||||
|
|
||||||
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
||||||
if (d != 0)
|
if (d != 0)
|
||||||
|
@ -254,9 +275,9 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t != 0) return t->status();
|
if (t) return t->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_invalid_handle();
|
throw_invalid_handle();
|
||||||
|
@ -293,13 +314,6 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent_handle::filter_file(int index, bool filter) const
|
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
call_member<void>(m_ses, m_chk, m_info_hash
|
|
||||||
, bind(&torrent::filter_file, _1, index, filter));
|
|
||||||
}
|
|
||||||
|
|
||||||
void torrent_handle::filter_files(std::vector<bool> const& files) const
|
void torrent_handle::filter_files(std::vector<bool> const& files) const
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -315,6 +329,14 @@ namespace libtorrent
|
||||||
, m_chk, m_info_hash, bind(&torrent::trackers, _1));
|
, m_chk, m_info_hash, bind(&torrent::trackers, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_handle::add_url_seed(std::string const& url)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
return call_member<void>(m_ses, m_chk, m_info_hash
|
||||||
|
, bind(&torrent::add_url_seed, _1, url));
|
||||||
|
}
|
||||||
|
|
||||||
void torrent_handle::replace_trackers(
|
void torrent_handle::replace_trackers(
|
||||||
std::vector<announce_entry> const& urls) const
|
std::vector<announce_entry> const& urls) const
|
||||||
{
|
{
|
||||||
|
@ -341,15 +363,15 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_chk)
|
if (m_chk)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
mutex::scoped_lock l(m_chk->m_mutex);
|
||||||
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
||||||
if (d != 0) return true;
|
if (d != 0) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::weak_ptr<torrent> t = m_ses->find_torrent(m_info_hash);
|
||||||
if (t != 0) return true;
|
if (!t.expired()) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -362,9 +384,9 @@ namespace libtorrent
|
||||||
std::vector<int> piece_index;
|
std::vector<int> piece_index;
|
||||||
if (m_ses == 0) return entry();
|
if (m_ses == 0) return entry();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) return entry();
|
if (!t) return entry();
|
||||||
|
|
||||||
if (!t->valid_metadata()) return entry();
|
if (!t->valid_metadata()) return entry();
|
||||||
|
|
||||||
|
@ -398,9 +420,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// info for each unfinished piece
|
// info for each unfinished piece
|
||||||
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
||||||
= q.begin();
|
= q.begin(); i != q.end(); ++i)
|
||||||
i != q.end();
|
|
||||||
++i)
|
|
||||||
{
|
{
|
||||||
if (i->finished_blocks.count() == 0) continue;
|
if (i->finished_blocks.count() == 0) continue;
|
||||||
|
|
||||||
|
@ -450,10 +470,10 @@ namespace libtorrent
|
||||||
// but still connectable
|
// but still connectable
|
||||||
if (!i->second->is_local()) continue;
|
if (!i->second->is_local()) continue;
|
||||||
|
|
||||||
address ip = i->second->remote();
|
tcp::endpoint ip = i->second->remote();
|
||||||
entry peer(entry::dictionary_t);
|
entry peer(entry::dictionary_t);
|
||||||
peer["ip"] = ip.as_string();
|
peer["ip"] = ip.address().to_string();
|
||||||
peer["port"] = ip.port;
|
peer["port"] = ip.port();
|
||||||
peer_list.push_back(peer);
|
peer_list.push_back(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,15 +511,15 @@ namespace libtorrent
|
||||||
, bind(&torrent::metadata, _1));
|
, bind(&torrent::metadata, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent_handle::connect_peer(address const& adr) const
|
void torrent_handle::connect_peer(tcp::endpoint const& adr) const
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) throw_invalid_handle();
|
if (!t) throw_invalid_handle();
|
||||||
|
|
||||||
peer_id id;
|
peer_id id;
|
||||||
std::fill(id.begin(), id.end(), 0);
|
std::fill(id.begin(), id.end(), 0);
|
||||||
|
@ -513,9 +533,9 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) throw_invalid_handle();
|
if (!t) throw_invalid_handle();
|
||||||
|
|
||||||
using boost::posix_time::second_clock;
|
using boost::posix_time::second_clock;
|
||||||
t->force_tracker_request(second_clock::universal_time()
|
t->force_tracker_request(second_clock::universal_time()
|
||||||
|
@ -528,9 +548,9 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) throw_invalid_handle();
|
if (!t) throw_invalid_handle();
|
||||||
|
|
||||||
t->force_tracker_request();
|
t->force_tracker_request();
|
||||||
}
|
}
|
||||||
|
@ -555,10 +575,10 @@ namespace libtorrent
|
||||||
v.clear();
|
v.clear();
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
|
|
||||||
const torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<const torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) return;
|
if (!t) return;
|
||||||
|
|
||||||
for (torrent::const_peer_iterator i = t->begin();
|
for (torrent::const_peer_iterator i = t->begin();
|
||||||
i != t->end(); ++i)
|
i != t->end(); ++i)
|
||||||
|
@ -567,75 +587,22 @@ namespace libtorrent
|
||||||
|
|
||||||
// peers that haven't finished the handshake should
|
// peers that haven't finished the handshake should
|
||||||
// not be included in this list
|
// not be included in this list
|
||||||
if (peer->associated_torrent() == 0) continue;
|
if (peer->associated_torrent().expired()) continue;
|
||||||
|
|
||||||
v.push_back(peer_info());
|
v.push_back(peer_info());
|
||||||
peer_info& p = v.back();
|
peer_info& p = v.back();
|
||||||
|
|
||||||
const stat& statistics = peer->statistics();
|
|
||||||
p.down_speed = statistics.download_rate();
|
|
||||||
p.up_speed = statistics.upload_rate();
|
|
||||||
p.payload_down_speed = statistics.download_payload_rate();
|
|
||||||
p.payload_up_speed = statistics.upload_payload_rate();
|
|
||||||
p.id = peer->get_peer_id();
|
|
||||||
p.ip = peer->remote();
|
|
||||||
|
|
||||||
p.total_download = statistics.total_payload_download();
|
|
||||||
p.total_upload = statistics.total_payload_upload();
|
|
||||||
|
|
||||||
if (peer->m_ul_bandwidth_quota.given == std::numeric_limits<int>::max())
|
|
||||||
p.upload_limit = -1;
|
|
||||||
else
|
|
||||||
p.upload_limit = peer->m_ul_bandwidth_quota.given;
|
|
||||||
|
|
||||||
if (peer->m_ul_bandwidth_quota.max == std::numeric_limits<int>::max())
|
|
||||||
p.upload_ceiling = -1;
|
|
||||||
else
|
|
||||||
p.upload_ceiling = peer->m_ul_bandwidth_quota.given;
|
|
||||||
|
|
||||||
p.load_balancing = peer->total_free_upload();
|
|
||||||
|
|
||||||
p.download_queue_length = (int)peer->download_queue().size();
|
|
||||||
p.upload_queue_length = (int)peer->upload_queue().size();
|
|
||||||
|
|
||||||
boost::optional<piece_block_progress> ret = peer->downloading_piece();
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
p.downloading_piece_index = ret->piece_index;
|
|
||||||
p.downloading_block_index = ret->block_index;
|
|
||||||
p.downloading_progress = ret->bytes_downloaded;
|
|
||||||
p.downloading_total = ret->full_block_bytes;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p.downloading_piece_index = -1;
|
|
||||||
p.downloading_block_index = -1;
|
|
||||||
p.downloading_progress = 0;
|
|
||||||
p.downloading_total = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.flags = 0;
|
|
||||||
if (peer->is_interesting()) p.flags |= peer_info::interesting;
|
|
||||||
if (peer->is_choked()) p.flags |= peer_info::choked;
|
|
||||||
if (peer->is_peer_interested()) p.flags |= peer_info::remote_interested;
|
|
||||||
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;
|
|
||||||
if (peer->support_extensions()) p.flags |= peer_info::supports_extensions;
|
|
||||||
if (peer->is_local()) p.flags |= peer_info::local_connection;
|
|
||||||
if (peer->is_connecting() && !peer->is_queued()) p.flags |= peer_info::connecting;
|
|
||||||
if (peer->is_queued()) p.flags |= peer_info::queued;
|
|
||||||
|
|
||||||
p.pieces = peer->get_bitfield();
|
peer->get_peer_info(p);
|
||||||
p.seed = peer->is_seed();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool torrent_handle::send_chat_message(address ip, std::string message) const
|
bool torrent_handle::send_chat_message(tcp::endpoint ip, std::string message) const
|
||||||
{
|
{
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
const torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t == 0) return false;
|
if (!t) return false;
|
||||||
|
|
||||||
for (torrent::const_peer_iterator i = t->begin();
|
for (torrent::const_peer_iterator i = t->begin();
|
||||||
i != t->end(); ++i)
|
i != t->end(); ++i)
|
||||||
|
@ -644,21 +611,23 @@ namespace libtorrent
|
||||||
|
|
||||||
// peers that haven't finished the handshake should
|
// peers that haven't finished the handshake should
|
||||||
// not be included in this list
|
// not be included in this list
|
||||||
if (peer->associated_torrent() == 0) continue;
|
if (peer->associated_torrent().expired()) continue;
|
||||||
|
|
||||||
|
tcp::endpoint sender = peer->get_socket()->remote_endpoint();
|
||||||
|
// loop until we find the required ip tcp::endpoint
|
||||||
|
if (ip != sender) continue;
|
||||||
|
|
||||||
|
bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
|
||||||
|
if (!p) return false;
|
||||||
|
|
||||||
// peers that don's support chat message extension
|
// peers that don's support chat message extension
|
||||||
// should not be included either
|
// should not be included either
|
||||||
if (!peer->supports_extension(
|
if (!p->supports_extension(extended_chat_message))
|
||||||
peer_connection::extended_chat_message))
|
return false;
|
||||||
continue;
|
|
||||||
|
|
||||||
// loop until we find the required ip address
|
// send the message
|
||||||
if (ip == peer->get_socket()->sender())
|
p->write_chat_message(message);
|
||||||
{
|
return true;
|
||||||
// send the message
|
|
||||||
peer->send_chat_message(message);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -669,11 +638,11 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
|
|
||||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
|
|
||||||
queue.clear();
|
queue.clear();
|
||||||
if (t == 0) return;
|
if (!t) return;
|
||||||
if (!t->valid_metadata()) return;
|
if (!t->valid_metadata()) return;
|
||||||
|
|
||||||
const piece_picker& p = t->picker();
|
const piece_picker& p = t->picker();
|
||||||
|
|
|
@ -279,8 +279,7 @@ namespace libtorrent
|
||||||
void torrent_info::read_torrent_info(const entry& torrent_file)
|
void torrent_info::read_torrent_info(const entry& torrent_file)
|
||||||
{
|
{
|
||||||
// extract the url of the tracker
|
// extract the url of the tracker
|
||||||
entry const* i = torrent_file.find_key("announce-list");
|
if (entry const* i = torrent_file.find_key("announce-list"))
|
||||||
if (i)
|
|
||||||
{
|
{
|
||||||
const entry::list_type& l = i->list();
|
const entry::list_type& l = i->list();
|
||||||
for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j)
|
for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j)
|
||||||
|
@ -302,19 +301,19 @@ namespace libtorrent
|
||||||
torrent_file["announce"].string()));
|
torrent_file["announce"].string()));
|
||||||
}
|
}
|
||||||
// shuffle each tier
|
// shuffle each tier
|
||||||
std::vector<announce_entry>::iterator i = m_urls.begin();
|
std::vector<announce_entry>::iterator start = m_urls.begin();
|
||||||
std::vector<announce_entry>::iterator j;
|
std::vector<announce_entry>::iterator stop;
|
||||||
int current_tier = m_urls.front().tier;
|
int current_tier = m_urls.front().tier;
|
||||||
for (j = m_urls.begin(); j != m_urls.end(); ++j)
|
for (stop = m_urls.begin(); stop != m_urls.end(); ++stop)
|
||||||
{
|
{
|
||||||
if (j->tier != current_tier)
|
if (stop->tier != current_tier)
|
||||||
{
|
{
|
||||||
std::random_shuffle(i, j);
|
std::random_shuffle(start, stop);
|
||||||
i = j;
|
start = stop;
|
||||||
current_tier = j->tier;
|
current_tier = stop->tier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::random_shuffle(i, j);
|
std::random_shuffle(start, stop);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -330,6 +329,26 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
catch (type_error) {}
|
catch (type_error) {}
|
||||||
|
|
||||||
|
// if there are any url-seeds, extract them
|
||||||
|
try
|
||||||
|
{
|
||||||
|
entry const& url_seeds = torrent_file["url-list"];
|
||||||
|
if (url_seeds.type() == entry::string_t)
|
||||||
|
{
|
||||||
|
m_url_seeds.push_back(url_seeds.string());
|
||||||
|
}
|
||||||
|
else if (url_seeds.type() == entry::list_t)
|
||||||
|
{
|
||||||
|
entry::list_type const& l = url_seeds.list();
|
||||||
|
for (entry::list_type::const_iterator i = l.begin();
|
||||||
|
i != l.end(); ++i)
|
||||||
|
{
|
||||||
|
m_url_seeds.push_back(i->string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (type_error&) {}
|
||||||
|
|
||||||
// extract comment
|
// extract comment
|
||||||
if (entry const* e = torrent_file.find_key("comment.utf-8"))
|
if (entry const* e = torrent_file.find_key("comment.utf-8"))
|
||||||
{ m_comment = e->string(); }
|
{ m_comment = e->string(); }
|
||||||
|
@ -409,6 +428,11 @@ namespace libtorrent
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_info::add_url_seed(std::string const& url)
|
||||||
|
{
|
||||||
|
m_url_seeds.push_back(url);
|
||||||
|
}
|
||||||
|
|
||||||
void torrent_info::set_comment(char const* str)
|
void torrent_info::set_comment(char const* str)
|
||||||
{
|
{
|
||||||
m_comment = str;
|
m_comment = str;
|
||||||
|
@ -458,7 +482,7 @@ namespace libtorrent
|
||||||
for (fs::path::iterator j = boost::next(file_path.begin());
|
for (fs::path::iterator j = boost::next(file_path.begin());
|
||||||
j != file_path.end(); ++j)
|
j != file_path.end(); ++j)
|
||||||
{
|
{
|
||||||
path_e.list().push_back(*j);
|
path_e.list().push_back(entry(*j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,7 +537,7 @@ namespace libtorrent
|
||||||
trackers.list().push_back(tier);
|
trackers.list().push_back(tier);
|
||||||
tier.list().clear();
|
tier.list().clear();
|
||||||
}
|
}
|
||||||
tier.list().push_back(i->url);
|
tier.list().push_back(entry(i->url));
|
||||||
}
|
}
|
||||||
trackers.list().push_back(tier);
|
trackers.list().push_back(tier);
|
||||||
dict["announce-list"] = trackers;
|
dict["announce-list"] = trackers;
|
||||||
|
@ -527,6 +551,24 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!m_created_by.empty())
|
if (!m_created_by.empty())
|
||||||
dict["created by"] = m_created_by;
|
dict["created by"] = m_created_by;
|
||||||
|
|
||||||
|
if (!m_url_seeds.empty())
|
||||||
|
{
|
||||||
|
if (m_url_seeds.size() == 1)
|
||||||
|
{
|
||||||
|
dict["url-list"] = m_url_seeds.front();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry& list = dict["url-list"];
|
||||||
|
list = entry(entry::list_t);
|
||||||
|
for (std::vector<std::string>::const_iterator i
|
||||||
|
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
|
||||||
|
{
|
||||||
|
list.list().push_back(entry(*i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dict["info"] = create_info_metadata();
|
dict["info"] = create_info_metadata();
|
||||||
|
|
||||||
|
@ -584,4 +626,55 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
return piece_length();
|
return piece_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<file_slice> torrent_info::map_block(int piece, size_type offset
|
||||||
|
, int size) const
|
||||||
|
{
|
||||||
|
assert(num_files() > 0);
|
||||||
|
std::vector<file_slice> ret;
|
||||||
|
|
||||||
|
size_type start = piece * (size_type)m_piece_length + offset;
|
||||||
|
|
||||||
|
// find the file iterator and file offset
|
||||||
|
// TODO: make a vector that can map piece -> file index in O(1)
|
||||||
|
size_type file_offset = start;
|
||||||
|
std::vector<file_entry>::const_iterator file_iter;
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
for (file_iter = begin_files();; ++counter, ++file_iter)
|
||||||
|
{
|
||||||
|
assert(file_iter != end_files());
|
||||||
|
if (file_offset < file_iter->size)
|
||||||
|
{
|
||||||
|
file_slice f;
|
||||||
|
f.file_index = counter;
|
||||||
|
f.offset = file_offset;
|
||||||
|
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
||||||
|
size -= f.size;
|
||||||
|
file_offset += f.size;
|
||||||
|
ret.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(size >= 0);
|
||||||
|
if (size <= 0) break;
|
||||||
|
|
||||||
|
file_offset -= file_iter->size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
peer_request torrent_info::map_file(int file_index, size_type file_offset
|
||||||
|
, int size) const
|
||||||
|
{
|
||||||
|
size_type offset = file_offset;
|
||||||
|
for (int i = 0; i < file_index; ++i)
|
||||||
|
offset += file_at(i).size;
|
||||||
|
|
||||||
|
peer_request ret;
|
||||||
|
ret.piece = offset / piece_length();
|
||||||
|
ret.start = offset - ret.piece * piece_length();
|
||||||
|
ret.length = size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <boost/tuple/tuple.hpp>
|
|
||||||
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/http_tracker_connection.hpp"
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
#include "libtorrent/udp_tracker_connection.hpp"
|
#include "libtorrent/udp_tracker_connection.hpp"
|
||||||
|
@ -49,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
using boost::tuples::make_tuple;
|
using boost::tuples::make_tuple;
|
||||||
using boost::tuples::tuple;
|
using boost::tuples::tuple;
|
||||||
|
using boost::bind;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -76,54 +78,11 @@ namespace
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
/*
|
using boost::posix_time::second_clock;
|
||||||
address parse_url(std::string const& url)
|
using boost::posix_time::seconds;
|
||||||
{
|
using boost::posix_time::ptime;
|
||||||
std::string hostname; // hostname only
|
using boost::posix_time::time_duration;
|
||||||
int port = 80;
|
|
||||||
|
|
||||||
// PARSE URL
|
|
||||||
std::string::const_iterator start = url.begin();
|
|
||||||
std::string::const_iterator end
|
|
||||||
= std::find(url.begin(), url.end(), ':');
|
|
||||||
|
|
||||||
while ((*start == ' ' || *start == '\t') && start != end) ++start;
|
|
||||||
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
++end;
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
if (*end != '/') throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
++end;
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
if (*end != '/') throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
++end;
|
|
||||||
start = end;
|
|
||||||
|
|
||||||
end = std::find(start, url.end(), '/');
|
|
||||||
std::string::const_iterator port_pos
|
|
||||||
= std::find(start, url.end(), ':');
|
|
||||||
|
|
||||||
if (port_pos < end)
|
|
||||||
{
|
|
||||||
hostname.assign(start, port_pos);
|
|
||||||
++port_pos;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
port = boost::lexical_cast<int>(std::string(port_pos, end));
|
|
||||||
}
|
|
||||||
catch(boost::bad_lexical_cast&)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("invalid url: \"" + url + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hostname.assign(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return address(hostname.c_str(), port);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// returns -1 if gzip header is invalid or the header size in bytes
|
// returns -1 if gzip header is invalid or the header size in bytes
|
||||||
int gzip_header(const char* buf, int size)
|
int gzip_header(const char* buf, int size)
|
||||||
{
|
{
|
||||||
|
@ -332,6 +291,101 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void intrusive_ptr_add_ref(timeout_handler const* c)
|
||||||
|
{
|
||||||
|
assert(c != 0);
|
||||||
|
assert(c->m_refs >= 0);
|
||||||
|
timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
|
||||||
|
++c->m_refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intrusive_ptr_release(timeout_handler const* c)
|
||||||
|
{
|
||||||
|
assert(c != 0);
|
||||||
|
assert(c->m_refs > 0);
|
||||||
|
timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
|
||||||
|
--c->m_refs;
|
||||||
|
if (c->m_refs == 0)
|
||||||
|
{
|
||||||
|
l.unlock();
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
timeout_handler::timeout_handler(demuxer& d)
|
||||||
|
: m_demuxer(d)
|
||||||
|
, m_start_time(second_clock::universal_time())
|
||||||
|
, m_read_time(second_clock::universal_time())
|
||||||
|
, m_timeout(d)
|
||||||
|
, m_completion_timeout(0)
|
||||||
|
, m_read_timeout(0)
|
||||||
|
, m_refs(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
|
||||||
|
{
|
||||||
|
m_completion_timeout = completion_timeout;
|
||||||
|
m_read_timeout = read_timeout;
|
||||||
|
m_start_time = second_clock::universal_time();
|
||||||
|
m_read_time = second_clock::universal_time();
|
||||||
|
|
||||||
|
m_timeout.expires_at(std::min(
|
||||||
|
m_read_time + seconds(m_read_timeout)
|
||||||
|
, m_start_time + seconds(m_completion_timeout)));
|
||||||
|
m_timeout.async_wait(bind(&timeout_handler::timeout_callback, self(), _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void timeout_handler::restart_read_timeout()
|
||||||
|
{
|
||||||
|
m_read_time = second_clock::universal_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void timeout_handler::cancel()
|
||||||
|
{
|
||||||
|
m_timeout.cancel();
|
||||||
|
m_completion_timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timeout_handler::timeout_callback(asio::error const& error) try
|
||||||
|
{
|
||||||
|
if (error) return;
|
||||||
|
if (m_completion_timeout == 0) return;
|
||||||
|
|
||||||
|
ptime now(second_clock::universal_time());
|
||||||
|
time_duration receive_timeout = now - m_read_time;
|
||||||
|
time_duration completion_timeout = now - m_start_time;
|
||||||
|
|
||||||
|
if (m_read_timeout
|
||||||
|
< receive_timeout.total_seconds()
|
||||||
|
|| m_completion_timeout
|
||||||
|
< completion_timeout.total_seconds())
|
||||||
|
{
|
||||||
|
on_timeout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timeout.expires_at(std::min(
|
||||||
|
m_read_time + seconds(m_read_timeout)
|
||||||
|
, m_start_time + seconds(m_completion_timeout)));
|
||||||
|
m_timeout.async_wait(bind(&timeout_handler::timeout_callback, self(), _1));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker_connection::tracker_connection(
|
||||||
|
tracker_manager& man
|
||||||
|
, tracker_request req
|
||||||
|
, demuxer& d
|
||||||
|
, boost::weak_ptr<request_callback> r)
|
||||||
|
: timeout_handler(d)
|
||||||
|
, m_requester(r)
|
||||||
|
, m_man(man)
|
||||||
|
, m_req(req)
|
||||||
|
{}
|
||||||
|
|
||||||
request_callback& tracker_connection::requester()
|
request_callback& tracker_connection::requester()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<request_callback> r = m_requester.lock();
|
boost::shared_ptr<request_callback> r = m_requester.lock();
|
||||||
|
@ -339,92 +393,97 @@ namespace libtorrent
|
||||||
return *r;
|
return *r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tracker_connection::fail(int code, char const* msg)
|
||||||
void tracker_manager::tick()
|
|
||||||
{
|
{
|
||||||
tracker_connections_t::iterator i;
|
if (has_requester()) requester().tracker_request_error(
|
||||||
for (i = m_connections.begin(); i != m_connections.end();)
|
m_req, code, msg);
|
||||||
{
|
close();
|
||||||
boost::shared_ptr<tracker_connection>& c = *i;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!c->tick())
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
if (c->has_requester())
|
|
||||||
c->requester().tracker_request_error(c->tracker_req()
|
|
||||||
, -1, e.what());
|
|
||||||
}
|
|
||||||
if (c->has_requester()) c->requester().m_manager = 0;
|
|
||||||
i = m_connections.erase(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
void tracker_connection::fail_timeout()
|
||||||
{
|
{
|
||||||
|
if (has_requester()) requester().tracker_request_timed_out(m_req);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracker_connection::close()
|
||||||
|
{
|
||||||
|
m_man.remove_request(this);
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
tuple<std::string, std::string, int, std::string>
|
void tracker_manager::remove_request(tracker_connection const* c)
|
||||||
parse_url_components(std::string url)
|
{
|
||||||
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
|
tracker_connections_t::iterator i = std::find(m_connections.begin()
|
||||||
|
, m_connections.end(), boost::intrusive_ptr<const tracker_connection>(c));
|
||||||
|
if (i == m_connections.end()) return;
|
||||||
|
|
||||||
|
m_connections.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple<std::string, std::string, int, std::string>
|
||||||
|
parse_url_components(std::string url)
|
||||||
|
{
|
||||||
|
std::string hostname; // hostname only
|
||||||
|
std::string protocol; // should be http
|
||||||
|
int port = 80;
|
||||||
|
|
||||||
|
// PARSE URL
|
||||||
|
std::string::iterator start = url.begin();
|
||||||
|
// remove white spaces in front of the url
|
||||||
|
while (start != url.end() && (*start == ' ' || *start == '\t'))
|
||||||
|
++start;
|
||||||
|
std::string::iterator end
|
||||||
|
= std::find(url.begin(), url.end(), ':');
|
||||||
|
protocol = std::string(start, end);
|
||||||
|
|
||||||
|
if (end == url.end()) throw std::runtime_error("invalid url");
|
||||||
|
++end;
|
||||||
|
if (end == url.end()) throw std::runtime_error("invalid url");
|
||||||
|
if (*end != '/') throw std::runtime_error("invalid url");
|
||||||
|
++end;
|
||||||
|
if (end == url.end()) throw std::runtime_error("invalid url");
|
||||||
|
if (*end != '/') throw std::runtime_error("invalid url");
|
||||||
|
++end;
|
||||||
|
start = end;
|
||||||
|
|
||||||
|
end = std::find(start, url.end(), '/');
|
||||||
|
std::string::iterator port_pos
|
||||||
|
= std::find(start, url.end(), ':');
|
||||||
|
|
||||||
|
if (port_pos < end)
|
||||||
{
|
{
|
||||||
std::string hostname; // hostname only
|
hostname.assign(start, port_pos);
|
||||||
std::string protocol; // should be http
|
++port_pos;
|
||||||
int port = 80;
|
try
|
||||||
|
|
||||||
// PARSE URL
|
|
||||||
std::string::iterator start = url.begin();
|
|
||||||
std::string::iterator end
|
|
||||||
= std::find(url.begin(), url.end(), ':');
|
|
||||||
protocol = std::string(start, end);
|
|
||||||
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url");
|
|
||||||
++end;
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url");
|
|
||||||
if (*end != '/') throw std::runtime_error("invalid url");
|
|
||||||
++end;
|
|
||||||
if (end == url.end()) throw std::runtime_error("invalid url");
|
|
||||||
if (*end != '/') throw std::runtime_error("invalid url");
|
|
||||||
++end;
|
|
||||||
start = end;
|
|
||||||
|
|
||||||
end = std::find(start, url.end(), '/');
|
|
||||||
std::string::iterator port_pos
|
|
||||||
= std::find(start, url.end(), ':');
|
|
||||||
|
|
||||||
if (port_pos < end)
|
|
||||||
{
|
{
|
||||||
hostname.assign(start, port_pos);
|
port = boost::lexical_cast<int>(std::string(port_pos, end));
|
||||||
++port_pos;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
port = boost::lexical_cast<int>(std::string(port_pos, end));
|
|
||||||
}
|
|
||||||
catch(boost::bad_lexical_cast&)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("invalid url: \"" + url
|
|
||||||
+ "\", port number expected");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
catch(boost::bad_lexical_cast&)
|
||||||
{
|
{
|
||||||
hostname.assign(start, end);
|
throw std::runtime_error("invalid url: \"" + url
|
||||||
|
+ "\", port number expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
start = end;
|
|
||||||
return make_tuple(protocol, hostname, port
|
|
||||||
, std::string(start, url.end()));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hostname.assign(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
return make_tuple(protocol, hostname, port
|
||||||
|
, std::string(start, url.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tracker_manager::queue_request(
|
void tracker_manager::queue_request(
|
||||||
tracker_request req
|
demuxer& d
|
||||||
|
, tracker_request req
|
||||||
, std::string const& auth
|
, std::string const& auth
|
||||||
, boost::weak_ptr<request_callback> c)
|
, boost::weak_ptr<request_callback> c)
|
||||||
{
|
{
|
||||||
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
assert(req.num_want >= 0);
|
assert(req.num_want >= 0);
|
||||||
if (req.event == tracker_request::stopped)
|
if (req.event == tracker_request::stopped)
|
||||||
req.num_want = 0;
|
req.num_want = 0;
|
||||||
|
@ -439,28 +498,31 @@ namespace libtorrent
|
||||||
boost::tie(protocol, hostname, port, request_string)
|
boost::tie(protocol, hostname, port, request_string)
|
||||||
= parse_url_components(req.url);
|
= parse_url_components(req.url);
|
||||||
|
|
||||||
boost::shared_ptr<tracker_connection> con;
|
boost::intrusive_ptr<tracker_connection> con;
|
||||||
|
|
||||||
if (protocol == "http")
|
if (protocol == "http")
|
||||||
{
|
{
|
||||||
con.reset(new http_tracker_connection(
|
con = new http_tracker_connection(
|
||||||
*this
|
d
|
||||||
|
, *this
|
||||||
, req
|
, req
|
||||||
, hostname
|
, hostname
|
||||||
, port
|
, port
|
||||||
, request_string
|
, request_string
|
||||||
, c
|
, c
|
||||||
, m_settings
|
, m_settings
|
||||||
, auth));
|
, auth);
|
||||||
}
|
}
|
||||||
else if (protocol == "udp")
|
else if (protocol == "udp")
|
||||||
{
|
{
|
||||||
con.reset(new udp_tracker_connection(
|
con = new udp_tracker_connection(
|
||||||
req
|
d
|
||||||
|
, *this
|
||||||
|
, req
|
||||||
, hostname
|
, hostname
|
||||||
, port
|
, port
|
||||||
, c
|
, c
|
||||||
, m_settings));
|
, m_settings);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -473,54 +535,28 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
if (!c.expired())
|
if (boost::shared_ptr<request_callback> r = c.lock())
|
||||||
{
|
|
||||||
boost::shared_ptr<request_callback> r = c.lock();
|
|
||||||
r->tracker_request_error(req, -1, e.what());
|
r->tracker_request_error(req, -1, e.what());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void tracker_manager::abort_request(request_callback* c)
|
|
||||||
{
|
|
||||||
assert(c != 0);
|
|
||||||
tracker_connections_t::iterator i;
|
|
||||||
for (i = m_connections.begin(); i != m_connections.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->requester() == c)
|
|
||||||
{
|
|
||||||
m_connections.erase(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void tracker_manager::abort_all_requests()
|
void tracker_manager::abort_all_requests()
|
||||||
{
|
{
|
||||||
// removes all connections from m_connections
|
// removes all connections from m_connections
|
||||||
// except those with a requester == 0 (since those are
|
// except those with a requester == 0 (since those are
|
||||||
// 'event=stopped'-requests)
|
// 'event=stopped'-requests)
|
||||||
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
|
|
||||||
tracker_connections_t keep_connections;
|
tracker_connections_t keep_connections;
|
||||||
|
|
||||||
for (tracker_connections_t::const_iterator i =
|
for (tracker_connections_t::const_iterator i =
|
||||||
m_connections.begin(); i != m_connections.end(); ++i)
|
m_connections.begin(); i != m_connections.end(); ++i)
|
||||||
{
|
{
|
||||||
if (!(*i)->has_requester()) keep_connections.push_back(*i);
|
tracker_request const& req = (*i)->tracker_req();
|
||||||
|
if (req.event == tracker_request::stopped)
|
||||||
|
keep_connections.push_back(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(m_connections, keep_connections);
|
std::swap(m_connections, keep_connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tracker_manager::send_finished() const
|
|
||||||
{
|
|
||||||
for (tracker_connections_t::const_iterator i =
|
|
||||||
m_connections.begin(); i != m_connections.end(); ++i)
|
|
||||||
{
|
|
||||||
if (!(*i)->send_finished()) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/udp_tracker_connection.hpp"
|
#include "libtorrent/udp_tracker_connection.hpp"
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
|
@ -55,135 +66,183 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
using boost::bind;
|
||||||
|
using boost::lexical_cast;
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
udp_tracker_connection::udp_tracker_connection(
|
udp_tracker_connection::udp_tracker_connection(
|
||||||
tracker_request const& req
|
demuxer& d
|
||||||
|
, tracker_manager& man
|
||||||
|
, tracker_request const& req
|
||||||
, std::string const& hostname
|
, std::string const& hostname
|
||||||
, unsigned short port
|
, unsigned short port
|
||||||
, boost::weak_ptr<request_callback> c
|
, boost::weak_ptr<request_callback> c
|
||||||
, const http_settings& stn)
|
, const http_settings& stn)
|
||||||
: tracker_connection(c)
|
: tracker_connection(man, req, d, c)
|
||||||
, m_request_time(second_clock::universal_time())
|
, m_man(man)
|
||||||
, m_request(req)
|
, m_name_lookup(d)
|
||||||
|
, m_port(port)
|
||||||
, m_transaction_id(0)
|
, m_transaction_id(0)
|
||||||
, m_connection_id(0)
|
, m_connection_id(0)
|
||||||
, m_settings(stn)
|
, m_settings(stn)
|
||||||
, m_attempts(0)
|
, m_attempts(0)
|
||||||
{
|
{
|
||||||
m_name_lookup = dns_lookup(hostname.c_str(), port);
|
m_socket.reset(new datagram_socket(d));
|
||||||
m_socket.reset(new socket(socket::udp, false));
|
m_name_lookup.async_by_name(m_host, hostname.c_str()
|
||||||
|
, bind(&udp_tracker_connection::name_lookup, self(), _1));
|
||||||
|
set_timeout(m_settings.tracker_completion_timeout
|
||||||
|
, m_settings.tracker_receive_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool udp_tracker_connection::send_finished() const
|
void udp_tracker_connection::name_lookup(asio::error const& error) try
|
||||||
{
|
{
|
||||||
using namespace boost::posix_time;
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (error)
|
||||||
time_duration d = second_clock::universal_time() - m_request_time;
|
|
||||||
return (m_transaction_id != 0
|
|
||||||
&& m_connection_id != 0)
|
|
||||||
|| d > seconds(m_settings.tracker_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool udp_tracker_connection::tick()
|
|
||||||
{
|
|
||||||
using namespace boost::posix_time;
|
|
||||||
|
|
||||||
if (m_name_lookup.running())
|
|
||||||
{
|
{
|
||||||
if (!m_name_lookup.finished()) return false;
|
fail(-1, error.what());
|
||||||
|
return;
|
||||||
if (m_name_lookup.failed())
|
}
|
||||||
{
|
|
||||||
if (has_requester()) requester().tracker_request_error(
|
|
||||||
m_request, -1, m_name_lookup.error());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
address a(m_name_lookup.ip());
|
|
||||||
if (has_requester()) requester().m_tracker_address = a;
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
if (has_requester()) requester().debug_log("name lookup successful");
|
if (has_requester()) requester().debug_log("udp tracker name lookup successful");
|
||||||
#endif
|
#endif
|
||||||
|
restart_read_timeout();
|
||||||
m_socket->connect(a);
|
m_target = udp::endpoint(m_port, m_host.address(0));
|
||||||
send_udp_connect();
|
if (has_requester()) requester().m_tracker_address
|
||||||
|
= tcp::endpoint(m_port, m_host.address(0));
|
||||||
// clear the lookup entry so it will not be
|
m_socket->connect(m_target);
|
||||||
// marked as running anymore
|
send_udp_connect();
|
||||||
m_name_lookup = dns_lookup();
|
}
|
||||||
}
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
time_duration d = second_clock::universal_time() - m_request_time;
|
fail(-1, e.what());
|
||||||
if (m_connection_id == 0
|
|
||||||
&& d > seconds(udp_connect_timeout))
|
|
||||||
{
|
|
||||||
if (m_attempts >= udp_connection_retries)
|
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
requester().tracker_request_timed_out(m_request);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
send_udp_connect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_connection_id != 0
|
|
||||||
&& d > seconds(udp_announce_timeout))
|
|
||||||
{
|
|
||||||
if (m_attempts >= udp_announce_retries)
|
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
requester().tracker_request_timed_out(m_request);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_request.kind == tracker_request::announce_request)
|
|
||||||
send_udp_announce();
|
|
||||||
else if (m_request.kind == tracker_request::scrape_request)
|
|
||||||
send_udp_scrape();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[udp_buffer_size];
|
|
||||||
int ret = m_socket->receive(buf, udp_buffer_size);
|
|
||||||
|
|
||||||
// if there was nothing to receive, return
|
|
||||||
if (ret == 0) return false;
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
socket::error_code err = m_socket->last_error();
|
|
||||||
if (err == socket::would_block) return false;
|
|
||||||
throw network_error(m_socket->last_error());
|
|
||||||
}
|
|
||||||
if (ret == udp_buffer_size)
|
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
requester().tracker_request_error(
|
|
||||||
m_request, -1, "tracker reply too big");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_connection_id == 0)
|
|
||||||
{
|
|
||||||
return parse_connect_response(buf, ret);
|
|
||||||
}
|
|
||||||
else if (m_request.kind == tracker_request::announce_request)
|
|
||||||
{
|
|
||||||
return parse_announce_response(buf, ret);
|
|
||||||
}
|
|
||||||
else if (m_request.kind == tracker_request::scrape_request)
|
|
||||||
{
|
|
||||||
return parse_scrape_response(buf, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void udp_tracker_connection::on_timeout()
|
||||||
|
{
|
||||||
|
m_socket.reset();
|
||||||
|
m_name_lookup.cancel();
|
||||||
|
fail_timeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_tracker_connection::send_udp_connect()
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
if (has_requester())
|
||||||
|
{
|
||||||
|
requester().debug_log("==> UDP_TRACKER_CONNECT ["
|
||||||
|
+ lexical_cast<std::string>(tracker_req().info_hash) + "]");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char send_buf[16];
|
||||||
|
char* ptr = send_buf;
|
||||||
|
|
||||||
|
if (m_transaction_id == 0)
|
||||||
|
m_transaction_id = rand() ^ (rand() << 16);
|
||||||
|
|
||||||
|
// connection_id
|
||||||
|
detail::write_uint32(0x417, ptr);
|
||||||
|
detail::write_uint32(0x27101980, ptr);
|
||||||
|
// action (connect)
|
||||||
|
detail::write_int32(action_connect, ptr);
|
||||||
|
// transaction_id
|
||||||
|
detail::write_int32(m_transaction_id, ptr);
|
||||||
|
|
||||||
|
m_socket->send(asio::buffer((void*)send_buf, 16), 0);
|
||||||
|
++m_attempts;
|
||||||
|
m_buffer.resize(udp_buffer_size);
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_tracker_connection::connect_response(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) try
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fail(-1, error.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_target != m_sender)
|
||||||
|
{
|
||||||
|
// this packet was not received from the tracker
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred >= udp_buffer_size)
|
||||||
|
{
|
||||||
|
fail(-1, "udp response too big");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 8)
|
||||||
|
{
|
||||||
|
fail(-1, "got a message with size < 8");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_read_timeout();
|
||||||
|
|
||||||
|
const char* ptr = &m_buffer[0];
|
||||||
|
int action = detail::read_int32(ptr);
|
||||||
|
int transaction = detail::read_int32(ptr);
|
||||||
|
|
||||||
|
if (action == action_error)
|
||||||
|
{
|
||||||
|
fail(-1, std::string(ptr, bytes_transferred - 8).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action != action_connect)
|
||||||
|
{
|
||||||
|
fail(-1, "invalid action in connect reply");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transaction_id != transaction)
|
||||||
|
{
|
||||||
|
fail(-1, "incorrect transaction id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 16)
|
||||||
|
{
|
||||||
|
fail(-1, "udp_tracker_connection: "
|
||||||
|
"got a message with size < 16");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// reset transaction
|
||||||
|
m_transaction_id = 0;
|
||||||
|
m_attempts = 0;
|
||||||
|
m_connection_id = detail::read_int64(ptr);
|
||||||
|
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
if (has_requester())
|
||||||
|
{
|
||||||
|
requester().debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
|
||||||
|
+ lexical_cast<std::string>(m_connection_id) + "]");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (tracker_req().kind == tracker_request::announce_request)
|
||||||
|
send_udp_announce();
|
||||||
|
else if (tracker_req().kind == tracker_request::scrape_request)
|
||||||
|
send_udp_scrape();
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
fail(-1, e.what());
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void udp_tracker_connection::send_udp_announce()
|
void udp_tracker_connection::send_udp_announce()
|
||||||
{
|
{
|
||||||
if (m_transaction_id == 0)
|
if (m_transaction_id == 0)
|
||||||
|
@ -191,39 +250,51 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<char> buf;
|
std::vector<char> buf;
|
||||||
std::back_insert_iterator<std::vector<char> > out(buf);
|
std::back_insert_iterator<std::vector<char> > out(buf);
|
||||||
|
|
||||||
|
tracker_request const& req = tracker_req();
|
||||||
|
|
||||||
// connection_id
|
// connection_id
|
||||||
detail::write_int64(m_connection_id, out);
|
detail::write_int64(m_connection_id, out);
|
||||||
// action (announce)
|
// action (announce)
|
||||||
detail::write_int32(announce, out);
|
detail::write_int32(action_announce, out);
|
||||||
// transaction_id
|
// transaction_id
|
||||||
detail::write_int32(m_transaction_id, out);
|
detail::write_int32(m_transaction_id, out);
|
||||||
// info_hash
|
// info_hash
|
||||||
std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);
|
std::copy(req.info_hash.begin(), req.info_hash.end(), out);
|
||||||
// peer_id
|
// peer_id
|
||||||
std::copy(m_request.id.begin(), m_request.id.end(), out);
|
std::copy(req.pid.begin(), req.pid.end(), out);
|
||||||
// downloaded
|
// downloaded
|
||||||
detail::write_int64(m_request.downloaded, out);
|
detail::write_int64(req.downloaded, out);
|
||||||
// left
|
// left
|
||||||
detail::write_int64(m_request.left, out);
|
detail::write_int64(req.left, out);
|
||||||
// uploaded
|
// uploaded
|
||||||
detail::write_int64(m_request.uploaded, out);
|
detail::write_int64(req.uploaded, out);
|
||||||
// event
|
// event
|
||||||
detail::write_int32(m_request.event, out);
|
detail::write_int32(req.event, out);
|
||||||
// ip address
|
// ip address
|
||||||
detail::write_int32(0, out);
|
detail::write_int32(0, out);
|
||||||
// key
|
// key
|
||||||
detail::write_int32(m_request.key, out);
|
detail::write_int32(req.key, out);
|
||||||
// num_want
|
// num_want
|
||||||
detail::write_int32(m_request.num_want, out);
|
detail::write_int32(req.num_want, out);
|
||||||
// port
|
// port
|
||||||
detail::write_uint16(m_request.listen_port, out);
|
detail::write_uint16(req.listen_port, out);
|
||||||
// extensions
|
// extensions
|
||||||
detail::write_uint16(0, out);
|
detail::write_uint16(0, out);
|
||||||
|
|
||||||
m_socket->send(&buf[0], buf.size());
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
m_request_time = second_clock::universal_time();
|
if (has_requester())
|
||||||
|
{
|
||||||
|
requester().debug_log("==> UDP_TRACKER_ANNOUNCE ["
|
||||||
|
+ lexical_cast<std::string>(req.info_hash) + "]");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_socket->send(asio::buffer(buf), 0);
|
||||||
++m_attempts;
|
++m_attempts;
|
||||||
|
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, bind(&udp_tracker_connection::announce_response, self(), _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void udp_tracker_connection::send_udp_scrape()
|
void udp_tracker_connection::send_udp_scrape()
|
||||||
|
@ -237,91 +308,100 @@ namespace libtorrent
|
||||||
// connection_id
|
// connection_id
|
||||||
detail::write_int64(m_connection_id, out);
|
detail::write_int64(m_connection_id, out);
|
||||||
// action (scrape)
|
// action (scrape)
|
||||||
detail::write_int32(scrape, out);
|
detail::write_int32(action_scrape, out);
|
||||||
// transaction_id
|
// transaction_id
|
||||||
detail::write_int32(m_transaction_id, out);
|
detail::write_int32(m_transaction_id, out);
|
||||||
// info_hash
|
// info_hash
|
||||||
std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);
|
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
|
||||||
|
|
||||||
m_socket->send(&buf[0], buf.size());
|
m_socket->send(asio::buffer(&buf[0], buf.size()), 0);
|
||||||
m_request_time = second_clock::universal_time();
|
|
||||||
++m_attempts;
|
++m_attempts;
|
||||||
|
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void udp_tracker_connection::send_udp_connect()
|
void udp_tracker_connection::announce_response(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) try
|
||||||
{
|
{
|
||||||
char send_buf[16];
|
if (error == asio::error::operation_aborted) return;
|
||||||
char* ptr = send_buf;
|
if (error)
|
||||||
|
|
||||||
if (m_transaction_id == 0)
|
|
||||||
m_transaction_id = rand() ^ (rand() << 16);
|
|
||||||
|
|
||||||
// connection_id
|
|
||||||
detail::write_uint32(0x417, ptr);
|
|
||||||
detail::write_uint32(0x27101980, ptr);
|
|
||||||
// action (connect)
|
|
||||||
detail::write_int32(connect, ptr);
|
|
||||||
// transaction_id
|
|
||||||
detail::write_int32(m_transaction_id, ptr);
|
|
||||||
|
|
||||||
m_socket->send(send_buf, 16);
|
|
||||||
m_request_time = second_clock::universal_time();
|
|
||||||
++m_attempts;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool udp_tracker_connection::parse_announce_response(const char* buf, int len)
|
|
||||||
{
|
|
||||||
assert(buf != 0);
|
|
||||||
assert(len > 0);
|
|
||||||
|
|
||||||
if (len < 8)
|
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
fail(-1, error.what());
|
||||||
if (has_requester())
|
return;
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with size < 8, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_target != m_sender)
|
||||||
|
{
|
||||||
|
// this packet was not received from the tracker
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, bind(&udp_tracker_connection::connect_response, self(), _1, _2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred >= udp_buffer_size)
|
||||||
|
{
|
||||||
|
fail(-1, "udp response too big");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 8)
|
||||||
|
{
|
||||||
|
fail(-1, "got a message with size < 8");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_read_timeout();
|
||||||
|
char* buf = &m_buffer[0];
|
||||||
int action = detail::read_int32(buf);
|
int action = detail::read_int32(buf);
|
||||||
int transaction = detail::read_int32(buf);
|
int transaction = detail::read_int32(buf);
|
||||||
|
|
||||||
if (transaction != m_transaction_id)
|
if (transaction != m_transaction_id)
|
||||||
{
|
{
|
||||||
return false;
|
fail(-1, "incorrect transaction id");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == error)
|
if (action == action_error)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, std::string(buf, bytes_transferred - 8).c_str());
|
||||||
requester().tracker_request_error(
|
return;
|
||||||
m_request, -1, std::string(buf, buf + len - 8));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (action != announce) return false;
|
|
||||||
|
|
||||||
if (len < 20)
|
if (action != action_announce)
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
fail(-1, "invalid action in announce response");
|
||||||
if (has_requester())
|
return;
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with size < 20, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 20)
|
||||||
|
{
|
||||||
|
fail(-1, "got a message with size < 20");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int interval = detail::read_int32(buf);
|
int interval = detail::read_int32(buf);
|
||||||
int incomplete = detail::read_int32(buf);
|
int incomplete = detail::read_int32(buf);
|
||||||
int complete = detail::read_int32(buf);
|
int complete = detail::read_int32(buf);
|
||||||
int num_peers = (len - 20) / 6;
|
int num_peers = (bytes_transferred - 20) / 6;
|
||||||
if ((len - 20) % 6 != 0)
|
if ((bytes_transferred - 20) % 6 != 0)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, "invalid udp tracker response length");
|
||||||
requester().tracker_request_error(
|
return;
|
||||||
m_request, -1, "invalid tracker response");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_requester()) return true;
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
if (has_requester())
|
||||||
|
{
|
||||||
|
requester().debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!has_requester())
|
||||||
|
{
|
||||||
|
m_man.remove_request(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<peer_entry> peer_list;
|
std::vector<peer_entry> peer_list;
|
||||||
for (int i = 0; i < num_peers; ++i)
|
for (int i = 0; i < num_peers; ++i)
|
||||||
|
@ -334,126 +414,102 @@ namespace libtorrent
|
||||||
s << (int)detail::read_uint8(buf);
|
s << (int)detail::read_uint8(buf);
|
||||||
e.ip = s.str();
|
e.ip = s.str();
|
||||||
e.port = detail::read_uint16(buf);
|
e.port = detail::read_uint16(buf);
|
||||||
e.id.clear();
|
e.pid.clear();
|
||||||
peer_list.push_back(e);
|
peer_list.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
requester().tracker_response(m_request, peer_list, interval
|
requester().tracker_response(tracker_req(), peer_list, interval
|
||||||
, complete, incomplete);
|
, complete, incomplete);
|
||||||
return true;
|
|
||||||
|
m_man.remove_request(this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
bool udp_tracker_connection::parse_scrape_response(const char* buf, int len)
|
|
||||||
{
|
{
|
||||||
assert(buf != 0);
|
fail(-1, e.what());
|
||||||
assert(len > 0);
|
assert(false);
|
||||||
|
}; // msvc 7.1 seems to require this
|
||||||
|
|
||||||
if (len < 8)
|
void udp_tracker_connection::scrape_response(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred) try
|
||||||
|
{
|
||||||
|
if (error == asio::error::operation_aborted) return;
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
fail(-1, error.what());
|
||||||
if (has_requester())
|
return;
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with size < 8, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_target != m_sender)
|
||||||
|
{
|
||||||
|
// this packet was not received from the tracker
|
||||||
|
m_socket->async_receive_from(asio::buffer(m_buffer), 0, m_sender
|
||||||
|
, bind(&udp_tracker_connection::connect_response, self(), _1, _2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred >= udp_buffer_size)
|
||||||
|
{
|
||||||
|
fail(-1, "udp response too big");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 8)
|
||||||
|
{
|
||||||
|
fail(-1, "got a message with size < 8");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_read_timeout();
|
||||||
|
char* buf = &m_buffer[0];
|
||||||
int action = detail::read_int32(buf);
|
int action = detail::read_int32(buf);
|
||||||
int transaction = detail::read_int32(buf);
|
int transaction = detail::read_int32(buf);
|
||||||
|
|
||||||
if (transaction != m_transaction_id)
|
if (transaction != m_transaction_id)
|
||||||
{
|
{
|
||||||
return false;
|
fail(-1, "incorrect transaction id");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == error)
|
if (action == action_error)
|
||||||
{
|
{
|
||||||
if (has_requester())
|
fail(-1, std::string(buf, bytes_transferred - 8).c_str());
|
||||||
requester().tracker_request_error(
|
return;
|
||||||
m_request, -1, std::string(buf, buf + len - 8));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (action != scrape) return false;
|
|
||||||
|
|
||||||
if (len < 20)
|
if (action != action_scrape)
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
fail(-1, "invalid action in announce response");
|
||||||
if (has_requester())
|
return;
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with size < 20, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes_transferred < 20)
|
||||||
|
{
|
||||||
|
fail(-1, "got a message with size < 20");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int complete = detail::read_int32(buf);
|
int complete = detail::read_int32(buf);
|
||||||
/*int downloaded = */detail::read_int32(buf);
|
/*int downloaded = */detail::read_int32(buf);
|
||||||
int incomplete = detail::read_int32(buf);
|
int incomplete = detail::read_int32(buf);
|
||||||
|
|
||||||
if (!has_requester()) return true;
|
if (!has_requester())
|
||||||
|
{
|
||||||
|
m_man.remove_request(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<peer_entry> peer_list;
|
std::vector<peer_entry> peer_list;
|
||||||
requester().tracker_response(m_request, peer_list, 0
|
requester().tracker_response(tracker_req(), peer_list, 0
|
||||||
, complete, incomplete);
|
, complete, incomplete);
|
||||||
return true;
|
|
||||||
|
m_man.remove_request(this);
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
|
||||||
bool udp_tracker_connection::parse_connect_response(const char* buf, int len)
|
|
||||||
{
|
{
|
||||||
assert(buf != 0);
|
fail(-1, e.what());
|
||||||
assert(len > 0);
|
assert(false);
|
||||||
|
|
||||||
if (len < 8)
|
|
||||||
{
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
if (has_requester())
|
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with size < 8, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const char* ptr = buf;
|
|
||||||
int action = detail::read_int32(ptr);
|
|
||||||
int transaction = detail::read_int32(ptr);
|
|
||||||
|
|
||||||
if (action == error)
|
|
||||||
{
|
|
||||||
if (has_requester())
|
|
||||||
requester().tracker_request_error(
|
|
||||||
m_request, -1, std::string(ptr, buf + len));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (action != connect) return false;
|
|
||||||
if (m_transaction_id != transaction)
|
|
||||||
{
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
if (has_requester())
|
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a message with incorrect transaction id, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < 16)
|
|
||||||
{
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
if (has_requester())
|
|
||||||
requester().debug_log("udp_tracker_connection: "
|
|
||||||
"got a connection message size < 16, ignoring");
|
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// reset transaction
|
|
||||||
m_transaction_id = 0;
|
|
||||||
m_attempts = 0;
|
|
||||||
m_connection_id = detail::read_int64(ptr);
|
|
||||||
|
|
||||||
if (m_request.kind == tracker_request::announce_request)
|
|
||||||
send_udp_announce();
|
|
||||||
else if (m_request.kind == tracker_request::scrape_request)
|
|
||||||
send_udp_scrape();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2003, 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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <limits>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "libtorrent/web_peer_connection.hpp"
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
#include "libtorrent/identify_client.hpp"
|
||||||
|
#include "libtorrent/entry.hpp"
|
||||||
|
#include "libtorrent/bencode.hpp"
|
||||||
|
#include "libtorrent/alert_types.hpp"
|
||||||
|
#include "libtorrent/invariant_check.hpp"
|
||||||
|
#include "libtorrent/io.hpp"
|
||||||
|
#include "libtorrent/version.hpp"
|
||||||
|
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
using boost::bind;
|
||||||
|
using boost::shared_ptr;
|
||||||
|
using libtorrent::detail::session_impl;
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
web_peer_connection::web_peer_connection(
|
||||||
|
detail::session_impl& ses
|
||||||
|
, boost::weak_ptr<torrent> t
|
||||||
|
, boost::shared_ptr<stream_socket> s
|
||||||
|
, tcp::endpoint const& remote
|
||||||
|
, std::string const& url)
|
||||||
|
: peer_connection(ses, t, s, remote)
|
||||||
|
, m_url(url)
|
||||||
|
, m_first_request(true)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << "*** web_peer_connection\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string protocol;
|
||||||
|
boost::tie(protocol, m_host, m_port, m_path)
|
||||||
|
= parse_url_components(url);
|
||||||
|
|
||||||
|
m_server_string = "URL seed @ ";
|
||||||
|
m_server_string += m_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
web_peer_connection::~web_peer_connection()
|
||||||
|
{}
|
||||||
|
|
||||||
|
boost::optional<piece_block_progress>
|
||||||
|
web_peer_connection::downloading_piece_progress() const
|
||||||
|
{
|
||||||
|
if (!m_parser.header_finished() || m_requests.empty())
|
||||||
|
return boost::optional<piece_block_progress>();
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
int body_start = m_parser.body_start();
|
||||||
|
buffer::const_interval recv_buffer = receive_buffer();
|
||||||
|
assert(body_start <= recv_buffer.left());
|
||||||
|
piece_block_progress ret;
|
||||||
|
|
||||||
|
ret.piece_index = m_requests.front().piece;
|
||||||
|
ret.block_index = m_requests.front().start / t->block_size();
|
||||||
|
ret.bytes_downloaded = recv_buffer.left() - body_start;
|
||||||
|
ret.full_block_bytes = m_requests.front().length;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void web_peer_connection::on_connected()
|
||||||
|
{
|
||||||
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
// this is always a seed
|
||||||
|
incoming_bitfield(std::vector<bool>(
|
||||||
|
t->torrent_file().num_pieces(), true));
|
||||||
|
// it is always possible to request pieces
|
||||||
|
incoming_unchoke();
|
||||||
|
|
||||||
|
reset_recv_buffer(512*1024+1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void web_peer_connection::write_request(peer_request const& r)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
assert(t->valid_metadata());
|
||||||
|
|
||||||
|
bool single_file_request = false;
|
||||||
|
if (!m_path.empty() && m_path[m_path.size() - 1] != '/')
|
||||||
|
single_file_request = true;
|
||||||
|
|
||||||
|
torrent_info const& info = t->torrent_file();
|
||||||
|
|
||||||
|
std::string request;
|
||||||
|
|
||||||
|
m_requests.push_back(r);
|
||||||
|
|
||||||
|
if (single_file_request)
|
||||||
|
{
|
||||||
|
request += "GET ";
|
||||||
|
request += escape_path(m_path.c_str(), m_path.length());
|
||||||
|
request += " HTTP/1.1\r\n";
|
||||||
|
request += "Host: ";
|
||||||
|
request += m_host;
|
||||||
|
if (m_first_request)
|
||||||
|
{
|
||||||
|
request += "\r\nUser-Agent: ";
|
||||||
|
request += escape_string(m_ses.m_http_settings.user_agent.c_str()
|
||||||
|
, m_ses.m_http_settings.user_agent.size());
|
||||||
|
}
|
||||||
|
request += "\r\nRange: bytes=";
|
||||||
|
request += boost::lexical_cast<std::string>(r.piece
|
||||||
|
* info.piece_length() + r.start);
|
||||||
|
request += "-";
|
||||||
|
request += boost::lexical_cast<std::string>(r.piece
|
||||||
|
* info.piece_length() + r.start + r.length - 1);
|
||||||
|
if (m_first_request)
|
||||||
|
request += "\r\nConnection: keep-alive";
|
||||||
|
request += "\r\n\r\n";
|
||||||
|
m_first_request = false;
|
||||||
|
m_file_requests.push_back(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<file_slice> files = info.map_block(r.piece, r.start
|
||||||
|
, r.length);
|
||||||
|
|
||||||
|
for (std::vector<file_slice>::iterator i = files.begin();
|
||||||
|
i != files.end(); ++i)
|
||||||
|
{
|
||||||
|
file_slice const& f = *i;
|
||||||
|
|
||||||
|
std::string path = m_path;
|
||||||
|
path += info.file_at(f.file_index).path.string();
|
||||||
|
request += "GET ";
|
||||||
|
request += escape_path(path.c_str(), path.length());
|
||||||
|
request += " HTTP/1.1\r\n";
|
||||||
|
request += "Host: ";
|
||||||
|
request += m_host;
|
||||||
|
if (m_first_request)
|
||||||
|
{
|
||||||
|
request += "\r\nUser-Agent: ";
|
||||||
|
request += escape_string(m_ses.m_http_settings.user_agent.c_str()
|
||||||
|
, m_ses.m_http_settings.user_agent.size());
|
||||||
|
}
|
||||||
|
request += "\r\nRange: bytes=";
|
||||||
|
request += boost::lexical_cast<std::string>(f.offset);
|
||||||
|
request += "-";
|
||||||
|
request += boost::lexical_cast<std::string>(f.offset + f.size - 1);
|
||||||
|
if (m_first_request)
|
||||||
|
request += "\r\nConnection: keep-alive";
|
||||||
|
request += "\r\n\r\n";
|
||||||
|
m_first_request = false;
|
||||||
|
m_file_requests.push_back(f.file_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_buffer(request.c_str(), request.c_str() + request.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// RECEIVE DATA
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
// throws exception when the client should be disconnected
|
||||||
|
void web_peer_connection::on_receive(const asio::error& error
|
||||||
|
, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
incoming_piece_fragment();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
buffer::const_interval recv_buffer = receive_buffer();
|
||||||
|
int payload;
|
||||||
|
int protocol;
|
||||||
|
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
|
||||||
|
m_statistics.received_bytes(payload, protocol);
|
||||||
|
|
||||||
|
if (m_parser.status_code() != 206 && m_parser.status_code() != -1)
|
||||||
|
{
|
||||||
|
// we should not try this server again.
|
||||||
|
t->remove_url_seed(m_url);
|
||||||
|
if (m_parser.status_code() == 404)
|
||||||
|
throw std::runtime_error("File not found on server");
|
||||||
|
throw std::runtime_error("HTTP server does not support byte range requests");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_parser.finished()) break;
|
||||||
|
|
||||||
|
std::string server_version = m_parser.header<std::string>("Server");
|
||||||
|
if (!server_version.empty())
|
||||||
|
{
|
||||||
|
m_server_string = "URL seed @ ";
|
||||||
|
m_server_string += m_host;
|
||||||
|
m_server_string += " (";
|
||||||
|
m_server_string += server_version;
|
||||||
|
m_server_string += ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream range_str(m_parser.header<std::string>("Content-Range"));
|
||||||
|
size_type range_start;
|
||||||
|
size_type range_end;
|
||||||
|
char dummy;
|
||||||
|
std::string bytes;
|
||||||
|
range_str >> bytes >> range_start >> dummy >> range_end;
|
||||||
|
if (!range_str)
|
||||||
|
{
|
||||||
|
// we should not try this server again.
|
||||||
|
t->remove_url_seed(m_url);
|
||||||
|
throw std::runtime_error("invalid range in HTTP response: " + range_str.str());
|
||||||
|
}
|
||||||
|
// the http range is inclusive
|
||||||
|
range_end++;
|
||||||
|
|
||||||
|
torrent_info const& info = t->torrent_file();
|
||||||
|
|
||||||
|
if (m_requests.empty() || m_file_requests.empty())
|
||||||
|
throw std::runtime_error("unexpected HTTP response");
|
||||||
|
|
||||||
|
int file_index = m_file_requests.front();
|
||||||
|
m_file_requests.pop_front();
|
||||||
|
|
||||||
|
peer_request r = info.map_file(file_index, range_start
|
||||||
|
, range_end - range_start);
|
||||||
|
|
||||||
|
buffer::const_interval http_body = m_parser.get_body();
|
||||||
|
|
||||||
|
if (r == m_requests.front())
|
||||||
|
{
|
||||||
|
m_requests.pop_front();
|
||||||
|
incoming_piece(r, http_body.begin);
|
||||||
|
cut_receive_buffer(http_body.end - recv_buffer.begin, 512*1024+1024);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_piece.empty())
|
||||||
|
{
|
||||||
|
// this is not the first partial request we get
|
||||||
|
if (m_intermediate_piece.start + m_intermediate_piece.length != r.start
|
||||||
|
|| m_intermediate_piece.piece != r.piece)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid range in HTTP response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// this is the first part of a partial request
|
||||||
|
if (r.start != m_requests.front().start
|
||||||
|
|| r.piece != m_requests.front().piece)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid range in HTTP response");
|
||||||
|
}
|
||||||
|
m_intermediate_piece.piece = r.piece;
|
||||||
|
m_intermediate_piece.start = r.start;
|
||||||
|
m_intermediate_piece.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_piece.reserve(info.piece_length());
|
||||||
|
std::copy(http_body.begin, http_body.end, back_inserter(m_piece));
|
||||||
|
m_intermediate_piece.length += r.length;
|
||||||
|
if (m_intermediate_piece.length == m_requests.front().length)
|
||||||
|
{
|
||||||
|
assert(m_requests.front() == m_intermediate_piece);
|
||||||
|
assert(int(m_piece.size()) == m_intermediate_piece.length);
|
||||||
|
m_requests.pop_front();
|
||||||
|
incoming_piece(m_intermediate_piece, &m_piece[0]);
|
||||||
|
m_piece.clear();
|
||||||
|
}
|
||||||
|
else if (m_intermediate_piece.length > m_requests.front().length)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("too large HTTP response body");
|
||||||
|
}
|
||||||
|
|
||||||
|
cut_receive_buffer(http_body.end - recv_buffer.begin, 512*1024+1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// SEND DATA
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
void web_peer_connection::get_peer_info(peer_info& p) const
|
||||||
|
{
|
||||||
|
assert(!associated_torrent().expired());
|
||||||
|
|
||||||
|
p.down_speed = statistics().download_rate();
|
||||||
|
p.up_speed = statistics().upload_rate();
|
||||||
|
p.payload_down_speed = statistics().download_payload_rate();
|
||||||
|
p.payload_up_speed = statistics().upload_payload_rate();
|
||||||
|
p.pid = pid();
|
||||||
|
p.ip = remote();
|
||||||
|
|
||||||
|
p.total_download = statistics().total_payload_download();
|
||||||
|
p.total_upload = statistics().total_payload_upload();
|
||||||
|
|
||||||
|
if (m_ul_bandwidth_quota.given == std::numeric_limits<int>::max())
|
||||||
|
p.upload_limit = -1;
|
||||||
|
else
|
||||||
|
p.upload_limit = m_ul_bandwidth_quota.given;
|
||||||
|
|
||||||
|
if (m_dl_bandwidth_quota.given == std::numeric_limits<int>::max())
|
||||||
|
p.download_limit = -1;
|
||||||
|
else
|
||||||
|
p.download_limit = m_dl_bandwidth_quota.given;
|
||||||
|
|
||||||
|
p.load_balancing = total_free_upload();
|
||||||
|
|
||||||
|
p.download_queue_length = (int)download_queue().size();
|
||||||
|
p.upload_queue_length = (int)upload_queue().size();
|
||||||
|
|
||||||
|
if (boost::optional<piece_block_progress> ret = downloading_piece_progress())
|
||||||
|
{
|
||||||
|
p.downloading_piece_index = ret->piece_index;
|
||||||
|
p.downloading_block_index = ret->block_index;
|
||||||
|
p.downloading_progress = ret->bytes_downloaded;
|
||||||
|
p.downloading_total = ret->full_block_bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.downloading_piece_index = -1;
|
||||||
|
p.downloading_block_index = -1;
|
||||||
|
p.downloading_progress = 0;
|
||||||
|
p.downloading_total = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.flags = 0;
|
||||||
|
if (is_interesting()) p.flags |= peer_info::interesting;
|
||||||
|
if (is_choked()) p.flags |= peer_info::choked;
|
||||||
|
if (is_peer_interested()) p.flags |= peer_info::remote_interested;
|
||||||
|
if (has_peer_choked()) p.flags |= peer_info::remote_choked;
|
||||||
|
if (is_local()) p.flags |= peer_info::local_connection;
|
||||||
|
if (!is_connecting() && m_server_string.empty())
|
||||||
|
p.flags |= peer_info::handshake;
|
||||||
|
if (is_connecting() && !is_queued()) p.flags |= peer_info::connecting;
|
||||||
|
if (is_queued()) p.flags |= peer_info::queued;
|
||||||
|
|
||||||
|
p.pieces = get_bitfield();
|
||||||
|
p.seed = is_seed();
|
||||||
|
|
||||||
|
p.client = m_server_string;
|
||||||
|
p.connection_type = peer_info::web_seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// throws exception when the client should be disconnected
|
||||||
|
void web_peer_connection::on_sent(asio::error const& error
|
||||||
|
, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (error) return;
|
||||||
|
m_statistics.sent_bytes(0, bytes_transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void web_peer_connection::check_invariant() const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
assert(m_num_pieces == std::count(
|
||||||
|
m_have_piece.begin()
|
||||||
|
, m_have_piece.end()
|
||||||
|
, true));
|
||||||
|
*/ }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -15,5 +15,6 @@ test-suite libtorrent :
|
||||||
[ run test_bencoding.cpp ]
|
[ run test_bencoding.cpp ]
|
||||||
[ run test_ip_filter.cpp ]
|
[ run test_ip_filter.cpp ]
|
||||||
[ run test_hasher.cpp ]
|
[ run test_hasher.cpp ]
|
||||||
|
[ run test_metadata_extension.cpp ]
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
bin_PROGRAMS = test_hasher test_bencoding test_ip_filter test_piece_picker test_storage
|
bin_PROGRAMS = test_hasher test_bencoding test_ip_filter test_piece_picker test_storage test_metadata_extension test_buffer
|
||||||
EXTRA_DIST = Jamfile
|
EXTRA_DIST = Jamfile
|
||||||
|
|
||||||
test_hasher_SOURCES = main.cpp test_hasher.cpp
|
test_hasher_SOURCES = main.cpp test_hasher.cpp
|
||||||
|
@ -16,7 +16,13 @@ test_piece_picker_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
test_storage_SOURCES = main.cpp test_storage.cpp
|
test_storage_SOURCES = main.cpp test_storage.cpp
|
||||||
test_storage_LDADD = $(top_builddir)/src/libtorrent.la
|
test_storage_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
|
|
||||||
|
test_buffer_SOURCES = main.cpp test_buffer.cpp
|
||||||
|
test_buffer_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
|
|
||||||
|
test_metadata_extension_SOURCES = main.cpp test_metadata_extension.cpp
|
||||||
|
test_metadata_extension_LDADD = $(top_builddir)/src/libtorrent.la
|
||||||
|
|
||||||
noinst_HEADERS = test.hpp
|
noinst_HEADERS = test.hpp
|
||||||
|
|
||||||
AM_CXXFLAGS=-ftemplate-depth-50 -I$(top_srcdir)/include @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
AM_CXXFLAGS=-ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/asio/include @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
||||||
AM_LDFLAGS= -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
AM_LDFLAGS= -L./ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
||||||
|
|
|
@ -63,8 +63,8 @@ int test_main()
|
||||||
// ** dictionaries **
|
// ** dictionaries **
|
||||||
{
|
{
|
||||||
entry e(entry::dictionary_t);
|
entry e(entry::dictionary_t);
|
||||||
e["cow"] = entry("moo");
|
|
||||||
e["spam"] = entry("eggs");
|
e["spam"] = entry("eggs");
|
||||||
|
e["cow"] = entry("moo");
|
||||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||||
TEST_CHECK(decode(encode(e)) == e);
|
TEST_CHECK(decode(encode(e)) == e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ void test_rules_invariant(std::vector<ip_filter::ip_range> const& r, ip_filter c
|
||||||
TEST_CHECK(!r.empty());
|
TEST_CHECK(!r.empty());
|
||||||
if (r.empty()) return;
|
if (r.empty()) return;
|
||||||
|
|
||||||
TEST_CHECK(r.front().first == address(0,0,0,0,0));
|
TEST_CHECK(r.front().first == address("0.0.0.0"));
|
||||||
TEST_CHECK(r.back().last == address(255,255,255,255,0));
|
TEST_CHECK(r.back().last == address("255.255.255.255"));
|
||||||
|
|
||||||
iterator i = r.begin();
|
iterator i = r.begin();
|
||||||
iterator j = boost::next(i);
|
iterator j = boost::next(i);
|
||||||
|
@ -29,7 +29,7 @@ void test_rules_invariant(std::vector<ip_filter::ip_range> const& r, ip_filter c
|
||||||
{
|
{
|
||||||
TEST_CHECK(f.access(i->last) == i->flags);
|
TEST_CHECK(f.access(i->last) == i->flags);
|
||||||
TEST_CHECK(f.access(j->first) == j->flags);
|
TEST_CHECK(f.access(j->first) == j->flags);
|
||||||
TEST_CHECK(i->last.ip() + 1 == j->first.ip());
|
TEST_CHECK(i->last.to_ulong() + 1 == j->first.to_ulong());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,15 +41,15 @@ int test_main()
|
||||||
// **** test joining of ranges at the end ****
|
// **** test joining of ranges at the end ****
|
||||||
ip_filter::ip_range expected1[] =
|
ip_filter::ip_range expected1[] =
|
||||||
{
|
{
|
||||||
{address(0,0,0,0,0), address(0,255,255,255,0), 0}
|
{address("0.0.0.0"), address("0.255.255.255"), 0}
|
||||||
, {address(1,0,0,0,0), address(3,0,0,0,0), ip_filter::blocked}
|
, {address("1.0.0.0"), address("3.0.0.0"), ip_filter::blocked}
|
||||||
, {address(3,0,0,1,0), address(255,255,255,255,0), 0}
|
, {address("3.0.0.1"), address("255.255.255.255"), 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("2.0.0.1"), address("3.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -62,8 +62,8 @@ int test_main()
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("2.0.0.1"), address("3.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -77,8 +77,8 @@ int test_main()
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("2.0.0.1"), address("3.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,4,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.4.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -92,8 +92,8 @@ int test_main()
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,4,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.4.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(2,0,0,1,0), address(3,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("2.0.0.1"), address("3.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -107,12 +107,12 @@ int test_main()
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(3,0,0,0,0), address(4,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("3.0.0.0"), address("4.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(5,0,0,0,0), address(6,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("5.0.0.0"), address("6.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(7,0,0,0,0), address(8,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("7.0.0.0"), address("8.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
f.add_rule(address(1,0,1,0,0), address(9,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.1.0"), address("9.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -120,9 +120,9 @@ int test_main()
|
||||||
TEST_CHECK(range.size() == 3);
|
TEST_CHECK(range.size() == 3);
|
||||||
ip_filter::ip_range expected[] =
|
ip_filter::ip_range expected[] =
|
||||||
{
|
{
|
||||||
{address(0,0,0,0,0), address(0,255,255,255,0), 0}
|
{address("0.0.0.0"), address("0.255.255.255"), 0}
|
||||||
, {address(1,0,0,0,0), address(9,0,0,0,0), ip_filter::blocked}
|
, {address("1.0.0.0"), address("9.0.0.0"), ip_filter::blocked}
|
||||||
, {address(9,0,0,1,0), address(255,255,255,255,0), 0}
|
, {address("9.0.0.1"), address("255.255.255.255"), 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare));
|
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare));
|
||||||
|
@ -132,12 +132,12 @@ int test_main()
|
||||||
|
|
||||||
{
|
{
|
||||||
ip_filter f;
|
ip_filter f;
|
||||||
f.add_rule(address(1,0,0,0,0), address(2,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("1.0.0.0"), address("2.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(3,0,0,0,0), address(4,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("3.0.0.0"), address("4.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(5,0,0,0,0), address(6,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("5.0.0.0"), address("6.0.0.0"), ip_filter::blocked);
|
||||||
f.add_rule(address(7,0,0,0,0), address(8,0,0,0,0), ip_filter::blocked);
|
f.add_rule(address("7.0.0.0"), address("8.0.0.0"), ip_filter::blocked);
|
||||||
|
|
||||||
f.add_rule(address(0,0,1,0,0), address(7,0,4,0,0), ip_filter::blocked);
|
f.add_rule(address("0.0.1.0"), address("7.0.4.0"), ip_filter::blocked);
|
||||||
|
|
||||||
range = f.export_filter();
|
range = f.export_filter();
|
||||||
test_rules_invariant(range, f);
|
test_rules_invariant(range, f);
|
||||||
|
@ -145,9 +145,9 @@ int test_main()
|
||||||
TEST_CHECK(range.size() == 3);
|
TEST_CHECK(range.size() == 3);
|
||||||
ip_filter::ip_range expected[] =
|
ip_filter::ip_range expected[] =
|
||||||
{
|
{
|
||||||
{address(0,0,0,0,0), address(0,0,0,255,0), 0}
|
{address("0.0.0.0"), address("0.0.0.255"), 0}
|
||||||
, {address(0,0,1,0,0), address(8,0,0,0,0), ip_filter::blocked}
|
, {address("0.0.1.0"), address("8.0.0.0"), ip_filter::blocked}
|
||||||
, {address(8,0,0,1,0), address(255,255,255,255,0), 0}
|
, {address("8.0.0.1"), address("255.255.255.255"), 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare));
|
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare));
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
#include "libtorrent/hasher.hpp"
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#include "test.hpp"
|
||||||
|
|
||||||
|
void sleep(int msec)
|
||||||
|
{
|
||||||
|
boost::xtime xt;
|
||||||
|
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||||
|
xt.nsec += msec * 1000000;
|
||||||
|
boost::thread::sleep(xt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_transfer(char const* tracker_url, libtorrent::torrent_info const& t)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
session ses1;
|
||||||
|
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
|
||||||
|
|
||||||
|
// they should not use the same save dir, because the
|
||||||
|
// file pool will complain if two torrents are trying to
|
||||||
|
// use the same files
|
||||||
|
torrent_handle tor1 = ses1.add_torrent(t, "./tmp1");
|
||||||
|
torrent_handle tor2 = ses2.add_torrent(tracker_url
|
||||||
|
, t.info_hash(), "./tmp2");
|
||||||
|
|
||||||
|
std::cerr << "waiting for file check to complete\n";
|
||||||
|
|
||||||
|
// wait for 5 seconds or until the torrent is in a state
|
||||||
|
// were it can accept connections
|
||||||
|
for (int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
torrent_status st = tor1.status();
|
||||||
|
if (st.state != torrent_status::queued_for_checking
|
||||||
|
&&st.state != torrent_status::checking_files)
|
||||||
|
break;
|
||||||
|
sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "connecting peer\n";
|
||||||
|
tor1.connect_peer(tcp::endpoint(ses2.listen_port(), "127.0.0.1"));
|
||||||
|
|
||||||
|
for (int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
// make sure this function can be called on
|
||||||
|
// torrents without metadata
|
||||||
|
tor2.status();
|
||||||
|
if (tor2.has_metadata()) break;
|
||||||
|
sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "metadata received. waiting for transfer to complete\n";
|
||||||
|
TEST_CHECK(tor2.has_metadata());
|
||||||
|
|
||||||
|
for (int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
tor2.status();
|
||||||
|
if (tor2.is_seed()) break;
|
||||||
|
sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "done\n";
|
||||||
|
TEST_CHECK(tor2.is_seed());
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
using namespace boost::filesystem;
|
||||||
|
|
||||||
|
char const* tracker_url = "http://non-existant-name.com/announce";
|
||||||
|
|
||||||
|
torrent_info t;
|
||||||
|
t.add_file(path("temporary"), 42);
|
||||||
|
t.set_piece_size(256 * 1024);
|
||||||
|
t.add_tracker(tracker_url);
|
||||||
|
|
||||||
|
std::vector<char> piece(42);
|
||||||
|
std::fill(piece.begin(), piece.end(), 0xfe);
|
||||||
|
|
||||||
|
// calculate the hash for all pieces
|
||||||
|
int num = t.num_pieces();
|
||||||
|
for (int i = 0; i < num; ++i)
|
||||||
|
{
|
||||||
|
t.set_hash(i, hasher(&piece[0], piece.size()).final());
|
||||||
|
}
|
||||||
|
|
||||||
|
create_directory("./tmp1");
|
||||||
|
std::ofstream file("./tmp1/temporary");
|
||||||
|
file.write(&piece[0], piece.size());
|
||||||
|
file.close();
|
||||||
|
remove_all("./tmp2/temporary");
|
||||||
|
|
||||||
|
t.create_torrent();
|
||||||
|
|
||||||
|
// test where one has data and one doesn't
|
||||||
|
test_transfer(tracker_url, t);
|
||||||
|
|
||||||
|
// test where both have data (to trigger the file check)
|
||||||
|
test_transfer(tracker_url, t);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ int test_main()
|
||||||
const int num_pieces = 6;
|
const int num_pieces = 6;
|
||||||
|
|
||||||
// 4 blocks per piece
|
// 4 blocks per piece
|
||||||
piece_picker p(4, num_pieces * 4);
|
piece_picker p(4, num_pieces * 4, 7);
|
||||||
|
|
||||||
// we have the first piece
|
// we have the first piece
|
||||||
std::vector<bool> have(num_pieces, false);
|
std::vector<bool> have(num_pieces, false);
|
||||||
|
@ -86,21 +86,21 @@ int test_main()
|
||||||
|
|
||||||
std::vector<piece_block> picked;
|
std::vector<piece_block> picked;
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer1, picked, 1, false, address());
|
p.pick_pieces(peer1, picked, 1, false, tcp::endpoint());
|
||||||
TEST_CHECK(picked.size() == 1);
|
TEST_CHECK(picked.size() == 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 2);
|
TEST_CHECK(picked.front().piece_index == 2);
|
||||||
|
|
||||||
// now pick a piece from peer2. The block is supposed to be
|
// now pick a piece from peer2. The block is supposed to be
|
||||||
// from piece 3, since it is the rarest piece that peer has.
|
// from piece 3, since it is the rarest piece that peer has.
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer2, picked, 1, false, address());
|
p.pick_pieces(peer2, picked, 1, false, tcp::endpoint());
|
||||||
TEST_CHECK(picked.size() == 1);
|
TEST_CHECK(picked.size() == 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 3);
|
TEST_CHECK(picked.front().piece_index == 3);
|
||||||
|
|
||||||
// same thing for peer3.
|
// same thing for peer3.
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer3, picked, 1, false, address());
|
p.pick_pieces(peer3, picked, 1, false, tcp::endpoint());
|
||||||
TEST_CHECK(picked.size() == 1);
|
TEST_CHECK(picked.size() == 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 5);
|
TEST_CHECK(picked.front().piece_index == 5);
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ int test_main()
|
||||||
p.inc_refcount(1);
|
p.inc_refcount(1);
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer3, picked, 1, false, address());
|
p.pick_pieces(peer3, picked, 1, false, tcp::endpoint());
|
||||||
TEST_CHECK(picked.size() == 1);
|
TEST_CHECK(picked.size() == 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
TEST_CHECK(picked.front().piece_index == 1);
|
||||||
// and the block picked should not be 0 or 2
|
// and the block picked should not be 0 or 2
|
||||||
|
@ -138,9 +138,9 @@ int test_main()
|
||||||
|
|
||||||
// we have block 0 and 2 already, so we can't mark
|
// we have block 0 and 2 already, so we can't mark
|
||||||
// them as begin downloaded.
|
// them as begin downloaded.
|
||||||
p.mark_as_downloading(piece_block(1, 1), address(1,1,1,1,0));
|
p.mark_as_downloading(piece_block(1, 1), tcp::endpoint(0, address("1.1.1.1")));
|
||||||
p.mark_as_downloading(piece_block(1, 3), address(1,1,1,1,0));
|
p.mark_as_downloading(piece_block(1, 3), tcp::endpoint(0, address("1.1.1.1")));
|
||||||
p.mark_as_downloading(piece_block(2, 0), address(1,1,1,1,0));
|
p.mark_as_downloading(piece_block(2, 0), tcp::endpoint(0, address("1.1.1.1")));
|
||||||
|
|
||||||
std::vector<piece_picker::downloading_piece> const& downloads = p.get_download_queue();
|
std::vector<piece_picker::downloading_piece> const& downloads = p.get_download_queue();
|
||||||
TEST_CHECK(downloads.size() == 2);
|
TEST_CHECK(downloads.size() == 2);
|
||||||
|
@ -168,7 +168,7 @@ int test_main()
|
||||||
TEST_CHECK(!p.is_downloading(piece_block(2, 1)));
|
TEST_CHECK(!p.is_downloading(piece_block(2, 1)));
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer1, picked, 1, false, address());
|
p.pick_pieces(peer1, picked, 1, false, tcp::endpoint());
|
||||||
TEST_CHECK(picked.size() == 2);
|
TEST_CHECK(picked.size() == 2);
|
||||||
|
|
||||||
piece_block expected3[] = { piece_block(2, 0), piece_block(2, 1) };
|
piece_block expected3[] = { piece_block(2, 0), piece_block(2, 1) };
|
||||||
|
@ -181,7 +181,7 @@ int test_main()
|
||||||
// partially selected)
|
// partially selected)
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer1, picked, 1, true, address());
|
p.pick_pieces(peer1, picked, 1, true, tcp::endpoint());
|
||||||
|
|
||||||
// it will pick 4 blocks, since we said we
|
// it will pick 4 blocks, since we said we
|
||||||
// wanted whole pieces.
|
// wanted whole pieces.
|
||||||
|
@ -199,7 +199,7 @@ int test_main()
|
||||||
// to make sure it can still fall back on partial pieces
|
// to make sure it can still fall back on partial pieces
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer1, picked, 100, true, address());
|
p.pick_pieces(peer1, picked, 100, true, tcp::endpoint());
|
||||||
|
|
||||||
TEST_CHECK(picked.size() == 14);
|
TEST_CHECK(picked.size() == 14);
|
||||||
|
|
||||||
|
@ -221,13 +221,8 @@ int test_main()
|
||||||
// to make sure it can still fall back on partial pieces
|
// to make sure it can still fall back on partial pieces
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p.pick_pieces(peer1, picked, 100, true, address(1,1,1,1,0));
|
p.pick_pieces(peer1, picked, 100, true, tcp::endpoint(0, address("1.1.1.1")));
|
||||||
|
|
||||||
for (std::vector<piece_block>::iterator i = picked.begin(); i != picked.end(); ++i)
|
|
||||||
{
|
|
||||||
std::cerr << "(" << i->piece_index << "," << i->block_index << ")\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CHECK(picked.size() == 11);
|
TEST_CHECK(picked.size() == 11);
|
||||||
|
|
||||||
piece_block expected6[] =
|
piece_block expected6[] =
|
||||||
|
@ -245,7 +240,7 @@ int test_main()
|
||||||
|
|
||||||
// make sure the piece picker allows filtered pieces
|
// make sure the piece picker allows filtered pieces
|
||||||
// to become available
|
// to become available
|
||||||
p.mark_as_finished(piece_block(4, 2), address());
|
p.mark_as_finished(piece_block(4, 2), tcp::endpoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -79,12 +79,17 @@ int test_main()
|
||||||
libtorrent::detail::piece_checker_data d;
|
libtorrent::detail::piece_checker_data d;
|
||||||
|
|
||||||
std::vector<bool> pieces;
|
std::vector<bool> pieces;
|
||||||
TEST_CHECK(pm.check_fastresume(d, pieces, true) == false);
|
num_pieces = 0;
|
||||||
|
TEST_CHECK(pm.check_fastresume(d, pieces, num_pieces, true) == false);
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
float progress;
|
float progress;
|
||||||
|
num_pieces = 0;
|
||||||
while (!finished)
|
while (!finished)
|
||||||
boost::tie(finished, progress) = pm.check_files(pieces);
|
boost::tie(finished, progress) = pm.check_files(pieces, num_pieces);
|
||||||
|
|
||||||
|
TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
|
||||||
|
, true));
|
||||||
|
|
||||||
pm.read(piece, 0, 0, piece_size);
|
pm.read(piece, 0, 0, piece_size);
|
||||||
TEST_CHECK(std::equal(piece, piece + piece_size, piece0));
|
TEST_CHECK(std::equal(piece, piece + piece_size, piece0));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue