diff --git a/ChangeLog b/ChangeLog index 54d6be462..7d62ab013 100644 --- a/ChangeLog +++ b/ChangeLog @@ -93,6 +93,7 @@ 1.0.9 release + * fix issue in checking outgoing interfaces (when that option is enabled) * python binding fix for boost-1.60.0 * optimize enumeration of network interfaces on windows * improve reliability of binding listen sockets diff --git a/Makefile.am b/Makefile.am index f3c0ef9df..ca7e224c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,6 +93,8 @@ DOCS_PAGES = \ docs/udp_tracker_protocol.rst \ docs/utp.rst \ docs/streaming.rst \ + docs/tutorial.rst \ + docs/tutorial.html \ docs/reference-Alerts.html \ docs/reference-Bdecoding.html \ docs/reference-Bencoding.html \ diff --git a/docs/contributing.html b/docs/contributing.html index d72c9bad0..1df40233d 100644 --- a/docs/contributing.html +++ b/docs/contributing.html @@ -75,7 +75,9 @@ as explicit_cache).

Finding typos or outdated sections in the documentation. Contributing documentation based on your own experience and experimentation with the library or with BitTorrent in general. Non-reference documentation is very much welcome as well, higher level -descriptions on how to configure libtorrent for various situations for instance.

+descriptions on how to configure libtorrent for various situations for instance. +The reference documentation for libtorrent is generated from the header files. +For updates, please submit a pull request.

@@ -83,7 +85,8 @@ descriptions on how to configure libtorrent for various situations for instance.
Code

Contributing code for new features or bug-fixes is highly welcome. If you're interested in adding a feature but not sure where to start, please contact the mailing list or -#libtorrent @ irc.freenode.net.

+#libtorrent @ irc.freenode.net. For proposed fixes or udpates, please +submit a pull request.

New features might be better support for integrating with other services, new choking algorithms, seeding policies, ports to new platforms etc.

diff --git a/docs/contributing.rst b/docs/contributing.rst index cb93797c2..35307c9e2 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -34,11 +34,14 @@ enumerated on this page, please contact arvid@libtorrent.org or the `mailing lis based on your own experience and experimentation with the library or with BitTorrent in general. Non-reference documentation is very much welcome as well, higher level descriptions on how to configure libtorrent for various situations for instance. + The reference documentation for libtorrent is generated from the header files. + For updates, please submit a `pull request`_. 3. Code Contributing code for new features or bug-fixes is highly welcome. If you're interested in adding a feature but not sure where to start, please contact the `mailing list`_ or - ``#libtorrent`` @ ``irc.freenode.net``. + ``#libtorrent`` @ ``irc.freenode.net``. For proposed fixes or udpates, please + submit a `pull request`_. New features might be better support for integrating with other services, new choking algorithms, seeding policies, ports to new platforms etc. @@ -49,5 +52,7 @@ For outstanding things to do, see the `todo list`_. .. _hacking: hacking.html +.. _`pull request`: https://github.com/arvidn/libtorrent + .. _`todo list`: todo.html diff --git a/docs/features.html b/docs/features.html index 142ddf944..efe362179 100644 --- a/docs/features.html +++ b/docs/features.html @@ -79,7 +79,7 @@ the library.

features

-

libtorrent is under active development. It is an ongoing project. Its +

libtorrent is an ongoing project under active development. Its current state supports and includes the following features:

extensions

@@ -113,22 +113,22 @@ ratio rather than downloading the torrent.

disk management

    -
  • uses a separate disk I/O thread to not have the disk ever block on network or -client interaction. (see threads).
  • -
  • uses asynchronous disk I/O when available (overlapped I/O, kaio, and posix-aio) -to make optimal use of disk bandwidth capacity
  • -
  • supports verifying the SHA-1 hash of pieces in multiple threads, to take full +
  • can use multipled disk I/O threads to not have the disk block network or +client interaction.
  • +
  • supports verifying the SHA-1 hash of pieces in multiple threads, to take advantage of multi core machines.
  • supports files > 2 gigabytes.
  • -
  • fast resume support, a way to get rid of the costly piece check at the +
  • fast resume support, a way to avoid the costly piece check at the start of a resumed torrent. Saves the storage state, piece_picker state -as well as all local peers in a separate fast-resume file.
  • +as well as all local peers in a fast-resume file.
  • has an adjustable read and write disk cache for improved disk throughput.
  • queues torrents for file check, instead of checking all of them in parallel.
  • does not have any requirements on the piece order in a torrent that it resumes. This means it can resume a torrent downloaded by any client.
  • seed mode, where the files on disk are assumed to be complete, and each piece's hash is verified the first time it is requested.
  • +
  • implements an ARC disk cache, tuned for performing well under bittorrent work +loads
diff --git a/docs/features.rst b/docs/features.rst index a2043ae92..47b4a0a9e 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -21,7 +21,7 @@ the library. features ======== -libtorrent is under active development. It is an ongoing project. Its +libtorrent is an ongoing project under active development. Its current state supports and includes the following features: extensions @@ -59,24 +59,22 @@ extensions disk management --------------- -* uses a separate disk I/O thread to not have the disk ever block on network or - client interaction. (see threads_). -* uses asynchronous disk I/O when available (overlapped I/O, kaio, and posix-aio) - to make optimal use of disk bandwidth capacity -* supports verifying the SHA-1 hash of pieces in multiple threads, to take full +* can use multipled disk I/O threads to not have the disk block network or + client interaction. +* supports verifying the SHA-1 hash of pieces in multiple threads, to take advantage of multi core machines. * supports files > 2 gigabytes. -* fast resume support, a way to get rid of the costly piece check at the +* fast resume support, a way to avoid the costly piece check at the start of a resumed torrent. Saves the storage state, piece_picker state - as well as all local peers in a separate fast-resume file. + as well as all local peers in a fast-resume file. * has an adjustable read and write disk cache for improved disk throughput. * queues torrents for file check, instead of checking all of them in parallel. * does not have any requirements on the piece order in a torrent that it resumes. This means it can resume a torrent downloaded by any client. * seed mode, where the files on disk are assumed to be complete, and each piece's hash is verified the first time it is requested. - -.. _threads: manualref.html#threads +* implements an ARC disk cache, tuned for performing well under bittorrent work + loads network ------- diff --git a/docs/hacking.diagram b/docs/hacking.diagram index 02d64968d..d9604ef6e 100644 --- a/docs/hacking.diagram +++ b/docs/hacking.diagram @@ -6,25 +6,25 @@ | "torrent_handle" +--------+ | | +---------------------+ "weak" | +--------------+ | | | | "m_connections[]" - | | +-------------+----+ - | | | | - "m_picker" v v | v "peers we are connected to" - +----------------+ +----------++ +-------------------+ - | "piece_picker" |<---+-+ "torrent" ++ +--+ "peer_connection" ++ - +----------------+ | ++----------+| | ++------------------+| - "m_torrent_file" | +-----------+ | +-------------------+ + | | +-------------+ +--+ + | | | | | + "m_picker" v v | v v "peers we are connected to" + +----------------+ +----------++ +-------------------+ + | "piece_picker" |<---+-+ "torrent" ++ +--+ "peer_connection" ++ + +----------------+ | ++----------+| | ++------------------+| + "m_torrent_file" | +-----------+ | +-------------------+ +-------------------+ | | - | "torrent_info" |<---+ | "m_socket" + | "torrent_info" |<---+ | "m_socket" +-------------------+ | | +----------------------------+ | +->| "socket_type (variant)" | "m_peer_list" v | | "(TCP/uTP/SSL/socks5/...)" | +--------------+ | +----------------------------+ - | "peer_list" | | + | "peer_list" | | +------------+-+ | "m_peer_info" "list of all" | "m_peers[]" | "contains contact information" "peers we" | | "for peers we're not necessarily" "know of" | v "connected to" - | +----------------+ + | +----------------+ +---->| "torrent_peer" ++ ++---------------+| +----------------+ diff --git a/docs/index.html b/docs/index.html index 1e81365de..205b158bb 100644 --- a/docs/index.html +++ b/docs/index.html @@ -47,14 +47,13 @@
  • download
  • -
  • download python binding
  • features
  • -
  • contributing
  • -
  • building libtorrent
  • examples
  • -
  • library overview
  • +
  • overview
  • reference documentation
  • -
  • troubleshooting issues
  • +
  • contributing
  • +
  • building
  • +
  • troubleshooting
  • tuning
  • screenshot
  • mailing list (archive)
  • @@ -125,8 +124,8 @@ list or posted to the

    Acknowledgements

    -

    Written by Arvid Norberg. Copyright © 2003-2015

    -

    Contributions by Magnus Jonsson, Daniel Wallin and Cory Nelson

    +

    Written by Arvid Norberg. Copyright © 2003-2016

    +

    Contributions by Steven Siloti, Magnus Jonsson, Daniel Wallin and Cory Nelson

    Thanks to Reimond Retz for bugfixes, suggestions and testing

    Thanks to Umeå University for providing development and test hardware.

    Project is hosted by github.

    diff --git a/docs/index.rst b/docs/index.rst index 0141d7193..3543475f4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,14 +6,14 @@
    * download_ -* `download python binding`_ * features_ -* contributing_ -* `building libtorrent`_ +* tutorial_ * examples_ -* `library overview`_ +* overview_ * `reference documentation`_ -* `troubleshooting issues`_ +* contributing_ +* building_ +* troubleshooting_ * `tuning`_ * screenshot_ * `mailing list`_ (archive_) @@ -58,14 +58,14 @@ libtorrent ========== .. _download: https://github.com/arvidn/libtorrent/releases -.. _`download python binding`: https://sourceforge.net/projects/libtorrent/files/py-libtorrent/ .. _features: features.html +.. _tutorial: tutorial.html .. _contributing: contributing.html -.. _`building libtorrent`: building.html +.. _building: building.html .. _examples: examples.html -.. _`library overview`: manual-ref.html +.. _overview: manual-ref.html .. _`reference documentation`: reference.html -.. _`troubleshooting issues`: troubleshooting.html +.. _troubleshooting: troubleshooting.html .. _`tuning`: tuning.html .. _screenshot: client_test.png .. _`uTP`: utp.html @@ -104,7 +104,6 @@ The main goals of libtorrent are: * to be memory efficient * to be very easy to use - Donate ====== @@ -147,9 +146,9 @@ list or posted to the `bug tracker`_. Acknowledgements ================ -Written by Arvid Norberg. Copyright |copy| 2003-2015 +Written by Arvid Norberg. Copyright |copy| 2003-2016 -Contributions by Magnus Jonsson, Daniel Wallin and Cory Nelson +Contributions by Steven Siloti, Magnus Jonsson, Daniel Wallin and Cory Nelson Thanks to Reimond Retz for bugfixes, suggestions and testing diff --git a/docs/makefile b/docs/makefile index 9499fd6ab..972099b5f 100644 --- a/docs/makefile +++ b/docs/makefile @@ -44,6 +44,7 @@ TARGETS = index \ tuning \ hacking \ streaming \ + tutorial \ $(REFERENCE_TARGETS) FIGURES = \ diff --git a/docs/manual.rst b/docs/manual.rst index 58eef1341..81036ed84 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -37,7 +37,10 @@ The basic usage is as follows: * save session state (see save_state()) * destruct session object -Each class and function is described in this manual. +Each class and function is described in this manual, you may want to have a +look at the tutorial_ as well. + +.. _tutorial: tutorial.html For a description on how to create torrent files, see create_torrent. diff --git a/docs/todo.html b/docs/todo.html index 281ff6b5d..4d759622a 100644 --- a/docs/todo.html +++ b/docs/todo.html @@ -349,8 +349,8 @@ unchoking

    ../src/session_impl.cpp:4105

    relevance 3../src/torrent.cpp:9593this really needs to be moved to do_async_save_resume_data. flags need to be passed on

    this really needs to be moved to do_async_save_resume_data. -flags need to be passed on

    ../src/torrent.cpp:9593

    				alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
    +
    relevance 3../src/torrent.cpp:9611this really needs to be moved to do_async_save_resume_data. flags need to be passed on

    this really needs to be moved to do_async_save_resume_data. +flags need to be passed on

    ../src/torrent.cpp:9611

    				alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
     					, m_error);
     				return;
     			}
    @@ -2579,9 +2579,9 @@ session host resolver interface

    ../src/torrent.cpp:4941

    relevance 2../src/torrent.cpp:8109if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)

    if peer is a really good peer, maybe we shouldn't disconnect it +

    relevance 2../src/torrent.cpp:8127if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)

    if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers -(with some definition of idle)

    ../src/torrent.cpp:8109

    #ifndef TORRENT_DISABLE_LOGGING
    +(with some definition of idle)

    ../src/torrent.cpp:8127

    #ifndef TORRENT_DISABLE_LOGGING
     		debug_log("incoming peer (%d)", int(m_connections.size()));
     #endif
     
    @@ -4341,9 +4341,9 @@ it may pose an issue when downgrading though

    ../src/torrent.cpp:7227

    relevance 1../src/torrent.cpp:8453should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though

    should disconnect all peers that have the pieces we have +

    relevance 1../src/torrent.cpp:8471should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though

    should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces -for all peers though

    ../src/torrent.cpp:8453

    +for all peers though

    ../src/torrent.cpp:8471

     		set_state(torrent_status::finished);
     		set_queue_position(-1);
     
    @@ -8392,25 +8392,25 @@ no one uses merkle torrents

    ../src/torrent.cpp:7059

    relevance 0../src/torrent.cpp:7285make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance. using file_base

    make this more generic to not just work if files have been +

    relevance 0../src/torrent.cpp:7303make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance. using file_base

    make this more generic to not just work if files have been renamed, but also if they have been merged into a single file for instance. -using file_base

    ../src/torrent.cpp:7285

    		pieces.resize(m_torrent_file->num_pieces());
    -		if (!has_picker())
    -		{
    -			std::memset(&pieces[0], m_have_all, pieces.size());
    -		}
    -		else if (has_picker())
    -		{
    -			for (int i = 0, end(pieces.size()); i < end; ++i)
    -				pieces[i] = m_picker->have_piece(i) ? 1 : 0;
    -		}
    +using file_base

    ../src/torrent.cpp:7303

    			if (!has_picker())
    +			{
    +				std::memset(&pieces[0], m_have_all, pieces.size());
    +			}
    +			else if (has_picker())
    +			{
    +				for (int i = 0, end(pieces.size()); i < end; ++i)
    +					pieces[i] = m_picker->have_piece(i) ? 1 : 0;
    +			}
     
    -		if (m_seed_mode)
    -		{
    -			TORRENT_ASSERT(m_verified.size() == pieces.size());
    -			TORRENT_ASSERT(m_verifying.size() == pieces.size());
    -			for (int i = 0, end(pieces.size()); i < end; ++i)
    -				pieces[i] |= m_verified[i] ? 2 : 0;
    +			if (m_seed_mode)
    +			{
    +				TORRENT_ASSERT(m_verified.size() == pieces.size());
    +				TORRENT_ASSERT(m_verifying.size() == pieces.size());
    +				for (int i = 0, end(pieces.size()); i < end; ++i)
    +					pieces[i] |= m_verified[i] ? 2 : 0;
    +			}
     		}
     
     		// write renamed files
    @@ -8445,9 +8445,9 @@ using file_base

    ../src/torrent.cpp:7285

    relevance 0../src/torrent.cpp:9541add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata just to save an empty resume data file

    add a flag to ignore stats, and only care about resume data for +

    relevance 0../src/torrent.cpp:9559add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata just to save an empty resume data file

    add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata -just to save an empty resume data file

    ../src/torrent.cpp:9541

    		if (m_complete != 0xffffff) seeds = m_complete;
    +just to save an empty resume data file

    ../src/torrent.cpp:9559

    		if (m_complete != 0xffffff) seeds = m_complete;
     		else seeds = m_peer_list ? m_peer_list->num_seeds() : 0;
     
     		if (m_incomplete != 0xffffff) downloaders = m_incomplete;
    @@ -8466,7 +8466,7 @@ just to save an empty resume data file

    ../src/torrent.cpp:9541

    	void torrent::save_resume_data(int flags)
     
    { TORRENT_ASSERT(is_single_thread()); @@ -8498,8 +8498,8 @@ just to save an empty resume data file

    ../src/torrent.cpp:9541

    relevance 0../src/torrent.cpp:11168instead of resorting the whole list, insert the peers directly into the right place

    instead of resorting the whole list, insert the peers -directly into the right place

    ../src/torrent.cpp:11168

    				printf("timed out [average-piece-time: %d ms ]\n"
    +
    relevance 0../src/torrent.cpp:11186instead of resorting the whole list, insert the peers directly into the right place

    instead of resorting the whole list, insert the peers +directly into the right place

    ../src/torrent.cpp:11186

    				printf("timed out [average-piece-time: %d ms ]\n"
     					, m_average_piece_time);
     #endif
     			}
    diff --git a/docs/tutorial.rst b/docs/tutorial.rst
    new file mode 100644
    index 000000000..cd165f650
    --- /dev/null
    +++ b/docs/tutorial.rst
    @@ -0,0 +1,125 @@
    +=================
    +libtorrent manual
    +=================
    +
    +:Author: Arvid Norberg, arvid@libtorrent.org
    +:Version: 1.1.0
    +
    +.. contents:: Table of contents
    +  :depth: 2
    +  :backlinks: none
    +
    +tutorial
    +========
    +
    +The fundamental feature of starting and downloading torrents in libtorrent is
    +achieved by creating a *session*, which provides the context and a container for
    +torrents. This is done with via the session_ class, most of its interface is
    +documented under session_handle_ though.
    +
    +To add a torrent to the session, you fill in an add_torrent_params_ object and
    +pass it either to `add_torrent()`_ or `async_add_torrent()`_.
    +
    +``add_torrent()`` is a blocking call which returns a torrent_handle_.
    +
    +For example:
    +
    +.. code:: c++
    +
    +	#include 
    +	#include 
    +	#include 
    +	
    +	namespace lt = libtorrent;
    +	int main(int argc, char const* argv[])
    +	{
    +		if (argc != 2) {
    +			fprintf(stderr, "usage: %s \n");
    +			return 1;
    +		}
    +		lt::session ses;
    +
    +		lt::add_torrent_params atp;
    +		atp.url = argv[1];
    +		atp.save_path = "."; // save in current dir
    +		lt::torrent_handle h = ses.add_torrent(atp);
    +
    +		// ...
    +	}
    +
    +Once you have a torrent_handle_, you can affect it as well as querying status.
    +First, let's extend the example to print out messages from the bittorrent engine
    +about progress and events happening under the hood. libtorrent has a mechanism
    +referred to as *alerts* to communicate back information to the client application.
    +
    +Clients can poll libtorrents for new alerts via the `pop_alerts()`_ call on the
    +session object. This call fills in a vector of alert pointers with all new
    +alerts since the last call to this function. The pointers are owned by the
    +session object at will become invalidated by the next call to `pop_alerts()`_.
    +
    +The alerts form a class hierarchy with alert_ as the root class. Each specific
    +kind of alert may include additional state, specific to the kind of message. All
    +alerts implement a message() function that prints out pertinent information
    +of the alert message. This can be convenient for simply logging events.
    +
    +For programatically react to certain events, use `alert_cast<>`_ to attempt
    +a down cast of an alert object to a more specific type.
    +
    +In order to print out events from libtorrent as well as exiting when the torrent
    +completes downloading, we can poll the session for alerts periodically and print
    +them out, as well as listening for the torrent_finished_alert_, which is posted
    +when a torrent completes.
    +
    +.. code:: c++
    +
    +	#include 
    +	
    +	#include 
    +	#include 
    +	#include 
    +	#include 
    +	
    +	namespace lt = libtorrent;
    +	int main(int argc, char const* argv[])
    +	{
    +		if (argc != 2) {
    +			std::cerr << "usage: " << argv[0] << " " << std::endl;
    +			return 1;
    +		}
    +		lt::session ses;
    +
    +		lt::add_torrent_params atp;
    +		atp.url = argv[1];
    +		atp.save_path = "."; // save in current dir
    +		lt::torrent_handle h = ses.add_torrent(atp);
    +
    +		bool done = false;
    +		while (!done) {
    +			std::vector alerts;
    +			ses.pop_alerts(&alerts);
    +
    +			for (lt::alert const* a : alerts) {
    +				std::cout << a->message() << std::endl;
    +				if (lt::alert_cast(a)) {
    +					done = true;
    +				}
    +			}
    +		}
    +	}
    +
    +*TODO* cover async_add_torrent()
    +*TODO* cover post_torrent_updates()
    +*TODO* cover save_resume_data()
    +
    +.. _session: reference-Core.html#session
    +.. _session_handle: reference-Core.html#session_handle
    +.. _add_torrent_params: reference-Core.html#add_torrent_params
    +.. _`add_torrent()`: reference-Core.html#add_torrent()
    +.. _`async_add_torrent()`: reference-Core.html#add_torrent()
    +.. _torrent_handle: reference-Core.html#torrent_handle
    +.. _`pop_alerts()`: reference-Core.html#pop_alerts()
    +.. _`alert`: reference-Alerts.html#alert
    +.. _`alert_cast<>`: reference-Alerts.html#alert_cast()
    +.. _torrent_finished_alert: reference-Alerts.html#torrent-finished-alert
    +
    +
    diff --git a/include/libtorrent/alert.hpp b/include/libtorrent/alert.hpp
    index 7b0487f0e..08751de51 100644
    --- a/include/libtorrent/alert.hpp
    +++ b/include/libtorrent/alert.hpp
    @@ -310,15 +310,13 @@ namespace libtorrent {
     
     // When you get an alert, you can use ``alert_cast<>`` to attempt to cast the pointer to a
     // more specific alert type, in order to query it for more information.
    -template 
    -T* alert_cast(alert* a)
    +template  T* alert_cast(alert* a)
     {
     	if (a == 0) return 0;
     	if (a->type() == T::alert_type) return static_cast(a);
     	return 0;
     }
    -template 
    -T const* alert_cast(alert const* a)
    +template  T const* alert_cast(alert const* a)
     {
     	if (a == 0) return 0;
     	if (a->type() == T::alert_type) return static_cast(a);
    diff --git a/src/torrent.cpp b/src/torrent.cpp
    index 85e9bc1dc..964690d40 100644
    --- a/src/torrent.cpp
    +++ b/src/torrent.cpp
    @@ -6752,9 +6752,6 @@ namespace libtorrent
     		// bit 0: set if we have the piece
     		// bit 1: set if we have verified the piece (in seed mode)
     		bool const is_checking = state() == torrent_status::checking_files;
    -		bool const has_checked = state() == torrent_status::downloading
    -			|| state() == torrent_status::finished
    -			|| state() == torrent_status::seeding;
     
     		// if we are checking, only save the have_pieces bitfield up to the piece
     		// we have actually checked. This allows us to resume the checking when we
    @@ -6763,7 +6760,7 @@ namespace libtorrent
     		// bitfield.
     		int const max_piece
     			= is_checking ? m_num_checked_pieces
    -			: has_checked ? m_torrent_file->num_pieces()
    +			: m_files_checked ? m_torrent_file->num_pieces()
     			: 0;
     
     		if (max_piece > 0)
    diff --git a/src/utp_socket_manager.cpp b/src/utp_socket_manager.cpp
    index 2392ad365..c6cb1ee4b 100644
    --- a/src/utp_socket_manager.cpp
    +++ b/src/utp_socket_manager.cpp
    @@ -195,13 +195,13 @@ namespace libtorrent
     			if (is_any(i->destination) && i->destination.is_v4() == remote.is_v4())
     			{
     				best = &*i;
    -				continue;
    +				break;
     			}
     
     			if (match_addr_mask(remote, i->destination, i->netmask))
     			{
     				best = &*i;
    -				continue;
    +				break;
     			}
     		}