merged RC_1_1
This commit is contained in:
commit
0b173c6651
|
@ -91,6 +91,9 @@ script:
|
||||||
|
|
||||||
- cd ../examples
|
- cd ../examples
|
||||||
- bjam --hash -j3 warnings-as-errors=on variant=$variant $toolset link=shared
|
- bjam --hash -j3 warnings-as-errors=on variant=$variant $toolset link=shared
|
||||||
|
- if [[ lang == "cpp11" ]]; then
|
||||||
|
bjam --hash -j3 warnings-as-errors=on variant=$variant $toolset link=shared bt-get bt-get2;
|
||||||
|
fi
|
||||||
- cd ..
|
- cd ..
|
||||||
|
|
||||||
# build libtorrent separately and install it in a temporary (well known) dir
|
# build libtorrent separately and install it in a temporary (well known) dir
|
||||||
|
|
|
@ -118,6 +118,9 @@ build_script:
|
||||||
- if not defined x64 (
|
- if not defined x64 (
|
||||||
cd %ROOT_DIRECTORY%\examples
|
cd %ROOT_DIRECTORY%\examples
|
||||||
& b2.exe --hash -j2 %compiler% variant=%variant% linkflags=%linkflags% include=%include% link=shared
|
& b2.exe --hash -j2 %compiler% variant=%variant% linkflags=%linkflags% include=%include% link=shared
|
||||||
|
& if %compiler% == msvc-14.0 ( b2.exe --hash -j2 %compiler% variant=%variant% linkflags=%linkflags% include=%include% link=shared bt-get bt-get2 )
|
||||||
|
& cd %ROOT_DIRECTORY%\examples
|
||||||
|
& b2.exe --hash -j2 %compiler% variant=%variant% linkflags=%linkflags% include=%include% link=shared
|
||||||
& cd %ROOT_DIRECTORY%\bindings\python
|
& cd %ROOT_DIRECTORY%\bindings\python
|
||||||
& b2.exe --hash -j2 %compiler% stage_module install-dependencies=on variant=%variant% libtorrent-link=shared linkflags=%linkflags% include=%include%
|
& b2.exe --hash -j2 %compiler% stage_module install-dependencies=on variant=%variant% libtorrent-link=shared linkflags=%linkflags% include=%include%
|
||||||
& python test.py
|
& python test.py
|
||||||
|
|
|
@ -149,6 +149,7 @@ def is_visible(desc):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def highlight_signature(s):
|
def highlight_signature(s):
|
||||||
|
s = s.replace('TORRENT_OVERRIDE', 'override').replace('TORRENT_FINAL', 'final')
|
||||||
name = s.split('(', 1)
|
name = s.split('(', 1)
|
||||||
name2 = name[0].split(' ')
|
name2 = name[0].split(' ')
|
||||||
if len(name2[-1]) == 0: return s
|
if len(name2[-1]) == 0: return s
|
||||||
|
@ -273,7 +274,8 @@ def parse_class(lno, lines, filename):
|
||||||
state = 'private'
|
state = 'private'
|
||||||
class_type = 'class'
|
class_type = 'class'
|
||||||
|
|
||||||
name = decl.split(':')[0].replace('class ', '').replace('struct ', '').replace('TORRENT_FINAL', '').strip()
|
decl = decl.replace('TORRENT_FINAL', 'final')
|
||||||
|
name = decl.split(':')[0].replace('class ', '').replace('struct ', '').replace('final', '').strip()
|
||||||
|
|
||||||
|
|
||||||
while lno < len(lines):
|
while lno < len(lines):
|
||||||
|
|
|
@ -70,46 +70,165 @@ 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
|
them out, as well as listening for the torrent_finished_alert_, which is posted
|
||||||
when a torrent completes.
|
when a torrent completes.
|
||||||
|
|
||||||
|
.. include:: ../examples/bt-get.cpp
|
||||||
|
:code: c++
|
||||||
|
:tab-width: 2
|
||||||
|
:start-after: */
|
||||||
|
|
||||||
|
alert masks
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The output from this program will be quite verbose, which is probably a good
|
||||||
|
starting point to get some understanding of what's going on. Alerts are
|
||||||
|
categorized into alert categories. Each category can be enabled and disabled
|
||||||
|
independently via the *alert mask*.
|
||||||
|
|
||||||
|
The alert mask is a configuration option offered by libtorrent. There are many
|
||||||
|
configuration options, see settings_pack_. The alert_mask_ setting is an integer
|
||||||
|
of the `category flags`_ ORed together.
|
||||||
|
|
||||||
|
For instance, to only see the most pertinent alerts, the session can be
|
||||||
|
constructed like this:
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
#include <iostream>
|
lt::settings_pack pack;
|
||||||
|
pack.set_int(lt::settings_pack::alert_mask
|
||||||
|
, lt::alert::error_notification
|
||||||
|
| lt::alert::storage_notification
|
||||||
|
| lt::alert::status_notification);
|
||||||
|
|
||||||
#include <libtorrent/session.hpp>
|
lt::session ses(pack);
|
||||||
#include <libtorrent/add_torrent_params.hpp>
|
|
||||||
#include <libtorrent/torrent_handle.hpp>
|
|
||||||
#include <libtorrent/alert_types.hpp>
|
|
||||||
|
|
||||||
namespace lt = libtorrent;
|
Configuration options can be updated after the session is started by calling
|
||||||
int main(int argc, char const* argv[])
|
`apply_settings()`_. Some settings are best set before starting the session
|
||||||
|
though, like listen_interfaces_, to avoid race conditions. If you start the
|
||||||
|
session with the default settings and then immediately change them, there will
|
||||||
|
still be a window where the default settings apply.
|
||||||
|
|
||||||
|
Changing the settings may trigger listen sockets to close and re-open and
|
||||||
|
NAT-PMP, UPnP updates to be sent. For this reason, it's typically a good idea
|
||||||
|
to batch settings updates into a single call.
|
||||||
|
|
||||||
|
session destruction
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The session destructor is blocking by default. When shutting down, trackers
|
||||||
|
will need to be contacted to stop torrents and other outstanding operations
|
||||||
|
need to be cancelled. Shutting down can sometimes take several seconds,
|
||||||
|
primarily because of trackers that are unresponsive (and time out) and also
|
||||||
|
DNS servers that are unresponsive. DNS lookups are especially difficult to
|
||||||
|
abort when stalled.
|
||||||
|
|
||||||
|
In order to be able to start destruction an wait for it asynchronously, one
|
||||||
|
can call `session::abort()`_.
|
||||||
|
|
||||||
|
This call returns a session_proxy_ object, which is a handle keeping the session
|
||||||
|
state alive while destructing it. It deliberately does not provide any of the
|
||||||
|
session operations, since it's shutting down.
|
||||||
|
|
||||||
|
After having a session_proxy_ object, the session destructor does not block.
|
||||||
|
However, the session_proxy_ destructor *will*.
|
||||||
|
|
||||||
|
This can be used to shut down multiple sessions or other parts of the
|
||||||
|
application in parallel.
|
||||||
|
|
||||||
|
asynchronous operations
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Essentially any call to a member function of session_ or torrent_handle_ that
|
||||||
|
returns a value is a blocking synchronous call. Meaning it will post a message
|
||||||
|
to the main libtorrent thread and wait for a response. Such calls may be
|
||||||
|
expensive, and in applications where stalls should be avoided (such as user
|
||||||
|
interface threads), blocking calls should be avoided.
|
||||||
|
|
||||||
|
In the example above, session::add_torrent() returns a torrent_handle_ and is
|
||||||
|
thus blocking. For higher efficiency, `async_add_torrent()`_ will post a message
|
||||||
|
to the main thread to add a torrent, and post the resulting torrent_handle_ back
|
||||||
|
in an alert (add_torrent_alert_). This is especially useful when adding a lot
|
||||||
|
of torrents in quick succession, as there's no stall in between calls.
|
||||||
|
|
||||||
|
In the example above, we don't actually use the torrent_handle_ for anything, so
|
||||||
|
converting it to use `async_add_torrent()`_ is just a matter of replacing the
|
||||||
|
`add_torrent()`_ call with `async_add_torrent()`_.
|
||||||
|
|
||||||
|
torrent_status_updates
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
To get updates to the status of torrents, call `post_torrent_updates()`_ on the
|
||||||
|
session object. This will cause libtorrent to post a state_update_alert_
|
||||||
|
containing torrent_status_ objects for all torrents whose status has *changed*
|
||||||
|
since the last call to `post_torrent_updates()`_.
|
||||||
|
|
||||||
|
The state_update_alert_ looks something like this:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
struct state_update_alert : alert
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
virtual std::string message() const;
|
||||||
std::cerr << "usage: " << argv[0] << " <magnet-url>" << std::endl;
|
std::vector<torrent_status> status;
|
||||||
return 1;
|
};
|
||||||
}
|
|
||||||
lt::session ses;
|
|
||||||
|
|
||||||
lt::add_torrent_params atp;
|
The ``status`` field only contains the torrent_status_ for torrents with
|
||||||
atp.url = argv[1];
|
updates since the last call. It may be empty if no torrent has updated its
|
||||||
atp.save_path = "."; // save in current dir
|
state. This feature is critical for scalability_.
|
||||||
lt::torrent_handle h = ses.add_torrent(atp);
|
|
||||||
|
|
||||||
bool done = false;
|
See the torrent_status_ object for more information on what is in there.
|
||||||
while (!done) {
|
Perhaps the most interesting fields are ``total_payload_download``,
|
||||||
std::vector<lt::alert*> alerts;
|
``total_payload_upload``, ``num_peers`` and ``state``.
|
||||||
ses.pop_alerts(&alerts);
|
|
||||||
|
|
||||||
for (lt::alert const* a : alerts) {
|
resuming torrents
|
||||||
std::cout << a->message() << std::endl;
|
-----------------
|
||||||
if (lt::alert_cast<lt::torrent_finished_alert>(a)) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*TODO* cover async_add_torrent()
|
Since bittorrent downloads pieces of files in random order, it's not trivial to
|
||||||
*TODO* cover post_torrent_updates()
|
resume a partial download. When resuming a download, the bittorrent engine must
|
||||||
*TODO* cover save_resume_data()
|
restore the state of the downloading torrent, specifically, which parts of the
|
||||||
|
file(s) are downloaded. There are two approaches to doing this:
|
||||||
|
|
||||||
|
1. read every piece of the downloaded files from disk and compare it against the
|
||||||
|
expected hash.
|
||||||
|
2. save to disk the state of which pieces (and partial pieces) are downloaded,
|
||||||
|
and load it back in again when resuming.
|
||||||
|
|
||||||
|
If no resume data is provided with a torrent that's added, libtorrent will
|
||||||
|
employ (1) by default.
|
||||||
|
|
||||||
|
To save resume data, call `save_resume_data()`_ on the torrent_handle_ object.
|
||||||
|
This will ask libtorrent to generate the resume data and post it back in
|
||||||
|
a save_resume_data_alert_. If generating the resume data fails for any reason,
|
||||||
|
a save_resume_data_failed_alert_ is posted instead. Exactly one of those alerts
|
||||||
|
will be posted for every call to `save_resume_data()`_.
|
||||||
|
|
||||||
|
The save_resume_data_alert_ looks something like this:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
struct save_resume_data_alert : torrent_alert
|
||||||
|
{
|
||||||
|
virtual std::string message() const;
|
||||||
|
|
||||||
|
// points to the resume data.
|
||||||
|
boost::shared_ptr<entry> resume_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
``resume_data`` points to an entry_ object. This represents a node or a tree
|
||||||
|
of nodes in a bencoded_ structure, which is the native encoding scheme in
|
||||||
|
bittorrent. It can be encoded into a byte buffer or file using `bencode()`_.
|
||||||
|
|
||||||
|
example
|
||||||
|
-------
|
||||||
|
|
||||||
|
Here's an updated version of the above example with the following updates:
|
||||||
|
|
||||||
|
1. not using blocking calls
|
||||||
|
2. printing torrent status updates rather than the raw log
|
||||||
|
3. saving and loading resume files
|
||||||
|
|
||||||
|
.. include:: ../examples/bt-get2.cpp
|
||||||
|
:code: c++
|
||||||
|
:tab-width: 2
|
||||||
|
:start-after: */
|
||||||
|
|
||||||
.. _session: reference-Core.html#session
|
.. _session: reference-Core.html#session
|
||||||
.. _session_handle: reference-Core.html#session_handle
|
.. _session_handle: reference-Core.html#session_handle
|
||||||
|
@ -121,5 +240,22 @@ when a torrent completes.
|
||||||
.. _`alert`: reference-Alerts.html#alert
|
.. _`alert`: reference-Alerts.html#alert
|
||||||
.. _`alert_cast<>`: reference-Alerts.html#alert_cast()
|
.. _`alert_cast<>`: reference-Alerts.html#alert_cast()
|
||||||
.. _torrent_finished_alert: reference-Alerts.html#torrent-finished-alert
|
.. _torrent_finished_alert: reference-Alerts.html#torrent-finished-alert
|
||||||
|
.. _listen_interfaces: reference-Settings.html#listen_interfaces
|
||||||
|
.. _`add_torrent_alert`: reference-Alerts.html#add-torrent-alert
|
||||||
|
.. _settings_pack: reference-Settings.html#settings_pack
|
||||||
|
.. _alert_mask: reference-Settings.html#alert_mask
|
||||||
|
.. _`category flags`: reference-Alerts.html#category_t
|
||||||
|
.. _`apply_settings()`: reference-Core.html#apply_settings()
|
||||||
|
.. _`session::abort()`: reference-Core.html#abort()
|
||||||
|
.. _session_proxy: reference-Core.html#session_proxy
|
||||||
|
.. _`post_torrent_updates()`: reference-Core.html#post_torrent_updates()
|
||||||
|
.. _torrent_status: reference-Core.html#torrent_status
|
||||||
|
.. _state_update_alert: reference-Alerts.html#state_update_alert
|
||||||
|
.. _scalability: http://blog.libtorrent.org/2011/11/scalable-interfaces/
|
||||||
|
.. _`save_resume_data()`: reference-Core.html#save_resume_data()
|
||||||
|
.. _save_resume_data_alert: reference-Alerts.html#save_resume_data_alert
|
||||||
|
.. _save_resume_data_failed_alert: reference-Alerts.html#save_resume_data_failed_alert
|
||||||
|
.. _bencoded: https://en.wikipedia.org/wiki/Bencode
|
||||||
|
.. _entry: reference-Bencoding.html#entry
|
||||||
|
.. _`bencode()`: reference-Bencoding.html#bencode()
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ project client_test
|
||||||
exe client_test : client_test.cpp print.cpp torrent_view.cpp session_view.cpp ;
|
exe client_test : client_test.cpp print.cpp torrent_view.cpp session_view.cpp ;
|
||||||
|
|
||||||
exe simple_client : simple_client.cpp ;
|
exe simple_client : simple_client.cpp ;
|
||||||
|
exe bt-get : bt-get.cpp ;
|
||||||
|
exe bt-get2 : bt-get2.cpp ;
|
||||||
exe stats_counters : stats_counters.cpp ;
|
exe stats_counters : stats_counters.cpp ;
|
||||||
exe dump_torrent : dump_torrent.cpp ;
|
exe dump_torrent : dump_torrent.cpp ;
|
||||||
exe make_torrent : make_torrent.cpp ;
|
exe make_torrent : make_torrent.cpp ;
|
||||||
|
@ -28,6 +30,8 @@ exe upnp_test : upnp_test.cpp ;
|
||||||
|
|
||||||
explicit stage_client_test ;
|
explicit stage_client_test ;
|
||||||
explicit stage_connection_tester ;
|
explicit stage_connection_tester ;
|
||||||
|
explicit bt-get ;
|
||||||
|
explicit bt-get2 ;
|
||||||
|
|
||||||
install stage_client_test : client_test : <location>. ;
|
install stage_client_test : client_test : <location>. ;
|
||||||
install stage_connection_tester : connection_tester : <location>. ;
|
install stage_connection_tester : connection_tester : <location>. ;
|
||||||
|
|
|
@ -5,6 +5,8 @@ example_programs = \
|
||||||
make_torrent \
|
make_torrent \
|
||||||
simple_client \
|
simple_client \
|
||||||
upnp_test \
|
upnp_test \
|
||||||
|
bt_get \
|
||||||
|
bt_get2 \
|
||||||
connection_tester
|
connection_tester
|
||||||
|
|
||||||
if ENABLE_EXAMPLES
|
if ENABLE_EXAMPLES
|
||||||
|
@ -15,25 +17,14 @@ EXTRA_PROGRAMS = $(example_programs)
|
||||||
EXTRA_DIST = Jamfile CMakeLists.txt run_cmake.sh.in cmake/FindLibtorrentRasterbar.cmake
|
EXTRA_DIST = Jamfile CMakeLists.txt run_cmake.sh.in cmake/FindLibtorrentRasterbar.cmake
|
||||||
|
|
||||||
client_test_SOURCES = client_test.cpp print.cpp session_view.cpp torrent_view.cpp
|
client_test_SOURCES = client_test.cpp print.cpp session_view.cpp torrent_view.cpp
|
||||||
#client_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
stats_counters_SOURCES = stats_counters.cpp
|
stats_counters_SOURCES = stats_counters.cpp
|
||||||
#stats_counters_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
bt_get_SOURCES = bt-get.cpp
|
||||||
|
bt_get2_SOURCES = bt-get2.cpp
|
||||||
dump_torrent_SOURCES = dump_torrent.cpp
|
dump_torrent_SOURCES = dump_torrent.cpp
|
||||||
#dump_torrent_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
make_torrent_SOURCES = make_torrent.cpp
|
make_torrent_SOURCES = make_torrent.cpp
|
||||||
#make_torrent_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
simple_client_SOURCES = simple_client.cpp
|
simple_client_SOURCES = simple_client.cpp
|
||||||
#simple_client_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
connection_tester_SOURCES = connection_tester.cpp
|
connection_tester_SOURCES = connection_tester.cpp
|
||||||
#connection_tester_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
upnp_test_SOURCES = upnp_test.cpp
|
upnp_test_SOURCES = upnp_test.cpp
|
||||||
#upnp_test_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
|
||||||
|
|
||||||
LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
LDADD = $(top_builddir)/src/libtorrent-rasterbar.la
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016, 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 <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <libtorrent/session.hpp>
|
||||||
|
#include <libtorrent/add_torrent_params.hpp>
|
||||||
|
#include <libtorrent/torrent_handle.hpp>
|
||||||
|
#include <libtorrent/alert_types.hpp>
|
||||||
|
|
||||||
|
namespace lt = libtorrent;
|
||||||
|
int main(int argc, char const* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
std::cerr << "usage: " << argv[0] << " <magnet-url>" << 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);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
std::vector<lt::alert*> alerts;
|
||||||
|
ses.pop_alerts(&alerts);
|
||||||
|
|
||||||
|
for (lt::alert const* a : alerts) {
|
||||||
|
std::cout << a->message() << std::endl;
|
||||||
|
// if we receive the finished alert or an error, we're done
|
||||||
|
if (lt::alert_cast<lt::torrent_finished_alert>(a)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (lt::alert_cast<lt::torrent_error_alert>(a)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
std::cout << "done, shutting down" << std::endl;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016, 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 <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <libtorrent/session.hpp>
|
||||||
|
#include <libtorrent/add_torrent_params.hpp>
|
||||||
|
#include <libtorrent/torrent_handle.hpp>
|
||||||
|
#include <libtorrent/alert_types.hpp>
|
||||||
|
#include <libtorrent/bencode.hpp>
|
||||||
|
#include <libtorrent/torrent_status.hpp>
|
||||||
|
|
||||||
|
namespace lt = libtorrent;
|
||||||
|
|
||||||
|
// return the name of a torrent status enum
|
||||||
|
char const* state(lt::torrent_status::state_t s)
|
||||||
|
{
|
||||||
|
switch(s)
|
||||||
|
{
|
||||||
|
case lt::torrent_status::checking_files: return "checking";
|
||||||
|
case lt::torrent_status::downloading_metadata: return "dl metadata";
|
||||||
|
case lt::torrent_status::downloading: return "downloading";
|
||||||
|
case lt::torrent_status::finished: return "finished";
|
||||||
|
case lt::torrent_status::seeding: return "seeding";
|
||||||
|
case lt::torrent_status::allocating: return "allocating";
|
||||||
|
case lt::torrent_status::checking_resume_data: return "checking resume";
|
||||||
|
default: return "<>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char const* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
std::cerr << "usage: " << argv[0] << " <magnet-url>" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lt::settings_pack pack;
|
||||||
|
pack.set_int(lt::settings_pack::alert_mask
|
||||||
|
, lt::alert::error_notification
|
||||||
|
| lt::alert::storage_notification
|
||||||
|
| lt::alert::status_notification);
|
||||||
|
|
||||||
|
lt::session ses(pack);
|
||||||
|
|
||||||
|
lt::add_torrent_params atp;
|
||||||
|
|
||||||
|
// load resume data from disk and pass it in as we add the magnet link
|
||||||
|
std::ifstream ifs(".resume_file", std::ios_base::binary);
|
||||||
|
ifs.unsetf(std::ios_base::skipws);
|
||||||
|
atp.resume_data.assign(std::istream_iterator<char>(ifs)
|
||||||
|
, std::istream_iterator<char>());
|
||||||
|
atp.url = argv[1];
|
||||||
|
atp.save_path = "."; // save in current dir
|
||||||
|
ses.async_add_torrent(atp);
|
||||||
|
|
||||||
|
// this is the handle we'll set once we get the notification of it being
|
||||||
|
// added
|
||||||
|
lt::torrent_handle h;
|
||||||
|
for (;;) {
|
||||||
|
std::vector<lt::alert*> alerts;
|
||||||
|
ses.pop_alerts(&alerts);
|
||||||
|
|
||||||
|
for (lt::alert const* a : alerts) {
|
||||||
|
if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
|
||||||
|
h = at->handle;
|
||||||
|
}
|
||||||
|
// if we receive the finished alert or an error, we're done
|
||||||
|
if (lt::alert_cast<lt::torrent_finished_alert>(a)) {
|
||||||
|
h.save_resume_data();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (lt::alert_cast<lt::torrent_error_alert>(a)) {
|
||||||
|
std::cout << a->message() << std::endl;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when resume data is ready, save it
|
||||||
|
if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) {
|
||||||
|
std::ofstream of(".resume_file", std::ios_base::binary);
|
||||||
|
of.unsetf(std::ios_base::skipws);
|
||||||
|
lt::bencode(std::ostream_iterator<char>(of)
|
||||||
|
, *rd->resume_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
|
||||||
|
if (st->status.empty()) continue;
|
||||||
|
|
||||||
|
// we only have a single torrent, so we know which one
|
||||||
|
// the status is for
|
||||||
|
lt::torrent_status const& s = st->status[0];
|
||||||
|
std::cout << "\r" << state(s.state) << " "
|
||||||
|
<< (s.download_payload_rate / 1000) << " kB/s "
|
||||||
|
<< (s.total_done / 1000) << " kB ("
|
||||||
|
<< (s.progress_ppm / 10000) << "%) downloaded\x1b[K";
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
|
||||||
|
// ask the session to post a state_update_alert, to update our
|
||||||
|
// state output for the torrent
|
||||||
|
ses.post_torrent_updates();
|
||||||
|
|
||||||
|
// TODO: 3 call save_resume_data() once every 30 seconds or so
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
std::cout << "\ndone, shutting down" << std::endl;
|
||||||
|
}
|
||||||
|
|
|
@ -1366,7 +1366,7 @@ namespace libtorrent
|
||||||
struct TORRENT_EXPORT portmap_alert TORRENT_FINAL : alert
|
struct TORRENT_EXPORT portmap_alert TORRENT_FINAL : alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
portmap_alert(aux::stack_allocator& alloc, int i, int port, int t);
|
portmap_alert(aux::stack_allocator& alloc, int i, int port, int t, int protocol);
|
||||||
|
|
||||||
TORRENT_DEFINE_ALERT(portmap_alert, 51)
|
TORRENT_DEFINE_ALERT(portmap_alert, 51)
|
||||||
|
|
||||||
|
@ -1382,6 +1382,15 @@ namespace libtorrent
|
||||||
|
|
||||||
// 0 for NAT-PMP and 1 for UPnP.
|
// 0 for NAT-PMP and 1 for UPnP.
|
||||||
int map_type;
|
int map_type;
|
||||||
|
|
||||||
|
enum protocol_t
|
||||||
|
{
|
||||||
|
tcp,
|
||||||
|
udp
|
||||||
|
};
|
||||||
|
|
||||||
|
// the protocol this mapping was for. one of protocol_t enums
|
||||||
|
int protocol;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
@ -1942,8 +1951,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_DEFINE_ALERT(dht_error_alert, 73)
|
TORRENT_DEFINE_ALERT(dht_error_alert, 73)
|
||||||
|
|
||||||
static const int static_category = alert::error_notification
|
static const int static_category = alert::error_notification | alert::dht_notification;
|
||||||
| alert::dht_notification;
|
|
||||||
virtual std::string message() const TORRENT_OVERRIDE;
|
virtual std::string message() const TORRENT_OVERRIDE;
|
||||||
|
|
||||||
// the error code
|
// the error code
|
||||||
|
|
|
@ -353,7 +353,7 @@ namespace libtorrent
|
||||||
, std::vector<address> const& addresses, int port);
|
, std::vector<address> const& addresses, int port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void maybe_update_udp_mapping(int nat, int local_port, int external_port);
|
void maybe_update_udp_mapping(int nat, bool ssl, int local_port, int external_port);
|
||||||
|
|
||||||
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
||||||
torrent const* find_encrypted_torrent(
|
torrent const* find_encrypted_torrent(
|
||||||
|
@ -372,7 +372,7 @@ namespace libtorrent
|
||||||
// called when a port mapping is successful, or a router returns
|
// called when a port mapping is successful, or a router returns
|
||||||
// a failure to map a port
|
// a failure to map a port
|
||||||
void on_port_mapping(int mapping, address const& ip, int port
|
void on_port_mapping(int mapping, address const& ip, int port
|
||||||
, error_code const& ec, int nat_transport);
|
, int protocol, error_code const& ec, int nat_transport);
|
||||||
|
|
||||||
bool is_aborted() const TORRENT_OVERRIDE { return m_abort; }
|
bool is_aborted() const TORRENT_OVERRIDE { return m_abort; }
|
||||||
bool is_paused() const TORRENT_OVERRIDE { return m_paused; }
|
bool is_paused() const TORRENT_OVERRIDE { return m_paused; }
|
||||||
|
|
|
@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
||||||
#include <boost/function/function1.hpp>
|
#include <boost/function/function1.hpp>
|
||||||
#include <boost/function/function4.hpp>
|
#include <boost/function/function5.hpp>
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
|
|
||||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||||
|
@ -54,7 +54,7 @@ namespace libtorrent
|
||||||
// int: port mapping index
|
// int: port mapping index
|
||||||
// int: external port
|
// int: external port
|
||||||
// std::string: error message
|
// std::string: error message
|
||||||
typedef boost::function<void(int, address, int, error_code const&)> portmap_callback_t;
|
typedef boost::function<void(int, address, int, int, error_code const&)> portmap_callback_t;
|
||||||
typedef boost::function<void(char const*)> log_callback_t;
|
typedef boost::function<void(char const*)> log_callback_t;
|
||||||
|
|
||||||
class natpmp : public boost::enable_shared_from_this<natpmp>
|
class natpmp : public boost::enable_shared_from_this<natpmp>
|
||||||
|
|
|
@ -662,9 +662,8 @@ namespace libtorrent
|
||||||
only_if_modified = 4
|
only_if_modified = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
// ``save_resume_data()`` generates fast-resume data and returns it as an
|
// ``save_resume_data()`` asks libtorrent to generate fast-resume data for
|
||||||
// entry. This entry is suitable for being bencoded. For more information
|
// this torrent.
|
||||||
// about how fast-resume works, see fast-resume_.
|
|
||||||
//
|
//
|
||||||
// The ``flags`` argument is a bitmask of flags ORed together. see
|
// The ``flags`` argument is a bitmask of flags ORed together. see
|
||||||
// save_resume_flags_t
|
// save_resume_flags_t
|
||||||
|
@ -676,9 +675,7 @@ namespace libtorrent
|
||||||
// The fast resume data will be empty in the following cases:
|
// The fast resume data will be empty in the following cases:
|
||||||
//
|
//
|
||||||
// 1. The torrent handle is invalid.
|
// 1. The torrent handle is invalid.
|
||||||
// 2. The torrent is checking (or is queued for checking) its storage, it
|
// 2. The torrent hasn't received valid metadata and was started without
|
||||||
// will obviously not be ready to write resume data.
|
|
||||||
// 3. The torrent hasn't received valid metadata and was started without
|
|
||||||
// metadata (see libtorrent's metadata-from-peers_ extension)
|
// metadata (see libtorrent's metadata-from-peers_ extension)
|
||||||
//
|
//
|
||||||
// Note that by the time you receive the fast resume data, it may already
|
// Note that by the time you receive the fast resume data, it may already
|
||||||
|
|
|
@ -78,14 +78,7 @@ namespace libtorrent
|
||||||
, dont_queue = 4
|
, dont_queue = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_open() const
|
bool is_open() const { return m_abort == false; }
|
||||||
{
|
|
||||||
return m_ipv4_sock.is_open()
|
|
||||||
#if TORRENT_USE_IPV6
|
|
||||||
|| m_ipv6_sock.is_open()
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
}
|
|
||||||
io_service& get_io_service() { return m_ipv4_sock.get_io_service(); }
|
io_service& get_io_service() { return m_ipv4_sock.get_io_service(); }
|
||||||
|
|
||||||
void subscribe(udp_socket_observer* o);
|
void subscribe(udp_socket_observer* o);
|
||||||
|
@ -143,7 +136,7 @@ namespace libtorrent
|
||||||
|
|
||||||
udp::endpoint proxy_addr() const { return m_proxy_addr; }
|
udp::endpoint proxy_addr() const { return m_proxy_addr; }
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
|
||||||
struct queued_packet
|
struct queued_packet
|
||||||
{
|
{
|
||||||
|
@ -169,12 +162,12 @@ namespace libtorrent
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
udp_socket(udp_socket const&);
|
udp_socket(udp_socket const&);
|
||||||
udp_socket& operator=(udp_socket const&);
|
udp_socket& operator=(udp_socket const&);
|
||||||
|
|
||||||
|
void close_impl();
|
||||||
|
|
||||||
// observers on this udp socket
|
// observers on this udp socket
|
||||||
std::vector<udp_socket_observer*> m_observers;
|
std::vector<udp_socket_observer*> m_observers;
|
||||||
std::vector<udp_socket_observer*> m_added_observers;
|
std::vector<udp_socket_observer*> m_added_observers;
|
||||||
|
|
|
@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/resolver.hpp"
|
#include "libtorrent/resolver.hpp"
|
||||||
|
|
||||||
#include <boost/function/function1.hpp>
|
#include <boost/function/function1.hpp>
|
||||||
#include <boost/function/function4.hpp>
|
#include <boost/function/function5.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
|
@ -100,9 +100,7 @@ namespace libtorrent
|
||||||
// int: external port
|
// int: external port
|
||||||
// std::string: error message
|
// std::string: error message
|
||||||
// an empty string as error means success
|
// an empty string as error means success
|
||||||
// a port-mapping index of -1 means it's
|
typedef boost::function<void(int, address, int, int, error_code const&)> portmap_callback_t;
|
||||||
// an informational log message
|
|
||||||
typedef boost::function<void(int, address, int, error_code const&)> portmap_callback_t;
|
|
||||||
typedef boost::function<void(char const*)> log_callback_t;
|
typedef boost::function<void(char const*)> log_callback_t;
|
||||||
|
|
||||||
struct parse_state
|
struct parse_state
|
||||||
|
|
|
@ -774,6 +774,8 @@ namespace libtorrent {
|
||||||
|
|
||||||
static char const* const nat_type_str[] = {"NAT-PMP", "UPnP"};
|
static char const* const nat_type_str[] = {"NAT-PMP", "UPnP"};
|
||||||
|
|
||||||
|
static char const* const protocol_str[] = {"TCP", "UDP"};
|
||||||
|
|
||||||
static char const* const socket_type_str[] = {
|
static char const* const socket_type_str[] = {
|
||||||
"null",
|
"null",
|
||||||
"TCP",
|
"TCP",
|
||||||
|
@ -907,15 +909,16 @@ namespace libtorrent {
|
||||||
+ ": " + convert_from_native(error.message());
|
+ ": " + convert_from_native(error.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
portmap_alert::portmap_alert(aux::stack_allocator&, int i, int port, int t)
|
portmap_alert::portmap_alert(aux::stack_allocator&, int i, int port, int t
|
||||||
: mapping(i), external_port(port), map_type(t)
|
, int proto)
|
||||||
|
: mapping(i), external_port(port), map_type(t), protocol(proto)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string portmap_alert::message() const
|
std::string portmap_alert::message() const
|
||||||
{
|
{
|
||||||
char ret[200];
|
char ret[200];
|
||||||
snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %u"
|
snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %s/%u"
|
||||||
, nat_type_str[map_type], external_port);
|
, nat_type_str[map_type], protocol_str[protocol], external_port);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,10 +185,11 @@ void natpmp::disable(error_code const& ec, mutex::scoped_lock& l)
|
||||||
, end(m_mappings.end()); i != end; ++i)
|
, end(m_mappings.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
if (i->protocol == none) continue;
|
if (i->protocol == none) continue;
|
||||||
|
int const proto = i->protocol;
|
||||||
i->protocol = none;
|
i->protocol = none;
|
||||||
int index = i - m_mappings.begin();
|
int index = i - m_mappings.begin();
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, address(), 0, ec);
|
m_callback(index, address(), 0, proto, ec);
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
close_impl(l);
|
close_impl(l);
|
||||||
|
@ -563,15 +564,18 @@ void natpmp::on_reply(error_code const& e
|
||||||
if (result >= 1 && result <= 5) ev = errors[result - 1];
|
if (result >= 1 && result <= 5) ev = errors[result - 1];
|
||||||
|
|
||||||
m->expires = aux::time_now() + hours(2);
|
m->expires = aux::time_now() + hours(2);
|
||||||
|
int const proto = m->protocol;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, address(), 0, error_code(ev, get_libtorrent_category()));
|
m_callback(index, address(), 0, proto
|
||||||
|
, error_code(ev, get_libtorrent_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
else if (m->action == mapping_t::action_add)
|
else if (m->action == mapping_t::action_add)
|
||||||
{
|
{
|
||||||
|
int const proto = m->protocol;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(index, m_external_ip, m->external_port,
|
m_callback(index, m_external_ip, m->external_port, proto
|
||||||
error_code(errors::no_error, get_libtorrent_category()));
|
, error_code(errors::no_error, get_libtorrent_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2000,7 +2000,8 @@ namespace aux {
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
created_ssl_udp_socket = true;
|
created_ssl_udp_socket = true;
|
||||||
// TODO: 3 port map SSL udp socket here
|
maybe_update_udp_mapping(0, true, bind_ep.port(), bind_ep.port());
|
||||||
|
maybe_update_udp_mapping(1, true, bind_ep.port(), bind_ep.port());
|
||||||
}
|
}
|
||||||
} while (ec == error_code(error::address_in_use) && retries > 0);
|
} while (ec == error_code(error::address_in_use) && retries > 0);
|
||||||
}
|
}
|
||||||
|
@ -2035,8 +2036,8 @@ namespace aux {
|
||||||
{
|
{
|
||||||
created_udp_socket = true;
|
created_udp_socket = true;
|
||||||
m_external_udp_port = m_udp_socket.local_port();
|
m_external_udp_port = m_udp_socket.local_port();
|
||||||
maybe_update_udp_mapping(0, bind_ep.port(), bind_ep.port());
|
maybe_update_udp_mapping(0, false, bind_ep.port(), bind_ep.port());
|
||||||
maybe_update_udp_mapping(1, bind_ep.port(), bind_ep.port());
|
maybe_update_udp_mapping(1, false, bind_ep.port(), bind_ep.port());
|
||||||
}
|
}
|
||||||
} while (ec == error_code(error::address_in_use) && retries > 0);
|
} while (ec == error_code(error::address_in_use) && retries > 0);
|
||||||
}
|
}
|
||||||
|
@ -2046,11 +2047,39 @@ namespace aux {
|
||||||
// previous one
|
// previous one
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
if (!created_ssl_udp_socket)
|
if (!created_ssl_udp_socket)
|
||||||
|
{
|
||||||
m_ssl_udp_socket.close();
|
m_ssl_udp_socket.close();
|
||||||
|
|
||||||
|
// if there are mappings for the SSL socket, delete them now
|
||||||
|
if (m_ssl_udp_mapping[0] != -1 && m_natpmp)
|
||||||
|
{
|
||||||
|
m_natpmp->delete_mapping(m_ssl_udp_mapping[0]);
|
||||||
|
m_ssl_udp_mapping[0] = -1;
|
||||||
|
}
|
||||||
|
if (m_ssl_udp_mapping[1] != -1 && m_upnp)
|
||||||
|
{
|
||||||
|
m_upnp->delete_mapping(m_ssl_udp_mapping[1]);
|
||||||
|
m_ssl_udp_mapping[1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!created_udp_socket)
|
if (!created_udp_socket)
|
||||||
|
{
|
||||||
m_udp_socket.close();
|
m_udp_socket.close();
|
||||||
|
|
||||||
|
// if there are mappings for the socket, delete them now
|
||||||
|
if (m_udp_mapping[0] != -1 && m_natpmp)
|
||||||
|
{
|
||||||
|
m_natpmp->delete_mapping(m_udp_mapping[0]);
|
||||||
|
m_udp_mapping[0] = -1;
|
||||||
|
}
|
||||||
|
if (m_udp_mapping[1] != -1 && m_upnp)
|
||||||
|
{
|
||||||
|
m_upnp->delete_mapping(m_udp_mapping[1]);
|
||||||
|
m_udp_mapping[1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we made it! now post all the listen_succeeded_alerts
|
// we made it! now post all the listen_succeeded_alerts
|
||||||
|
|
||||||
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
||||||
|
@ -5241,6 +5270,11 @@ namespace aux {
|
||||||
boost::uint16_t session_impl::ssl_listen_port() const
|
boost::uint16_t session_impl::ssl_listen_port() const
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
|
||||||
|
// honor the SSL listen port being disabled
|
||||||
|
if (m_settings.get_int(settings_pack::ssl_listen) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// if peer connections are set up to be received over a socks
|
// if peer connections are set up to be received over a socks
|
||||||
// proxy, and it's the same one as we're using for the tracker
|
// proxy, and it's the same one as we're using for the tracker
|
||||||
// just tell the tracker the socks5 port we're listening on
|
// just tell the tracker the socks5 port we're listening on
|
||||||
|
@ -5317,7 +5351,7 @@ namespace aux {
|
||||||
|
|
||||||
// transport is 0 for NAT-PMP and 1 for UPnP
|
// transport is 0 for NAT-PMP and 1 for UPnP
|
||||||
void session_impl::on_port_mapping(int mapping, address const& ip, int port
|
void session_impl::on_port_mapping(int mapping, address const& ip, int port
|
||||||
, error_code const& ec, int map_transport)
|
, int const protocol, error_code const& ec, int map_transport)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
||||||
|
@ -5334,7 +5368,8 @@ namespace aux {
|
||||||
m_external_udp_port = port;
|
m_external_udp_port = port;
|
||||||
if (m_alerts.should_post<portmap_alert>())
|
if (m_alerts.should_post<portmap_alert>())
|
||||||
m_alerts.emplace_alert<portmap_alert>(mapping, port
|
m_alerts.emplace_alert<portmap_alert>(mapping, port
|
||||||
, map_transport);
|
, map_transport, protocol == natpmp::udp
|
||||||
|
? portmap_alert::udp : portmap_alert::tcp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5361,7 +5396,8 @@ namespace aux {
|
||||||
if (!ec && m_alerts.should_post<portmap_alert>())
|
if (!ec && m_alerts.should_post<portmap_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<portmap_alert>(mapping, port
|
m_alerts.emplace_alert<portmap_alert>(mapping, port
|
||||||
, map_transport);
|
, map_transport, protocol == natpmp::udp
|
||||||
|
? portmap_alert::udp : portmap_alert::tcp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5759,38 +5795,45 @@ namespace aux {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void session_impl::maybe_update_udp_mapping(int nat, int local_port, int external_port)
|
void session_impl::maybe_update_udp_mapping(int const nat, bool const ssl
|
||||||
|
, int const local_port, int const external_port)
|
||||||
{
|
{
|
||||||
int local, external, protocol;
|
int local, external, protocol;
|
||||||
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
|
int* mapping = ssl ? m_ssl_udp_mapping : m_udp_mapping;
|
||||||
|
#else
|
||||||
|
TORRENT_UNUSED(ssl);
|
||||||
|
int* mapping = m_udp_mapping;
|
||||||
|
#endif
|
||||||
if (nat == 0 && m_natpmp)
|
if (nat == 0 && m_natpmp)
|
||||||
{
|
{
|
||||||
if (m_udp_mapping[nat] != -1)
|
if (mapping[nat] != -1)
|
||||||
{
|
{
|
||||||
if (m_natpmp->get_mapping(m_udp_mapping[nat], local, external, protocol))
|
if (m_natpmp->get_mapping(mapping[nat], local, external, protocol))
|
||||||
{
|
{
|
||||||
// we already have a mapping. If it's the same, don't do anything
|
// we already have a mapping. If it's the same, don't do anything
|
||||||
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_natpmp->delete_mapping(m_udp_mapping[nat]);
|
m_natpmp->delete_mapping(mapping[nat]);
|
||||||
}
|
}
|
||||||
m_udp_mapping[nat] = m_natpmp->add_mapping(natpmp::udp
|
mapping[nat] = m_natpmp->add_mapping(natpmp::udp
|
||||||
, local_port, external_port);
|
, local_port, external_port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (nat == 1 && m_upnp)
|
else if (nat == 1 && m_upnp)
|
||||||
{
|
{
|
||||||
if (m_udp_mapping[nat] != -1)
|
if (mapping[nat] != -1)
|
||||||
{
|
{
|
||||||
if (m_upnp->get_mapping(m_udp_mapping[nat], local, external, protocol))
|
if (m_upnp->get_mapping(mapping[nat], local, external, protocol))
|
||||||
{
|
{
|
||||||
// we already have a mapping. If it's the same, don't do anything
|
// we already have a mapping. If it's the same, don't do anything
|
||||||
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_upnp->delete_mapping(m_udp_mapping[nat]);
|
m_upnp->delete_mapping(mapping[nat]);
|
||||||
}
|
}
|
||||||
m_udp_mapping[nat] = m_upnp->add_mapping(upnp::udp
|
mapping[nat] = m_upnp->add_mapping(upnp::udp
|
||||||
, local_port, external_port);
|
, local_port, external_port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -6489,7 +6532,7 @@ namespace aux {
|
||||||
// into the session_impl.
|
// into the session_impl.
|
||||||
m_natpmp = boost::make_shared<natpmp>(boost::ref(m_io_service)
|
m_natpmp = boost::make_shared<natpmp>(boost::ref(m_io_service)
|
||||||
, boost::bind(&session_impl::on_port_mapping
|
, boost::bind(&session_impl::on_port_mapping
|
||||||
, this, _1, _2, _3, _4, 0)
|
, this, _1, _2, _3, _4, _5, 0)
|
||||||
, boost::bind(&session_impl::on_port_map_log
|
, boost::bind(&session_impl::on_port_map_log
|
||||||
, this, _1, 0));
|
, this, _1, 0));
|
||||||
m_natpmp->start();
|
m_natpmp->start();
|
||||||
|
@ -6537,7 +6580,7 @@ namespace aux {
|
||||||
m_upnp = boost::make_shared<upnp>(boost::ref(m_io_service)
|
m_upnp = boost::make_shared<upnp>(boost::ref(m_io_service)
|
||||||
, m_settings.get_str(settings_pack::user_agent)
|
, m_settings.get_str(settings_pack::user_agent)
|
||||||
, boost::bind(&session_impl::on_port_mapping
|
, boost::bind(&session_impl::on_port_mapping
|
||||||
, this, _1, _2, _3, _4, 1)
|
, this, _1, _2, _3, _4, _5, 1)
|
||||||
, boost::bind(&session_impl::on_port_map_log
|
, boost::bind(&session_impl::on_port_map_log
|
||||||
, this, _1, 1)
|
, this, _1, 1)
|
||||||
, m_settings.get_bool(settings_pack::upnp_ignore_nonrouters));
|
, m_settings.get_bool(settings_pack::upnp_ignore_nonrouters));
|
||||||
|
|
|
@ -78,7 +78,7 @@ udp_socket::udp_socket(io_service& ios)
|
||||||
, m_queue_packets(false)
|
, m_queue_packets(false)
|
||||||
, m_tunnel_packets(false)
|
, m_tunnel_packets(false)
|
||||||
, m_force_proxy(false)
|
, m_force_proxy(false)
|
||||||
, m_abort(false)
|
, m_abort(true)
|
||||||
, m_outstanding_ops(0)
|
, m_outstanding_ops(0)
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
, m_v6_write_subscribed(false)
|
, m_v6_write_subscribed(false)
|
||||||
|
@ -307,7 +307,11 @@ void udp_socket::on_read(error_code const& ec, udp::socket* s)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
|
|
||||||
|
@ -493,7 +497,11 @@ void udp_socket::on_read_impl(udp::endpoint const& ep
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -516,7 +524,11 @@ void udp_socket::on_read_impl(udp::endpoint const& ep
|
||||||
|
|
||||||
void udp_socket::setup_read(udp::socket* s)
|
void udp_socket::setup_read(udp::socket* s)
|
||||||
{
|
{
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
if (s == &m_ipv6_sock)
|
if (s == &m_ipv6_sock)
|
||||||
|
@ -774,17 +786,13 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
||||||
TORRENT_ASSERT(m_abort == false);
|
m_abort = false;
|
||||||
if (m_abort)
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::operation_aborted;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
|
if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
||||||
#endif
|
#endif
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
if (ep.address().is_v4())
|
if (ep.address().is_v4())
|
||||||
{
|
{
|
||||||
|
@ -858,7 +866,11 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)
|
||||||
|
|
||||||
m_proxy_settings = ps;
|
m_proxy_settings = ps;
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.type == settings_pack::socks5
|
if (ps.type == settings_pack::socks5
|
||||||
|| ps.type == settings_pack::socks5_pw)
|
|| ps.type == settings_pack::socks5_pw)
|
||||||
|
@ -880,6 +892,19 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void udp_socket::close_impl()
|
||||||
|
{
|
||||||
|
if (m_outstanding_ops == 0)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
m_ipv4_sock.close(ec);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_ipv6_sock.close(ec);
|
||||||
|
#endif
|
||||||
|
m_socks5_sock.close(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
|
void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
|
||||||
{
|
{
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
@ -897,7 +922,12 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
|
|
||||||
if (e == boost::asio::error::operation_aborted) return;
|
if (e == boost::asio::error::operation_aborted) return;
|
||||||
|
@ -976,7 +1006,11 @@ void udp_socket::on_connect_timeout(error_code const& ec)
|
||||||
|
|
||||||
m_queue_packets = false;
|
m_queue_packets = false;
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
@ -1009,7 +1043,11 @@ void udp_socket::on_connected(error_code const& e)
|
||||||
|
|
||||||
if (e == boost::asio::error::operation_aborted) return;
|
if (e == boost::asio::error::operation_aborted) return;
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1068,7 +1106,11 @@ void udp_socket::handshake1(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1104,7 +1146,11 @@ void udp_socket::handshake2(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
|
|
||||||
if (e)
|
if (e)
|
||||||
|
@ -1185,7 +1231,11 @@ void udp_socket::handshake3(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1221,7 +1271,11 @@ void udp_socket::handshake4(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1287,7 +1341,11 @@ void udp_socket::connect1(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
|
@ -1394,7 +1452,11 @@ void udp_socket::hung_up(error_code const& e)
|
||||||
+ m_outstanding_timeout
|
+ m_outstanding_timeout
|
||||||
+ m_outstanding_resolve
|
+ m_outstanding_resolve
|
||||||
+ m_outstanding_socks);
|
+ m_outstanding_socks);
|
||||||
if (m_abort) return;
|
if (m_abort)
|
||||||
|
{
|
||||||
|
close_impl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
||||||
|
|
12
src/upnp.cpp
12
src/upnp.cpp
|
@ -1041,9 +1041,10 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l)
|
||||||
, end(m_mappings.end()); i != end; ++i)
|
, end(m_mappings.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
if (i->protocol == none) continue;
|
if (i->protocol == none) continue;
|
||||||
|
int const proto = i->protocol;
|
||||||
i->protocol = none;
|
i->protocol = none;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(i - m_mappings.begin(), address(), 0, ec);
|
m_callback(i - m_mappings.begin(), address(), 0, proto, ec);
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1372,7 +1373,7 @@ void upnp::on_upnp_map_response(error_code const& e
|
||||||
if (s.error_code == -1)
|
if (s.error_code == -1)
|
||||||
{
|
{
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(mapping, d.external_ip, m.external_port, error_code());
|
m_callback(mapping, d.external_ip, m.external_port, m.protocol, error_code());
|
||||||
l.lock();
|
l.lock();
|
||||||
if (d.lease_duration > 0)
|
if (d.lease_duration > 0)
|
||||||
{
|
{
|
||||||
|
@ -1414,8 +1415,9 @@ void upnp::return_error(int mapping, int code, mutex::scoped_lock& l)
|
||||||
error_string += ": ";
|
error_string += ": ";
|
||||||
error_string += e->msg;
|
error_string += e->msg;
|
||||||
}
|
}
|
||||||
|
const int proto = m_mappings[mapping].protocol;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(mapping, address(), 0, error_code(code, get_upnp_category()));
|
m_callback(mapping, address(), 0, proto, error_code(code, get_upnp_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,8 +1470,10 @@ void upnp::on_upnp_unmap_response(error_code const& e
|
||||||
, boost::bind(&find_error_code, _1, _2, boost::ref(s)));
|
, boost::bind(&find_error_code, _1, _2, boost::ref(s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int const proto = m_mappings[mapping].protocol;
|
||||||
|
|
||||||
l.unlock();
|
l.unlock();
|
||||||
m_callback(mapping, address(), 0, p.status_code() != 200
|
m_callback(mapping, address(), 0, proto, p.status_code() != 200
|
||||||
? error_code(p.status_code(), get_http_category())
|
? error_code(p.status_code(), get_http_category())
|
||||||
: error_code(s.error_code, get_upnp_category()));
|
: error_code(s.error_code, get_upnp_category()));
|
||||||
l.lock();
|
l.lock();
|
||||||
|
|
Loading…
Reference in New Issue