merged changes from RC_1_0
This commit is contained in:
parent
1ce69d122b
commit
48ea42c990
|
@ -27,6 +27,8 @@
|
||||||
* almost completely changed the storage interface (for custom storage)
|
* almost completely changed the storage interface (for custom storage)
|
||||||
* added support for hashing pieces in multiple threads
|
* added support for hashing pieces in multiple threads
|
||||||
|
|
||||||
|
* support IPv6 multicast in local service discovery
|
||||||
|
* simplify CAS function in DHT put
|
||||||
* support IPv6 traffic class (via the TOS setting)
|
* support IPv6 traffic class (via the TOS setting)
|
||||||
* made uTP re-enter slow-start after time-out
|
* made uTP re-enter slow-start after time-out
|
||||||
* fixed uTP upload performance issue
|
* fixed uTP upload performance issue
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from distutils import sysconfig
|
||||||
|
from distutils.core import setup, Extension
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import multiprocessing
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def parse_cmd(cmdline, prefix, keep_prefix = False):
|
||||||
|
ret = []
|
||||||
|
for token in cmdline.split():
|
||||||
|
if token[:len(prefix)] == prefix:
|
||||||
|
if keep_prefix:
|
||||||
|
ret.append(token)
|
||||||
|
else:
|
||||||
|
ret.append(token[len(prefix):])
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def arch():
|
||||||
|
if platform.system() != 'Darwin': return []
|
||||||
|
a = os.uname()[4]
|
||||||
|
if a == 'Power Macintosh': a = 'ppc'
|
||||||
|
return ['-arch', a]
|
||||||
|
|
||||||
|
def target_specific():
|
||||||
|
|
||||||
|
if platform.system() != 'Darwin': return []
|
||||||
|
|
||||||
|
# on mavericks, clang will fail when unknown arguments are
|
||||||
|
# passed in. python distutils will pass in arguments it doesn't
|
||||||
|
# know about
|
||||||
|
return ['-Wno-error=unused-command-line-argument-hard-error-in-future']
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('compile_flags') as _file:
|
||||||
|
extra_cmd = _file.read()
|
||||||
|
|
||||||
|
except:
|
||||||
|
extra_cmd = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('link_flags') as _file:
|
||||||
|
ldflags = _file.read()
|
||||||
|
|
||||||
|
except:
|
||||||
|
ldflags = None
|
||||||
|
|
||||||
|
ext = None
|
||||||
|
packages = None
|
||||||
|
|
||||||
|
if '--bjam' in sys.argv or ldflags == None or extra_cmd == None:
|
||||||
|
|
||||||
|
del sys.argv[sys.argv.index('--bjam')]
|
||||||
|
|
||||||
|
if not '--help' in sys.argv \
|
||||||
|
and not '--help-commands' in sys.argv:
|
||||||
|
|
||||||
|
toolset = ''
|
||||||
|
file_ext = '.so'
|
||||||
|
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
# msvc 9.0 (2008) is the official windows compiler for python 2.6
|
||||||
|
# http://docs.python.org/whatsnew/2.6.html#build-and-c-api-changes
|
||||||
|
toolset = ' msvc-9.0'
|
||||||
|
file_ext = '.pyd'
|
||||||
|
|
||||||
|
parallell_builds = ' -j%d' % multiprocessing.cpu_count()
|
||||||
|
|
||||||
|
# build libtorrent using bjam and build the installer with distutils
|
||||||
|
cmdline = 'bjam boost=source link=static geoip=static boost-link=static release optimization=space stage_module --abbreviate-paths' + toolset + parallell_builds
|
||||||
|
print(cmdline)
|
||||||
|
if os.system(cmdline) != 0:
|
||||||
|
print('build failed')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try: os.mkdir('build')
|
||||||
|
except: pass
|
||||||
|
try: shutil.rmtree('build/lib')
|
||||||
|
except: pass
|
||||||
|
try: os.mkdir('build/lib')
|
||||||
|
except: pass
|
||||||
|
try: os.mkdir('libtorrent')
|
||||||
|
except: pass
|
||||||
|
shutil.copyfile('libtorrent' + file_ext, 'build/lib/libtorrent' + file_ext)
|
||||||
|
|
||||||
|
packages = ['libtorrent']
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
source_list = os.listdir(os.path.join(os.path.dirname(__file__), "src"))
|
||||||
|
source_list = [os.path.join("src", s) for s in source_list if s.endswith(".cpp")]
|
||||||
|
|
||||||
|
ext = [Extension('libtorrent',
|
||||||
|
sources = source_list,
|
||||||
|
language='c++',
|
||||||
|
include_dirs = ['../../../include'] + parse_cmd(extra_cmd, '-I'),
|
||||||
|
library_dirs = ['../../src/.libs'] + parse_cmd(extra_cmd, '-L'),
|
||||||
|
extra_link_args = ldflags.split() + arch(),
|
||||||
|
extra_compile_args = parse_cmd(extra_cmd, '-D', True) + arch() \
|
||||||
|
+ target_specific(),
|
||||||
|
libraries = ['torrent-rasterbar'] + parse_cmd(extra_cmd, '-l'))]
|
||||||
|
|
||||||
|
setup(name = 'python-libtorrent',
|
||||||
|
version = '1.0.1',
|
||||||
|
author = 'Arvid Norberg',
|
||||||
|
author_email = 'arvid@rasterbar.com',
|
||||||
|
description = 'Python bindings for libtorrent-rasterbar',
|
||||||
|
long_description = 'Python bindings for libtorrent-rasterbar',
|
||||||
|
url = 'http://libtorrent.org',
|
||||||
|
platforms = [platform.system() + '-' + platform.machine()],
|
||||||
|
license = 'BSD',
|
||||||
|
packages = packages,
|
||||||
|
ext_modules = ext
|
||||||
|
)
|
||||||
|
|
|
@ -57,18 +57,21 @@
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#mutable-items" id="id8">mutable items</a><ul>
|
<li><a class="reference internal" href="#mutable-items" id="id8">mutable items</a><ul>
|
||||||
<li><a class="reference internal" href="#id1" id="id9">put message</a></li>
|
<li><a class="reference internal" href="#id1" id="id9">put message</a></li>
|
||||||
<li><a class="reference internal" href="#id2" id="id10">get message</a></li>
|
<li><a class="reference internal" href="#cas" id="id10">CAS</a></li>
|
||||||
|
<li><a class="reference internal" href="#response" id="id11">response</a></li>
|
||||||
|
<li><a class="reference internal" href="#errors" id="id12">errors</a></li>
|
||||||
|
<li><a class="reference internal" href="#id2" id="id13">get message</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#signature-verification" id="id11">signature verification</a></li>
|
<li><a class="reference internal" href="#signature-verification" id="id14">signature verification</a></li>
|
||||||
<li><a class="reference internal" href="#expiration" id="id12">expiration</a></li>
|
<li><a class="reference internal" href="#expiration" id="id15">expiration</a></li>
|
||||||
<li><a class="reference internal" href="#test-vectors" id="id13">test vectors</a><ul>
|
<li><a class="reference internal" href="#test-vectors" id="id16">test vectors</a><ul>
|
||||||
<li><a class="reference internal" href="#test-1-mutable" id="id14">test 1 (mutable)</a></li>
|
<li><a class="reference internal" href="#test-1-mutable" id="id17">test 1 (mutable)</a></li>
|
||||||
<li><a class="reference internal" href="#test-2-mutable-with-salt" id="id15">test 2 (mutable with salt)</a></li>
|
<li><a class="reference internal" href="#test-2-mutable-with-salt" id="id18">test 2 (mutable with salt)</a></li>
|
||||||
<li><a class="reference internal" href="#test-3-immutable" id="id16">test 3 (immutable)</a></li>
|
<li><a class="reference internal" href="#test-3-immutable" id="id19">test 3 (immutable)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#resources" id="id17">resources</a></li>
|
<li><a class="reference internal" href="#resources" id="id20">resources</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p>This is a proposal for an extension to the BitTorrent DHT to allow
|
<p>This is a proposal for an extension to the BitTorrent DHT to allow
|
||||||
|
@ -220,7 +223,7 @@ the buffer to be signed is:</p>
|
||||||
{
|
{
|
||||||
"a":
|
"a":
|
||||||
{
|
{
|
||||||
"cas": <em><optional 20 byte hash (string)></em>,
|
"cas": <em><optional expected seq-nr (int)></em>,
|
||||||
"id": <em><20 byte id of sending node (string)></em>,
|
"id": <em><20 byte id of sending node (string)></em>,
|
||||||
"k": <em><ed25519 public key (32 bytes string)></em>,
|
"k": <em><ed25519 public key (32 bytes string)></em>,
|
||||||
"salt": <em><optional salt to be appended to "k" when hashing (string)></em>
|
"salt": <em><optional salt to be appended to "k" when hashing (string)></em>
|
||||||
|
@ -262,15 +265,25 @@ is intentional. When issuing a <tt class="docutils literal">get</tt> request for
|
||||||
know what the salt is (because it is part of what the target ID that is being
|
know what the salt is (because it is part of what the target ID that is being
|
||||||
looked up is derived from). There is no need to repeat it back for bystanders
|
looked up is derived from). There is no need to repeat it back for bystanders
|
||||||
to see.</p>
|
to see.</p>
|
||||||
<p>The <tt class="docutils literal">cas</tt> field is optional. If present it is interpreted as the sha-1 hash of
|
</div>
|
||||||
the sequence number, <tt class="docutils literal">v</tt> field and possibly the <tt class="docutils literal">salt</tt> field, that is
|
<div class="section" id="cas">
|
||||||
expected to be replaced. The buffer to hash is the same as the one signed when
|
<h2>CAS</h2>
|
||||||
storing. <tt class="docutils literal">cas</tt> is short for <em>compare and swap</em>, it has similar semantics as
|
<p>CAS is short for <em>compare and swap</em>, it has similar semantics as CAS CPU
|
||||||
CAS CPU instructions. If specified as part of the put command, and the current
|
instructions. It is used to avoid race conditions when multiple nodes are
|
||||||
value stored under the public key differs from the expected value, the store
|
writing to the same slot in the DHT.</p>
|
||||||
fails. The <tt class="docutils literal">cas</tt> field only applies to mutable puts. If there is no current
|
<p>The <tt class="docutils literal">cas</tt> field is optional. If present it specifies the sequence number of
|
||||||
value, the <tt class="docutils literal">cas</tt> field SHOULD be ignored. A put operation should not be
|
the data blob being overwritten by the put. When present, the storing node
|
||||||
prevented based on the <tt class="docutils literal">cas</tt> field if no value is currently present.</p>
|
MUST compare this number to the current sequence number it has stored under
|
||||||
|
this key. Only if the <tt class="docutils literal">cas</tt> matches the stored sequence number is the put
|
||||||
|
performed. If it mismatches, the store fails and an error is returned.
|
||||||
|
See <a class="reference internal" href="#errors">errors</a> below.</p>
|
||||||
|
<p>The <tt class="docutils literal">cas</tt> field only applies to mutable puts. If there is no current
|
||||||
|
value, the <tt class="docutils literal">cas</tt> field SHOULD be ignored.</p>
|
||||||
|
<p>When sending a <tt class="docutils literal">put</tt> request to a node that did not return any data for the
|
||||||
|
<tt class="docutils literal">get</tt>, the <tt class="docutils literal">cas</tt> field SHOULD NOT be included.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="response">
|
||||||
|
<h2>response</h2>
|
||||||
<p>Response:</p>
|
<p>Response:</p>
|
||||||
<pre class="literal-block">
|
<pre class="literal-block">
|
||||||
{
|
{
|
||||||
|
@ -279,13 +292,13 @@ prevented based on the <tt class="docutils literal">cas</tt> field if no value i
|
||||||
"y": "r",
|
"y": "r",
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="errors">
|
||||||
|
<h2>errors</h2>
|
||||||
<p>If the store fails for any reason an error message is returned instead of the
|
<p>If the store fails for any reason an error message is returned instead of the
|
||||||
message template above, i.e. one where "y" is "e" and "e" is a tuple of
|
message template above, i.e. one where "y" is "e" and "e" is a tuple of
|
||||||
[error-code, message]). Failures include where the <tt class="docutils literal">cas</tt> hash mismatches and
|
[error-code, message]). Failures include <tt class="docutils literal">cas</tt> mismatches and the sequence
|
||||||
the sequence number is outdated.</p>
|
number is outdated.</p>
|
||||||
<p>If no <tt class="docutils literal">cas</tt> field is included in the <tt class="docutils literal">put</tt> message, the value of the current
|
|
||||||
<tt class="docutils literal">v</tt> field should be disregarded when determining whether or not to save the
|
|
||||||
item. (However, the signature, sequence number obviously still should).</p>
|
|
||||||
<p>The error message (as specified by <a class="reference external" href="http://www.bittorrent.org/beps/bep_0005.html">BEP5</a>) looks like this:</p>
|
<p>The error message (as specified by <a class="reference external" href="http://www.bittorrent.org/beps/bep_0005.html">BEP5</a>) looks like this:</p>
|
||||||
<pre class="literal-block">
|
<pre class="literal-block">
|
||||||
{
|
{
|
||||||
|
@ -329,7 +342,7 @@ current.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p>An implementation MUST emit 301 errors if the cas-hash mismatches. This is a
|
<p>An implementation MUST emit 301 errors if the cas mismatches. This is a
|
||||||
critical feature in synchronization of multiple agents sharing an immutable
|
critical feature in synchronization of multiple agents sharing an immutable
|
||||||
item.</p>
|
item.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -189,7 +189,7 @@ Request:
|
||||||
{
|
{
|
||||||
"a":
|
"a":
|
||||||
{
|
{
|
||||||
"cas": *<optional 20 byte hash (string)>*,
|
"cas": *<optional expected seq-nr (int)>*,
|
||||||
"id": *<20 byte id of sending node (string)>*,
|
"id": *<20 byte id of sending node (string)>*,
|
||||||
"k": *<ed25519 public key (32 bytes string)>*,
|
"k": *<ed25519 public key (32 bytes string)>*,
|
||||||
"salt": *<optional salt to be appended to "k" when hashing (string)>*
|
"salt": *<optional salt to be appended to "k" when hashing (string)>*
|
||||||
|
@ -237,15 +237,28 @@ know what the salt is (because it is part of what the target ID that is being
|
||||||
looked up is derived from). There is no need to repeat it back for bystanders
|
looked up is derived from). There is no need to repeat it back for bystanders
|
||||||
to see.
|
to see.
|
||||||
|
|
||||||
The ``cas`` field is optional. If present it is interpreted as the sha-1 hash of
|
CAS
|
||||||
the sequence number, ``v`` field and possibly the ``salt`` field, that is
|
...
|
||||||
expected to be replaced. The buffer to hash is the same as the one signed when
|
|
||||||
storing. ``cas`` is short for *compare and swap*, it has similar semantics as
|
CAS is short for *compare and swap*, it has similar semantics as CAS CPU
|
||||||
CAS CPU instructions. If specified as part of the put command, and the current
|
instructions. It is used to avoid race conditions when multiple nodes are
|
||||||
value stored under the public key differs from the expected value, the store
|
writing to the same slot in the DHT.
|
||||||
fails. The ``cas`` field only applies to mutable puts. If there is no current
|
|
||||||
value, the ``cas`` field SHOULD be ignored. A put operation should not be
|
The ``cas`` field is optional. If present it specifies the sequence number of
|
||||||
prevented based on the ``cas`` field if no value is currently present.
|
the data blob being overwritten by the put. When present, the storing node
|
||||||
|
MUST compare this number to the current sequence number it has stored under
|
||||||
|
this key. Only if the ``cas`` matches the stored sequence number is the put
|
||||||
|
performed. If it mismatches, the store fails and an error is returned.
|
||||||
|
See errors_ below.
|
||||||
|
|
||||||
|
The ``cas`` field only applies to mutable puts. If there is no current
|
||||||
|
value, the ``cas`` field SHOULD be ignored.
|
||||||
|
|
||||||
|
When sending a ``put`` request to a node that did not return any data for the
|
||||||
|
``get``, the ``cas`` field SHOULD NOT be included.
|
||||||
|
|
||||||
|
response
|
||||||
|
........
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
|
|
||||||
|
@ -257,14 +270,13 @@ Response:
|
||||||
"y": "r",
|
"y": "r",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errors
|
||||||
|
......
|
||||||
|
|
||||||
If the store fails for any reason an error message is returned instead of the
|
If the store fails for any reason an error message is returned instead of the
|
||||||
message template above, i.e. one where "y" is "e" and "e" is a tuple of
|
message template above, i.e. one where "y" is "e" and "e" is a tuple of
|
||||||
[error-code, message]). Failures include where the ``cas`` hash mismatches and
|
[error-code, message]). Failures include ``cas`` mismatches and the sequence
|
||||||
the sequence number is outdated.
|
number is outdated.
|
||||||
|
|
||||||
If no ``cas`` field is included in the ``put`` message, the value of the current
|
|
||||||
``v`` field should be disregarded when determining whether or not to save the
|
|
||||||
item. (However, the signature, sequence number obviously still should).
|
|
||||||
|
|
||||||
The error message (as specified by BEP5_) looks like this:
|
The error message (as specified by BEP5_) looks like this:
|
||||||
|
|
||||||
|
@ -300,7 +312,7 @@ some additional error codes.
|
||||||
| | current. |
|
| | current. |
|
||||||
+------------+-----------------------------+
|
+------------+-----------------------------+
|
||||||
|
|
||||||
An implementation MUST emit 301 errors if the cas-hash mismatches. This is a
|
An implementation MUST emit 301 errors if the cas mismatches. This is a
|
||||||
critical feature in synchronization of multiple agents sharing an immutable
|
critical feature in synchronization of multiple agents sharing an immutable
|
||||||
item.
|
item.
|
||||||
|
|
||||||
|
|
|
@ -75,11 +75,6 @@ void TORRENT_EXPORT sign_mutable_item(
|
||||||
, char const* sk
|
, char const* sk
|
||||||
, char* sig);
|
, char* sig);
|
||||||
|
|
||||||
sha1_hash TORRENT_EXTRA_EXPORT mutable_item_cas(
|
|
||||||
std::pair<char const*, int> v
|
|
||||||
, std::pair<char const*, int> salt
|
|
||||||
, boost::uint64_t seq);
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
item_pk_len = 32,
|
item_pk_len = 32,
|
||||||
|
@ -120,8 +115,6 @@ public:
|
||||||
|
|
||||||
bool is_mutable() const { return m_mutable; }
|
bool is_mutable() const { return m_mutable; }
|
||||||
|
|
||||||
sha1_hash cas();
|
|
||||||
|
|
||||||
entry const& value() const { return m_value; }
|
entry const& value() const { return m_value; }
|
||||||
boost::array<char, item_pk_len> const& pk() const
|
boost::array<char, item_pk_len> const& pk() const
|
||||||
{ return m_pk; }
|
{ return m_pk; }
|
||||||
|
|
|
@ -65,24 +65,26 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void resend_announce(error_code const& e, std::string msg);
|
void announce_impl(sha1_hash const& ih, int listen_port
|
||||||
|
, bool broadcast, int retry_count);
|
||||||
|
void resend_announce(error_code const& e, sha1_hash const& ih
|
||||||
|
, int listen_port, int retry_count);
|
||||||
void on_announce(udp::endpoint const& from, char* buffer
|
void on_announce(udp::endpoint const& from, char* buffer
|
||||||
, std::size_t bytes_transferred);
|
, std::size_t bytes_transferred);
|
||||||
// void setup_receive();
|
|
||||||
|
|
||||||
peer_callback_t m_callback;
|
peer_callback_t m_callback;
|
||||||
|
|
||||||
// the udp socket used to send and receive
|
// the udp socket used to send and receive
|
||||||
// multicast messages on
|
// multicast messages on
|
||||||
broadcast_socket m_socket;
|
broadcast_socket m_socket;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
broadcast_socket m_socket6;
|
||||||
|
#endif
|
||||||
|
|
||||||
// used to resend udp packets in case
|
// used to resend udp packets in case
|
||||||
// they time out
|
// they time out
|
||||||
deadline_timer m_broadcast_timer;
|
deadline_timer m_broadcast_timer;
|
||||||
|
|
||||||
// current retry count
|
|
||||||
boost::uint32_t m_retry_count;
|
|
||||||
|
|
||||||
// this is a random (presumably unique)
|
// this is a random (presumably unique)
|
||||||
// ID for this LSD node. It is used to
|
// ID for this LSD node. It is used to
|
||||||
// ignore our own broadcast messages.
|
// ignore our own broadcast messages.
|
||||||
|
@ -91,6 +93,9 @@ private:
|
||||||
int m_cookie;
|
int m_cookie;
|
||||||
|
|
||||||
bool m_disabled;
|
bool m_disabled;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
bool m_disabled6;
|
||||||
|
#endif
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
FILE* m_log;
|
FILE* m_log;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -209,7 +209,7 @@ namespace libtorrent
|
||||||
- common_bits(b1.data(), b2.data(), b1.size());
|
- common_bits(b1.data(), b2.data(), b1.size());
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
}
|
}
|
||||||
|
|
||||||
address_v6::bytes_type b1;
|
address_v6::bytes_type b1;
|
||||||
address_v6::bytes_type b2;
|
address_v6::bytes_type b2;
|
||||||
if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
|
if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
|
||||||
|
@ -244,7 +244,7 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
open_multicast_socket(ios, address_v4::any(), loopback, ec);
|
open_multicast_socket(ios, address_v4::any(), loopback, ec);
|
||||||
|
|
||||||
for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
|
for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
|
||||||
, end(interfaces.end()); i != end; ++i)
|
, end(interfaces.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
|
@ -254,6 +254,19 @@ namespace libtorrent
|
||||||
if (!loopback && is_loopback(i->interface_address)) continue;
|
if (!loopback && is_loopback(i->interface_address)) continue;
|
||||||
|
|
||||||
ec = error_code();
|
ec = error_code();
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (i->interface_address.is_v6() &&
|
||||||
|
i->interface_address.to_v6().is_link_local()) {
|
||||||
|
address_v6 addr6 = i->interface_address.to_v6();
|
||||||
|
addr6.scope_id(if_nametoindex(i->name));
|
||||||
|
open_multicast_socket(ios, addr6, loopback, ec);
|
||||||
|
|
||||||
|
address_v4 const& mask = i->netmask.is_v4() ?
|
||||||
|
i->netmask.to_v4() : address_v4();
|
||||||
|
open_unicast_socket(ios, addr6, mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
open_multicast_socket(ios, i->interface_address, loopback, ec);
|
open_multicast_socket(ios, i->interface_address, loopback, ec);
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
// fprintf(stderr, "broadcast socket [ if: %s group: %s mask: %s ] %s\n"
|
// fprintf(stderr, "broadcast socket [ if: %s group: %s mask: %s ] %s\n"
|
||||||
|
|
|
@ -150,15 +150,6 @@ void sign_mutable_item(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_hash mutable_item_cas(std::pair<char const*, int> v
|
|
||||||
, std::pair<char const*, int> salt
|
|
||||||
, boost::uint64_t seq)
|
|
||||||
{
|
|
||||||
char str[canonical_length];
|
|
||||||
int len = canonical_string(v, seq, salt, str);
|
|
||||||
return hasher(str, len).final();
|
|
||||||
}
|
|
||||||
|
|
||||||
item::item(char const* pk, std::string const& salt)
|
item::item(char const* pk, std::string const& salt)
|
||||||
: m_salt(salt)
|
: m_salt(salt)
|
||||||
, m_seq(0)
|
, m_seq(0)
|
||||||
|
@ -230,12 +221,4 @@ void item::assign(entry const& v, std::string salt, boost::uint64_t seq
|
||||||
m_value = v;
|
m_value = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_hash item::cas()
|
|
||||||
{
|
|
||||||
char buffer[1000];
|
|
||||||
int bsize = bencode(buffer, m_value);
|
|
||||||
return mutable_item_cas(std::make_pair(buffer, bsize)
|
|
||||||
, std::pair<char const*, int>(m_salt.c_str(), m_salt.size()), m_seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
} } // namespace libtorrent::dht
|
} } // namespace libtorrent::dht
|
||||||
|
|
|
@ -952,7 +952,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
||||||
// public key
|
// public key
|
||||||
{"k", lazy_entry::string_t, item_pk_len, key_desc_t::optional},
|
{"k", lazy_entry::string_t, item_pk_len, key_desc_t::optional},
|
||||||
{"sig", lazy_entry::string_t, item_sig_len, key_desc_t::optional},
|
{"sig", lazy_entry::string_t, item_sig_len, key_desc_t::optional},
|
||||||
{"cas", lazy_entry::string_t, 20, key_desc_t::optional},
|
{"cas", lazy_entry::int_t, 0, key_desc_t::optional},
|
||||||
{"salt", lazy_entry::string_t, 0, key_desc_t::optional},
|
{"salt", lazy_entry::string_t, 0, key_desc_t::optional},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1115,20 +1115,14 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
||||||
dht_mutable_item* item = &i->second;
|
dht_mutable_item* item = &i->second;
|
||||||
|
|
||||||
// this is the "cas" field in the put message
|
// this is the "cas" field in the put message
|
||||||
// if it was specified, we MUST make sure the current value
|
// if it was specified, we MUST make sure the current sequence
|
||||||
// matches the expected value before replacing it
|
// number matches the expected value before replacing it
|
||||||
if (msg_keys[5])
|
// this is critical for avoiding race conditions when multiple
|
||||||
|
// writers are accessing the same slot
|
||||||
|
if (msg_keys[5] && item->seq != msg_keys[5]->int_value())
|
||||||
{
|
{
|
||||||
sha1_hash h = mutable_item_cas(
|
incoming_error(e, "CAS mismatch", 301);
|
||||||
std::make_pair(item->value, item->size)
|
return;
|
||||||
, std::make_pair(item->salt, item->salt_size)
|
|
||||||
, item->seq);
|
|
||||||
|
|
||||||
if (h != sha1_hash(msg_keys[5]->string_ptr()))
|
|
||||||
{
|
|
||||||
incoming_error(e, "CAS hash failed", 301);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->seq > boost::uint64_t(msg_keys[2]->int_value()))
|
if (item->seq > boost::uint64_t(msg_keys[2]->int_value()))
|
||||||
|
|
119
src/lsd.cpp
119
src/lsd.cpp
|
@ -69,10 +69,16 @@ lsd::lsd(io_service& ios, peer_callback_t const& cb)
|
||||||
: m_callback(cb)
|
: m_callback(cb)
|
||||||
, m_socket(udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
|
, m_socket(udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
|
||||||
, boost::bind(&lsd::on_announce, self(), _1, _2, _3))
|
, boost::bind(&lsd::on_announce, self(), _1, _2, _3))
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
, m_socket6(udp::endpoint(address_v6::from_string("ff15::efc0:988f", ec), 6771)
|
||||||
|
, boost::bind(&lsd::on_announce, self(), _1, _2, _3))
|
||||||
|
#endif
|
||||||
, m_broadcast_timer(ios)
|
, m_broadcast_timer(ios)
|
||||||
, m_retry_count(1)
|
|
||||||
, m_cookie(random())
|
, m_cookie(random())
|
||||||
, m_disabled(false)
|
, m_disabled(false)
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
, m_disabled6(false)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_log = fopen("lsd.log", "w+");
|
m_log = fopen("lsd.log", "w+");
|
||||||
|
@ -93,6 +99,17 @@ lsd::lsd(io_service& ios, peer_callback_t const& cb)
|
||||||
, ec.value(), ec.message().c_str());
|
, ec.value(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_socket6.open(ios, ec);
|
||||||
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
if (m_log) fprintf(m_log, "FAILED TO OPEN SOCKET6: (%d) %s\n"
|
||||||
|
, ec.value(), ec.message().c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
lsd::~lsd()
|
lsd::~lsd()
|
||||||
|
@ -102,70 +119,100 @@ lsd::~lsd()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int render_lsd_packet(char* dst, int len, int listen_port
|
||||||
|
, char const* info_hash_hex, int m_cookie, char const* host)
|
||||||
|
{
|
||||||
|
return snprintf(dst, len,
|
||||||
|
"BT-SEARCH * HTTP/1.1\r\n"
|
||||||
|
"Host: %s:6771\r\n"
|
||||||
|
"Port: %d\r\n"
|
||||||
|
"Infohash: %s\r\n"
|
||||||
|
"cookie: %x\r\n"
|
||||||
|
"\r\n\r\n", host, listen_port, info_hash_hex, m_cookie);
|
||||||
|
}
|
||||||
|
|
||||||
void lsd::announce(sha1_hash const& ih, int listen_port, bool broadcast)
|
void lsd::announce(sha1_hash const& ih, int listen_port, bool broadcast)
|
||||||
{
|
{
|
||||||
|
announce_impl(ih, listen_port, broadcast, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lsd::announce_impl(sha1_hash const& ih, int listen_port, bool broadcast
|
||||||
|
, int retry_count)
|
||||||
|
{
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (m_disabled && m_disabled6) return;
|
||||||
|
#else
|
||||||
if (m_disabled) return;
|
if (m_disabled) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
char ih_hex[41];
|
char ih_hex[41];
|
||||||
to_hex((char const*)&ih[0], 20, ih_hex);
|
to_hex((char const*)&ih[0], 20, ih_hex);
|
||||||
char msg[200];
|
char msg[200];
|
||||||
int msg_len = snprintf(msg, sizeof(msg),
|
|
||||||
"BT-SEARCH * HTTP/1.1\r\n"
|
|
||||||
"Host: 239.192.152.143:6771\r\n"
|
|
||||||
"Port: %d\r\n"
|
|
||||||
"Infohash: %s\r\n"
|
|
||||||
"cookie: %x\r\n"
|
|
||||||
"\r\n\r\n", listen_port, ih_hex, m_cookie);
|
|
||||||
|
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
{
|
if (m_log) fprintf(m_log, "%s ==> announce: ih: %s port: %u\n"
|
||||||
if (m_log) fprintf(m_log, "%s ==> announce: ih: %s port: %u\n"
|
, time_now_string(), ih_hex, listen_port);
|
||||||
, time_now_string(), ih_hex, listen_port);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_retry_count = 1;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
m_socket.send(msg, msg_len, ec, broadcast ? broadcast_socket::broadcast : 0);
|
if (!m_disabled)
|
||||||
if (ec)
|
|
||||||
{
|
{
|
||||||
m_disabled = true;
|
int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
, m_cookie, "239.192.152.143");
|
||||||
|
m_socket.send(msg, msg_len, ec, broadcast ? broadcast_socket::broadcast : 0);
|
||||||
|
if (ec)
|
||||||
{
|
{
|
||||||
|
m_disabled = true;
|
||||||
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
if (m_log) fprintf(m_log, "%s failed to send message: (%d) %s"
|
if (m_log) fprintf(m_log, "%s failed to send message: (%d) %s"
|
||||||
, time_now_string(), ec.value(), ec.message().c_str());
|
, time_now_string(), ec.value(), ec.message().c_str());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (!m_disabled6)
|
||||||
|
{
|
||||||
|
int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex
|
||||||
|
, m_cookie, "[ff15::efc0:988f]");
|
||||||
|
m_socket6.send(msg, msg_len, ec, broadcast ? broadcast_socket::broadcast : 0);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
m_disabled6 = true;
|
||||||
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
|
if (m_log) fprintf(m_log, "%s failed to send message6: (%d) %s"
|
||||||
|
, time_now_string(), ec.value(), ec.message().c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return;
|
++retry_count;
|
||||||
}
|
if (retry_count >= 3) return;
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (m_disabled && m_disabled6) return;
|
||||||
|
#else
|
||||||
|
if (m_disabled) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("lsd::resend_announce");
|
add_outstanding_async("lsd::resend_announce");
|
||||||
#endif
|
#endif
|
||||||
m_broadcast_timer.expires_from_now(seconds(2 * m_retry_count), ec);
|
m_broadcast_timer.expires_from_now(seconds(2 * retry_count), ec);
|
||||||
m_broadcast_timer.async_wait(boost::bind(&lsd::resend_announce, self(), _1
|
m_broadcast_timer.async_wait(boost::bind(&lsd::resend_announce, self(), _1
|
||||||
, std::string(msg)));
|
, ih, listen_port, retry_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lsd::resend_announce(error_code const& e, std::string msg)
|
void lsd::resend_announce(error_code const& e, sha1_hash const& info_hash
|
||||||
|
, int listen_port, int retry_count)
|
||||||
{
|
{
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
complete_async("lsd::resend_announce");
|
complete_async("lsd::resend_announce");
|
||||||
#endif
|
#endif
|
||||||
if (e) return;
|
if (e) return;
|
||||||
|
|
||||||
error_code ec;
|
announce_impl(info_hash, listen_port, false, retry_count);
|
||||||
m_socket.send(msg.c_str(), int(msg.size()), ec);
|
|
||||||
|
|
||||||
++m_retry_count;
|
|
||||||
if (m_retry_count >= 3) return;
|
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
|
||||||
add_outstanding_async("lsd::resend_announce");
|
|
||||||
#endif
|
|
||||||
m_broadcast_timer.expires_from_now(seconds(2 * m_retry_count), ec);
|
|
||||||
m_broadcast_timer.async_wait(boost::bind(&lsd::resend_announce, self(), _1, msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lsd::on_announce(udp::endpoint const& from, char* buffer
|
void lsd::on_announce(udp::endpoint const& from, char* buffer
|
||||||
|
@ -263,9 +310,15 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer
|
||||||
void lsd::close()
|
void lsd::close()
|
||||||
{
|
{
|
||||||
m_socket.close();
|
m_socket.close();
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_socket6.close();
|
||||||
|
#endif
|
||||||
error_code ec;
|
error_code ec;
|
||||||
m_broadcast_timer.cancel(ec);
|
m_broadcast_timer.cancel(ec);
|
||||||
m_disabled = true;
|
m_disabled = true;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_disabled6 = true;
|
||||||
|
#endif
|
||||||
m_callback.clear();
|
m_callback.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ void send_dht_request(node_impl& node, char const* msg, udp::endpoint const& ep
|
||||||
, char const* target = 0, entry const* value = 0
|
, char const* target = 0, entry const* value = 0
|
||||||
, bool scrape = false, bool seed = false
|
, bool scrape = false, bool seed = false
|
||||||
, std::string const key = std::string(), std::string const sig = std::string()
|
, std::string const key = std::string(), std::string const sig = std::string()
|
||||||
, int seq = -1, char const* cas = 0, sha1_hash const* nid = NULL
|
, int seq = -1, boost::int64_t cas = -1, sha1_hash const* nid = NULL
|
||||||
, char const* put_salt = NULL)
|
, char const* put_salt = NULL)
|
||||||
{
|
{
|
||||||
// we're about to clear out the backing buffer
|
// we're about to clear out the backing buffer
|
||||||
|
@ -164,7 +164,7 @@ void send_dht_request(node_impl& node, char const* msg, udp::endpoint const& ep
|
||||||
if (scrape) a["scrape"] = 1;
|
if (scrape) a["scrape"] = 1;
|
||||||
if (seed) a["seed"] = 1;
|
if (seed) a["seed"] = 1;
|
||||||
if (seq >= 0) a["seq"] = seq;
|
if (seq >= 0) a["seq"] = seq;
|
||||||
if (cas) a["cas"] = std::string(cas, 20);
|
if (cas != -1) a["cas"] = cas;
|
||||||
if (put_salt) a["salt"] = put_salt;
|
if (put_salt) a["salt"] = put_salt;
|
||||||
char msg_buf[1500];
|
char msg_buf[1500];
|
||||||
int size = bencode(msg_buf, e);
|
int size = bencode(msg_buf, e);
|
||||||
|
@ -832,7 +832,7 @@ int test_main()
|
||||||
send_dht_request(node, "put", source, &response, "10", 0
|
send_dht_request(node, "put", source, &response, "10", 0
|
||||||
, 0, token, 0, 0, &items[0].ent, false, false
|
, 0, token, 0, 0, &items[0].ent, false, false
|
||||||
, std::string(public_key, item_pk_len)
|
, std::string(public_key, item_pk_len)
|
||||||
, std::string(signature, item_sig_len), seq, NULL, NULL, salt.first);
|
, std::string(signature, item_sig_len), seq, -1, NULL, salt.first);
|
||||||
|
|
||||||
ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string));
|
ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string));
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -905,7 +905,7 @@ int test_main()
|
||||||
send_dht_request(node, "put", source, &response, "10", 0
|
send_dht_request(node, "put", source, &response, "10", 0
|
||||||
, 0, token, 0, 0, &items[0].ent, false, false
|
, 0, token, 0, 0, &items[0].ent, false, false
|
||||||
, std::string(public_key, item_pk_len)
|
, std::string(public_key, item_pk_len)
|
||||||
, std::string(signature, item_sig_len), seq, NULL, NULL, salt.first);
|
, std::string(signature, item_sig_len), seq, -1, NULL, salt.first);
|
||||||
|
|
||||||
ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string));
|
ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string));
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -924,8 +924,9 @@ int test_main()
|
||||||
|
|
||||||
// === test CAS put ===
|
// === test CAS put ===
|
||||||
|
|
||||||
// this is the hash that we expect to be there
|
// this is the sequence number we expect to be there
|
||||||
sha1_hash cas = mutable_item_cas(itemv, salt, seq);
|
boost::uint64_t cas = seq;
|
||||||
|
|
||||||
// increment sequence number
|
// increment sequence number
|
||||||
++seq;
|
++seq;
|
||||||
// put item 1
|
// put item 1
|
||||||
|
@ -944,7 +945,7 @@ int test_main()
|
||||||
, 0, token, 0, 0, &items[1].ent, false, false
|
, 0, token, 0, 0, &items[1].ent, false, false
|
||||||
, std::string(public_key, item_pk_len)
|
, std::string(public_key, item_pk_len)
|
||||||
, std::string(signature, item_sig_len), seq
|
, std::string(signature, item_sig_len), seq
|
||||||
, (char const*)&cas[0], NULL, salt.first);
|
, cas, NULL, salt.first);
|
||||||
|
|
||||||
ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string));
|
ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string));
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -969,7 +970,7 @@ int test_main()
|
||||||
, 0, token, 0, 0, &items[1].ent, false, false
|
, 0, token, 0, 0, &items[1].ent, false, false
|
||||||
, std::string(public_key, item_pk_len)
|
, std::string(public_key, item_pk_len)
|
||||||
, std::string(signature, item_sig_len), seq
|
, std::string(signature, item_sig_len), seq
|
||||||
, (char const*)&cas[0], NULL, salt.first);
|
, cas, NULL, salt.first);
|
||||||
|
|
||||||
ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string));
|
ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string));
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
Loading…
Reference in New Issue