mirror of
https://git.deluge-torrent.org/deluge
synced 2025-04-20 11:35:49 +00:00
here we go...lt 0.13...upnp & natpmp support!
This commit is contained in:
parent
3324d7afc7
commit
4722aa5796
107 changed files with 9717 additions and 6390 deletions
|
@ -49,15 +49,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
#define TORRENT_MAX_ALERT_TYPES 10
|
||||
#ifndef TORRENT_MAX_ALERT_TYPES
|
||||
#define TORRENT_MAX_ALERT_TYPES 15
|
||||
#endif
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
|
@ -70,9 +72,9 @@ namespace libtorrent {
|
|||
virtual ~alert();
|
||||
|
||||
// a timestamp is automatically created in the constructor
|
||||
boost::posix_time::ptime timestamp() const;
|
||||
ptime timestamp() const;
|
||||
|
||||
const std::string& msg() const;
|
||||
std::string const& msg() const;
|
||||
|
||||
severity_t severity() const;
|
||||
|
||||
|
@ -81,7 +83,7 @@ namespace libtorrent {
|
|||
private:
|
||||
std::string m_msg;
|
||||
severity_t m_severity;
|
||||
boost::posix_time::ptime m_timestamp;
|
||||
ptime m_timestamp;
|
||||
};
|
||||
|
||||
class TORRENT_EXPORT alert_manager
|
||||
|
@ -112,57 +114,45 @@ namespace libtorrent {
|
|||
|
||||
struct void_;
|
||||
|
||||
template<
|
||||
class Handler
|
||||
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)
|
||||
>
|
||||
template<class Handler
|
||||
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)>
|
||||
void handle_alert_dispatch(
|
||||
const std::auto_ptr<alert>& alert_
|
||||
, const Handler& handler
|
||||
, const std::type_info& typeid_
|
||||
, BOOST_PP_ENUM_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
|
||||
const std::auto_ptr<alert>& alert_, const Handler& handler
|
||||
, const std::type_info& typeid_
|
||||
, BOOST_PP_ENUM_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
|
||||
{
|
||||
if (typeid_ == typeid(T0))
|
||||
handler(*static_cast<T0*>(alert_.get()));
|
||||
else
|
||||
handle_alert_dispatch(
|
||||
alert_
|
||||
, handler
|
||||
, typeid_
|
||||
, BOOST_PP_ENUM_SHIFTED_PARAMS(TORRENT_MAX_ALERT_TYPES, p), (void_*)0
|
||||
);
|
||||
handle_alert_dispatch(alert_, handler, typeid_
|
||||
, BOOST_PP_ENUM_SHIFTED_PARAMS(
|
||||
TORRENT_MAX_ALERT_TYPES, p), (void_*)0);
|
||||
}
|
||||
|
||||
template<class Handler>
|
||||
void handle_alert_dispatch(
|
||||
const std::auto_ptr<alert>& alert_
|
||||
, const Handler& handler
|
||||
, const std::type_info& typeid_
|
||||
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
|
||||
const std::auto_ptr<alert>& alert_
|
||||
, const Handler& handler
|
||||
, const std::type_info& typeid_
|
||||
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
|
||||
{
|
||||
throw unhandled_alert();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<
|
||||
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(TORRENT_MAX_ALERT_TYPES, class T, detail::void_)
|
||||
>
|
||||
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
|
||||
TORRENT_MAX_ALERT_TYPES, class T, detail::void_)>
|
||||
struct TORRENT_EXPORT handle_alert
|
||||
{
|
||||
template<class Handler>
|
||||
handle_alert(
|
||||
const std::auto_ptr<alert>& alert_
|
||||
, const Handler& handler)
|
||||
handle_alert(const std::auto_ptr<alert>& alert_
|
||||
, const Handler& handler)
|
||||
{
|
||||
#define ALERT_POINTER_TYPE(z, n, text) (BOOST_PP_CAT(T, n)*)0
|
||||
|
||||
detail::handle_alert_dispatch(
|
||||
alert_
|
||||
, handler
|
||||
, typeid(*alert_)
|
||||
, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _)
|
||||
);
|
||||
detail::handle_alert_dispatch(alert_, handler, typeid(*alert_)
|
||||
, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _));
|
||||
|
||||
#undef ALERT_POINTER_TYPE
|
||||
}
|
||||
|
|
|
@ -249,6 +249,26 @@ namespace libtorrent
|
|||
{ return std::auto_ptr<alert>(new listen_failed_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT portmap_error_alert: alert
|
||||
{
|
||||
portmap_error_alert(const std::string& msg)
|
||||
: alert(alert::warning, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new portmap_error_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT portmap_alert: alert
|
||||
{
|
||||
portmap_alert(const std::string& msg)
|
||||
: alert(alert::info, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new portmap_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT fastresume_rejected_alert: torrent_alert
|
||||
{
|
||||
fastresume_rejected_alert(torrent_handle const& h
|
||||
|
@ -260,6 +280,20 @@ namespace libtorrent
|
|||
{ return std::auto_ptr<alert>(new fastresume_rejected_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT peer_blocked_alert: alert
|
||||
{
|
||||
peer_blocked_alert(address const& ip_
|
||||
, std::string const& msg)
|
||||
: alert(alert::info, msg)
|
||||
, ip(ip_)
|
||||
{}
|
||||
|
||||
address ip;
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new peer_blocked_alert(*this)); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
@ -42,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/thread/mutex.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace pt = boost::posix_time;
|
||||
using boost::weak_ptr;
|
||||
using boost::shared_ptr;
|
||||
using boost::intrusive_ptr;
|
||||
|
@ -70,8 +70,8 @@ namespace libtorrent
|
|||
struct history_entry
|
||||
{
|
||||
history_entry(intrusive_ptr<peer_connection> p, weak_ptr<torrent> t
|
||||
, int a, pt::ptime exp);
|
||||
pt::ptime expires_at;
|
||||
, int a, ptime exp);
|
||||
ptime expires_at;
|
||||
int amount;
|
||||
intrusive_ptr<peer_connection> peer;
|
||||
weak_ptr<torrent> tor;
|
||||
|
|
|
@ -48,7 +48,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
|
@ -91,14 +90,16 @@ namespace libtorrent
|
|||
bt_peer_connection(
|
||||
aux::session_impl& ses
|
||||
, boost::weak_ptr<torrent> t
|
||||
, boost::shared_ptr<stream_socket> s
|
||||
, tcp::endpoint const& remote);
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, tcp::endpoint const& remote
|
||||
, policy::peer* peerinfo);
|
||||
|
||||
// with this constructor we have been contacted and we still don't
|
||||
// know which torrent the connection belongs to
|
||||
bt_peer_connection(
|
||||
aux::session_impl& ses
|
||||
, boost::shared_ptr<stream_socket> s);
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, policy::peer* peerinfo);
|
||||
|
||||
~bt_peer_connection();
|
||||
|
||||
|
@ -199,7 +200,7 @@ namespace libtorrent
|
|||
|
||||
#ifndef NDEBUG
|
||||
void check_invariant() const;
|
||||
boost::posix_time::ptime m_last_choke;
|
||||
ptime m_last_choke;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
96
libtorrent/include/libtorrent/connection_queue.hpp
Normal file
96
libtorrent/include/libtorrent/connection_queue.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_CONNECTION_QUEUE
|
||||
#define TORRENT_CONNECTION_QUEUE
|
||||
|
||||
#include <list>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
class connection_queue : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
connection_queue(io_service& ios);
|
||||
|
||||
bool free_slots() const;
|
||||
|
||||
void enqueue(boost::function<void(int)> const& on_connect
|
||||
, boost::function<void()> const& on_timeout
|
||||
, time_duration timeout);
|
||||
void done(int ticket);
|
||||
void limit(int limit);
|
||||
int limit() const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void check_invariant() const;
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void try_connect();
|
||||
void on_timeout(asio::error_code const& e);
|
||||
|
||||
struct entry
|
||||
{
|
||||
entry(): connecting(false), ticket(0), expires(max_time()) {}
|
||||
// called when the connection is initiated
|
||||
boost::function<void(int)> on_connect;
|
||||
// called if done hasn't been called within the timeout
|
||||
boost::function<void()> on_timeout;
|
||||
bool connecting;
|
||||
int ticket;
|
||||
ptime expires;
|
||||
time_duration timeout;
|
||||
};
|
||||
|
||||
std::list<entry> m_queue;
|
||||
|
||||
// the next ticket id a connection will be given
|
||||
int m_next_ticket;
|
||||
int m_num_connecting;
|
||||
int m_half_open_limit;
|
||||
|
||||
deadline_timer m_timer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -52,17 +52,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
// PROFILING CODE
|
||||
#ifdef TORRENT_PROFILE
|
||||
|
||||
void add_checkpoint(std::string const& str);
|
||||
void print_checkpoints();
|
||||
#define TORRENT_CHECKPOINT(str) libtorrent::add_checkpoint(str)
|
||||
#else
|
||||
#define TORRENT_CHECKPOINT(str) void(0)
|
||||
#endif
|
||||
|
||||
// DEBUG API
|
||||
|
||||
struct logger
|
||||
|
|
|
@ -77,6 +77,10 @@ namespace libtorrent
|
|||
// default behavior will be skipped
|
||||
virtual bool on_pause() { return false; }
|
||||
virtual bool on_resume() { return false;}
|
||||
|
||||
// this is called when the initial checking of
|
||||
// files is completed.
|
||||
virtual void on_files_checked() {}
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT peer_plugin
|
||||
|
@ -84,6 +88,7 @@ namespace libtorrent
|
|||
virtual ~peer_plugin() {}
|
||||
|
||||
// can add entries to the extension handshake
|
||||
// this is not called for web seeds
|
||||
virtual void add_handshake(entry&) {}
|
||||
|
||||
// throwing an exception from any of the handlers (except add_handshake)
|
||||
|
@ -92,12 +97,14 @@ namespace libtorrent
|
|||
// this is called when the initial BT handshake is received. Returning false
|
||||
// means that the other end doesn't support this extension and will remove
|
||||
// it from the list of plugins.
|
||||
// this is not called for web seeds
|
||||
virtual bool on_handshake() { return true; }
|
||||
|
||||
// called when the extension handshake from the other end is received
|
||||
// if this returns false, it means that this extension isn't
|
||||
// supported by this peer. It will result in this peer_plugin
|
||||
// being removed from the peer_connection and destructed.
|
||||
// this is not called for web seeds
|
||||
virtual bool on_extension_handshake(entry const& h) { return true; }
|
||||
|
||||
// returning true from any of the message handlers
|
||||
|
@ -137,10 +144,12 @@ namespace libtorrent
|
|||
// the message is not processed by any other plugin and if false
|
||||
// is returned the next plugin in the chain will receive it to
|
||||
// be able to handle it
|
||||
// this is not called for web seeds
|
||||
virtual bool on_extended(int length
|
||||
, int msg, buffer::const_interval body)
|
||||
{ return false; }
|
||||
|
||||
// this is not called for web seeds
|
||||
virtual bool on_unknown_message(int length, int msg
|
||||
, buffer::const_interval body)
|
||||
{ return false; }
|
||||
|
|
|
@ -110,6 +110,7 @@ namespace libtorrent
|
|||
|
||||
void open(boost::filesystem::path const& p, open_mode m);
|
||||
void close();
|
||||
void set_size(size_type size);
|
||||
|
||||
size_type write(const char*, size_type num_bytes);
|
||||
size_type read(char*, size_type num_bytes);
|
||||
|
|
|
@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
|
@ -50,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -59,7 +59,6 @@ namespace libtorrent
|
|||
using boost::multi_index::ordered_unique;
|
||||
using boost::multi_index::indexed_by;
|
||||
using boost::multi_index::member;
|
||||
namespace pt = boost::posix_time;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
struct TORRENT_EXPORT file_pool : boost::noncopyable
|
||||
|
@ -77,11 +76,11 @@ namespace libtorrent
|
|||
{
|
||||
lru_file_entry(boost::shared_ptr<file> const& f)
|
||||
: file_ptr(f)
|
||||
, last_use(pt::second_clock::universal_time()) {}
|
||||
, last_use(time_now()) {}
|
||||
mutable boost::shared_ptr<file> file_ptr;
|
||||
fs::path file_path;
|
||||
void* key;
|
||||
pt::ptime last_use;
|
||||
ptime last_use;
|
||||
file::open_mode mode;
|
||||
};
|
||||
|
||||
|
@ -89,7 +88,7 @@ namespace libtorrent
|
|||
lru_file_entry, indexed_by<
|
||||
ordered_unique<member<lru_file_entry, fs::path
|
||||
, &lru_file_entry::file_path> >
|
||||
, ordered_non_unique<member<lru_file_entry, pt::ptime
|
||||
, ordered_non_unique<member<lru_file_entry, ptime
|
||||
, &lru_file_entry::last_use> >
|
||||
, ordered_non_unique<member<lru_file_entry, void*
|
||||
, &lru_file_entry::key> >
|
||||
|
|
|
@ -38,24 +38,27 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "zlib.h"
|
||||
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
extern "C"
|
||||
{
|
||||
#include <openssl/sha.h>
|
||||
}
|
||||
#else
|
||||
// from sha1.cpp
|
||||
struct TORRENT_EXPORT SHA1_CTX
|
||||
struct TORRENT_EXPORT SHA_CTX
|
||||
{
|
||||
boost::uint32_t state[5];
|
||||
boost::uint32_t count[2];
|
||||
boost::uint8_t buffer[64];
|
||||
};
|
||||
|
||||
TORRENT_EXPORT void SHA1Init(SHA1_CTX* context);
|
||||
TORRENT_EXPORT void SHA1Update(SHA1_CTX* context, boost::uint8_t const* data, boost::uint32_t len);
|
||||
TORRENT_EXPORT void SHA1Final(SHA1_CTX* context, boost::uint8_t* digest);
|
||||
TORRENT_EXPORT void SHA1_Init(SHA_CTX* context);
|
||||
TORRENT_EXPORT void SHA1_Update(SHA_CTX* context, boost::uint8_t const* data, boost::uint32_t len);
|
||||
TORRENT_EXPORT void SHA1_Final(boost::uint8_t* digest, SHA_CTX* context);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// from zlib/adler32.c
|
||||
unsigned long adler32(unsigned long adler, const char* data, unsigned int len);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -69,7 +72,7 @@ namespace libtorrent
|
|||
{
|
||||
assert(data != 0);
|
||||
assert(len > 0);
|
||||
m_adler = adler32(m_adler, data, len);
|
||||
m_adler = adler32(m_adler, (const Bytef*)data, len);
|
||||
}
|
||||
unsigned long final() const { return m_adler; }
|
||||
void reset() { m_adler = adler32(0, 0, 0); }
|
||||
|
@ -84,33 +87,33 @@ namespace libtorrent
|
|||
{
|
||||
public:
|
||||
|
||||
hasher() { SHA1Init(&m_context); }
|
||||
hasher() { SHA1_Init(&m_context); }
|
||||
hasher(const char* data, int len)
|
||||
{
|
||||
SHA1Init(&m_context);
|
||||
SHA1_Init(&m_context);
|
||||
assert(data != 0);
|
||||
assert(len > 0);
|
||||
SHA1Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
|
||||
SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
|
||||
}
|
||||
void update(const char* data, int len)
|
||||
{
|
||||
assert(data != 0);
|
||||
assert(len > 0);
|
||||
SHA1Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
|
||||
SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
|
||||
}
|
||||
|
||||
sha1_hash final()
|
||||
{
|
||||
sha1_hash digest;
|
||||
SHA1Final(&m_context, digest.begin());
|
||||
SHA1_Final(digest.begin(), &m_context);
|
||||
return digest;
|
||||
}
|
||||
|
||||
void reset() { SHA1Init(&m_context); }
|
||||
void reset() { SHA1_Init(&m_context); }
|
||||
|
||||
private:
|
||||
|
||||
SHA1_CTX m_context;
|
||||
SHA_CTX m_context;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
154
libtorrent/include/libtorrent/http_connection.hpp
Normal file
154
libtorrent/include/libtorrent/http_connection.hpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_HTTP_CONNECTION
|
||||
#define TORRENT_HTTP_CONNECTION
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/http_tracker_connection.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
typedef boost::function<void(asio::error_code const&
|
||||
, http_parser const&, char const* data, int size)> http_handler;
|
||||
|
||||
// TODO: add bind interface
|
||||
|
||||
// when bottled, the last two arguments to the handler
|
||||
// will always be 0
|
||||
struct http_connection : boost::enable_shared_from_this<http_connection>, boost::noncopyable
|
||||
{
|
||||
http_connection(asio::io_service& ios, connection_queue& cc
|
||||
, http_handler handler, bool bottled = true)
|
||||
: m_sock(ios)
|
||||
, m_read_pos(0)
|
||||
, m_resolver(ios)
|
||||
, m_handler(handler)
|
||||
, m_timer(ios)
|
||||
, m_last_receive(time_now())
|
||||
, m_bottled(bottled)
|
||||
, m_called(false)
|
||||
, m_rate_limit(0)
|
||||
, m_download_quota(0)
|
||||
, m_limiter_timer_active(false)
|
||||
, m_limiter_timer(ios)
|
||||
, m_redirect(true)
|
||||
, m_connection_ticket(-1)
|
||||
, m_cc(cc)
|
||||
{
|
||||
assert(!m_handler.empty());
|
||||
}
|
||||
|
||||
void rate_limit(int limit);
|
||||
|
||||
int rate_limit() const
|
||||
{ return m_rate_limit; }
|
||||
|
||||
std::string sendbuffer;
|
||||
|
||||
void get(std::string const& url, time_duration timeout = seconds(30)
|
||||
, bool handle_redirect = true);
|
||||
|
||||
void start(std::string const& hostname, std::string const& port
|
||||
, time_duration timeout, bool handle_redirect = true);
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
void on_resolve(asio::error_code const& e
|
||||
, tcp::resolver::iterator i);
|
||||
void connect(int ticket, tcp::endpoint target_address);
|
||||
void on_connect_timeout();
|
||||
void on_connect(asio::error_code const& e
|
||||
/* , tcp::resolver::iterator i*/);
|
||||
void on_write(asio::error_code const& e);
|
||||
void on_read(asio::error_code const& e, std::size_t bytes_transferred);
|
||||
static void on_timeout(boost::weak_ptr<http_connection> p
|
||||
, asio::error_code const& e);
|
||||
void on_assign_bandwidth(asio::error_code const& e);
|
||||
|
||||
std::vector<char> m_recvbuffer;
|
||||
tcp::socket m_sock;
|
||||
int m_read_pos;
|
||||
tcp::resolver m_resolver;
|
||||
http_parser m_parser;
|
||||
http_handler m_handler;
|
||||
deadline_timer m_timer;
|
||||
time_duration m_timeout;
|
||||
ptime m_last_receive;
|
||||
// bottled means that the handler is called once, when
|
||||
// everything is received (and buffered in memory).
|
||||
// non bottled means that once the headers have been
|
||||
// received, data is streamed to the handler
|
||||
bool m_bottled;
|
||||
// set to true the first time the handler is called
|
||||
bool m_called;
|
||||
std::string m_hostname;
|
||||
std::string m_port;
|
||||
|
||||
// the current download limit, in bytes per second
|
||||
// 0 is unlimited.
|
||||
int m_rate_limit;
|
||||
|
||||
// the number of bytes we are allowed to receive
|
||||
int m_download_quota;
|
||||
|
||||
// only hand out new quota 4 times a second if the
|
||||
// quota is 0. If it isn't 0 wait for it to reach
|
||||
// 0 and continue to hand out quota at that time.
|
||||
bool m_limiter_timer_active;
|
||||
|
||||
// the timer fires every 250 millisecond as long
|
||||
// as all the quota was used.
|
||||
deadline_timer m_limiter_timer;
|
||||
|
||||
// if set to true, the connection should handle
|
||||
// HTTP redirects.
|
||||
bool m_redirect;
|
||||
|
||||
int m_connection_ticket;
|
||||
connection_queue& m_cc;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
193
libtorrent/include/libtorrent/http_stream.hpp
Normal file
193
libtorrent/include/libtorrent/http_stream.hpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <asio/read.hpp>
|
||||
#include <asio/write.hpp>
|
||||
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
class http_stream : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
typedef stream_socket::lowest_layer_type lowest_layer_type;
|
||||
typedef stream_socket::endpoint_type endpoint_type;
|
||||
typedef stream_socket::protocol_type protocol_type;
|
||||
|
||||
explicit http_stream(asio::io_service& io_service)
|
||||
: m_sock(io_service)
|
||||
, m_resolver(io_service)
|
||||
, m_no_connect(false)
|
||||
{}
|
||||
|
||||
void set_no_connect(bool c) { m_no_connect = c; }
|
||||
|
||||
void set_proxy(std::string hostname, int port)
|
||||
{
|
||||
m_hostname = hostname;
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
void set_username(std::string const& user
|
||||
, std::string const& password)
|
||||
{
|
||||
m_user = user;
|
||||
m_password = password;
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers, class Handler>
|
||||
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
m_sock.async_read_some(buffers, handler);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
|
||||
{
|
||||
return m_sock.read_some(buffers, ec);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers)
|
||||
{
|
||||
return m_sock.read_some(buffers);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc)
|
||||
{
|
||||
m_sock.io_control(ioc);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
|
||||
{
|
||||
m_sock.io_control(ioc, ec);
|
||||
}
|
||||
|
||||
template <class Const_Buffers, class Handler>
|
||||
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
m_sock.async_write_some(buffers, handler);
|
||||
}
|
||||
|
||||
void bind(endpoint_type const& endpoint)
|
||||
{
|
||||
m_sock.bind(endpoint);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void bind(endpoint_type const& endpoint, Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.bind(endpoint, error_handler);
|
||||
}
|
||||
|
||||
void open(protocol_type const& p)
|
||||
{
|
||||
m_sock.open(p);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void open(protocol_type const& p, Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.open(p, error_handler);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_remote_endpoint = endpoint_type();
|
||||
m_sock.close();
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void close(Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.close(error_handler);
|
||||
}
|
||||
|
||||
endpoint_type remote_endpoint()
|
||||
{
|
||||
return m_remote_endpoint;
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type remote_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
return m_remote_endpoint;
|
||||
}
|
||||
|
||||
endpoint_type local_endpoint()
|
||||
{
|
||||
return m_sock.local_endpoint();
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type local_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
return m_sock.local_endpoint(error_handler);
|
||||
}
|
||||
|
||||
asio::io_service& io_service()
|
||||
{
|
||||
return m_sock.io_service();
|
||||
}
|
||||
|
||||
lowest_layer_type& lowest_layer()
|
||||
{
|
||||
return m_sock.lowest_layer();
|
||||
}
|
||||
|
||||
typedef boost::function<void(asio::error_code const&)> handler_type;
|
||||
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
{
|
||||
m_remote_endpoint = endpoint;
|
||||
|
||||
// the connect is split up in the following steps:
|
||||
// 1. resolve name of proxy server
|
||||
// 2. connect to proxy server
|
||||
// 3. send HTTP CONNECT method and possibly username+password
|
||||
// 4. read CONNECT response
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
|
||||
tcp::resolver::query q(m_hostname
|
||||
, boost::lexical_cast<std::string>(m_port));
|
||||
m_resolver.async_resolve(q, boost::bind(
|
||||
&http_stream::name_lookup, this, _1, _2, h));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void name_lookup(asio::error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h);
|
||||
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
|
||||
stream_socket m_sock;
|
||||
// the http proxy
|
||||
std::string m_hostname;
|
||||
int m_port;
|
||||
// send and receive buffer
|
||||
std::vector<char> m_buffer;
|
||||
// proxy authentication
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
|
||||
endpoint_type m_remote_endpoint;
|
||||
|
||||
tcp::resolver m_resolver;
|
||||
// this is true if the connection is HTTP based and
|
||||
// want to talk directly to the proxy
|
||||
bool m_no_connect;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -43,9 +43,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -59,6 +59,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/tracker_manager.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/buffer.hpp"
|
||||
#include "libtorrent/socket_type.hpp"
|
||||
#include "libtorrent/connection_queue.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -114,6 +116,7 @@ namespace libtorrent
|
|||
|
||||
http_tracker_connection(
|
||||
asio::strand& str
|
||||
, connection_queue& cc
|
||||
, tracker_manager& man
|
||||
, tracker_request const& req
|
||||
, std::string const& hostname
|
||||
|
@ -122,6 +125,7 @@ namespace libtorrent
|
|||
, address bind_infc
|
||||
, boost::weak_ptr<request_callback> c
|
||||
, session_settings const& stn
|
||||
, proxy_settings const& ps
|
||||
, std::string const& password = "");
|
||||
|
||||
private:
|
||||
|
@ -136,6 +140,7 @@ namespace libtorrent
|
|||
, std::string const& request);
|
||||
|
||||
void name_lookup(asio::error_code const& error, tcp::resolver::iterator i);
|
||||
void connect(int ticket, tcp::endpoint target_address);
|
||||
void connected(asio::error_code const& error);
|
||||
void sent(asio::error_code const& error);
|
||||
void receive(asio::error_code const& error
|
||||
|
@ -152,15 +157,19 @@ namespace libtorrent
|
|||
asio::strand& m_strand;
|
||||
tcp::resolver m_name_lookup;
|
||||
int m_port;
|
||||
boost::shared_ptr<stream_socket> m_socket;
|
||||
boost::shared_ptr<socket_type> m_socket;
|
||||
int m_recv_pos;
|
||||
std::vector<char> m_buffer;
|
||||
std::string m_send_buffer;
|
||||
|
||||
session_settings const& m_settings;
|
||||
proxy_settings const& m_proxy;
|
||||
std::string m_password;
|
||||
|
||||
bool m_timed_out;
|
||||
|
||||
int m_connection_ticket;
|
||||
connection_queue& m_cc;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
49
libtorrent/include/libtorrent/instantiate_connection.hpp
Normal file
49
libtorrent/include/libtorrent/instantiate_connection.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_INSTANTIATE_CONNECTION
|
||||
#define TORRENT_INSTANTIATE_CONNECTION
|
||||
|
||||
#include "libtorrent/socket_type.hpp"
|
||||
#include <asio/io_service.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
struct proxy_settings;
|
||||
|
||||
boost::shared_ptr<socket_type> instantiate_connection(
|
||||
asio::io_service& ios, proxy_settings const& ps);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_IO_HPP_INCLUDED
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -134,6 +135,18 @@ namespace libtorrent
|
|||
void write_int8(boost::int8_t val, OutIt& start)
|
||||
{ write_impl(val, start); }
|
||||
|
||||
inline void write_string(std::string const& str, char*& start)
|
||||
{
|
||||
std::copy(str.begin(), str.end(), start);
|
||||
start += str.size();
|
||||
}
|
||||
|
||||
template <class OutIt>
|
||||
void write_string(std::string const& str, OutIt& start)
|
||||
{
|
||||
std::copy(str.begin(), str.end(), start);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace detail
|
|||
// a filter for a specific address type.
|
||||
// it works with IPv4 and IPv6
|
||||
template<class Addr>
|
||||
class filter_impl
|
||||
class TORRENT_EXPORT filter_impl
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
105
libtorrent/include/libtorrent/lsd.hpp
Normal file
105
libtorrent/include/libtorrent/lsd.hpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_LSD_HPP
|
||||
#define TORRENT_LSD_HPP
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
typedef boost::function<void(tcp::endpoint, sha1_hash)> peer_callback_t;
|
||||
|
||||
class lsd : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
lsd(io_service& ios, address const& listen_interface
|
||||
, peer_callback_t const& cb);
|
||||
~lsd();
|
||||
|
||||
void rebind(address const& listen_interface);
|
||||
|
||||
void announce(sha1_hash const& ih, int listen_port);
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
static address_v4 lsd_multicast_address;
|
||||
static udp::endpoint lsd_multicast_endpoint;
|
||||
|
||||
void resend_announce(asio::error_code const& e, std::string msg);
|
||||
void on_announce(asio::error_code const& e
|
||||
, std::size_t bytes_transferred);
|
||||
void setup_receive();
|
||||
|
||||
peer_callback_t m_callback;
|
||||
|
||||
// current retry count
|
||||
int m_retry_count;
|
||||
|
||||
// used to receive responses in
|
||||
char m_receive_buffer[1024];
|
||||
|
||||
// the endpoint we received the message from
|
||||
udp::endpoint m_remote;
|
||||
|
||||
// the udp socket used to send and receive
|
||||
// multicast messages on
|
||||
datagram_socket m_socket;
|
||||
|
||||
// used to resend udp packets in case
|
||||
// they time out
|
||||
deadline_timer m_broadcast_timer;
|
||||
|
||||
bool m_disabled;
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
std::ofstream m_log;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
150
libtorrent/include/libtorrent/natpmp.hpp
Normal file
150
libtorrent/include/libtorrent/natpmp.hpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_NATPMP_HPP
|
||||
#define TORRENT_NATPMP_HPP
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
// int: external tcp port
|
||||
// int: external udp port
|
||||
// std::string: error message
|
||||
typedef boost::function<void(int, int, std::string const&)> portmap_callback_t;
|
||||
|
||||
class natpmp
|
||||
{
|
||||
public:
|
||||
natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb);
|
||||
|
||||
void rebind(address const& listen_interface);
|
||||
|
||||
// maps the ports, if a port is set to 0
|
||||
// it will not be mapped
|
||||
void set_mappings(int tcp, int udp);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
void update_mapping(int i, int port);
|
||||
void send_map_request(int i);
|
||||
void resend_request(int i, asio::error_code const& e);
|
||||
void on_reply(asio::error_code const& e
|
||||
, std::size_t bytes_transferred);
|
||||
void try_next_mapping(int i);
|
||||
void update_expiration_timer();
|
||||
void refresh_mapping(int i);
|
||||
void mapping_expired(asio::error_code const& e, int i);
|
||||
|
||||
struct mapping
|
||||
{
|
||||
mapping()
|
||||
: need_update(false)
|
||||
, local_port(0)
|
||||
, external_port(0)
|
||||
, protocol(1)
|
||||
{}
|
||||
|
||||
// indicates that the mapping has changed
|
||||
// and needs an update
|
||||
bool need_update;
|
||||
|
||||
// the time the port mapping will expire
|
||||
ptime expires;
|
||||
|
||||
// the local port for this mapping. If this is set
|
||||
// to 0, the mapping is not in use
|
||||
int local_port;
|
||||
|
||||
// the external (on the NAT router) port
|
||||
// for the mapping. This is the port we
|
||||
// should announce to others
|
||||
int external_port;
|
||||
|
||||
// 1 = udp, 2 = tcp
|
||||
int protocol;
|
||||
};
|
||||
|
||||
portmap_callback_t m_callback;
|
||||
|
||||
// 0 is tcp and 1 is udp
|
||||
mapping m_mappings[2];
|
||||
|
||||
// the endpoint to the nat router
|
||||
udp::endpoint m_nat_endpoint;
|
||||
|
||||
// this is the mapping that is currently
|
||||
// being updated. It is -1 in case no
|
||||
// mapping is being updated at the moment
|
||||
int m_currently_mapping;
|
||||
|
||||
// current retry count
|
||||
int m_retry_count;
|
||||
|
||||
// used to receive responses in
|
||||
char m_response_buffer[16];
|
||||
|
||||
// the endpoint we received the message from
|
||||
udp::endpoint m_remote;
|
||||
|
||||
// the udp socket used to communicate
|
||||
// with the NAT router
|
||||
datagram_socket m_socket;
|
||||
|
||||
// used to resend udp packets in case
|
||||
// they time out
|
||||
deadline_timer m_send_timer;
|
||||
|
||||
// timer used to refresh mappings
|
||||
deadline_timer m_refresh_timer;
|
||||
|
||||
bool m_disabled;
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
std::ofstream m_log;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
96
libtorrent/include/libtorrent/pch.hpp
Normal file
96
libtorrent/include/libtorrent/pch.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#ifdef BOOST_BUILD_PCH_ENABLED
|
||||
|
||||
#include <algorithm>
|
||||
#include <asio/ip/host_name.hpp>
|
||||
#include <assert.h>
|
||||
#include <bitset>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian_types.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/date_time/posix_time/ptime.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cwchar>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#define Protocol Protocol_
|
||||
#endif
|
||||
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/ip/udp.hpp>
|
||||
#include <asio/io_service.hpp>
|
||||
#include <asio/deadline_timer.hpp>
|
||||
#include <asio/write.hpp>
|
||||
#include <asio/strand.hpp>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#undef Protocol
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -49,7 +49,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/detail/atomic_count.hpp>
|
||||
|
@ -72,6 +71,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/bandwidth_manager.hpp"
|
||||
#include "libtorrent/policy.hpp"
|
||||
#include "libtorrent/socket_type.hpp"
|
||||
|
||||
// TODO: each time a block is 'taken over'
|
||||
// from another peer. That peer must be given
|
||||
|
@ -88,7 +89,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
|
||||
TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
|
||||
TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
|
||||
|
||||
struct TORRENT_EXPORT protocol_error: std::runtime_error
|
||||
{
|
||||
|
@ -99,8 +100,8 @@ namespace libtorrent
|
|||
: public boost::noncopyable
|
||||
{
|
||||
friend class invariant_access;
|
||||
friend void intrusive_ptr_add_ref(peer_connection const*);
|
||||
friend void intrusive_ptr_release(peer_connection const*);
|
||||
friend TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
|
||||
friend TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
|
||||
public:
|
||||
|
||||
enum channels
|
||||
|
@ -116,18 +117,28 @@ namespace libtorrent
|
|||
peer_connection(
|
||||
aux::session_impl& ses
|
||||
, boost::weak_ptr<torrent> t
|
||||
, boost::shared_ptr<stream_socket> s
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, tcp::endpoint const& remote
|
||||
, tcp::endpoint const& proxy);
|
||||
, policy::peer* peerinfo);
|
||||
|
||||
// with this constructor we have been contacted and we still don't
|
||||
// know which torrent the connection belongs to
|
||||
peer_connection(
|
||||
aux::session_impl& ses
|
||||
, boost::shared_ptr<stream_socket> s);
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, policy::peer* peerinfo);
|
||||
|
||||
virtual ~peer_connection();
|
||||
|
||||
void set_peer_info(policy::peer* pi)
|
||||
{ m_peer_info = pi; }
|
||||
|
||||
policy::peer* peer_info_struct() const
|
||||
{ return m_peer_info; }
|
||||
|
||||
enum peer_speed_t { slow, medium, fast };
|
||||
peer_speed_t peer_speed();
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
void add_extension(boost::shared_ptr<peer_plugin>);
|
||||
#endif
|
||||
|
@ -145,6 +156,9 @@ namespace libtorrent
|
|||
void set_upload_limit(int limit);
|
||||
void set_download_limit(int limit);
|
||||
|
||||
int upload_limit() const { return m_upload_limit; }
|
||||
int download_limit() const { return m_download_limit; }
|
||||
|
||||
bool prefer_whole_pieces() const
|
||||
{ return m_prefer_whole_pieces; }
|
||||
|
||||
|
@ -160,6 +174,9 @@ namespace libtorrent
|
|||
void set_non_prioritized(bool b)
|
||||
{ m_non_prioritized = b; }
|
||||
|
||||
bool on_parole() const
|
||||
{ return m_on_parole; }
|
||||
|
||||
// this adds an announcement in the announcement queue
|
||||
// it will let the peer know that we have the given piece
|
||||
void announce_piece(int index);
|
||||
|
@ -190,6 +207,8 @@ namespace libtorrent
|
|||
bool is_peer_interested() const { return m_peer_interested; }
|
||||
bool has_peer_choked() const { return m_peer_choked; }
|
||||
|
||||
void update_interest();
|
||||
|
||||
// returns the torrent this connection is a part of
|
||||
// may be zero if the connection is an incoming connection
|
||||
// and it hasn't received enough information to determine
|
||||
|
@ -203,12 +222,12 @@ namespace libtorrent
|
|||
// is called once every second by the main loop
|
||||
void second_tick(float tick_interval);
|
||||
|
||||
boost::shared_ptr<stream_socket> get_socket() const { return m_socket; }
|
||||
boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
|
||||
tcp::endpoint const& remote() const { return m_remote; }
|
||||
tcp::endpoint const& proxy() const { return m_remote_proxy; }
|
||||
|
||||
std::vector<bool> const& get_bitfield() const;
|
||||
|
||||
void timed_out();
|
||||
// this will cause this peer_connection to be disconnected.
|
||||
void disconnect();
|
||||
bool is_disconnecting() const { return m_disconnecting; }
|
||||
|
@ -231,7 +250,7 @@ namespace libtorrent
|
|||
// initiate the tcp connection. This may be postponed until
|
||||
// the library isn't using up the limitation of half-open
|
||||
// tcp connections.
|
||||
void connect();
|
||||
void connect(int ticket);
|
||||
|
||||
// This is called for every peer right after the upload
|
||||
// bandwidth has been distributed among them
|
||||
|
@ -253,6 +272,10 @@ namespace libtorrent
|
|||
// if it was an incoming connection, it is remote
|
||||
bool is_local() const { return m_active; }
|
||||
|
||||
bool on_local_network() const;
|
||||
bool ignore_bandwidth_limits() const
|
||||
{ return m_ignore_bandwidth_limits; }
|
||||
|
||||
void set_failed() { m_failed = true; }
|
||||
bool failed() const { return m_failed; }
|
||||
|
||||
|
@ -309,7 +332,7 @@ namespace libtorrent
|
|||
|
||||
#ifndef NDEBUG
|
||||
void check_invariant() const;
|
||||
boost::posix_time::ptime m_last_choke;
|
||||
ptime m_last_choke;
|
||||
#endif
|
||||
|
||||
virtual void get_peer_info(peer_info& p) const = 0;
|
||||
|
@ -336,6 +359,7 @@ namespace libtorrent
|
|||
buffer::interval allocate_send_buffer(int size);
|
||||
void setup_send();
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void set_country(char const* c)
|
||||
{
|
||||
assert(strlen(c) == 2);
|
||||
|
@ -343,6 +367,7 @@ namespace libtorrent
|
|||
m_country[1] = c[1];
|
||||
}
|
||||
bool has_country() const { return m_country[0] != 0; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -432,11 +457,13 @@ namespace libtorrent
|
|||
extension_list_t m_extensions;
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
// in case the session settings is set
|
||||
// to resolve countries, this is set to
|
||||
// the two character country code this
|
||||
// peer resides in.
|
||||
char m_country[2];
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
|
@ -447,7 +474,7 @@ namespace libtorrent
|
|||
|
||||
// the time when we last got a part of a
|
||||
// piece packet from this peer
|
||||
boost::posix_time::ptime m_last_piece;
|
||||
ptime m_last_piece;
|
||||
|
||||
int m_packet_size;
|
||||
int m_recv_pos;
|
||||
|
@ -474,18 +501,15 @@ namespace libtorrent
|
|||
int m_write_pos;
|
||||
|
||||
// timeouts
|
||||
boost::posix_time::ptime m_last_receive;
|
||||
boost::posix_time::ptime m_last_sent;
|
||||
ptime m_last_receive;
|
||||
ptime m_last_sent;
|
||||
|
||||
boost::shared_ptr<stream_socket> m_socket;
|
||||
boost::shared_ptr<socket_type> m_socket;
|
||||
// this is the peer we're actually talking to
|
||||
// it may not necessarily be the peer we're
|
||||
// connected to, in case we use a proxy
|
||||
tcp::endpoint m_remote;
|
||||
|
||||
// if we use a proxy, this is the address to it
|
||||
tcp::endpoint m_remote_proxy;
|
||||
|
||||
// this is the torrent this connection is
|
||||
// associated with. If the connection is an
|
||||
// incoming conncetion, this is set to zero
|
||||
|
@ -520,6 +544,11 @@ namespace libtorrent
|
|||
// this peer
|
||||
bool m_failed;
|
||||
|
||||
// if this is set to true, the peer will not
|
||||
// request bandwidth from the limiter, but instead
|
||||
// just send and receive as much as possible.
|
||||
bool m_ignore_bandwidth_limits;
|
||||
|
||||
// the pieces the other end have
|
||||
std::vector<bool> m_have_piece;
|
||||
|
||||
|
@ -583,11 +612,11 @@ namespace libtorrent
|
|||
|
||||
// the time when this peer sent us a not_interested message
|
||||
// the last time.
|
||||
boost::posix_time::ptime m_became_uninterested;
|
||||
ptime m_became_uninterested;
|
||||
|
||||
// the time when we sent a not_interested message to
|
||||
// this peer the last time.
|
||||
boost::posix_time::ptime m_became_uninteresting;
|
||||
ptime m_became_uninteresting;
|
||||
|
||||
// this is true until this socket has become
|
||||
// writable for the first time (i.e. the
|
||||
|
@ -616,6 +645,14 @@ namespace libtorrent
|
|||
// are preferred.
|
||||
bool m_prefer_whole_pieces;
|
||||
|
||||
// if this is true, the peer has previously participated
|
||||
// in a piece that failed the piece hash check. This will
|
||||
// put the peer on parole and only request entire pieces.
|
||||
// if a piece pass that was partially requested from this
|
||||
// peer it will leave parole mode and continue download
|
||||
// pieces as normal peers.
|
||||
bool m_on_parole;
|
||||
|
||||
// if this is true, the blocks picked by the piece
|
||||
// picker will be merged before passed to the
|
||||
// request function. i.e. subsequent blocks are
|
||||
|
@ -636,6 +673,21 @@ namespace libtorrent
|
|||
int m_upload_limit;
|
||||
int m_download_limit;
|
||||
|
||||
// this peer's peer info struct. This may
|
||||
// be 0, in case the connection is incoming
|
||||
// and hasn't been added to a torrent yet.
|
||||
policy::peer* m_peer_info;
|
||||
|
||||
// this is a measurement of how fast the peer
|
||||
// it allows some variance without changing
|
||||
// back and forth between states
|
||||
peer_speed_t m_speed;
|
||||
|
||||
// the ticket id from the connection queue.
|
||||
// This is used to identify the connection
|
||||
// so that it can be removed from the queue
|
||||
// once the connection completes
|
||||
int m_connection_ticket;
|
||||
#ifndef NDEBUG
|
||||
public:
|
||||
bool m_in_constructor;
|
||||
|
|
|
@ -56,7 +56,20 @@ namespace libtorrent
|
|||
connecting = 0x80,
|
||||
queued = 0x100
|
||||
};
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
enum peer_source_flags
|
||||
{
|
||||
tracker = 0x1,
|
||||
dht = 0x2,
|
||||
pex = 0x4,
|
||||
lsd = 0x8,
|
||||
resume_data = 0x10
|
||||
};
|
||||
|
||||
int source;
|
||||
|
||||
tcp::endpoint ip;
|
||||
float up_speed;
|
||||
float down_speed;
|
||||
|
@ -69,12 +82,14 @@ namespace libtorrent
|
|||
bool seed; // true if this is a seed
|
||||
int upload_limit;
|
||||
int download_limit;
|
||||
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
// in case the session settings is set
|
||||
// to resolve countries, this is set to
|
||||
// the two character country code this
|
||||
// peer resides in.
|
||||
char country[2];
|
||||
#endif
|
||||
|
||||
size_type load_balancing;
|
||||
|
||||
|
@ -89,6 +104,10 @@ namespace libtorrent
|
|||
// that we haven't sent yet
|
||||
int upload_queue_length;
|
||||
|
||||
// the number of times this IP
|
||||
// has failed to connect
|
||||
int failcount;
|
||||
|
||||
// the currently downloading piece
|
||||
// if piece index is -1 all associated
|
||||
// members are just set to 0
|
||||
|
|
|
@ -36,12 +36,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -86,28 +88,38 @@ namespace libtorrent
|
|||
{
|
||||
public:
|
||||
|
||||
enum { max_blocks_per_piece = 256 };
|
||||
|
||||
struct block_info
|
||||
{
|
||||
block_info(): num_downloads(0) {}
|
||||
block_info(): num_downloads(0), requested(0), finished(0) {}
|
||||
// the peer this block was requested or
|
||||
// downloaded from
|
||||
tcp::endpoint peer;
|
||||
// the number of times this block has been downloaded
|
||||
int num_downloads;
|
||||
unsigned num_downloads:14;
|
||||
unsigned requested:1;
|
||||
unsigned finished:1;
|
||||
};
|
||||
|
||||
// the peers that are downloading this piece
|
||||
// are considered fast peers or slow peers.
|
||||
// none is set if the blocks were downloaded
|
||||
// in a previous session
|
||||
enum piece_state_t
|
||||
{ none, slow, medium, fast };
|
||||
|
||||
struct downloading_piece
|
||||
{
|
||||
downloading_piece(): finished(0), requested(0) {}
|
||||
piece_state_t state;
|
||||
|
||||
// the index of the piece
|
||||
int index;
|
||||
// each bit represents a block in the piece
|
||||
// set to one if the block has been requested
|
||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||
// the bit is set to one if the block has been acquired
|
||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||
// info about each block
|
||||
block_info info[max_blocks_per_piece];
|
||||
// this is a pointer into the m_block_info
|
||||
// vector owned by the piece_picker
|
||||
block_info* info;
|
||||
boost::uint16_t finished;
|
||||
boost::uint16_t requested;
|
||||
};
|
||||
|
||||
piece_picker(int blocks_per_piece
|
||||
|
@ -115,8 +127,6 @@ namespace libtorrent
|
|||
|
||||
void set_sequenced_download_threshold(int sequenced_download_threshold);
|
||||
|
||||
// this is called before any other method is called
|
||||
// after the local files has been checked.
|
||||
// the vector tells which pieces we already have
|
||||
// and which we don't have.
|
||||
void files_checked(
|
||||
|
@ -130,6 +140,12 @@ namespace libtorrent
|
|||
// decreases the peer count for the given piece
|
||||
// (used when a peer disconnects)
|
||||
void dec_refcount(int index);
|
||||
|
||||
// these will increase and decrease the peer count
|
||||
// of all pieces. They are used when seeds join
|
||||
// or leave the swarm.
|
||||
void inc_refcount_all();
|
||||
void dec_refcount_all();
|
||||
|
||||
// This indicates that we just received this piece
|
||||
// it means that the refcounter will indicate that
|
||||
|
@ -137,23 +153,22 @@ namespace libtorrent
|
|||
// (i.e. we don't have to maintain a refcount)
|
||||
void we_have(int index);
|
||||
|
||||
// This will mark a piece as unfiltered, and if it was
|
||||
// previously marked as filtered, it will be considered
|
||||
// interesting again and be placed in the piece list available
|
||||
// for downloading.
|
||||
void mark_as_unfiltered(int index);
|
||||
// sets the priority of a piece.
|
||||
void set_piece_priority(int index, int prio);
|
||||
|
||||
// This will mark a piece as filtered. The piece will be
|
||||
// removed from the list of pieces avalable for downloading
|
||||
// and hence, will not be downloaded.
|
||||
void mark_as_filtered(int index);
|
||||
// returns the priority for the piece at 'index'
|
||||
int piece_priority(int index) const;
|
||||
|
||||
// returns true if the pieces at 'index' is marked as filtered
|
||||
bool is_filtered(int index) const;
|
||||
// returns the current piece priorities for all pieces
|
||||
void piece_priorities(std::vector<int>& pieces) const;
|
||||
|
||||
// ========== start deprecation ==============
|
||||
|
||||
// fills the bitmask with 1's for pieces that are filtered
|
||||
void filtered_pieces(std::vector<bool>& mask) const;
|
||||
|
||||
// ========== end deprecation ==============
|
||||
|
||||
// pieces should be the vector that represents the pieces a
|
||||
// client has. It returns a list of all pieces that this client
|
||||
// has and that are interesting to download. It returns them in
|
||||
|
@ -168,7 +183,7 @@ namespace libtorrent
|
|||
void pick_pieces(const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_pieces, bool prefer_whole_pieces
|
||||
, tcp::endpoint peer) const;
|
||||
, tcp::endpoint peer, piece_state_t speed) const;
|
||||
|
||||
// returns true if any client is currently downloading this
|
||||
// piece-block, or if it's queued for downloading by some client
|
||||
|
@ -177,7 +192,8 @@ namespace libtorrent
|
|||
bool is_finished(piece_block block) const;
|
||||
|
||||
// marks this piece-block as queued for downloading
|
||||
void mark_as_downloading(piece_block block, tcp::endpoint const& peer);
|
||||
void mark_as_downloading(piece_block block, tcp::endpoint const& peer
|
||||
, piece_state_t s);
|
||||
void mark_as_finished(piece_block block, tcp::endpoint const& peer);
|
||||
|
||||
// if a piece had a hash-failure, it must be restored and
|
||||
|
@ -209,6 +225,7 @@ namespace libtorrent
|
|||
|
||||
// the number of filtered pieces we already have
|
||||
int num_have_filtered() const { return m_num_have_filtered; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
// used in debug mode
|
||||
void check_invariant(const torrent* t = 0) const;
|
||||
|
@ -236,7 +253,7 @@ namespace libtorrent
|
|||
piece_pos(int peer_count_, int index_)
|
||||
: peer_count(peer_count_)
|
||||
, downloading(0)
|
||||
, filtered(0)
|
||||
, piece_priority(1)
|
||||
, index(index_)
|
||||
{
|
||||
assert(peer_count_ >= 0);
|
||||
|
@ -244,26 +261,59 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
// selects which vector to look in
|
||||
unsigned peer_count : 11;
|
||||
unsigned peer_count : 10;
|
||||
// is 1 if the piece is marked as being downloaded
|
||||
unsigned downloading : 1;
|
||||
// is 1 if the piece is filtered (not to be downloaded)
|
||||
unsigned filtered : 1;
|
||||
// is 0 if the piece is filtered (not to be downloaded)
|
||||
// 1 is normal priority (default)
|
||||
// 2 is higher priority than pieces at the same availability level
|
||||
// 3 is same priority as partial pieces
|
||||
// 4 is higher priority than partial pieces
|
||||
// 5 and 6 same priority as availability 1 (ignores availability)
|
||||
// 7 is maximum priority (ignores availability)
|
||||
unsigned piece_priority : 3;
|
||||
// index in to the piece_info vector
|
||||
unsigned index : 19;
|
||||
unsigned index : 18;
|
||||
|
||||
enum { we_have_index = 0x3ffff };
|
||||
enum
|
||||
{
|
||||
// index is set to this to indicate that we have the
|
||||
// piece. There is no entry for the piece in the
|
||||
// buckets if this is the case.
|
||||
we_have_index = 0x3ffff,
|
||||
// the priority value that means the piece is filtered
|
||||
filter_priority = 0,
|
||||
// the max number the peer count can hold
|
||||
max_peer_count = 0x3ff
|
||||
};
|
||||
|
||||
bool have() const { return index == we_have_index; }
|
||||
void set_have() { index = we_have_index; assert(have()); }
|
||||
|
||||
bool filtered() const { return piece_priority == filter_priority; }
|
||||
void filtered(bool f) { piece_priority = f ? filter_priority : 0; }
|
||||
|
||||
int priority(int limit) const
|
||||
{
|
||||
return peer_count >= (unsigned)limit ? limit : peer_count;
|
||||
if (filtered() || have()) return 0;
|
||||
// pieces we are currently downloading have high priority
|
||||
int prio = downloading ? (std::min)(1, int(peer_count)) : peer_count * 2;
|
||||
// if the peer_count is 0 or 1, the priority cannot be higher
|
||||
if (prio <= 1) return prio;
|
||||
if (prio >= limit * 2) prio = limit * 2;
|
||||
// the different priority levels
|
||||
switch (piece_priority)
|
||||
{
|
||||
case 2: return prio - 1;
|
||||
case 3: return (std::max)(prio / 2, 1);
|
||||
case 4: return (std::max)(prio / 2 - 1, 1);
|
||||
case 5:
|
||||
case 6: return (std::min)(prio / 2 - 1, 2);
|
||||
case 7: return 1;
|
||||
}
|
||||
return prio;
|
||||
}
|
||||
|
||||
bool ordered(int limit) const
|
||||
{
|
||||
return peer_count >= (unsigned)limit;
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(piece_pos p) const
|
||||
{ return index != p.index || peer_count != p.peer_count; }
|
||||
|
||||
|
@ -272,42 +322,36 @@ namespace libtorrent
|
|||
|
||||
};
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(piece_pos) == sizeof(char) * 4);
|
||||
|
||||
bool is_ordered(int priority) const
|
||||
{
|
||||
return priority >= m_sequenced_download_threshold * 2;
|
||||
}
|
||||
|
||||
void add(int index);
|
||||
void move(bool downloading, bool filtered, int vec_index, int elem_index);
|
||||
void remove(bool downloading, bool filtered, int vec_index, int elem_index);
|
||||
std::vector<std::vector<int> >& pick_piece_info_vector(bool downloading
|
||||
, bool filtered);
|
||||
void move(int vec_index, int elem_index);
|
||||
|
||||
std::vector<std::vector<int> > const& pick_piece_info_vector(
|
||||
bool downloading, bool filtered) const;
|
||||
|
||||
int add_interesting_blocks_free(const std::vector<int>& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces) const;
|
||||
|
||||
int add_interesting_blocks_partial(const std::vector<int>& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, tcp::endpoint peer) const;
|
||||
int add_interesting_blocks(const std::vector<int>& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, tcp::endpoint peer, piece_state_t speed) const;
|
||||
|
||||
downloading_piece& add_download_piece();
|
||||
void erase_download_piece(std::vector<downloading_piece>::iterator i);
|
||||
|
||||
// this vector contains all pieces we don't have.
|
||||
// in the first entry (index 0) is a vector of all pieces
|
||||
// that no peer have, the vector at index 1 contains
|
||||
// all pieces that exactly one peer have, index 2 contains
|
||||
// all pieces exactly two peers have and so on.
|
||||
// this is not entirely true. The availibility of a piece
|
||||
// is adjusted depending on its priority. But the principle
|
||||
// is that the higher index, the lower priority a piece has.
|
||||
std::vector<std::vector<int> > m_piece_info;
|
||||
|
||||
// this vector has the same structure as m_piece_info
|
||||
// but only contains pieces we are currently downloading
|
||||
// they have higher priority than pieces we aren't downloading
|
||||
// during piece picking
|
||||
std::vector<std::vector<int> > m_downloading_piece_info;
|
||||
|
||||
// this maps indices to number of peers that has this piece and
|
||||
// index into the m_piece_info vectors.
|
||||
// piece_pos::we_have_index means that we have the piece, so it
|
||||
|
@ -322,6 +366,15 @@ namespace libtorrent
|
|||
// is being downloaded
|
||||
std::vector<downloading_piece> m_downloads;
|
||||
|
||||
// this holds the information of the
|
||||
// blocks in partially downloaded pieces.
|
||||
// the first m_blocks_per_piece entries
|
||||
// in the vector belongs to the first
|
||||
// entry in m_downloads, the second
|
||||
// m_blocks_per_piece entries to the
|
||||
// second entry in m_downloads and so on.
|
||||
std::vector<block_info> m_block_info;
|
||||
|
||||
int m_blocks_per_piece;
|
||||
int m_blocks_in_last_piece;
|
||||
|
||||
|
@ -333,6 +386,9 @@ namespace libtorrent
|
|||
|
||||
// the number of pieces we have that also are filtered
|
||||
int m_num_have_filtered;
|
||||
|
||||
// the number of pieces we have
|
||||
int m_num_have;
|
||||
|
||||
// the required popularity of a piece in order to download
|
||||
// it in sequence instead of random order.
|
||||
|
|
|
@ -40,8 +40,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
@ -52,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -85,24 +84,16 @@ namespace libtorrent
|
|||
void pulse();
|
||||
|
||||
// this is called once for every peer we get from
|
||||
// the tracker
|
||||
void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid);
|
||||
// the tracker, pex, lsd or dht.
|
||||
void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid
|
||||
, int source, char flags);
|
||||
|
||||
// called when an incoming connection is accepted
|
||||
void new_connection(peer_connection& c);
|
||||
|
||||
// this is called if a peer timed-out or
|
||||
// forcefully closed the connection. This
|
||||
// will mark the connection as non-reconnectale
|
||||
void peer_failed(peer_connection const& c);
|
||||
|
||||
// the given connection was just closed
|
||||
void connection_closed(const peer_connection& c);
|
||||
|
||||
// is called when a peer is believed to have
|
||||
// sent invalid data
|
||||
void ban_peer(const peer_connection& c);
|
||||
|
||||
// the peer has got at least one interesting piece
|
||||
void peer_is_interesting(peer_connection& c);
|
||||
|
||||
|
@ -132,7 +123,7 @@ namespace libtorrent
|
|||
{
|
||||
enum connection_type { not_connectable,connectable };
|
||||
|
||||
peer(const tcp::endpoint& ip, connection_type t);
|
||||
peer(const tcp::endpoint& ip, connection_type t, int src);
|
||||
|
||||
size_type total_download() const;
|
||||
size_type total_upload() const;
|
||||
|
@ -144,13 +135,19 @@ namespace libtorrent
|
|||
tcp::endpoint ip;
|
||||
connection_type type;
|
||||
|
||||
// the number of failed connection attempts this peer has
|
||||
int failcount;
|
||||
|
||||
// this is true if the peer is a seed
|
||||
bool seed;
|
||||
|
||||
// the time when this peer was optimistically unchoked
|
||||
// the last time.
|
||||
boost::posix_time::ptime last_optimistically_unchoked;
|
||||
libtorrent::ptime last_optimistically_unchoked;
|
||||
|
||||
// the time when the peer connected to us
|
||||
// or disconnected if it isn't connected right now
|
||||
boost::posix_time::ptime connected;
|
||||
libtorrent::ptime connected;
|
||||
|
||||
// this is the accumulated amount of
|
||||
// uploaded and downloaded data to this
|
||||
|
@ -167,6 +164,10 @@ namespace libtorrent
|
|||
// is set to true if this peer has been banned
|
||||
bool banned;
|
||||
|
||||
// a bitmap combining the peer_source flags
|
||||
// from peer_info.
|
||||
int source;
|
||||
|
||||
// if the peer is connected now, this
|
||||
// will refer to a valid peer_connection
|
||||
peer_connection* connection;
|
||||
|
@ -182,49 +183,32 @@ namespace libtorrent
|
|||
return m_num_unchoked;
|
||||
}
|
||||
|
||||
typedef std::vector<peer>::iterator iterator;
|
||||
typedef std::list<peer>::iterator iterator;
|
||||
typedef std::list<peer>::const_iterator const_iterator;
|
||||
iterator begin_peer() { return m_peers.begin(); }
|
||||
iterator end_peer() { return m_peers.end(); }
|
||||
|
||||
bool connect_one_peer();
|
||||
|
||||
private:
|
||||
|
||||
bool unchoke_one_peer();
|
||||
void choke_one_peer();
|
||||
peer* find_choke_candidate();
|
||||
peer* find_unchoke_candidate();
|
||||
iterator find_choke_candidate();
|
||||
iterator find_unchoke_candidate();
|
||||
|
||||
// the seed prefix means that the
|
||||
// function is used while seeding.
|
||||
bool seed_unchoke_one_peer();
|
||||
void seed_choke_one_peer();
|
||||
peer* find_seed_choke_candidate();
|
||||
peer* find_seed_unchoke_candidate();
|
||||
iterator find_seed_choke_candidate();
|
||||
iterator find_seed_unchoke_candidate();
|
||||
|
||||
bool connect_peer(peer *);
|
||||
bool connect_one_peer();
|
||||
bool disconnect_one_peer();
|
||||
peer* find_disconnect_candidate();
|
||||
peer* find_connect_candidate();
|
||||
iterator find_disconnect_candidate();
|
||||
iterator find_connect_candidate();
|
||||
|
||||
// a functor that identifies peers that have disconnected and that
|
||||
// are too old for still being saved.
|
||||
struct old_disconnected_peer
|
||||
{
|
||||
bool operator()(const peer& p)
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
|
||||
ptime not_tried_yet(boost::gregorian::date(1970,boost::gregorian::Jan,1));
|
||||
|
||||
// this timeout has to be customizable!
|
||||
return p.connection == 0
|
||||
&& p.connected != not_tried_yet
|
||||
&& second_clock::universal_time() - p.connected > minutes(30);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
std::vector<peer> m_peers;
|
||||
std::list<peer> m_peers;
|
||||
|
||||
torrent* m_torrent;
|
||||
|
||||
|
@ -239,7 +223,7 @@ namespace libtorrent
|
|||
// if there is a connection limit,
|
||||
// we disconnect one peer every minute in hope of
|
||||
// establishing a connection with a better peer
|
||||
boost::posix_time::ptime m_last_optimistic_disconnect;
|
||||
ptime m_last_optimistic_disconnect;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/fingerprint.hpp"
|
||||
|
||||
#include "libtorrent/resource_request.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <eh.h>
|
||||
|
@ -71,7 +72,7 @@ namespace libtorrent
|
|||
struct torrent_plugin;
|
||||
class torrent;
|
||||
class ip_filter;
|
||||
|
||||
class connection_queue;
|
||||
|
||||
namespace aux
|
||||
{
|
||||
|
@ -137,7 +138,8 @@ namespace libtorrent
|
|||
, boost::filesystem::path const& save_path
|
||||
, entry const& resume_data = entry()
|
||||
, bool compact_mode = true
|
||||
, int block_size = 16 * 1024);
|
||||
, int block_size = 16 * 1024
|
||||
, storage_constructor_type sc = default_storage_constructor);
|
||||
|
||||
// TODO: deprecated, this is for backwards compatibility only
|
||||
torrent_handle add_torrent(
|
||||
|
@ -145,10 +147,11 @@ namespace libtorrent
|
|||
, boost::filesystem::path const& save_path
|
||||
, entry const& resume_data = entry()
|
||||
, bool compact_mode = true
|
||||
, int block_size = 16 * 1024)
|
||||
, int block_size = 16 * 1024
|
||||
, storage_constructor_type sc = default_storage_constructor)
|
||||
{
|
||||
return add_torrent(torrent_info(e), save_path, resume_data
|
||||
, compact_mode, block_size);
|
||||
, compact_mode, block_size, sc);
|
||||
}
|
||||
|
||||
torrent_handle add_torrent(
|
||||
|
@ -158,7 +161,8 @@ namespace libtorrent
|
|||
, boost::filesystem::path const& save_path
|
||||
, entry const& resume_data = entry()
|
||||
, bool compact_mode = true
|
||||
, int block_size = 16 * 1024);
|
||||
, int block_size = 16 * 1024
|
||||
, storage_constructor_type sc = default_storage_constructor);
|
||||
|
||||
session_proxy abort() { return session_proxy(m_impl); }
|
||||
|
||||
|
@ -174,9 +178,7 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
|
||||
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
|
||||
|
||||
#endif
|
||||
|
||||
void set_ip_filter(ip_filter const& f);
|
||||
|
@ -215,6 +217,19 @@ namespace libtorrent
|
|||
void set_settings(session_settings const& s);
|
||||
session_settings const& settings();
|
||||
|
||||
void set_peer_proxy(proxy_settings const& s);
|
||||
void set_web_seed_proxy(proxy_settings const& s);
|
||||
void set_tracker_proxy(proxy_settings const& s);
|
||||
|
||||
proxy_settings const& peer_proxy() const;
|
||||
proxy_settings const& web_seed_proxy() const;
|
||||
proxy_settings const& tracker_proxy() const;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
void set_dht_proxy(proxy_settings const& s);
|
||||
proxy_settings const& dht_proxy() const;
|
||||
#endif
|
||||
|
||||
int upload_rate_limit() const;
|
||||
int download_rate_limit() const;
|
||||
|
||||
|
@ -227,6 +242,8 @@ namespace libtorrent
|
|||
std::auto_ptr<alert> pop_alert();
|
||||
void set_severity_level(alert::severity_t s);
|
||||
|
||||
connection_queue& get_connection_queue();
|
||||
|
||||
// Resource management used for global limits.
|
||||
resource_request m_ul_bandwidth_quota;
|
||||
resource_request m_dl_bandwidth_quota;
|
||||
|
|
|
@ -34,16 +34,53 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_SESSION_SETTINGS_HPP_INCLUDED
|
||||
|
||||
#include "libtorrent/version.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
struct TORRENT_EXPORT proxy_settings
|
||||
{
|
||||
proxy_settings() : port(0), type(none) {}
|
||||
|
||||
std::string hostname;
|
||||
int port;
|
||||
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
enum proxy_type
|
||||
{
|
||||
// a plain tcp socket is used, and
|
||||
// the other settings are ignored.
|
||||
none,
|
||||
// the hostname and port settings are
|
||||
// used to connect to the proxy. No
|
||||
// username or password is sent.
|
||||
socks5,
|
||||
// the hostname and port are used to
|
||||
// connect to the proxy. the username
|
||||
// and password are used to authenticate
|
||||
// with the proxy server.
|
||||
socks5_pw,
|
||||
// the http proxy is only available for
|
||||
// tracker and web seed traffic
|
||||
// assumes anonymous access to proxy
|
||||
http,
|
||||
// http proxy with basic authentication
|
||||
// uses username and password
|
||||
http_pw
|
||||
};
|
||||
|
||||
proxy_type type;
|
||||
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT session_settings
|
||||
{
|
||||
session_settings(std::string const& user_agent_ = "libtorrent/"
|
||||
LIBTORRENT_VERSION)
|
||||
: proxy_port(0)
|
||||
, user_agent(user_agent_)
|
||||
: user_agent(user_agent_)
|
||||
, tracker_completion_timeout(60)
|
||||
, tracker_receive_timeout(20)
|
||||
, stop_tracker_timeout(10)
|
||||
|
@ -58,16 +95,15 @@ namespace libtorrent
|
|||
, urlseed_pipeline_size(5)
|
||||
, file_pool_size(40)
|
||||
, allow_multiple_connections_per_ip(false)
|
||||
, max_failcount(3)
|
||||
, min_reconnect_time(60)
|
||||
, peer_connect_timeout(10)
|
||||
, ignore_limits_on_local_network(true)
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
, use_dht_as_fallback(true)
|
||||
#endif
|
||||
{}
|
||||
|
||||
std::string proxy_ip;
|
||||
int proxy_port;
|
||||
std::string proxy_login;
|
||||
std::string proxy_password;
|
||||
|
||||
// this is the user agent that will be sent to the tracker
|
||||
// when doing requests. It is used to identify the client.
|
||||
// It cannot contain \r or \n
|
||||
|
@ -154,6 +190,23 @@ namespace libtorrent
|
|||
// IP address. true will allow it.
|
||||
bool allow_multiple_connections_per_ip;
|
||||
|
||||
// the number of times we can fail to connect to a peer
|
||||
// before we stop retrying it.
|
||||
int max_failcount;
|
||||
|
||||
// the number of seconds to wait to reconnect to a peer.
|
||||
// this time is multiplied with the failcount.
|
||||
int min_reconnect_time;
|
||||
|
||||
// this is the timeout for a connection attempt. If
|
||||
// the connect does not succeed within this time, the
|
||||
// connection is dropped. The time is specified in seconds.
|
||||
int peer_connect_timeout;
|
||||
|
||||
// if set to true, upload, download and unchoke limits
|
||||
// are ignored for peers on the local network
|
||||
bool ignore_limits_on_local_network;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
// while this is true, the dht will note be used unless the
|
||||
// tracker is online
|
||||
|
@ -167,7 +220,7 @@ namespace libtorrent
|
|||
dht_settings()
|
||||
: max_peers_reply(50)
|
||||
, search_branching(5)
|
||||
, service_port(6881)
|
||||
, service_port(0)
|
||||
, max_fail_count(20)
|
||||
{}
|
||||
|
||||
|
@ -180,6 +233,7 @@ namespace libtorrent
|
|||
int search_branching;
|
||||
|
||||
// the listen port for the dht. This is a UDP port.
|
||||
// zero means use the same as the tcp interface
|
||||
int service_port;
|
||||
|
||||
// the maximum number of times a node can fail
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace libtorrent
|
|||
int dht_nodes;
|
||||
int dht_node_cache;
|
||||
int dht_torrents;
|
||||
size_type dht_global_nodes;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -51,12 +51,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <asio/deadline_timer.hpp>
|
||||
#include <asio/write.hpp>
|
||||
#include <asio/strand.hpp>
|
||||
#include <asio/time_traits.hpp>
|
||||
#include <asio/basic_deadline_timer.hpp>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#undef Protocol
|
||||
#endif
|
||||
|
||||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -64,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
/*
|
||||
namespace asio = boost::asio;
|
||||
|
||||
|
@ -91,7 +95,8 @@ namespace libtorrent
|
|||
typedef asio::io_service io_service;
|
||||
|
||||
using asio::async_write;
|
||||
using asio::deadline_timer;
|
||||
|
||||
typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
Copyright (c) 2005-2006, Thomas BERNARD
|
||||
/*
|
||||
|
||||
Copyright (c) 2007, 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:
|
||||
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.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
* 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
|
||||
|
@ -24,3 +28,19 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_SOCKET_TYPE
|
||||
#define TORRENT_SOCKET_TYPE
|
||||
|
||||
#include "libtorrent/socks5_stream.hpp"
|
||||
#include "libtorrent/http_stream.hpp"
|
||||
#include "libtorrent/variant_stream.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
typedef variant_stream<stream_socket, socks5_stream, http_stream> socket_type;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
195
libtorrent/include/libtorrent/socks5_stream.hpp
Normal file
195
libtorrent/include/libtorrent/socks5_stream.hpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <asio/read.hpp>
|
||||
#include <asio/write.hpp>
|
||||
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
class socks5_stream : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
typedef stream_socket::lowest_layer_type lowest_layer_type;
|
||||
typedef stream_socket::endpoint_type endpoint_type;
|
||||
typedef stream_socket::protocol_type protocol_type;
|
||||
|
||||
explicit socks5_stream(asio::io_service& io_service)
|
||||
: m_sock(io_service)
|
||||
, m_resolver(io_service)
|
||||
{}
|
||||
|
||||
void set_proxy(std::string hostname, int port)
|
||||
{
|
||||
m_hostname = hostname;
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
void set_username(std::string const& user
|
||||
, std::string const& password)
|
||||
{
|
||||
m_user = user;
|
||||
m_password = password;
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers, class Handler>
|
||||
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
m_sock.async_read_some(buffers, handler);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
|
||||
{
|
||||
return m_sock.read_some(buffers, ec);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers)
|
||||
{
|
||||
return m_sock.read_some(buffers);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc)
|
||||
{
|
||||
m_sock.io_control(ioc);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
|
||||
{
|
||||
m_sock.io_control(ioc, ec);
|
||||
}
|
||||
|
||||
template <class Const_Buffers, class Handler>
|
||||
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
m_sock.async_write_some(buffers, handler);
|
||||
}
|
||||
|
||||
void bind(endpoint_type const& endpoint)
|
||||
{
|
||||
m_sock.bind(endpoint);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void bind(endpoint_type const& endpoint, Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.bind(endpoint, error_handler);
|
||||
}
|
||||
|
||||
void open(protocol_type const& p)
|
||||
{
|
||||
m_sock.open(p);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void open(protocol_type const& p, Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.open(p, error_handler);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_remote_endpoint = endpoint_type();
|
||||
m_sock.close();
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void close(Error_Handler const& error_handler)
|
||||
{
|
||||
m_sock.close(error_handler);
|
||||
}
|
||||
|
||||
endpoint_type remote_endpoint()
|
||||
{
|
||||
return m_remote_endpoint;
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type remote_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
return m_remote_endpoint;
|
||||
}
|
||||
|
||||
endpoint_type local_endpoint()
|
||||
{
|
||||
return m_sock.local_endpoint();
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type local_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
return m_sock.local_endpoint(error_handler);
|
||||
}
|
||||
|
||||
asio::io_service& io_service()
|
||||
{
|
||||
return m_sock.io_service();
|
||||
}
|
||||
|
||||
lowest_layer_type& lowest_layer()
|
||||
{
|
||||
return m_sock.lowest_layer();
|
||||
}
|
||||
|
||||
typedef boost::function<void(asio::error_code const&)> handler_type;
|
||||
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
{
|
||||
m_remote_endpoint = endpoint;
|
||||
|
||||
// the connect is split up in the following steps:
|
||||
// 1. resolve name of proxy server
|
||||
// 2. connect to proxy server
|
||||
// 3. send SOCKS5 authentication method message
|
||||
// 4. read SOCKS5 authentication response
|
||||
// 5. send username+password
|
||||
// 6. send SOCKS5 CONNECT message
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
|
||||
tcp::resolver::query q(m_hostname
|
||||
, boost::lexical_cast<std::string>(m_port));
|
||||
m_resolver.async_resolve(q, boost::bind(
|
||||
&socks5_stream::name_lookup, this, _1, _2, h));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void name_lookup(asio::error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h);
|
||||
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake3(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void handshake4(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void socks_connect(boost::shared_ptr<handler_type> h);
|
||||
void connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
void connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h);
|
||||
|
||||
stream_socket m_sock;
|
||||
// the socks5 proxy
|
||||
std::string m_hostname;
|
||||
int m_port;
|
||||
// send and receive buffer
|
||||
std::vector<char> m_buffer;
|
||||
// proxy authentication
|
||||
std::string m_user;
|
||||
std::string m_password;
|
||||
|
||||
endpoint_type m_remote_endpoint;
|
||||
|
||||
tcp::resolver m_resolver;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/piece_picker.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
|
@ -77,6 +78,7 @@ namespace libtorrent
|
|||
torrent_info const& t
|
||||
, boost::filesystem::path p
|
||||
, std::vector<std::pair<size_type, std::time_t> > const& sizes
|
||||
, bool compact_mode
|
||||
, std::string* error = 0);
|
||||
|
||||
struct TORRENT_EXPORT file_allocation_failed: std::exception
|
||||
|
@ -87,40 +89,56 @@ namespace libtorrent
|
|||
std::string m_msg;
|
||||
};
|
||||
|
||||
class TORRENT_EXPORT storage
|
||||
struct TORRENT_EXPORT storage_interface
|
||||
{
|
||||
public:
|
||||
storage(
|
||||
const torrent_info& info
|
||||
, const boost::filesystem::path& path
|
||||
, file_pool& fp);
|
||||
|
||||
void swap(storage&);
|
||||
// create directories and set file sizes
|
||||
// if allocate_files is true.
|
||||
// allocate_files is true if allocation mode
|
||||
// is set to full and sparse files are supported
|
||||
virtual void initialize(bool allocate_files) = 0;
|
||||
|
||||
// may throw file_error if storage for slot does not exist
|
||||
size_type read(char* buf, int slot, int offset, int size);
|
||||
virtual size_type read(char* buf, int slot, int offset, int size) = 0;
|
||||
|
||||
// may throw file_error if storage for slot hasn't been allocated
|
||||
void write(const char* buf, int slot, int offset, int size);
|
||||
virtual void write(const char* buf, int slot, int offset, int size) = 0;
|
||||
|
||||
bool move_storage(boost::filesystem::path save_path);
|
||||
virtual bool move_storage(boost::filesystem::path save_path) = 0;
|
||||
|
||||
// verify storage dependent fast resume entries
|
||||
virtual bool verify_resume_data(entry& rd, std::string& error) = 0;
|
||||
|
||||
// write storage dependent fast resume entries
|
||||
virtual void write_resume_data(entry& rd) const = 0;
|
||||
|
||||
// moves (or copies) the content in src_slot to dst_slot
|
||||
virtual void move_slot(int src_slot, int dst_slot) = 0;
|
||||
|
||||
// swaps the data in slot1 and slot2
|
||||
virtual void swap_slots(int slot1, int slot2) = 0;
|
||||
|
||||
// swaps the puts the data in slot1 in slot2, the data in slot2
|
||||
// in slot3 and the data in slot3 in slot1
|
||||
virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;
|
||||
|
||||
// this will close all open files that are opened for
|
||||
// writing. This is called when a torrent has finished
|
||||
// downloading.
|
||||
void release_files();
|
||||
|
||||
#ifndef NDEBUG
|
||||
// overwrites some slots with the
|
||||
// contents of others
|
||||
void shuffle();
|
||||
#endif
|
||||
|
||||
private:
|
||||
class impl;
|
||||
boost::shared_ptr<impl> m_pimpl;
|
||||
virtual void release_files() = 0;
|
||||
virtual ~storage_interface() {}
|
||||
};
|
||||
|
||||
typedef storage_interface* (&storage_constructor_type)(
|
||||
torrent_info const&, boost::filesystem::path const&
|
||||
, file_pool&);
|
||||
|
||||
TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti
|
||||
, boost::filesystem::path const& path, file_pool& fp);
|
||||
|
||||
// returns true if the filesystem the path relies on supports
|
||||
// sparse files or automatic zero filling of files.
|
||||
TORRENT_EXPORT bool supports_sparse_files(boost::filesystem::path const& p);
|
||||
|
||||
class TORRENT_EXPORT piece_manager : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
|
@ -128,7 +146,8 @@ namespace libtorrent
|
|||
piece_manager(
|
||||
const torrent_info& info
|
||||
, const boost::filesystem::path& path
|
||||
, file_pool& fp);
|
||||
, file_pool& fp
|
||||
, storage_constructor_type sc);
|
||||
|
||||
~piece_manager();
|
||||
|
||||
|
@ -139,14 +158,17 @@ namespace libtorrent
|
|||
|
||||
void release_files();
|
||||
|
||||
void write_resume_data(entry& rd) const;
|
||||
bool verify_resume_data(entry& rd, std::string& error);
|
||||
|
||||
bool is_allocating() const;
|
||||
void allocate_slots(int num_slots);
|
||||
bool allocate_slots(int num_slots, bool abort_on_disk = false);
|
||||
void mark_failed(int index);
|
||||
|
||||
unsigned long piece_crc(
|
||||
int slot_index
|
||||
, int block_size
|
||||
, const std::bitset<256>& bitmask);
|
||||
, piece_picker::block_info const* bi);
|
||||
int slot_for_piece(int piece_index) const;
|
||||
|
||||
size_type read(
|
||||
|
@ -170,6 +192,8 @@ namespace libtorrent
|
|||
// of unassigned pieces and -1 is unallocated
|
||||
void export_piece_map(std::vector<int>& pieces) const;
|
||||
|
||||
bool compact_allocation() const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
std::auto_ptr<impl> m_pimpl;
|
||||
|
|
383
libtorrent/include/libtorrent/time.hpp
Normal file
383
libtorrent/include/libtorrent/time.hpp
Normal file
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_TIME_HPP_INCLUDED
|
||||
#define TORRENT_TIME_HPP_INCLUDED
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
inline char const* time_now_string()
|
||||
{
|
||||
time_t t = std::time(0);
|
||||
tm* timeinfo = std::localtime(&t);
|
||||
static char str[200];
|
||||
std::strftime(str, 200, "%b %d %X", timeinfo);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
#if (!defined (__MACH__) && !defined (_WIN32) && !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0) || defined (TORRENT_USE_BOOST_DATE_TIME)
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
typedef boost::posix_time::ptime ptime;
|
||||
typedef boost::posix_time::time_duration time_duration;
|
||||
inline ptime time_now()
|
||||
{ return boost::posix_time::microsec_clock::universal_time(); }
|
||||
inline ptime min_time()
|
||||
{ return boost::posix_time::ptime(boost::posix_time::min_date_time); }
|
||||
inline ptime max_time()
|
||||
{ return boost::posix_time::ptime(boost::posix_time::max_date_time); }
|
||||
inline time_duration seconds(int s) { return boost::posix_time::seconds(s); }
|
||||
inline time_duration milliseconds(int s) { return boost::posix_time::milliseconds(s); }
|
||||
inline time_duration microsec(int s) { return boost::posix_time::microsec(s); }
|
||||
inline time_duration minutes(int s) { return boost::posix_time::minutes(s); }
|
||||
inline time_duration hours(int s) { return boost::posix_time::hours(s); }
|
||||
|
||||
inline int total_seconds(time_duration td)
|
||||
{ return td.total_seconds(); }
|
||||
inline int total_milliseconds(time_duration td)
|
||||
{ return td.total_milliseconds(); }
|
||||
inline boost::int64_t total_microseconds(time_duration td)
|
||||
{ return td.total_microseconds(); }
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <asio/time_traits.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
// libtorrent time_duration type
|
||||
struct time_duration
|
||||
{
|
||||
time_duration() {}
|
||||
time_duration operator/(int rhs) const { return time_duration(diff / rhs); }
|
||||
explicit time_duration(boost::int64_t d) : diff(d) {}
|
||||
boost::int64_t diff;
|
||||
};
|
||||
|
||||
inline bool is_negative(time_duration dt) { return dt.diff < 0; }
|
||||
inline bool operator<(time_duration lhs, time_duration rhs)
|
||||
{ return lhs.diff < rhs.diff; }
|
||||
inline bool operator>(time_duration lhs, time_duration rhs)
|
||||
{ return lhs.diff > rhs.diff; }
|
||||
|
||||
// libtorrent time type
|
||||
struct ptime
|
||||
{
|
||||
ptime() {}
|
||||
explicit ptime(boost::int64_t t): time(t) {}
|
||||
boost::int64_t time;
|
||||
};
|
||||
|
||||
inline bool operator>(ptime lhs, ptime rhs)
|
||||
{ return lhs.time > rhs.time; }
|
||||
inline bool operator>=(ptime lhs, ptime rhs)
|
||||
{ return lhs.time >= rhs.time; }
|
||||
inline bool operator<=(ptime lhs, ptime rhs)
|
||||
{ return lhs.time <= rhs.time; }
|
||||
inline bool operator<(ptime lhs, ptime rhs)
|
||||
{ return lhs.time < rhs.time; }
|
||||
inline bool operator!=(ptime lhs, ptime rhs)
|
||||
{ return lhs.time != rhs.time;}
|
||||
inline bool operator==(ptime lhs, ptime rhs)
|
||||
{ return lhs.time == rhs.time;}
|
||||
inline time_duration operator-(ptime lhs, ptime rhs)
|
||||
{ return time_duration(lhs.time - rhs.time); }
|
||||
inline ptime operator+(ptime lhs, time_duration rhs)
|
||||
{ return ptime(lhs.time + rhs.diff); }
|
||||
inline ptime operator+(time_duration lhs, ptime rhs)
|
||||
{ return ptime(rhs.time + lhs.diff); }
|
||||
inline ptime operator-(ptime lhs, time_duration rhs)
|
||||
{ return ptime(lhs.time - rhs.diff); }
|
||||
|
||||
ptime time_now();
|
||||
inline ptime min_time() { return ptime(0); }
|
||||
inline ptime max_time() { return ptime((std::numeric_limits<boost::int64_t>::max)()); }
|
||||
int total_seconds(time_duration td);
|
||||
int total_milliseconds(time_duration td);
|
||||
boost::int64_t total_microseconds(time_duration td);
|
||||
}
|
||||
|
||||
// asio time_traits
|
||||
namespace asio
|
||||
{
|
||||
template<>
|
||||
struct time_traits<libtorrent::ptime>
|
||||
{
|
||||
typedef libtorrent::ptime time_type;
|
||||
typedef libtorrent::time_duration duration_type;
|
||||
static time_type now()
|
||||
{ return time_type(libtorrent::time_now()); }
|
||||
static time_type add(time_type t, duration_type d)
|
||||
{ return time_type(t.time + d.diff);}
|
||||
static duration_type subtract(time_type t1, time_type t2)
|
||||
{ return duration_type(t1 - t2); }
|
||||
static bool less_than(time_type t1, time_type t2)
|
||||
{ return t1 < t2; }
|
||||
static boost::posix_time::time_duration to_posix_duration(
|
||||
duration_type d)
|
||||
{ return boost::posix_time::microseconds(libtorrent::total_microseconds(d)); }
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__MACH__)
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
// high precision timer for darwin intel and ppc
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace aux
|
||||
{
|
||||
inline boost::int64_t absolutetime_to_microseconds(boost::int64_t at)
|
||||
{
|
||||
static mach_timebase_info_data_t timebase_info = {0,0};
|
||||
if (timebase_info.denom == 0)
|
||||
mach_timebase_info(&timebase_info);
|
||||
// make sure we don't overflow
|
||||
assert((at >= 0 && at >= at / 1000 * timebase_info.numer / timebase_info.denom)
|
||||
|| (at < 0 && at < at / 1000 * timebase_info.numer / timebase_info.denom));
|
||||
return at / 1000 * timebase_info.numer / timebase_info.denom;
|
||||
}
|
||||
|
||||
inline boost::int64_t microseconds_to_absolutetime(boost::int64_t ms)
|
||||
{
|
||||
static mach_timebase_info_data_t timebase_info = {0,0};
|
||||
if (timebase_info.denom == 0)
|
||||
{
|
||||
mach_timebase_info(&timebase_info);
|
||||
assert(timebase_info.numer > 0);
|
||||
assert(timebase_info.denom > 0);
|
||||
}
|
||||
// make sure we don't overflow
|
||||
assert((ms >= 0 && ms <= ms * timebase_info.denom / timebase_info.numer * 1000)
|
||||
|| (ms < 0 && ms > ms * timebase_info.denom / timebase_info.numer * 1000));
|
||||
return ms * timebase_info.denom / timebase_info.numer * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
inline int total_seconds(time_duration td)
|
||||
{
|
||||
return aux::absolutetime_to_microseconds(td.diff)
|
||||
/ 1000000;
|
||||
}
|
||||
inline int total_milliseconds(time_duration td)
|
||||
{
|
||||
return aux::absolutetime_to_microseconds(td.diff)
|
||||
/ 1000;
|
||||
}
|
||||
inline boost::int64_t total_microseconds(time_duration td)
|
||||
{
|
||||
return aux::absolutetime_to_microseconds(td.diff);
|
||||
}
|
||||
|
||||
inline ptime time_now() { return ptime(mach_absolute_time()); }
|
||||
|
||||
inline time_duration microsec(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_absolutetime(s));
|
||||
}
|
||||
inline time_duration milliseconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_absolutetime(s * 1000));
|
||||
}
|
||||
inline time_duration seconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_absolutetime(s * 1000000));
|
||||
}
|
||||
inline time_duration minutes(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_absolutetime(s * 1000000 * 60));
|
||||
}
|
||||
inline time_duration hours(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_absolutetime(s * 1000000 * 60 * 60));
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace aux
|
||||
{
|
||||
inline boost::int64_t performance_counter_to_microseconds(boost::int64_t pc)
|
||||
{
|
||||
static LARGE_INTEGER performace_counter_frequency = {0,0};
|
||||
if (performace_counter_frequency.QuadPart == 0)
|
||||
QueryPerformanceFrequency(&performace_counter_frequency);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// make sure we don't overflow
|
||||
boost::int64_t ret = (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
|
||||
assert((pc >= 0 && pc >= ret) || (pc < 0 && pc < ret));
|
||||
#endif
|
||||
return (pc * 1000 / performace_counter_frequency.QuadPart) * 1000;
|
||||
}
|
||||
|
||||
inline boost::int64_t microseconds_to_performance_counter(boost::int64_t ms)
|
||||
{
|
||||
static LARGE_INTEGER performace_counter_frequency = {0,0};
|
||||
if (performace_counter_frequency.QuadPart == 0)
|
||||
QueryPerformanceFrequency(&performace_counter_frequency);
|
||||
#ifndef NDEBUG
|
||||
// make sure we don't overflow
|
||||
boost::int64_t ret = (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
|
||||
assert((ms >= 0 && ms <= ret)
|
||||
|| (ms < 0 && ms > ret));
|
||||
#endif
|
||||
return (ms / 1000) * performace_counter_frequency.QuadPart / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
inline int total_seconds(time_duration td)
|
||||
{
|
||||
return aux::performance_counter_to_microseconds(td.diff)
|
||||
/ 1000000;
|
||||
}
|
||||
inline int total_milliseconds(time_duration td)
|
||||
{
|
||||
return aux::performance_counter_to_microseconds(td.diff)
|
||||
/ 1000;
|
||||
}
|
||||
inline boost::int64_t total_microseconds(time_duration td)
|
||||
{
|
||||
return aux::performance_counter_to_microseconds(td.diff);
|
||||
}
|
||||
|
||||
inline ptime time_now()
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
QueryPerformanceCounter(&now);
|
||||
return ptime(now.QuadPart);
|
||||
}
|
||||
|
||||
inline time_duration microsec(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_performance_counter(s));
|
||||
}
|
||||
inline time_duration milliseconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_performance_counter(
|
||||
s * 1000));
|
||||
}
|
||||
inline time_duration seconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_performance_counter(
|
||||
s * 1000000));
|
||||
}
|
||||
inline time_duration minutes(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_performance_counter(
|
||||
s * 1000000 * 60));
|
||||
}
|
||||
inline time_duration hours(boost::int64_t s)
|
||||
{
|
||||
return time_duration(aux::microseconds_to_performance_counter(
|
||||
s * 1000000 * 60 * 60));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
inline int total_seconds(time_duration td)
|
||||
{
|
||||
return td.diff / 1000000;
|
||||
}
|
||||
inline int total_milliseconds(time_duration td)
|
||||
{
|
||||
return td.diff / 1000;
|
||||
}
|
||||
inline boost::int64_t total_microseconds(time_duration td)
|
||||
{
|
||||
return td.diff;
|
||||
}
|
||||
|
||||
inline ptime time_now()
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ptime(boost::int64_t(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
inline time_duration microsec(boost::int64_t s)
|
||||
{
|
||||
return time_duration(s);
|
||||
}
|
||||
inline time_duration milliseconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(s * 1000);
|
||||
}
|
||||
inline time_duration seconds(boost::int64_t s)
|
||||
{
|
||||
return time_duration(s * 1000000);
|
||||
}
|
||||
inline time_duration minutes(boost::int64_t s)
|
||||
{
|
||||
return time_duration(s * 1000000 * 60);
|
||||
}
|
||||
inline time_duration hours(boost::int64_t s)
|
||||
{
|
||||
return time_duration(s * 1000000 * 60 * 60);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -45,7 +45,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
@ -68,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/escape_string.hpp"
|
||||
#include "libtorrent/bandwidth_manager.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -100,7 +100,8 @@ namespace libtorrent
|
|||
, tcp::endpoint const& net_interface
|
||||
, bool compact_mode
|
||||
, int block_size
|
||||
, session_settings const& s);
|
||||
, session_settings const& s
|
||||
, storage_constructor_type sc);
|
||||
|
||||
// used with metadata-less torrents
|
||||
// (the metadata is downloaded from the peers)
|
||||
|
@ -114,10 +115,14 @@ namespace libtorrent
|
|||
, tcp::endpoint const& net_interface
|
||||
, bool compact_mode
|
||||
, int block_size
|
||||
, session_settings const& s);
|
||||
, session_settings const& s
|
||||
, storage_constructor_type sc);
|
||||
|
||||
~torrent();
|
||||
|
||||
// starts the announce timer
|
||||
void start();
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
void add_extension(boost::shared_ptr<torrent_plugin>);
|
||||
#endif
|
||||
|
@ -142,7 +147,10 @@ namespace libtorrent
|
|||
aux::session_impl& session() { return m_ses; }
|
||||
|
||||
void set_sequenced_download_threshold(int threshold);
|
||||
|
||||
|
||||
bool verify_resume_data(entry& rd, std::string& error)
|
||||
{ assert(m_storage); return m_storage->verify_resume_data(rd, error); }
|
||||
|
||||
// is called every second by session. This will
|
||||
// caclulate the upload/download and number
|
||||
// of connections this torrent needs. And prepare
|
||||
|
@ -168,12 +176,21 @@ namespace libtorrent
|
|||
void resume();
|
||||
bool is_paused() const { return m_paused; }
|
||||
|
||||
// ============ start deprecation =============
|
||||
void filter_piece(int index, bool filter);
|
||||
void filter_pieces(std::vector<bool> const& bitmask);
|
||||
bool is_piece_filtered(int index) const;
|
||||
void filtered_pieces(std::vector<bool>& bitmask) const;
|
||||
|
||||
void filter_files(std::vector<bool> const& files);
|
||||
// ============ end deprecation =============
|
||||
|
||||
void set_piece_priority(int index, int priority);
|
||||
int piece_priority(int index) const;
|
||||
|
||||
void prioritize_pieces(std::vector<int> const& pieces);
|
||||
void piece_priorities(std::vector<int>&) const;
|
||||
|
||||
void prioritize_files(std::vector<int> const& files);
|
||||
|
||||
torrent_status status() const;
|
||||
void file_progress(std::vector<float>& fp) const;
|
||||
|
@ -182,7 +199,7 @@ namespace libtorrent
|
|||
tcp::endpoint const& get_interface() const { return m_net_interface; }
|
||||
|
||||
void connect_to_url_seed(std::string const& url);
|
||||
peer_connection& connect_to_peer(tcp::endpoint const& a);
|
||||
peer_connection* connect_to_peer(policy::peer* peerinfo);
|
||||
|
||||
void set_ratio(float ratio)
|
||||
{ assert(ratio >= 0.0f); m_ratio = ratio; }
|
||||
|
@ -190,10 +207,12 @@ namespace libtorrent
|
|||
float ratio() const
|
||||
{ return m_ratio; }
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void resolve_countries(bool r)
|
||||
{ m_resolve_countries = r; }
|
||||
|
||||
bool resolving_countries() const { return m_resolve_countries; }
|
||||
#endif
|
||||
|
||||
// --------------------------------------------
|
||||
// BANDWIDTH MANAGEMENT
|
||||
|
@ -230,6 +249,9 @@ namespace libtorrent
|
|||
// decreased in the piece_picker
|
||||
void remove_peer(peer_connection* p);
|
||||
|
||||
bool want_more_peers() const;
|
||||
void try_connect_peer();
|
||||
|
||||
peer_connection* connection_for(tcp::endpoint const& a)
|
||||
{
|
||||
peer_iterator i = m_connections.find(a);
|
||||
|
@ -282,7 +304,7 @@ namespace libtorrent
|
|||
|
||||
// returns the absolute time when the next tracker
|
||||
// announce will take place.
|
||||
boost::posix_time::ptime next_announce() const;
|
||||
ptime next_announce() const;
|
||||
|
||||
// returns true if it is time for this torrent to make another
|
||||
// tracker request
|
||||
|
@ -290,7 +312,7 @@ namespace libtorrent
|
|||
|
||||
// forcefully sets next_announce to the current time
|
||||
void force_tracker_request();
|
||||
void force_tracker_request(boost::posix_time::ptime);
|
||||
void force_tracker_request(ptime);
|
||||
|
||||
// sets the username and password that will be sent to
|
||||
// the tracker
|
||||
|
@ -332,6 +354,21 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void peer_has_all()
|
||||
{
|
||||
if (m_picker.get())
|
||||
{
|
||||
assert(!is_seed());
|
||||
m_picker->inc_refcount_all();
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
{
|
||||
assert(is_seed());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// when peer disconnects, this is called for every piece it had
|
||||
void peer_lost(int index)
|
||||
|
@ -394,19 +431,34 @@ namespace libtorrent
|
|||
void received_redundant_data(int num_bytes)
|
||||
{ assert(num_bytes > 0); m_total_redundant_bytes += num_bytes; }
|
||||
|
||||
// this is true if we have all the pieces
|
||||
bool is_seed() const
|
||||
{
|
||||
return valid_metadata()
|
||||
&& m_num_pieces == m_torrent_file.num_pieces();
|
||||
}
|
||||
|
||||
// this is true if we have all the pieces that we want
|
||||
bool is_finished() const
|
||||
{
|
||||
if (is_seed()) return true;
|
||||
return valid_metadata() && m_torrent_file.num_pieces()
|
||||
- m_num_pieces - m_picker->num_filtered() == 0;
|
||||
}
|
||||
|
||||
boost::filesystem::path save_path() const;
|
||||
alert_manager& alerts() const;
|
||||
piece_picker& picker()
|
||||
{
|
||||
assert(!is_seed());
|
||||
assert(m_picker.get());
|
||||
return *m_picker;
|
||||
}
|
||||
bool has_picker() const
|
||||
{
|
||||
assert((valid_metadata() && !is_seed()) == bool(m_picker.get() != 0));
|
||||
return m_picker.get() != 0;
|
||||
}
|
||||
policy& get_policy()
|
||||
{
|
||||
assert(m_policy);
|
||||
|
@ -445,7 +497,10 @@ namespace libtorrent
|
|||
void set_peer_download_limit(tcp::endpoint ip, int limit);
|
||||
|
||||
void set_upload_limit(int limit);
|
||||
int upload_limit() const;
|
||||
void set_download_limit(int limit);
|
||||
int download_limit() const;
|
||||
|
||||
void set_max_uploads(int limit);
|
||||
void set_max_connections(int limit);
|
||||
bool move_storage(boost::filesystem::path const& save_path);
|
||||
|
@ -471,6 +526,8 @@ namespace libtorrent
|
|||
, boost::intrusive_ptr<peer_connection> p) const;
|
||||
bool request_bandwidth_from_session(int channel) const;
|
||||
|
||||
void update_peer_interest();
|
||||
|
||||
torrent_info m_torrent_file;
|
||||
|
||||
// is set to true when the torrent has
|
||||
|
@ -498,7 +555,7 @@ namespace libtorrent
|
|||
boost::scoped_ptr<piece_manager> m_storage;
|
||||
|
||||
// the time of next tracker request
|
||||
boost::posix_time::ptime m_next_request;
|
||||
ptime m_next_request;
|
||||
|
||||
// -----------------------------
|
||||
// DATA FROM TRACKER RESPONSE
|
||||
|
@ -531,33 +588,44 @@ namespace libtorrent
|
|||
// used to resolve the names of web seeds
|
||||
mutable tcp::resolver m_host_resolver;
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
// this is true while there is a country
|
||||
// resolution in progress. To avoid flodding
|
||||
// the DNS request queue, only one ip is reolved
|
||||
// the DNS request queue, only one ip is resolved
|
||||
// at a time.
|
||||
mutable bool m_resolving_country;
|
||||
|
||||
// this is true if the user has enabled
|
||||
// country resolution in this torrent
|
||||
bool m_resolve_countries;
|
||||
#endif
|
||||
|
||||
// this announce timer is used both
|
||||
// by Local service discovery and
|
||||
// by the DHT.
|
||||
deadline_timer m_announce_timer;
|
||||
|
||||
static void on_announce_disp(boost::weak_ptr<torrent> p
|
||||
, asio::error_code const& e);
|
||||
|
||||
// this is called once per announce interval
|
||||
void on_announce();
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
static void on_dht_announce_response_disp(boost::weak_ptr<torrent> t
|
||||
, std::vector<tcp::endpoint> const& peers);
|
||||
deadline_timer m_dht_announce_timer;
|
||||
void on_dht_announce(asio::error_code const& e);
|
||||
void on_dht_announce_response(std::vector<tcp::endpoint> const& peers);
|
||||
bool should_announce_dht() const;
|
||||
|
||||
// the time when the DHT was last announced of our
|
||||
// presence on this torrent
|
||||
ptime m_last_dht_announce;
|
||||
#endif
|
||||
|
||||
// this is the upload and download statistics for the whole torrent.
|
||||
// it's updated from all its peers once every second.
|
||||
libtorrent::stat m_stat;
|
||||
|
||||
// this is the stats for web seeds in this torrent only. It is updated
|
||||
// once every second.
|
||||
libtorrent::stat m_web_stat;
|
||||
|
||||
// -----------------------------
|
||||
|
||||
boost::shared_ptr<policy> m_policy;
|
||||
|
@ -594,6 +662,11 @@ namespace libtorrent
|
|||
// m_have_pieces.end(), 0)
|
||||
int m_num_pieces;
|
||||
|
||||
// in case the piece picker hasn't been constructed
|
||||
// when this settings is set, this variable will keep
|
||||
// its value until the piece picker is created
|
||||
int m_sequenced_download_threshold;
|
||||
|
||||
// is false by default and set to
|
||||
// true when the first tracker reponse
|
||||
// is received
|
||||
|
@ -643,6 +716,8 @@ namespace libtorrent
|
|||
boost::scoped_ptr<std::string> m_name;
|
||||
|
||||
session_settings const& m_settings;
|
||||
|
||||
storage_constructor_type m_storage_constructor;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
|
||||
|
@ -667,20 +742,18 @@ namespace libtorrent
|
|||
#endif
|
||||
};
|
||||
|
||||
inline boost::posix_time::ptime torrent::next_announce() const
|
||||
inline ptime torrent::next_announce() const
|
||||
{
|
||||
return m_next_request;
|
||||
}
|
||||
|
||||
inline void torrent::force_tracker_request()
|
||||
{
|
||||
using boost::posix_time::second_clock;
|
||||
m_next_request = second_clock::universal_time();
|
||||
m_next_request = time_now();
|
||||
}
|
||||
|
||||
inline void torrent::force_tracker_request(boost::posix_time::ptime t)
|
||||
inline void torrent::force_tracker_request(ptime t)
|
||||
{
|
||||
namespace time = boost::posix_time;
|
||||
m_next_request = t;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/peer_info.hpp"
|
||||
#include "libtorrent/piece_picker.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
|
@ -188,7 +189,7 @@ namespace libtorrent
|
|||
// the number of distributed copies of the file.
|
||||
// note that one copy may be spread out among many peers.
|
||||
//
|
||||
// the whole number part tells how many copies
|
||||
// the integer part tells how many copies
|
||||
// there are of the rarest piece(s)
|
||||
//
|
||||
// the fractional part tells the fraction of pieces that
|
||||
|
@ -203,13 +204,15 @@ namespace libtorrent
|
|||
|
||||
struct TORRENT_EXPORT partial_piece_info
|
||||
{
|
||||
enum { max_blocks_per_piece = piece_picker::max_blocks_per_piece };
|
||||
enum { max_blocks_per_piece = 256 };
|
||||
int piece_index;
|
||||
int blocks_in_piece;
|
||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||
tcp::endpoint peer[max_blocks_per_piece];
|
||||
int num_downloads[max_blocks_per_piece];
|
||||
enum state_t { none, slow, medium, fast };
|
||||
state_t piece_state;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT torrent_handle
|
||||
|
@ -243,9 +246,16 @@ namespace libtorrent
|
|||
bool is_paused() const;
|
||||
void pause() const;
|
||||
void resume() const;
|
||||
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void resolve_countries(bool r);
|
||||
bool resolve_countries() const;
|
||||
#endif
|
||||
|
||||
// all these are deprecated, use piece
|
||||
// priority functions instead
|
||||
|
||||
// ================ start deprecation ============
|
||||
|
||||
// marks the piece with the given index as filtered
|
||||
// it will not be downloaded
|
||||
|
@ -253,11 +263,22 @@ namespace libtorrent
|
|||
void filter_pieces(std::vector<bool> const& pieces) const;
|
||||
bool is_piece_filtered(int index) const;
|
||||
std::vector<bool> filtered_pieces() const;
|
||||
|
||||
// marks the file with the given index as filtered
|
||||
// it will not be downloaded
|
||||
void filter_files(std::vector<bool> const& files) const;
|
||||
|
||||
// ================ end deprecation ============
|
||||
|
||||
// priority must be within the range [0, 7]
|
||||
void piece_priority(int index, int priority) const;
|
||||
int piece_priority(int index) const;
|
||||
|
||||
void prioritize_pieces(std::vector<int> const& pieces) const;
|
||||
std::vector<int> piece_priorities() const;
|
||||
|
||||
void prioritize_files(std::vector<int> const& files) const;
|
||||
|
||||
|
||||
// set the interface to bind outgoing connections
|
||||
// to.
|
||||
void use_interface(const char* net_interface) const;
|
||||
|
@ -284,14 +305,17 @@ namespace libtorrent
|
|||
// abort the torrent.
|
||||
|
||||
void set_upload_limit(int limit) const;
|
||||
int upload_limit() const;
|
||||
void set_download_limit(int limit) const;
|
||||
int download_limit() const;
|
||||
|
||||
void set_sequenced_download_threshold(int threshold) const;
|
||||
|
||||
void set_peer_upload_limit(tcp::endpoint ip, int limit) const;
|
||||
void set_peer_download_limit(tcp::endpoint ip, int limit) const;
|
||||
|
||||
// manually connect a peer
|
||||
void connect_peer(tcp::endpoint const& adr) const;
|
||||
void connect_peer(tcp::endpoint const& adr, int source = 0) const;
|
||||
|
||||
// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
|
||||
// the ratio is uploaded / downloaded. less than 1 is not allowed
|
||||
|
@ -349,3 +373,4 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
#endif // TORRENT_TORRENT_HANDLE_HPP_INCLUDED
|
||||
|
||||
|
|
|
@ -41,8 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian_types.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
@ -57,9 +55,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/peer_request.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace pt = boost::posix_time;
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
struct TORRENT_EXPORT file_entry
|
||||
{
|
||||
|
@ -114,7 +115,11 @@ namespace libtorrent
|
|||
std::vector<file_slice> map_block(int piece, size_type offset, int size) const;
|
||||
peer_request map_file(int file, size_type offset, int size) const;
|
||||
|
||||
std::vector<std::string> const& url_seeds() const { return m_url_seeds; }
|
||||
std::vector<std::string> const& url_seeds() const
|
||||
{
|
||||
assert(!m_half_metadata);
|
||||
return m_url_seeds;
|
||||
}
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
||||
|
@ -134,10 +139,14 @@ namespace libtorrent
|
|||
|
||||
size_type total_size() const { assert(m_piece_length > 0); return m_total_size; }
|
||||
size_type piece_length() const { assert(m_piece_length > 0); return m_piece_length; }
|
||||
int num_pieces() const { assert(m_piece_length > 0); return (int)m_piece_hash.size(); }
|
||||
int num_pieces() const { assert(m_piece_length > 0); return m_num_pieces; }
|
||||
const sha1_hash& info_hash() const { return m_info_hash; }
|
||||
const std::string& name() const { assert(m_piece_length > 0); return m_name; }
|
||||
|
||||
// ------- start deprecation -------
|
||||
void print(std::ostream& os) const;
|
||||
// ------- end deprecation -------
|
||||
|
||||
bool is_valid() const { return m_piece_length > 0; }
|
||||
|
||||
bool priv() const { return m_private; }
|
||||
|
@ -151,11 +160,11 @@ namespace libtorrent
|
|||
{
|
||||
assert(index >= 0);
|
||||
assert(index < (int)m_piece_hash.size());
|
||||
assert(!m_half_metadata);
|
||||
return m_piece_hash[index];
|
||||
}
|
||||
|
||||
boost::optional<boost::posix_time::ptime>
|
||||
creation_date() const;
|
||||
boost::optional<pt::ptime> creation_date() const;
|
||||
|
||||
const std::string& creator() const
|
||||
{ return m_created_by; }
|
||||
|
@ -167,12 +176,22 @@ namespace libtorrent
|
|||
typedef std::vector<std::pair<std::string, int> > nodes_t;
|
||||
|
||||
nodes_t const& nodes() const
|
||||
{ return m_nodes; }
|
||||
{
|
||||
assert(!m_half_metadata);
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
|
||||
void parse_info_section(entry const& e);
|
||||
|
||||
entry extra(char const* key) const
|
||||
{ return m_extra_info[key]; }
|
||||
|
||||
// frees parts of the metadata that isn't
|
||||
// used by seeds
|
||||
void seed_free();
|
||||
|
||||
private:
|
||||
|
||||
void read_torrent_info(const entry& libtorrent);
|
||||
|
@ -198,6 +217,9 @@ namespace libtorrent
|
|||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
|
@ -208,7 +230,7 @@ namespace libtorrent
|
|||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
boost::posix_time::ptime m_creation_date;
|
||||
pt::ptime m_creation_date;
|
||||
|
||||
// if a comment is found in the torrent file
|
||||
// this will be set to that comment
|
||||
|
@ -234,6 +256,11 @@ namespace libtorrent
|
|||
// reproduce the info-section when sending the metadata
|
||||
// to peers.
|
||||
entry m_extra_info;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// this is set to true when seed_free() is called
|
||||
bool m_half_metadata;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
@ -61,6 +60,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/peer.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/connection_queue.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -75,14 +76,13 @@ namespace libtorrent
|
|||
// returns -1 if gzip header is invalid or the header size in bytes
|
||||
TORRENT_EXPORT int gzip_header(const char* buf, int size);
|
||||
|
||||
TORRENT_EXPORT boost::tuple<std::string, std::string, int, std::string>
|
||||
TORRENT_EXPORT boost::tuple<std::string, std::string, std::string, int, std::string>
|
||||
parse_url_components(std::string url);
|
||||
|
||||
struct TORRENT_EXPORT tracker_request
|
||||
{
|
||||
tracker_request()
|
||||
: kind(announce_request)
|
||||
, web_downloaded(0)
|
||||
, event(none)
|
||||
, key(0)
|
||||
, num_want(0)
|
||||
|
@ -107,7 +107,6 @@ namespace libtorrent
|
|||
size_type downloaded;
|
||||
size_type uploaded;
|
||||
size_type left;
|
||||
size_type web_downloaded;
|
||||
unsigned short listen_port;
|
||||
event_t event;
|
||||
std::string url;
|
||||
|
@ -155,8 +154,8 @@ namespace libtorrent
|
|||
struct TORRENT_EXPORT timeout_handler
|
||||
: boost::noncopyable
|
||||
{
|
||||
friend void intrusive_ptr_add_ref(timeout_handler const*);
|
||||
friend void intrusive_ptr_release(timeout_handler const*);
|
||||
friend TORRENT_EXPORT void intrusive_ptr_add_ref(timeout_handler const*);
|
||||
friend TORRENT_EXPORT void intrusive_ptr_release(timeout_handler const*);
|
||||
|
||||
timeout_handler(asio::strand& str);
|
||||
|
||||
|
@ -177,11 +176,11 @@ namespace libtorrent
|
|||
asio::strand& m_strand;
|
||||
// used for timeouts
|
||||
// this is set when the request has been sent
|
||||
boost::posix_time::ptime m_start_time;
|
||||
ptime m_start_time;
|
||||
// this is set every time something is received
|
||||
boost::posix_time::ptime m_read_time;
|
||||
ptime m_read_time;
|
||||
// the asio async operation
|
||||
asio::deadline_timer m_timeout;
|
||||
deadline_timer m_timeout;
|
||||
|
||||
int m_completion_timeout;
|
||||
int m_read_timeout;
|
||||
|
@ -223,11 +222,14 @@ namespace libtorrent
|
|||
{
|
||||
public:
|
||||
|
||||
tracker_manager(const session_settings& s)
|
||||
: m_settings(s) {}
|
||||
tracker_manager(session_settings const& s, proxy_settings const& ps)
|
||||
: m_settings(s)
|
||||
, m_proxy(ps)
|
||||
, m_abort(false) {}
|
||||
|
||||
void queue_request(
|
||||
asio::strand& str
|
||||
, connection_queue& cc
|
||||
, tracker_request r
|
||||
, std::string const& auth
|
||||
, address bind_infc
|
||||
|
@ -247,6 +249,8 @@ namespace libtorrent
|
|||
tracker_connections_t;
|
||||
tracker_connections_t m_connections;
|
||||
session_settings const& m_settings;
|
||||
proxy_settings const& m_proxy;
|
||||
bool m_abort;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
237
libtorrent/include/libtorrent/upnp.hpp
Normal file
237
libtorrent/include/libtorrent/upnp.hpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_UPNP_HPP
|
||||
#define TORRENT_UPNP_HPP
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/http_connection.hpp"
|
||||
#include "libtorrent/connection_queue.hpp"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <set>
|
||||
|
||||
|
||||
#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined (TORRENT_UPNP_LOGGING)
|
||||
#define TORRENT_UPNP_LOGGING
|
||||
#endif
|
||||
|
||||
#if defined(TORRENT_UPNP_LOGGING)
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
bool is_local(address const& a);
|
||||
address_v4 guess_local_address(asio::io_service&);
|
||||
|
||||
// int: external tcp port
|
||||
// int: external udp port
|
||||
// std::string: error message
|
||||
typedef boost::function<void(int, int, std::string const&)> portmap_callback_t;
|
||||
|
||||
class upnp : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
upnp(io_service& ios, connection_queue& cc
|
||||
, address const& listen_interface, std::string const& user_agent
|
||||
, portmap_callback_t const& cb);
|
||||
~upnp();
|
||||
|
||||
void rebind(address const& listen_interface);
|
||||
|
||||
// maps the ports, if a port is set to 0
|
||||
// it will not be mapped
|
||||
void set_mappings(int tcp, int udp);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
static address_v4 upnp_multicast_address;
|
||||
static udp::endpoint upnp_multicast_endpoint;
|
||||
|
||||
enum { num_mappings = 2 };
|
||||
enum { default_lease_time = 3600 };
|
||||
|
||||
void update_mapping(int i, int port);
|
||||
void resend_request(asio::error_code const& e);
|
||||
void on_reply(asio::error_code const& e
|
||||
, std::size_t bytes_transferred);
|
||||
void discover_device();
|
||||
|
||||
struct rootdevice;
|
||||
|
||||
void on_upnp_xml(asio::error_code const& e
|
||||
, libtorrent::http_parser const& p, rootdevice& d);
|
||||
void on_upnp_map_response(asio::error_code const& e
|
||||
, libtorrent::http_parser const& p, rootdevice& d
|
||||
, int mapping);
|
||||
void on_upnp_unmap_response(asio::error_code const& e
|
||||
, libtorrent::http_parser const& p, rootdevice& d
|
||||
, int mapping);
|
||||
void on_expire(asio::error_code const& e);
|
||||
|
||||
void post(rootdevice& d, std::stringstream const& s
|
||||
, std::string const& soap_action);
|
||||
void map_port(rootdevice& d, int i);
|
||||
void unmap_port(rootdevice& d, int i);
|
||||
void disable();
|
||||
|
||||
struct mapping_t
|
||||
{
|
||||
mapping_t()
|
||||
: need_update(false)
|
||||
, local_port(0)
|
||||
, external_port(0)
|
||||
, protocol(1)
|
||||
{}
|
||||
|
||||
// the time the port mapping will expire
|
||||
ptime expires;
|
||||
|
||||
bool need_update;
|
||||
|
||||
// the local port for this mapping. If this is set
|
||||
// to 0, the mapping is not in use
|
||||
int local_port;
|
||||
|
||||
// the external (on the NAT router) port
|
||||
// for the mapping. This is the port we
|
||||
// should announce to others
|
||||
int external_port;
|
||||
|
||||
// 1 = udp, 0 = tcp
|
||||
int protocol;
|
||||
};
|
||||
|
||||
struct rootdevice
|
||||
{
|
||||
rootdevice(): service_namespace(0)
|
||||
, lease_duration(default_lease_time)
|
||||
, supports_specific_external(true)
|
||||
, disabled(false)
|
||||
{
|
||||
mapping[0].protocol = 0;
|
||||
mapping[1].protocol = 1;
|
||||
}
|
||||
|
||||
// the interface url, through which the list of
|
||||
// supported interfaces are fetched
|
||||
std::string url;
|
||||
|
||||
// the url to the WANIP or WANPPP interface
|
||||
std::string control_url;
|
||||
// either the WANIP namespace or the WANPPP namespace
|
||||
char const* service_namespace;
|
||||
|
||||
mapping_t mapping[num_mappings];
|
||||
|
||||
std::string hostname;
|
||||
int port;
|
||||
std::string path;
|
||||
|
||||
int lease_duration;
|
||||
// true if the device supports specifying a
|
||||
// specific external port, false if it doesn't
|
||||
bool supports_specific_external;
|
||||
|
||||
bool disabled;
|
||||
|
||||
mutable boost::shared_ptr<http_connection> upnp_connection;
|
||||
|
||||
void close() const
|
||||
{
|
||||
if (!upnp_connection) return;
|
||||
upnp_connection->close();
|
||||
upnp_connection.reset();
|
||||
}
|
||||
|
||||
bool operator<(rootdevice const& rhs) const
|
||||
{ return url < rhs.url; }
|
||||
};
|
||||
|
||||
int m_udp_local_port;
|
||||
int m_tcp_local_port;
|
||||
|
||||
std::string const& m_user_agent;
|
||||
|
||||
// the set of devices we've found
|
||||
std::set<rootdevice> m_devices;
|
||||
|
||||
portmap_callback_t m_callback;
|
||||
|
||||
// current retry count
|
||||
int m_retry_count;
|
||||
|
||||
// used to receive responses in
|
||||
char m_receive_buffer[1024];
|
||||
|
||||
// the endpoint we received the message from
|
||||
udp::endpoint m_remote;
|
||||
|
||||
// the local address we're listening on
|
||||
address_v4 m_local_ip;
|
||||
|
||||
// the udp socket used to send and receive
|
||||
// multicast messages on the network
|
||||
datagram_socket m_socket;
|
||||
|
||||
// used to resend udp packets in case
|
||||
// they time out
|
||||
deadline_timer m_broadcast_timer;
|
||||
|
||||
// timer used to refresh mappings
|
||||
deadline_timer m_refresh_timer;
|
||||
|
||||
asio::strand m_strand;
|
||||
|
||||
bool m_disabled;
|
||||
bool m_closing;
|
||||
|
||||
connection_queue& m_cc;
|
||||
|
||||
#ifdef TORRENT_UPNP_LOGGING
|
||||
std::ofstream m_log;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
716
libtorrent/include/libtorrent/variant_stream.hpp
Normal file
716
libtorrent/include/libtorrent/variant_stream.hpp
Normal file
|
@ -0,0 +1,716 @@
|
|||
// Copyright Daniel Wallin and Arvid Norberg 2007.
|
||||
// Use, modification and distribution is
|
||||
// subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef VARIANT_STREAM_070211_HPP
|
||||
# define VARIANT_STREAM_070211_HPP
|
||||
|
||||
# include <boost/variant.hpp>
|
||||
|
||||
# include <boost/mpl/vector.hpp>
|
||||
# include <boost/mpl/void.hpp>
|
||||
# include <boost/mpl/remove.hpp>
|
||||
# include <boost/mpl/transform.hpp>
|
||||
# include <boost/mpl/size.hpp>
|
||||
|
||||
# include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
# include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
# include <boost/preprocessor/facilities/intercept.hpp>
|
||||
|
||||
# include <boost/type_traits/add_pointer.hpp>
|
||||
# include <boost/noncopyable.hpp>
|
||||
|
||||
#include <asio/io_service.hpp>
|
||||
|
||||
# define NETWORK_VARIANT_STREAM_LIMIT 5
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
namespace aux
|
||||
{
|
||||
|
||||
struct delete_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
};
|
||||
|
||||
// -------------- io_control -----------
|
||||
|
||||
template<class IO_Control_Command>
|
||||
struct io_control_visitor_ec: boost::static_visitor<>
|
||||
{
|
||||
io_control_visitor_ec(IO_Control_Command& ioc, asio::error_code& ec)
|
||||
: ioc(ioc), ec(ec) {}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->io_control(ioc, ec);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
IO_Control_Command& ioc;
|
||||
asio::error_code& ec;
|
||||
};
|
||||
|
||||
template<class IO_Control_Command>
|
||||
struct io_control_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
io_control_visitor(IO_Control_Command& ioc)
|
||||
: ioc(ioc) {}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->io_control(ioc);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
IO_Control_Command& ioc;
|
||||
};
|
||||
// -------------- async_connect -----------
|
||||
|
||||
template <class EndpointType, class Handler>
|
||||
struct async_connect_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
async_connect_visitor(EndpointType const& endpoint, Handler const& handler)
|
||||
: endpoint(endpoint)
|
||||
, handler(handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->async_connect(endpoint, handler);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
EndpointType const& endpoint;
|
||||
Handler const& handler;
|
||||
};
|
||||
|
||||
// -------------- bind -----------
|
||||
|
||||
template <class EndpointType, class Error_Handler = boost::mpl::void_>
|
||||
struct bind_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
bind_visitor(EndpointType const& ep, Error_Handler const& error_handler)
|
||||
: endpoint(ep)
|
||||
, error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->bind(endpoint, error_handler);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
EndpointType const& endpoint;
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <class EndpointType>
|
||||
struct bind_visitor<EndpointType, boost::mpl::void_>
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
bind_visitor(EndpointType const& ep)
|
||||
: endpoint(ep)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->bind(endpoint);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
EndpointType const& endpoint;
|
||||
};
|
||||
|
||||
// -------------- open -----------
|
||||
|
||||
template <class Protocol, class Error_Handler = boost::mpl::void_>
|
||||
struct open_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
open_visitor(Protocol const& p, Error_Handler const& error_handler)
|
||||
: proto(p)
|
||||
, error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->open(proto, error_handler);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
Protocol const& proto;
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <class Protocol>
|
||||
struct open_visitor<Protocol, boost::mpl::void_>
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
open_visitor(Protocol const& p)
|
||||
: proto(p)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->open(proto);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
Protocol const& proto;
|
||||
};
|
||||
|
||||
// -------------- close -----------
|
||||
|
||||
template <class Error_Handler = boost::mpl::void_>
|
||||
struct close_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
close_visitor(Error_Handler const& error_handler)
|
||||
: error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->close(error_handler);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct close_visitor<boost::mpl::void_>
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->close();
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
};
|
||||
|
||||
// -------------- remote_endpoint -----------
|
||||
|
||||
template <class EndpointType, class Error_Handler = boost::mpl::void_>
|
||||
struct remote_endpoint_visitor
|
||||
: boost::static_visitor<EndpointType>
|
||||
{
|
||||
remote_endpoint_visitor(Error_Handler const& error_handler)
|
||||
: error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
EndpointType operator()(T* p) const
|
||||
{
|
||||
return p->remote_endpoint(error_handler);
|
||||
}
|
||||
|
||||
EndpointType operator()(boost::blank) const
|
||||
{
|
||||
return EndpointType();
|
||||
}
|
||||
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <class EndpointType>
|
||||
struct remote_endpoint_visitor<EndpointType, boost::mpl::void_>
|
||||
: boost::static_visitor<EndpointType>
|
||||
{
|
||||
template <class T>
|
||||
EndpointType operator()(T* p) const
|
||||
{
|
||||
return p->remote_endpoint();
|
||||
}
|
||||
|
||||
EndpointType operator()(boost::blank) const
|
||||
{
|
||||
return EndpointType();
|
||||
}
|
||||
};
|
||||
|
||||
// -------------- local_endpoint -----------
|
||||
|
||||
template <class EndpointType, class Error_Handler = boost::mpl::void_>
|
||||
struct local_endpoint_visitor
|
||||
: boost::static_visitor<EndpointType>
|
||||
{
|
||||
local_endpoint_visitor(Error_Handler const& error_handler)
|
||||
: error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
EndpointType operator()(T* p) const
|
||||
{
|
||||
return p->local_endpoint(error_handler);
|
||||
}
|
||||
|
||||
EndpointType operator()(boost::blank) const
|
||||
{
|
||||
return EndpointType();
|
||||
}
|
||||
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <class EndpointType>
|
||||
struct local_endpoint_visitor<EndpointType, boost::mpl::void_>
|
||||
: boost::static_visitor<EndpointType>
|
||||
{
|
||||
template <class T>
|
||||
EndpointType operator()(T* p) const
|
||||
{
|
||||
return p->local_endpoint();
|
||||
}
|
||||
|
||||
EndpointType operator()(boost::blank) const
|
||||
{
|
||||
return EndpointType();
|
||||
}
|
||||
};
|
||||
|
||||
// -------------- async_read_some -----------
|
||||
|
||||
template <class Mutable_Buffers, class Handler>
|
||||
struct async_read_some_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
async_read_some_visitor(Mutable_Buffers const& buffers, Handler const& handler)
|
||||
: buffers(buffers)
|
||||
, handler(handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->async_read_some(buffers, handler);
|
||||
}
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
Mutable_Buffers const& buffers;
|
||||
Handler const& handler;
|
||||
};
|
||||
|
||||
// -------------- read_some -----------
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
struct read_some_visitor
|
||||
: boost::static_visitor<std::size_t>
|
||||
{
|
||||
read_some_visitor(Mutable_Buffers const& buffers)
|
||||
: buffers(buffers)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
std::size_t operator()(T* p) const
|
||||
{ return p->read_some(buffers); }
|
||||
|
||||
std::size_t operator()(boost::blank) const
|
||||
{ return 0; }
|
||||
|
||||
Mutable_Buffers const& buffers;
|
||||
};
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
struct read_some_visitor_ec
|
||||
: boost::static_visitor<std::size_t>
|
||||
{
|
||||
read_some_visitor_ec(Mutable_Buffers const& buffers, asio::error_code& ec)
|
||||
: buffers(buffers)
|
||||
, ec(ec)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
std::size_t operator()(T* p) const
|
||||
{ return p->read_some(buffers, ec); }
|
||||
|
||||
std::size_t operator()(boost::blank) const
|
||||
{ return 0; }
|
||||
|
||||
Mutable_Buffers const& buffers;
|
||||
asio::error_code& ec;
|
||||
};
|
||||
|
||||
// -------------- async_write_some -----------
|
||||
|
||||
template <class Const_Buffers, class Handler>
|
||||
struct async_write_some_visitor
|
||||
: boost::static_visitor<>
|
||||
{
|
||||
async_write_some_visitor(Const_Buffers const& buffers, Handler const& handler)
|
||||
: buffers(buffers)
|
||||
, handler(handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
void operator()(T* p) const
|
||||
{
|
||||
p->async_write_some(buffers, handler);
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
|
||||
Const_Buffers const& buffers;
|
||||
Handler const& handler;
|
||||
};
|
||||
|
||||
// -------------- in_avail -----------
|
||||
|
||||
template <class Error_Handler = boost::mpl::void_>
|
||||
struct in_avail_visitor
|
||||
: boost::static_visitor<std::size_t>
|
||||
{
|
||||
in_avail_visitor(Error_Handler const& error_handler)
|
||||
: error_handler(error_handler)
|
||||
{}
|
||||
|
||||
template <class T>
|
||||
std::size_t operator()(T* p) const
|
||||
{
|
||||
return p->in_avail(error_handler);
|
||||
}
|
||||
|
||||
std::size_t operator()(boost::blank) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Error_Handler const& error_handler;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct in_avail_visitor<boost::mpl::void_>
|
||||
: boost::static_visitor<std::size_t>
|
||||
{
|
||||
template <class T>
|
||||
std::size_t operator()(T* p) const
|
||||
{
|
||||
return p->in_avail();
|
||||
}
|
||||
|
||||
void operator()(boost::blank) const
|
||||
{}
|
||||
};
|
||||
|
||||
// -------------- io_service -----------
|
||||
|
||||
template <class IOService>
|
||||
struct io_service_visitor
|
||||
: boost::static_visitor<IOService&>
|
||||
{
|
||||
template <class T>
|
||||
IOService& operator()(T* p) const
|
||||
{
|
||||
return p->io_service();
|
||||
}
|
||||
|
||||
IOService& operator()(boost::blank) const
|
||||
{
|
||||
return *(IOService*)0;
|
||||
}
|
||||
};
|
||||
|
||||
// -------------- lowest_layer -----------
|
||||
|
||||
template <class LowestLayer>
|
||||
struct lowest_layer_visitor
|
||||
: boost::static_visitor<LowestLayer&>
|
||||
{
|
||||
template <class T>
|
||||
LowestLayer& operator()(T* p) const
|
||||
{
|
||||
return p->lowest_layer();
|
||||
}
|
||||
|
||||
LowestLayer& operator()(boost::blank) const
|
||||
{
|
||||
return *(LowestLayer*)0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace aux
|
||||
|
||||
template <
|
||||
BOOST_PP_ENUM_BINARY_PARAMS(
|
||||
NETWORK_VARIANT_STREAM_LIMIT, class S, = boost::mpl::void_ BOOST_PP_INTERCEPT
|
||||
)
|
||||
>
|
||||
class variant_stream : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef BOOST_PP_CAT(boost::mpl::vector, NETWORK_VARIANT_STREAM_LIMIT)<
|
||||
BOOST_PP_ENUM_PARAMS(NETWORK_VARIANT_STREAM_LIMIT, S)
|
||||
> types0;
|
||||
|
||||
typedef typename boost::mpl::remove<types0, boost::mpl::void_>::type types;
|
||||
|
||||
typedef typename boost::make_variant_over<
|
||||
typename boost::mpl::push_back<
|
||||
typename boost::mpl::transform<
|
||||
types
|
||||
, boost::add_pointer<boost::mpl::_>
|
||||
>::type
|
||||
, boost::blank
|
||||
>::type
|
||||
>::type variant_type;
|
||||
|
||||
typedef typename S0::lowest_layer_type lowest_layer_type;
|
||||
typedef typename S0::endpoint_type endpoint_type;
|
||||
typedef typename S0::protocol_type protocol_type;
|
||||
|
||||
explicit variant_stream(asio::io_service& io_service)
|
||||
: m_io_service(io_service)
|
||||
, m_variant(boost::blank())
|
||||
{}
|
||||
|
||||
template <class S>
|
||||
void instantiate()
|
||||
{
|
||||
std::auto_ptr<S> owned(new S(m_io_service));
|
||||
boost::apply_visitor(aux::delete_visitor(), m_variant);
|
||||
m_variant = owned.get();
|
||||
owned.release();
|
||||
}
|
||||
|
||||
template <class S>
|
||||
S& get()
|
||||
{
|
||||
return *boost::get<S*>(m_variant);
|
||||
}
|
||||
|
||||
bool instantiated() const
|
||||
{
|
||||
return m_variant.which() != boost::mpl::size<types>::value;
|
||||
}
|
||||
|
||||
~variant_stream()
|
||||
{
|
||||
boost::apply_visitor(aux::delete_visitor(), m_variant);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::read_some_visitor_ec<Mutable_Buffers>(buffers, ec)
|
||||
, m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers>
|
||||
std::size_t read_some(Mutable_Buffers const& buffers)
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::read_some_visitor<Mutable_Buffers>(buffers)
|
||||
, m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class Mutable_Buffers, class Handler>
|
||||
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::async_read_some_visitor<Mutable_Buffers, Handler>(buffers, handler)
|
||||
, m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class Const_Buffers, class Handler>
|
||||
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::async_write_some_visitor<Const_Buffers, Handler>(buffers, handler)
|
||||
, m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::async_connect_visitor<endpoint_type, Handler>(endpoint, handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::io_control_visitor<IO_Control_Command>(ioc), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
template <class IO_Control_Command>
|
||||
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::io_control_visitor_ec<IO_Control_Command>(ioc, ec)
|
||||
, m_variant
|
||||
);
|
||||
}
|
||||
|
||||
void bind(endpoint_type const& endpoint)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(aux::bind_visitor<endpoint_type>(endpoint), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void bind(endpoint_type const& endpoint, Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::bind_visitor<endpoint_type, Error_Handler>(endpoint, error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
void open(protocol_type const& p)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(aux::open_visitor<protocol_type>(p), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void open(protocol_type const& p, Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::open_visitor<protocol_type, Error_Handler>(p, error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(aux::close_visitor<>(), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
void close(Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
boost::apply_visitor(
|
||||
aux::close_visitor<Error_Handler>(error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
std::size_t in_avail()
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(aux::in_avail_visitor<>(), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
std::size_t in_avail(Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::in_avail_visitor<Error_Handler>(error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
endpoint_type remote_endpoint()
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type remote_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::remote_endpoint_visitor<endpoint_type, Error_Handler>(error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
endpoint_type local_endpoint()
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant);
|
||||
}
|
||||
|
||||
template <class Error_Handler>
|
||||
endpoint_type local_endpoint(Error_Handler const& error_handler)
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::local_endpoint_visitor<endpoint_type, Error_Handler>(error_handler), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
asio::io_service& io_service()
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::io_service_visitor<asio::io_service>(), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
lowest_layer_type& lowest_layer()
|
||||
{
|
||||
assert(instantiated());
|
||||
return boost::apply_visitor(
|
||||
aux::lowest_layer_visitor<lowest_layer_type>(), m_variant
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_service& m_io_service;
|
||||
variant_type m_variant;
|
||||
};
|
||||
|
||||
} // namespace libtorrent
|
||||
|
||||
#endif // VARIANT_STREAM_070211_HPP
|
||||
|
|
@ -34,8 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_VERSION_HPP_INCLUDED
|
||||
|
||||
#define LIBTORRENT_VERSION_MAJOR 0
|
||||
#define LIBTORRENT_VERSION_MINOR 12
|
||||
#define LIBTORRENT_VERSION_MINOR 13
|
||||
|
||||
#define LIBTORRENT_VERSION "0.12.0.0"
|
||||
#define LIBTORRENT_VERSION "0.13.0.0"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
|
@ -96,10 +95,10 @@ namespace libtorrent
|
|||
web_peer_connection(
|
||||
aux::session_impl& ses
|
||||
, boost::weak_ptr<torrent> t
|
||||
, boost::shared_ptr<stream_socket> s
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, tcp::endpoint const& remote
|
||||
, tcp::endpoint const& proxy
|
||||
, std::string const& url);
|
||||
, std::string const& url
|
||||
, policy::peer* peerinfo);
|
||||
|
||||
~web_peer_connection();
|
||||
|
||||
|
@ -149,6 +148,7 @@ namespace libtorrent
|
|||
|
||||
std::string m_server_string;
|
||||
http_parser m_parser;
|
||||
std::string m_auth;
|
||||
std::string m_host;
|
||||
int m_port;
|
||||
std::string m_path;
|
||||
|
@ -164,6 +164,14 @@ namespace libtorrent
|
|||
std::vector<char> m_piece;
|
||||
// the mapping of the data in the m_piece buffer
|
||||
peer_request m_intermediate_piece;
|
||||
|
||||
// the number of bytes into the receive buffer where
|
||||
// current read cursor is.
|
||||
int m_body_start;
|
||||
// the number of bytes received in the current HTTP
|
||||
// response. used to know where in the buffer the
|
||||
// next response starts
|
||||
int m_received_body;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
99
libtorrent/include/libtorrent/xml_parse.hpp
Normal file
99
libtorrent/include/libtorrent/xml_parse.hpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_XML_PARSE_HPP
|
||||
#define TORRENT_XML_PARSE_HPP
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
const int xml_start_tag = 0;
|
||||
const int xml_end_tag = 1;
|
||||
const int xml_string = 2;
|
||||
|
||||
template <class CallbackType>
|
||||
void xml_parse(char* p, char* end, CallbackType callback)
|
||||
{
|
||||
for(;p != end; ++p)
|
||||
{
|
||||
char const* start = p;
|
||||
// look for tag start
|
||||
for(; *p != '<' && p != end; ++p);
|
||||
|
||||
if (p != start)
|
||||
{
|
||||
if (p != end)
|
||||
{
|
||||
assert(*p == '<');
|
||||
*p = 0;
|
||||
}
|
||||
callback(xml_string, start);
|
||||
if (p != end) *p = '<';
|
||||
}
|
||||
|
||||
if (p == end) break;
|
||||
|
||||
// skip '<'
|
||||
++p;
|
||||
|
||||
// parse the name of the tag. Ignore attributes
|
||||
for (start = p; p != end && *p != '>'; ++p)
|
||||
{
|
||||
// terminate the string at the first space
|
||||
// to ignore tag attributes
|
||||
if (*p == ' ') *p = 0;
|
||||
}
|
||||
|
||||
// parse error
|
||||
if (p == end) break;
|
||||
|
||||
assert(*p == '>');
|
||||
*p = 0;
|
||||
|
||||
if (*start == '/')
|
||||
{
|
||||
++start;
|
||||
callback(xml_end_tag, start);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(xml_start_tag, start);
|
||||
}
|
||||
*p = '>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -15,12 +15,13 @@ endif
|
|||
libtorrent_la_SOURCES = allocate_resources.cpp \
|
||||
bandwidth_manager.cpp entry.cpp escape_string.cpp \
|
||||
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
|
||||
piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp stat.cpp \
|
||||
storage.cpp torrent.cpp torrent_handle.cpp \
|
||||
torrent_info.cpp tracker_manager.cpp \
|
||||
natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \
|
||||
stat.cpp storage.cpp torrent.cpp torrent_handle.cpp \
|
||||
torrent_info.cpp tracker_manager.cpp http_connection.cpp \
|
||||
http_tracker_connection.cpp udp_tracker_connection.cpp \
|
||||
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
|
||||
logger.cpp file_pool.cpp ut_pex.cpp $(kademlia_sources)
|
||||
logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp \
|
||||
socks5_stream.cpp http_stream.cpp connection_queue.cpp $(kademlia_sources)
|
||||
|
||||
noinst_HEADERS = \
|
||||
$(top_srcdir)/include/libtorrent/alert.hpp \
|
||||
|
@ -31,6 +32,7 @@ $(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \
|
|||
$(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \
|
||||
$(top_srcdir)/include/libtorrent/bencode.hpp \
|
||||
$(top_srcdir)/include/libtorrent/buffer.hpp \
|
||||
$(top_srcdir)/include/libtorrent/connection_queue.hpp \
|
||||
$(top_srcdir)/include/libtorrent/debug.hpp \
|
||||
$(top_srcdir)/include/libtorrent/entry.hpp \
|
||||
$(top_srcdir)/include/libtorrent/escape_string.hpp \
|
||||
|
@ -42,16 +44,22 @@ $(top_srcdir)/include/libtorrent/file.hpp \
|
|||
$(top_srcdir)/include/libtorrent/file_pool.hpp \
|
||||
$(top_srcdir)/include/libtorrent/fingerprint.hpp \
|
||||
$(top_srcdir)/include/libtorrent/hasher.hpp \
|
||||
$(top_srcdir)/include/libtorrent/http_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/http_stream.hpp \
|
||||
$(top_srcdir)/include/libtorrent/session_settings.hpp \
|
||||
$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/identify_client.hpp \
|
||||
$(top_srcdir)/include/libtorrent/instantiate_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/invariant_check.hpp \
|
||||
$(top_srcdir)/include/libtorrent/io.hpp \
|
||||
$(top_srcdir)/include/libtorrent/ip_filter.hpp \
|
||||
$(top_srcdir)/include/libtorrent/lsd.hpp \
|
||||
$(top_srcdir)/include/libtorrent/peer.hpp \
|
||||
$(top_srcdir)/include/libtorrent/peer_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/bt_peer_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/web_peer_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/natpmp.hpp \
|
||||
$(top_srcdir)/include/libtorrent/pch.hpp \
|
||||
$(top_srcdir)/include/libtorrent/peer_id.hpp \
|
||||
$(top_srcdir)/include/libtorrent/peer_info.hpp \
|
||||
$(top_srcdir)/include/libtorrent/peer_request.hpp \
|
||||
|
@ -62,18 +70,23 @@ $(top_srcdir)/include/libtorrent/resource_request.hpp \
|
|||
$(top_srcdir)/include/libtorrent/session.hpp \
|
||||
$(top_srcdir)/include/libtorrent/size_type.hpp \
|
||||
$(top_srcdir)/include/libtorrent/socket.hpp \
|
||||
$(top_srcdir)/include/libtorrent/socket_type.hpp \
|
||||
$(top_srcdir)/include/libtorrent/socks5_stream.hpp \
|
||||
$(top_srcdir)/include/libtorrent/stat.hpp \
|
||||
$(top_srcdir)/include/libtorrent/storage.hpp \
|
||||
$(top_srcdir)/include/libtorrent/time.hpp \
|
||||
$(top_srcdir)/include/libtorrent/torrent.hpp \
|
||||
$(top_srcdir)/include/libtorrent/torrent_handle.hpp \
|
||||
$(top_srcdir)/include/libtorrent/torrent_info.hpp \
|
||||
$(top_srcdir)/include/libtorrent/tracker_manager.hpp \
|
||||
$(top_srcdir)/include/libtorrent/udp_tracker_connection.hpp \
|
||||
$(top_srcdir)/include/libtorrent/utf8.hpp \
|
||||
$(top_srcdir)/include/libtorrent/xml_parse.hpp \
|
||||
$(top_srcdir)/include/libtorrent/variant_stream.hpp \
|
||||
$(top_srcdir)/include/libtorrent/version.hpp
|
||||
|
||||
|
||||
libtorrent_la_LDFLAGS = $(LDFLAGS) -version-info 1:0:1
|
||||
libtorrent_la_LDFLAGS = $(LDFLAGS) -release @VERSION@
|
||||
libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@
|
||||
|
||||
AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/alert.hpp"
|
||||
|
||||
namespace libtorrent {
|
||||
|
@ -37,7 +39,7 @@ namespace libtorrent {
|
|||
alert::alert(severity_t severity, const std::string& msg)
|
||||
: m_msg(msg)
|
||||
, m_severity(severity)
|
||||
, m_timestamp(boost::posix_time::second_clock::universal_time())
|
||||
, m_timestamp(time_now())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -45,7 +47,7 @@ namespace libtorrent {
|
|||
{
|
||||
}
|
||||
|
||||
boost::posix_time::ptime alert::timestamp() const
|
||||
ptime alert::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
//generation of the min and max macros in Visual C++, #define
|
||||
//NOMINMAX before #including <windows.h>.
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
//support boost1.32.0(2004-11-19 18:47)
|
||||
//now all libs can be compiled and linked with static module
|
||||
|
|
|
@ -30,9 +30,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/bandwidth_manager.hpp"
|
||||
#include "libtorrent/peer_connection.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#endif
|
||||
|
@ -41,11 +45,11 @@ namespace libtorrent
|
|||
{
|
||||
namespace
|
||||
{
|
||||
const pt::time_duration window_size = pt::seconds(1);
|
||||
const time_duration window_size = seconds(1);
|
||||
}
|
||||
|
||||
history_entry::history_entry(intrusive_ptr<peer_connection> p
|
||||
, weak_ptr<torrent> t, int a, pt::ptime exp)
|
||||
, weak_ptr<torrent> t, int a, ptime exp)
|
||||
: expires_at(exp), amount(a), peer(p), tor(t)
|
||||
{}
|
||||
|
||||
|
@ -67,6 +71,8 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(!peer->ignore_bandwidth_limits());
|
||||
|
||||
// make sure this peer isn't already in line
|
||||
// waiting for bandwidth
|
||||
#ifndef NDEBUG
|
||||
|
@ -143,7 +149,7 @@ namespace libtorrent
|
|||
|
||||
assert(!m_history.empty());
|
||||
|
||||
pt::ptime now(pt::microsec_clock::universal_time());
|
||||
ptime now(time_now());
|
||||
while (!m_history.empty() && m_history.back().expires_at <= now)
|
||||
{
|
||||
history_entry e = m_history.back();
|
||||
|
@ -180,7 +186,7 @@ namespace libtorrent
|
|||
// (*m_ses->m_logger) << "hand out bw [" << m_channel << "]\n";
|
||||
#endif
|
||||
|
||||
pt::ptime now(pt::microsec_clock::universal_time());
|
||||
ptime now(time_now());
|
||||
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
int limit = m_limit;
|
||||
|
@ -240,3 +246,4 @@ namespace libtorrent
|
|||
{ assert(false); };
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
@ -48,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using boost::bind;
|
||||
using boost::shared_ptr;
|
||||
using libtorrent::aux::session_impl;
|
||||
|
@ -77,9 +78,11 @@ namespace libtorrent
|
|||
bt_peer_connection::bt_peer_connection(
|
||||
session_impl& ses
|
||||
, boost::weak_ptr<torrent> tor
|
||||
, shared_ptr<stream_socket> s
|
||||
, tcp::endpoint const& remote)
|
||||
: peer_connection(ses, tor, s, remote, tcp::endpoint())
|
||||
, shared_ptr<socket_type> s
|
||||
, tcp::endpoint const& remote
|
||||
, policy::peer* peerinfo)
|
||||
: peer_connection(ses, tor, s, remote
|
||||
, peerinfo)
|
||||
, m_state(read_protocol_length)
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
, m_supports_extensions(false)
|
||||
|
@ -116,8 +119,9 @@ namespace libtorrent
|
|||
|
||||
bt_peer_connection::bt_peer_connection(
|
||||
session_impl& ses
|
||||
, boost::shared_ptr<stream_socket> s)
|
||||
: peer_connection(ses, s)
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, policy::peer* peerinfo)
|
||||
: peer_connection(ses, s, peerinfo)
|
||||
, m_state(read_protocol_length)
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
, m_supports_extensions(false)
|
||||
|
@ -163,7 +167,10 @@ namespace libtorrent
|
|||
void bt_peer_connection::write_dht_port(int listen_port)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << time_now_string()
|
||||
<< " ==> DHT_PORT [ " << listen_port << " ]\n";
|
||||
#endif
|
||||
buffer::interval packet = allocate_send_buffer(7);
|
||||
detail::write_uint32(3, packet.begin);
|
||||
detail::write_uint8(msg_dht_port, packet.begin);
|
||||
|
@ -183,8 +190,10 @@ namespace libtorrent
|
|||
p.pid = pid();
|
||||
p.ip = remote();
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
p.country[0] = m_country[0];
|
||||
p.country[1] = m_country[1];
|
||||
#endif
|
||||
|
||||
p.total_download = statistics().total_payload_download();
|
||||
p.total_upload = statistics().total_payload_upload();
|
||||
|
@ -236,6 +245,18 @@ namespace libtorrent
|
|||
|
||||
p.client = m_client_version;
|
||||
p.connection_type = peer_info::standard_bittorrent;
|
||||
|
||||
if (peer_info_struct())
|
||||
{
|
||||
p.source = peer_info_struct()->source;
|
||||
p.failcount = peer_info_struct()->failcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!is_local());
|
||||
p.source = 0;
|
||||
p.failcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool bt_peer_connection::in_handshake() const
|
||||
|
@ -295,9 +316,7 @@ namespace libtorrent
|
|||
assert(i.begin == i.end);
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
using namespace boost::posix_time;
|
||||
(*m_logger) << to_simple_string(second_clock::universal_time())
|
||||
<< " ==> HANDSHAKE\n";
|
||||
(*m_logger) << time_now_string() << " ==> HANDSHAKE\n";
|
||||
#endif
|
||||
setup_send();
|
||||
}
|
||||
|
@ -346,9 +365,7 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
using namespace boost::posix_time;
|
||||
(*m_logger) << to_simple_string(second_clock::universal_time())
|
||||
<< " <== KEEPALIVE\n";
|
||||
(*m_logger) << time_now_string() << " <== KEEPALIVE\n";
|
||||
#endif
|
||||
incoming_keepalive();
|
||||
}
|
||||
|
@ -367,14 +384,6 @@ namespace libtorrent
|
|||
m_statistics.received_bytes(0, received);
|
||||
if (!packet_finished()) return;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_choke()) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_choke();
|
||||
}
|
||||
|
||||
|
@ -392,14 +401,6 @@ namespace libtorrent
|
|||
m_statistics.received_bytes(0, received);
|
||||
if (!packet_finished()) return;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_unchoke()) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_unchoke();
|
||||
}
|
||||
|
||||
|
@ -417,14 +418,6 @@ namespace libtorrent
|
|||
m_statistics.received_bytes(0, received);
|
||||
if (!packet_finished()) return;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_interested()) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_interested();
|
||||
}
|
||||
|
||||
|
@ -442,14 +435,6 @@ namespace libtorrent
|
|||
m_statistics.received_bytes(0, received);
|
||||
if (!packet_finished()) return;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_not_interested()) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_not_interested();
|
||||
}
|
||||
|
||||
|
@ -472,14 +457,6 @@ namespace libtorrent
|
|||
const char* ptr = recv_buffer.begin + 1;
|
||||
int index = detail::read_int32(ptr);
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_have(index)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_have(index);
|
||||
}
|
||||
|
||||
|
@ -521,14 +498,6 @@ namespace libtorrent
|
|||
for (int i = 0; i < (int)bitfield.size(); ++i)
|
||||
bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_bitfield(bitfield)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_bitfield(bitfield);
|
||||
}
|
||||
|
||||
|
@ -554,14 +523,6 @@ namespace libtorrent
|
|||
r.start = detail::read_int32(ptr);
|
||||
r.length = detail::read_int32(ptr);
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_request(r)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_request(r);
|
||||
}
|
||||
|
||||
|
@ -606,14 +567,6 @@ namespace libtorrent
|
|||
p.start = detail::read_int32(ptr);
|
||||
p.length = packet_size() - 9;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_piece(p, recv_buffer.begin + 9)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_piece(p, recv_buffer.begin + 9);
|
||||
}
|
||||
|
||||
|
@ -639,14 +592,6 @@ namespace libtorrent
|
|||
r.start = detail::read_int32(ptr);
|
||||
r.length = detail::read_int32(ptr);
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_cancel(r)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
incoming_cancel(r);
|
||||
}
|
||||
|
||||
|
@ -764,7 +709,7 @@ namespace libtorrent
|
|||
{
|
||||
tcp::endpoint adr(remote().address()
|
||||
, (unsigned short)listen_port->integer());
|
||||
t->get_policy().peer_from_tracker(adr, pid());
|
||||
t->get_policy().peer_from_tracker(adr, pid(), 0, 0);
|
||||
}
|
||||
}
|
||||
// there should be a version too
|
||||
|
@ -891,16 +836,16 @@ namespace libtorrent
|
|||
assert(t->valid_metadata());
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
using namespace boost::posix_time;
|
||||
(*m_logger) << to_simple_string(second_clock::universal_time())
|
||||
<< " ==> BITFIELD ";
|
||||
(*m_logger) << time_now_string() << " ==> BITFIELD ";
|
||||
|
||||
std::stringstream bitfield_string;
|
||||
for (int i = 0; i < (int)get_bitfield().size(); ++i)
|
||||
{
|
||||
if (bitfield[i]) (*m_logger) << "1";
|
||||
else (*m_logger) << "0";
|
||||
if (bitfield[i]) bitfield_string << "1";
|
||||
else bitfield_string << "0";
|
||||
}
|
||||
(*m_logger) << "\n";
|
||||
bitfield_string << "\n";
|
||||
(*m_logger) << bitfield_string.str();
|
||||
#endif
|
||||
const int packet_size = ((int)bitfield.size() + 7) / 8 + 5;
|
||||
|
||||
|
@ -928,9 +873,7 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
using namespace boost::posix_time;
|
||||
(*m_logger) << to_simple_string(second_clock::universal_time())
|
||||
<< " ==> EXTENSIONS\n";
|
||||
(*m_logger) << time_now_string() << " ==> EXTENSIONS\n";
|
||||
#endif
|
||||
assert(m_supports_extensions);
|
||||
|
||||
|
@ -1132,16 +1075,6 @@ namespace libtorrent
|
|||
|| !std::equal(recv_buffer.begin, recv_buffer.end
|
||||
, protocol_string))
|
||||
{
|
||||
const char cmd[] = "version";
|
||||
if (recv_buffer.end - recv_buffer.begin == 7 && std::equal(
|
||||
recv_buffer.begin, recv_buffer.end, cmd))
|
||||
{
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << "sending libtorrent version\n";
|
||||
#endif
|
||||
asio::write(*get_socket(), asio::buffer("libtorrent version " LIBTORRENT_VERSION "\n", 27));
|
||||
throw std::runtime_error("closing");
|
||||
}
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << "incorrect protocol name\n";
|
||||
#endif
|
||||
|
@ -1282,12 +1215,16 @@ namespace libtorrent
|
|||
throw protocol_error("duplicate peer-id, connection closed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (pid == m_ses.get_peer_id())
|
||||
{
|
||||
throw protocol_error("closing connection to ourself");
|
||||
}
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
if (m_supports_dht_port && m_ses.m_dht)
|
||||
write_dht_port(m_ses.kad_settings().service_port);
|
||||
write_dht_port(m_ses.get_dht_settings().service_port);
|
||||
#endif
|
||||
|
||||
m_client_version = identify_client(pid);
|
||||
|
@ -1320,6 +1257,8 @@ namespace libtorrent
|
|||
if (m_supports_extensions) write_extensions();
|
||||
#endif
|
||||
|
||||
// consider this a successful connection, reset the failcount
|
||||
if (peer_info_struct()) peer_info_struct()->failcount = 0;
|
||||
m_state = read_packet_size;
|
||||
reset_recv_buffer(4);
|
||||
}
|
||||
|
|
169
libtorrent/src/connection_queue.cpp
Normal file
169
libtorrent/src/connection_queue.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
|
||||
/*
|
||||
|
||||
Copyright (c) 2007, 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 <boost/bind.hpp>
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/connection_queue.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
|
||||
, m_num_connecting(0)
|
||||
, m_half_open_limit(0)
|
||||
, m_timer(ios)
|
||||
{}
|
||||
|
||||
bool connection_queue::free_slots() const
|
||||
{ return m_num_connecting < m_half_open_limit || m_half_open_limit <= 0; }
|
||||
|
||||
void connection_queue::enqueue(boost::function<void(int)> const& on_connect
|
||||
, boost::function<void()> const& on_timeout
|
||||
, time_duration timeout)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
m_queue.push_back(entry());
|
||||
entry& e = m_queue.back();
|
||||
e.on_connect = on_connect;
|
||||
e.on_timeout = on_timeout;
|
||||
e.ticket = m_next_ticket;
|
||||
e.timeout = timeout;
|
||||
++m_next_ticket;
|
||||
try_connect();
|
||||
}
|
||||
|
||||
void connection_queue::done(int ticket)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
std::list<entry>::iterator i = std::find_if(m_queue.begin()
|
||||
, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
|
||||
if (i == m_queue.end())
|
||||
{
|
||||
// this might not be here in case on_timeout calls remove
|
||||
return;
|
||||
}
|
||||
if (i->connecting) --m_num_connecting;
|
||||
m_queue.erase(i);
|
||||
try_connect();
|
||||
}
|
||||
|
||||
void connection_queue::limit(int limit)
|
||||
{ m_half_open_limit = limit; }
|
||||
|
||||
int connection_queue::limit() const
|
||||
{ return m_half_open_limit; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void connection_queue::check_invariant() const
|
||||
{
|
||||
int num_connecting = 0;
|
||||
for (std::list<entry>::const_iterator i = m_queue.begin();
|
||||
i != m_queue.end(); ++i)
|
||||
{
|
||||
if (i->connecting) ++num_connecting;
|
||||
}
|
||||
assert(num_connecting == m_num_connecting);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void connection_queue::try_connect()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (!free_slots() || m_queue.empty())
|
||||
return;
|
||||
|
||||
std::list<entry>::iterator i = std::find_if(m_queue.begin()
|
||||
, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
|
||||
while (i != m_queue.end())
|
||||
{
|
||||
assert(i->connecting == false);
|
||||
ptime expire = time_now() + i->timeout;
|
||||
if (m_num_connecting == 0)
|
||||
{
|
||||
m_timer.expires_at(expire);
|
||||
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
|
||||
}
|
||||
i->connecting = true;
|
||||
++m_num_connecting;
|
||||
i->expires = expire;
|
||||
|
||||
INVARIANT_CHECK;
|
||||
|
||||
entry& ent = *i;
|
||||
++i;
|
||||
try { ent.on_connect(ent.ticket); } catch (std::exception&) {}
|
||||
|
||||
if (!free_slots()) break;
|
||||
i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
|
||||
}
|
||||
}
|
||||
|
||||
void connection_queue::on_timeout(asio::error_code const& e)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(!e || e == asio::error::operation_aborted);
|
||||
if (e) return;
|
||||
|
||||
ptime next_expire = max_time();
|
||||
ptime now = time_now();
|
||||
for (std::list<entry>::iterator i = m_queue.begin();
|
||||
i != m_queue.end();)
|
||||
{
|
||||
if (i->connecting && i->expires < now)
|
||||
{
|
||||
boost::function<void()> on_timeout = i->on_timeout;
|
||||
m_queue.erase(i++);
|
||||
--m_num_connecting;
|
||||
try { on_timeout(); } catch (std::exception&) {}
|
||||
continue;
|
||||
}
|
||||
if (i->expires < next_expire)
|
||||
next_expire = i->expires;
|
||||
++i;
|
||||
}
|
||||
if (next_expire < max_time())
|
||||
{
|
||||
m_timer.expires_at(next_expire);
|
||||
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
|
||||
}
|
||||
try_connect();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include "libtorrent/entry.hpp"
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
// windows part
|
||||
#include "libtorrent/utf8.hpp"
|
||||
|
@ -243,6 +245,17 @@ namespace libtorrent
|
|||
return ret;
|
||||
}
|
||||
|
||||
void set_size(size_type s)
|
||||
{
|
||||
size_type pos = tell();
|
||||
seek(1, 0);
|
||||
char dummy = 0;
|
||||
read(&dummy, 1);
|
||||
seek(1, 0);
|
||||
write(&dummy, 1);
|
||||
seek(pos, 1);
|
||||
}
|
||||
|
||||
size_type seek(size_type offset, int m)
|
||||
{
|
||||
assert(m_open_mode);
|
||||
|
@ -316,6 +329,11 @@ namespace libtorrent
|
|||
return m_impl->read(buf, num_bytes);
|
||||
}
|
||||
|
||||
void file::set_size(size_type s)
|
||||
{
|
||||
m_impl->set_size(s);
|
||||
}
|
||||
|
||||
size_type file::seek(size_type pos, file::seek_mode m)
|
||||
{
|
||||
return m_impl->seek(pos, m.m_val);
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
@ -43,6 +45,7 @@ namespace libtorrent
|
|||
{
|
||||
assert(st != 0);
|
||||
assert(p.is_complete());
|
||||
assert(m == file::in || m == (file::in | file::out));
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
typedef nth_index<file_set, 0>::type path_view;
|
||||
path_view& pt = get<0>(m_files);
|
||||
|
@ -50,11 +53,15 @@ namespace libtorrent
|
|||
if (i != pt.end())
|
||||
{
|
||||
lru_file_entry e = *i;
|
||||
e.last_use = pt::second_clock::universal_time();
|
||||
e.last_use = time_now();
|
||||
|
||||
// if you hit this assert, you probably have more than one
|
||||
// storage/torrent using the same file at the same time!
|
||||
assert(e.key == st);
|
||||
if (e.key != st)
|
||||
{
|
||||
// this means that another instance of the storage
|
||||
// is using the exact same file.
|
||||
throw file_error("torrent uses the same file as another torrent "
|
||||
"(" + p.string() + ")");
|
||||
}
|
||||
|
||||
e.key = st;
|
||||
if ((e.mode & m) != m)
|
||||
|
|
|
@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <sstream>
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -168,9 +169,13 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
if (new_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::stringstream s;
|
||||
throw_exception(file_name);
|
||||
// try to make the file sparse if supported
|
||||
if (access_mask & GENERIC_WRITE)
|
||||
{
|
||||
DWORD temp;
|
||||
::DeviceIoControl(new_handle, FSCTL_SET_SPARSE, 0, 0
|
||||
, 0, 0, &temp, 0);
|
||||
}
|
||||
// will only close old file if the open succeeded
|
||||
close();
|
||||
|
@ -233,6 +238,16 @@ namespace libtorrent
|
|||
return bytes_read;
|
||||
}
|
||||
|
||||
void set_size(size_type s)
|
||||
{
|
||||
size_type pos = tell();
|
||||
seek(s, seek_begin);
|
||||
if (FALSE == ::SetEndOfFile(m_file_handle))
|
||||
throw_exception("file::set_size");
|
||||
|
||||
seek(pos, seek_begin);
|
||||
}
|
||||
|
||||
size_type seek(size_type pos, seek_mode from_where)
|
||||
{
|
||||
assert(pos >= 0 || from_where != seek_begin);
|
||||
|
@ -334,6 +349,11 @@ namespace libtorrent
|
|||
return m_impl->read(buffer, num_bytes);
|
||||
}
|
||||
|
||||
void file::set_size(size_type s)
|
||||
{
|
||||
m_impl->set_size(s);
|
||||
}
|
||||
|
||||
size_type file::seek(size_type pos, seek_mode m)
|
||||
{
|
||||
return m_impl->seek(pos,impl::seek_mode(m.m_val));
|
||||
|
|
384
libtorrent/src/http_connection.cpp
Normal file
384
libtorrent/src/http_connection.cpp
Normal file
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/http_connection.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <string>
|
||||
|
||||
using boost::bind;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
void http_connection::get(std::string const& url, time_duration timeout
|
||||
, bool handle_redirect)
|
||||
{
|
||||
m_redirect = handle_redirect;
|
||||
std::string protocol;
|
||||
std::string auth;
|
||||
std::string hostname;
|
||||
std::string path;
|
||||
int port;
|
||||
boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
|
||||
std::stringstream headers;
|
||||
headers << "GET " << path << " HTTP/1.0\r\n"
|
||||
"Host:" << hostname <<
|
||||
"\r\nConnection: close\r\n";
|
||||
if (!auth.empty())
|
||||
headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
|
||||
headers << "\r\n";
|
||||
sendbuffer = headers.str();
|
||||
start(hostname, boost::lexical_cast<std::string>(port), timeout);
|
||||
}
|
||||
|
||||
void http_connection::start(std::string const& hostname, std::string const& port
|
||||
, time_duration timeout, bool handle_redirect)
|
||||
{
|
||||
m_redirect = handle_redirect;
|
||||
m_timeout = timeout;
|
||||
m_timer.expires_from_now(m_timeout);
|
||||
m_timer.async_wait(bind(&http_connection::on_timeout
|
||||
, boost::weak_ptr<http_connection>(shared_from_this()), _1));
|
||||
m_called = false;
|
||||
if (m_sock.is_open() && m_hostname == hostname && m_port == port)
|
||||
{
|
||||
m_parser.reset();
|
||||
asio::async_write(m_sock, asio::buffer(sendbuffer)
|
||||
, bind(&http_connection::on_write, shared_from_this(), _1));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sock.close();
|
||||
tcp::resolver::query query(hostname, port);
|
||||
m_resolver.async_resolve(query, bind(&http_connection::on_resolve
|
||||
, shared_from_this(), _1, _2));
|
||||
m_hostname = hostname;
|
||||
m_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
void http_connection::on_connect_timeout()
|
||||
{
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(asio::error::timed_out, m_parser, 0, 0);
|
||||
close();
|
||||
}
|
||||
|
||||
void http_connection::on_timeout(boost::weak_ptr<http_connection> p
|
||||
, asio::error_code const& e)
|
||||
{
|
||||
boost::shared_ptr<http_connection> c = p.lock();
|
||||
if (!c) return;
|
||||
if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
|
||||
c->m_connection_ticket = -1;
|
||||
|
||||
if (e == asio::error::operation_aborted) return;
|
||||
|
||||
if (c->m_bottled && c->m_called) return;
|
||||
|
||||
if (c->m_last_receive + c->m_timeout < time_now())
|
||||
{
|
||||
c->m_called = true;
|
||||
c->m_handler(asio::error::timed_out, c->m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
|
||||
c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
|
||||
}
|
||||
|
||||
void http_connection::close()
|
||||
{
|
||||
m_timer.cancel();
|
||||
m_limiter_timer.cancel();
|
||||
m_sock.close();
|
||||
m_hostname.clear();
|
||||
m_port.clear();
|
||||
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
}
|
||||
|
||||
void http_connection::on_resolve(asio::error_code const& e
|
||||
, tcp::resolver::iterator i)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
assert(i != tcp::resolver::iterator());
|
||||
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
|
||||
, bind(&http_connection::on_connect_timeout, shared_from_this())
|
||||
, m_timeout);
|
||||
}
|
||||
|
||||
void http_connection::connect(int ticket, tcp::endpoint target_address)
|
||||
{
|
||||
m_connection_ticket = ticket;
|
||||
m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
|
||||
, shared_from_this(), _1/*, ++i*/));
|
||||
}
|
||||
|
||||
void http_connection::on_connect(asio::error_code const& e
|
||||
/*, tcp::resolver::iterator i*/)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
m_last_receive = time_now();
|
||||
asio::async_write(m_sock, asio::buffer(sendbuffer)
|
||||
, bind(&http_connection::on_write, shared_from_this(), _1));
|
||||
}
|
||||
/* else if (i != tcp::resolver::iterator())
|
||||
{
|
||||
// The connection failed. Try the next endpoint in the list.
|
||||
m_sock.close();
|
||||
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
|
||||
, bind(&http_connection::on_connect_timeout, shared_from_this())
|
||||
, m_timeout);
|
||||
}
|
||||
*/ else
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void http_connection::on_write(asio::error_code const& e)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string().swap(sendbuffer);
|
||||
m_recvbuffer.resize(4096);
|
||||
|
||||
int amount_to_read = m_recvbuffer.size() - m_read_pos;
|
||||
if (m_rate_limit > 0 && amount_to_read > m_download_quota)
|
||||
{
|
||||
amount_to_read = m_download_quota;
|
||||
if (m_download_quota == 0)
|
||||
{
|
||||
if (!m_limiter_timer_active)
|
||||
on_assign_bandwidth(asio::error_code());
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
|
||||
, amount_to_read)
|
||||
, bind(&http_connection::on_read
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
|
||||
void http_connection::on_read(asio::error_code const& e
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
if (m_rate_limit)
|
||||
{
|
||||
m_download_quota -= bytes_transferred;
|
||||
assert(m_download_quota >= 0);
|
||||
}
|
||||
|
||||
if (e == asio::error::eof)
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
char const* data = 0;
|
||||
std::size_t size = 0;
|
||||
if (m_bottled)
|
||||
{
|
||||
data = m_parser.get_body().begin;
|
||||
size = m_parser.get_body().left();
|
||||
}
|
||||
m_handler(asio::error_code(), m_parser, data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e)
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
m_read_pos += bytes_transferred;
|
||||
assert(m_read_pos <= int(m_recvbuffer.size()));
|
||||
|
||||
// having a nonempty path means we should handle redirects
|
||||
if (m_redirect && m_parser.header_finished())
|
||||
{
|
||||
int code = m_parser.status_code();
|
||||
if (code >= 300 && code < 400)
|
||||
{
|
||||
// attempt a redirect
|
||||
std::string url = m_parser.header<std::string>("location");
|
||||
if (url.empty())
|
||||
{
|
||||
// missing location header
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
m_limiter_timer_active = false;
|
||||
close();
|
||||
|
||||
get(url, m_timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
m_redirect = false;
|
||||
}
|
||||
|
||||
if (m_bottled || !m_parser.header_finished())
|
||||
{
|
||||
libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
|
||||
, &m_recvbuffer[0] + m_read_pos);
|
||||
m_parser.incoming(rcv_buf);
|
||||
if (!m_bottled && m_parser.header_finished())
|
||||
{
|
||||
if (m_read_pos > m_parser.body_start())
|
||||
m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start()
|
||||
, m_read_pos - m_parser.body_start());
|
||||
m_read_pos = 0;
|
||||
m_last_receive = time_now();
|
||||
}
|
||||
else if (m_bottled && m_parser.finished())
|
||||
{
|
||||
m_timer.cancel();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(e, m_parser, m_parser.get_body().begin, m_parser.get_body().left());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!m_bottled);
|
||||
m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos);
|
||||
m_read_pos = 0;
|
||||
m_last_receive = time_now();
|
||||
}
|
||||
|
||||
if (int(m_recvbuffer.size()) == m_read_pos)
|
||||
m_recvbuffer.resize((std::min)(m_read_pos + 2048, 1024*500));
|
||||
if (m_read_pos == 1024 * 500)
|
||||
{
|
||||
close();
|
||||
if (m_bottled && m_called) return;
|
||||
m_called = true;
|
||||
m_handler(asio::error::eof, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
int amount_to_read = m_recvbuffer.size() - m_read_pos;
|
||||
if (m_rate_limit > 0 && amount_to_read > m_download_quota)
|
||||
{
|
||||
amount_to_read = m_download_quota;
|
||||
if (m_download_quota == 0)
|
||||
{
|
||||
if (!m_limiter_timer_active)
|
||||
on_assign_bandwidth(asio::error_code());
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
|
||||
, amount_to_read)
|
||||
, bind(&http_connection::on_read
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
|
||||
void http_connection::on_assign_bandwidth(asio::error_code const& e)
|
||||
{
|
||||
if ((e == asio::error::operation_aborted
|
||||
&& m_limiter_timer_active)
|
||||
|| !m_sock.is_open())
|
||||
{
|
||||
if (!m_bottled || !m_called)
|
||||
m_handler(e, m_parser, 0, 0);
|
||||
return;
|
||||
}
|
||||
m_limiter_timer_active = false;
|
||||
if (e) return;
|
||||
|
||||
if (m_download_quota > 0) return;
|
||||
|
||||
m_download_quota = m_rate_limit / 4;
|
||||
|
||||
int amount_to_read = m_recvbuffer.size() - m_read_pos;
|
||||
if (amount_to_read > m_download_quota)
|
||||
amount_to_read = m_download_quota;
|
||||
|
||||
m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
|
||||
, amount_to_read)
|
||||
, bind(&http_connection::on_read
|
||||
, shared_from_this(), _1, _2));
|
||||
|
||||
m_limiter_timer_active = true;
|
||||
m_limiter_timer.expires_from_now(milliseconds(250));
|
||||
m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
|
||||
, shared_from_this(), _1));
|
||||
}
|
||||
|
||||
void http_connection::rate_limit(int limit)
|
||||
{
|
||||
if (!m_limiter_timer_active)
|
||||
{
|
||||
m_limiter_timer_active = true;
|
||||
m_limiter_timer.expires_from_now(milliseconds(250));
|
||||
m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
|
||||
, shared_from_this(), _1));
|
||||
}
|
||||
m_rate_limit = limit;
|
||||
}
|
||||
|
||||
}
|
||||
|
162
libtorrent/src/http_stream.cpp
Normal file
162
libtorrent/src/http_stream.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/http_stream.hpp"
|
||||
#include "libtorrent/tracker_manager.hpp" // for base64encode
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
void http_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e || i == tcp::resolver::iterator())
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
m_sock.async_connect(i->endpoint(), boost::bind(
|
||||
&http_stream::connected, this, _1, h));
|
||||
}
|
||||
|
||||
void http_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
if (m_no_connect)
|
||||
{
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// send CONNECT
|
||||
std::back_insert_iterator<std::vector<char> > p(m_buffer);
|
||||
write_string("CONNECT " + boost::lexical_cast<std::string>(m_remote_endpoint)
|
||||
+ " HTTP/1.0\r\n", p);
|
||||
if (!m_user.empty())
|
||||
{
|
||||
write_string("Proxy-Authorization: Basic " + base64encode(
|
||||
m_user + ":" + m_password) + "\r\n", p);
|
||||
}
|
||||
write_string("\r\n", p);
|
||||
asio::async_write(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&http_stream::handshake1, this, _1, h));
|
||||
}
|
||||
|
||||
void http_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
// read one byte from the socket
|
||||
m_buffer.resize(1);
|
||||
asio::async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&http_stream::handshake2, this, _1, h));
|
||||
}
|
||||
|
||||
void http_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
int read_pos = m_buffer.size();
|
||||
// look for \n\n and \r\n\r\n
|
||||
// both of which means end of http response header
|
||||
bool found_end = false;
|
||||
if (m_buffer[read_pos - 1] == '\n' && read_pos > 2)
|
||||
{
|
||||
if (m_buffer[read_pos - 2] == '\n')
|
||||
{
|
||||
found_end = true;
|
||||
}
|
||||
else if (read_pos > 4
|
||||
&& m_buffer[read_pos - 2] == '\r'
|
||||
&& m_buffer[read_pos - 3] == '\n'
|
||||
&& m_buffer[read_pos - 4] == '\r')
|
||||
{
|
||||
found_end = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_end)
|
||||
{
|
||||
m_buffer.push_back(0);
|
||||
char* status = strchr(&m_buffer[0], ' ');
|
||||
if (status == 0)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
status++;
|
||||
int code = atoi(status);
|
||||
if (code != 200)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
(*h)(e);
|
||||
std::vector<char>().swap(m_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// read another byte from the socket
|
||||
m_buffer.resize(read_pos + 1);
|
||||
asio::async_read(m_sock, asio::buffer(&m_buffer[0] + read_pos, 1)
|
||||
, boost::bind(&http_stream::handshake2, this, _1, h));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
|
@ -56,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/instantiate_connection.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
using boost::bind;
|
||||
|
@ -84,8 +87,6 @@ namespace
|
|||
|
||||
}
|
||||
|
||||
using namespace boost::posix_time;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool url_has_argument(std::string const& url, std::string argument)
|
||||
|
@ -170,20 +171,17 @@ namespace libtorrent
|
|||
char const* line_end = newline;
|
||||
if (pos != line_end && *(line_end - 1) == '\r') --line_end;
|
||||
line.assign(pos, line_end);
|
||||
++newline;
|
||||
m_recv_pos += newline - pos;
|
||||
boost::get<1>(ret) += newline - pos;
|
||||
pos = newline;
|
||||
|
||||
std::string::size_type separator = line.find(": ");
|
||||
std::string::size_type separator = line.find(':');
|
||||
if (separator == std::string::npos)
|
||||
{
|
||||
// this means we got a blank line,
|
||||
// the header is finished and the body
|
||||
// starts.
|
||||
++pos;
|
||||
++m_recv_pos;
|
||||
boost::get<1>(ret) += 1;
|
||||
|
||||
m_state = read_body;
|
||||
m_body_start_pos = m_recv_pos;
|
||||
break;
|
||||
|
@ -191,7 +189,12 @@ namespace libtorrent
|
|||
|
||||
std::string name = line.substr(0, separator);
|
||||
std::transform(name.begin(), name.end(), name.begin(), &to_lower);
|
||||
std::string value = line.substr(separator + 2, std::string::npos);
|
||||
++separator;
|
||||
// skip whitespace
|
||||
while (separator < line.size()
|
||||
&& (line[separator] == ' ' || line[separator] == '\t'))
|
||||
++separator;
|
||||
std::string value = line.substr(separator, std::string::npos);
|
||||
m_header.insert(std::make_pair(name, value));
|
||||
|
||||
if (name == "content-length")
|
||||
|
@ -217,9 +220,6 @@ namespace libtorrent
|
|||
m_content_length = range_end - range_start + 1;
|
||||
}
|
||||
|
||||
// TODO: make sure we don't step outside of the buffer
|
||||
++pos;
|
||||
++m_recv_pos;
|
||||
assert(m_recv_pos <= (int)recv_buffer.left());
|
||||
newline = std::find(pos, recv_buffer.end, '\n');
|
||||
}
|
||||
|
@ -272,6 +272,7 @@ namespace libtorrent
|
|||
|
||||
http_tracker_connection::http_tracker_connection(
|
||||
asio::strand& str
|
||||
, connection_queue& cc
|
||||
, tracker_manager& man
|
||||
, tracker_request const& req
|
||||
, std::string const& hostname
|
||||
|
@ -280,6 +281,7 @@ namespace libtorrent
|
|||
, address bind_infc
|
||||
, boost::weak_ptr<request_callback> c
|
||||
, session_settings const& stn
|
||||
, proxy_settings const& ps
|
||||
, std::string const& auth)
|
||||
: tracker_connection(man, req, str, bind_infc, c)
|
||||
, m_man(man)
|
||||
|
@ -289,19 +291,18 @@ namespace libtorrent
|
|||
, m_recv_pos(0)
|
||||
, m_buffer(http_buffer_size)
|
||||
, m_settings(stn)
|
||||
, m_proxy(ps)
|
||||
, m_password(auth)
|
||||
, m_timed_out(false)
|
||||
, m_connection_ticket(-1)
|
||||
, m_cc(cc)
|
||||
{
|
||||
const std::string* connect_to_host;
|
||||
bool using_proxy = false;
|
||||
|
||||
m_send_buffer.assign("GET ");
|
||||
|
||||
// should we use the proxy?
|
||||
if (!m_settings.proxy_ip.empty())
|
||||
if (m_proxy.type == proxy_settings::http
|
||||
|| m_proxy.type == proxy_settings::http_pw)
|
||||
{
|
||||
connect_to_host = &m_settings.proxy_ip;
|
||||
using_proxy = true;
|
||||
m_send_buffer += "http://";
|
||||
m_send_buffer += hostname;
|
||||
if (port != 80)
|
||||
|
@ -309,12 +310,6 @@ namespace libtorrent
|
|||
m_send_buffer += ":";
|
||||
m_send_buffer += boost::lexical_cast<std::string>(port);
|
||||
}
|
||||
m_port = m_settings.proxy_port != 0
|
||||
? m_settings.proxy_port : 80 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
connect_to_host = &hostname;
|
||||
}
|
||||
|
||||
if (tracker_req().kind == tracker_request::scrape_request)
|
||||
|
@ -441,12 +436,12 @@ namespace libtorrent
|
|||
m_send_buffer += ':';
|
||||
m_send_buffer += boost::lexical_cast<std::string>(port);
|
||||
}
|
||||
if (using_proxy && !m_settings.proxy_login.empty())
|
||||
if (m_proxy.type == proxy_settings::http_pw)
|
||||
{
|
||||
m_send_buffer += "\r\nProxy-Authorization: Basic ";
|
||||
m_send_buffer += base64encode(m_settings.proxy_login + ":" + m_settings.proxy_password);
|
||||
m_send_buffer += base64encode(m_proxy.username + ":" + m_proxy.password);
|
||||
}
|
||||
if (auth != "")
|
||||
if (!auth.empty())
|
||||
{
|
||||
m_send_buffer += "\r\nAuthorization: Basic ";
|
||||
m_send_buffer += base64encode(auth);
|
||||
|
@ -461,11 +456,11 @@ namespace libtorrent
|
|||
info_hash_str << req.info_hash;
|
||||
requester().debug_log("info_hash: "
|
||||
+ boost::lexical_cast<std::string>(req.info_hash));
|
||||
requester().debug_log("name lookup: " + *connect_to_host);
|
||||
requester().debug_log("name lookup: " + hostname);
|
||||
}
|
||||
#endif
|
||||
|
||||
tcp::resolver::query q(*connect_to_host
|
||||
tcp::resolver::query q(hostname
|
||||
, boost::lexical_cast<std::string>(m_port));
|
||||
m_name_lookup.async_resolve(q, m_strand.wrap(
|
||||
boost::bind(&http_tracker_connection::name_lookup, self(), _1, _2)));
|
||||
|
@ -478,6 +473,8 @@ namespace libtorrent
|
|||
m_timed_out = true;
|
||||
m_socket.reset();
|
||||
m_name_lookup.cancel();
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
fail_timeout();
|
||||
}
|
||||
|
||||
|
@ -527,19 +524,37 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
if (has_requester()) requester().m_tracker_address = target_address;
|
||||
m_socket.reset(new stream_socket(m_name_lookup.io_service()));
|
||||
m_socket = instantiate_connection(m_name_lookup.io_service(), m_proxy);
|
||||
|
||||
if (m_proxy.type == proxy_settings::http
|
||||
|| m_proxy.type == proxy_settings::http_pw)
|
||||
{
|
||||
// the tracker connection will talk immediately to
|
||||
// the proxy, without requiring CONNECT support
|
||||
m_socket->get<http_stream>().set_no_connect(true);
|
||||
}
|
||||
|
||||
m_socket->open(target_address.protocol());
|
||||
m_socket->bind(tcp::endpoint(bind_interface(), 0));
|
||||
m_socket->async_connect(target_address, bind(&http_tracker_connection::connected, self(), _1));
|
||||
m_cc.enqueue(bind(&http_tracker_connection::connect, self(), _1, target_address)
|
||||
, bind(&http_tracker_connection::on_timeout, self())
|
||||
, seconds(m_settings.tracker_receive_timeout));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
assert(false);
|
||||
fail(-1, e.what());
|
||||
};
|
||||
|
||||
void http_tracker_connection::connect(int ticket, tcp::endpoint target_address)
|
||||
{
|
||||
m_connection_ticket = ticket;
|
||||
m_socket->async_connect(target_address, bind(&http_tracker_connection::connected, self(), _1));
|
||||
}
|
||||
|
||||
void http_tracker_connection::connected(asio::error_code const& error) try
|
||||
{
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (m_timed_out) return;
|
||||
if (error)
|
||||
|
@ -559,7 +574,6 @@ namespace libtorrent
|
|||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
assert(false);
|
||||
fail(-1, e.what());
|
||||
}
|
||||
|
||||
|
@ -584,7 +598,6 @@ namespace libtorrent
|
|||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
assert(false);
|
||||
fail(-1, e.what());
|
||||
}; // msvc 7.1 seems to require this semi-colon
|
||||
|
||||
|
@ -704,11 +717,18 @@ namespace libtorrent
|
|||
|
||||
req.url = location;
|
||||
|
||||
m_man.queue_request(m_strand, req
|
||||
m_man.queue_request(m_strand, m_cc, req
|
||||
, m_password, bind_interface(), m_requester);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_parser.status_code() != 200)
|
||||
{
|
||||
fail(m_parser.status_code(), m_parser.message().c_str());
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos);
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -133,63 +135,77 @@ namespace
|
|||
return boost::optional<fingerprint>(ret);
|
||||
}
|
||||
|
||||
typedef std::pair<char const*, char const*> map_entry;
|
||||
struct map_entry
|
||||
{
|
||||
char const* id;
|
||||
char const* name;
|
||||
};
|
||||
|
||||
// only support BitTorrentSpecification
|
||||
// must be ordered alphabetically
|
||||
map_entry name_map[] =
|
||||
{
|
||||
map_entry("A", "ABC")
|
||||
, map_entry("AR", "Arctic Torrent")
|
||||
, map_entry("AX", "BitPump")
|
||||
, map_entry("AZ", "Azureus")
|
||||
, map_entry("BB", "BitBuddy")
|
||||
, map_entry("BC", "BitComet")
|
||||
, map_entry("BF", "Bitflu")
|
||||
, map_entry("BG", "btgdaemon")
|
||||
, map_entry("BS", "BTSlave")
|
||||
, map_entry("BX", "BittorrentX")
|
||||
, map_entry("CD", "Enhanced CTorrent")
|
||||
, map_entry("CT", "CTorrent")
|
||||
, map_entry("DE", "Deluge")
|
||||
, map_entry("ES", "electric sheep")
|
||||
, map_entry("HL", "Halite")
|
||||
, map_entry("KT", "KTorrent")
|
||||
, map_entry("LK", "Linkage")
|
||||
, map_entry("LP", "lphant")
|
||||
, map_entry("LT", "libtorrent")
|
||||
, map_entry("M", "Mainline")
|
||||
, map_entry("ML", "MLDonkey")
|
||||
, map_entry("MO", "Mono Torrent")
|
||||
, map_entry("MP", "MooPolice")
|
||||
, map_entry("MT", "Moonlight Torrent")
|
||||
, map_entry("O", "Osprey Permaseed")
|
||||
, map_entry("QT", "Qt 4")
|
||||
, map_entry("R", "Tribler")
|
||||
, map_entry("S", "Shadow")
|
||||
, map_entry("SB", "Swiftbit")
|
||||
, map_entry("SN", "ShareNet")
|
||||
, map_entry("SS", "SwarmScope")
|
||||
, map_entry("SZ", "Shareaza")
|
||||
, map_entry("T", "BitTornado")
|
||||
, map_entry("TN", "Torrent.NET")
|
||||
, map_entry("TR", "Transmission")
|
||||
, map_entry("TS", "TorrentStorm")
|
||||
, map_entry("U", "UPnP")
|
||||
, map_entry("UL", "uLeecher")
|
||||
, map_entry("UT", "MicroTorrent")
|
||||
, map_entry("XT", "XanTorrent")
|
||||
, map_entry("XX", "Xtorrent")
|
||||
, map_entry("ZT", "ZipTorrent")
|
||||
, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
|
||||
, map_entry("pX", "pHoeniX")
|
||||
, map_entry("qB", "qBittorrent")
|
||||
{"A", "ABC"}
|
||||
, {"AG", "Ares"}
|
||||
, {"AR", "Arctic Torrent"}
|
||||
, {"AV", "Avicora"}
|
||||
, {"AX", "BitPump"}
|
||||
, {"AZ", "Azureus"}
|
||||
, {"A~", "Ares"}
|
||||
, {"BB", "BitBuddy"}
|
||||
, {"BC", "BitComet"}
|
||||
, {"BF", "Bitflu"}
|
||||
, {"BG", "BTG"}
|
||||
, {"BR", "BitRocket"}
|
||||
, {"BS", "BTSlave"}
|
||||
, {"BX", "BittorrentX"}
|
||||
, {"CD", "Enhanced CTorrent"}
|
||||
, {"CT", "CTorrent"}
|
||||
, {"DE", "Deluge Torrent"}
|
||||
, {"EB", "EBit"}
|
||||
, {"ES", "electric sheep"}
|
||||
, {"HL", "Halite"}
|
||||
, {"HN", "Hydranode"}
|
||||
, {"KT", "KTorrent"}
|
||||
, {"LK", "Linkage"}
|
||||
, {"LP", "lphant"}
|
||||
, {"LT", "libtorrent"}
|
||||
, {"M", "Mainline"}
|
||||
, {"ML", "MLDonkey"}
|
||||
, {"MO", "Mono Torrent"}
|
||||
, {"MP", "MooPolice"}
|
||||
, {"MT", "Moonlight Torrent"}
|
||||
, {"O", "Osprey Permaseed"}
|
||||
, {"PD", "Pando"}
|
||||
, {"Q", "BTQueue"}
|
||||
, {"QT", "Qt 4"}
|
||||
, {"R", "Tribler"}
|
||||
, {"S", "Shadow"}
|
||||
, {"SB", "Swiftbit"}
|
||||
, {"SN", "ShareNet"}
|
||||
, {"SS", "SwarmScope"}
|
||||
, {"SZ", "Shareaza"}
|
||||
, {"S~", "Shareaza (beta)"}
|
||||
, {"T", "BitTornado"}
|
||||
, {"TN", "Torrent.NET"}
|
||||
, {"TR", "Transmission"}
|
||||
, {"TS", "TorrentStorm"}
|
||||
, {"TT", "TuoTu"}
|
||||
, {"U", "UPnP"}
|
||||
, {"UL", "uLeecher"}
|
||||
, {"UT", "MicroTorrent"}
|
||||
, {"XT", "XanTorrent"}
|
||||
, {"XX", "Xtorrent"}
|
||||
, {"ZT", "ZipTorrent"}
|
||||
, {"lt", "libTorrent (libtorrent.rakshasa.no/}"}
|
||||
, {"pX", "pHoeniX"}
|
||||
, {"qB", "qBittorrent"}
|
||||
};
|
||||
|
||||
bool compare_first_string(map_entry const& lhs, map_entry const& rhs)
|
||||
bool compare_id(map_entry const& lhs, map_entry const& rhs)
|
||||
{
|
||||
return lhs.first[0] < rhs.first[0]
|
||||
|| ((lhs.first[0] == rhs.first[0]) && (lhs.first[1] < rhs.first[1]));
|
||||
return lhs.id[0] < rhs.id[0]
|
||||
|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
|
||||
}
|
||||
|
||||
std::string lookup(fingerprint const& f)
|
||||
|
@ -197,20 +213,21 @@ namespace
|
|||
std::stringstream identity;
|
||||
|
||||
const int size = sizeof(name_map)/sizeof(name_map[0]);
|
||||
map_entry tmp = {f.name, ""};
|
||||
map_entry* i =
|
||||
std::lower_bound(name_map, name_map + size
|
||||
, map_entry(f.name, ""), &compare_first_string);
|
||||
, tmp, &compare_id);
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (int i = 1; i < size; ++i)
|
||||
{
|
||||
assert(compare_first_string(name_map[i-1]
|
||||
assert(compare_id(name_map[i-1]
|
||||
, name_map[i]));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i < name_map + size && std::equal(f.name, f.name + 2, i->first))
|
||||
identity << i->second;
|
||||
if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
|
||||
identity << i->name;
|
||||
else
|
||||
{
|
||||
identity << f.name[0];
|
||||
|
|
78
libtorrent/src/instantiate_connection.cpp
Normal file
78
libtorrent/src/instantiate_connection.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/session_settings.hpp"
|
||||
#include "libtorrent/socket_type.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <stdexcept>
|
||||
#include <asio/io_service.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
boost::shared_ptr<socket_type> instantiate_connection(
|
||||
asio::io_service& ios, proxy_settings const& ps)
|
||||
{
|
||||
boost::shared_ptr<socket_type> s(new socket_type(ios));
|
||||
|
||||
if (ps.type == proxy_settings::none)
|
||||
{
|
||||
s->instantiate<stream_socket>();
|
||||
}
|
||||
else if (ps.type == proxy_settings::http
|
||||
|| ps.type == proxy_settings::http_pw)
|
||||
{
|
||||
s->instantiate<http_stream>();
|
||||
s->get<http_stream>().set_proxy(ps.hostname, ps.port);
|
||||
if (ps.type == proxy_settings::socks5_pw)
|
||||
s->get<http_stream>().set_username(ps.username, ps.password);
|
||||
}
|
||||
else if (ps.type == proxy_settings::socks5
|
||||
|| ps.type == proxy_settings::socks5_pw)
|
||||
{
|
||||
s->instantiate<socks5_stream>();
|
||||
s->get<socks5_stream>().set_proxy(ps.hostname, ps.port);
|
||||
if (ps.type == proxy_settings::socks5_pw)
|
||||
s->get<socks5_stream>().set_username(ps.username, ps.password);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("unsupported proxy type");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
//#include <iostream>
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
@ -38,7 +40,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -70,9 +71,7 @@ namespace libtorrent { namespace
|
|||
|
||||
void log_timestamp()
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
std::string now(to_simple_string(second_clock::universal_time()));
|
||||
m_file << now << ": ";
|
||||
m_file << time_now_string() << ": ";
|
||||
}
|
||||
|
||||
// can add entries to the extension handshake
|
||||
|
|
250
libtorrent/src/lsd.cpp
Normal file
250
libtorrent/src/lsd.cpp
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/lsd.hpp"
|
||||
#include "libtorrent/io.hpp"
|
||||
#include "libtorrent/http_tracker_connection.hpp"
|
||||
#include "libtorrent/xml_parse.hpp"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <asio/ip/host_name.hpp>
|
||||
#include <asio/ip/multicast.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <cstdlib>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
using boost::bind;
|
||||
using namespace libtorrent;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
// defined in upnp.cpp
|
||||
address_v4 guess_local_address(asio::io_service&);
|
||||
}
|
||||
|
||||
address_v4 lsd::lsd_multicast_address;
|
||||
udp::endpoint lsd::lsd_multicast_endpoint;
|
||||
|
||||
lsd::lsd(io_service& ios, address const& listen_interface
|
||||
, peer_callback_t const& cb)
|
||||
: m_callback(cb)
|
||||
, m_retry_count(0)
|
||||
, m_socket(ios)
|
||||
, m_broadcast_timer(ios)
|
||||
, m_disabled(false)
|
||||
{
|
||||
// Bittorrent Local discovery multicast address and port
|
||||
lsd_multicast_address = address_v4::from_string("239.192.152.143");
|
||||
lsd_multicast_endpoint = udp::endpoint(lsd_multicast_address, 6771);
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
|
||||
#endif
|
||||
assert(lsd_multicast_address.is_multicast());
|
||||
rebind(listen_interface);
|
||||
}
|
||||
|
||||
lsd::~lsd() {}
|
||||
|
||||
void lsd::rebind(address const& listen_interface)
|
||||
{
|
||||
address_v4 local_ip = address_v4::any();
|
||||
if (listen_interface.is_v4() && listen_interface != address_v4::any())
|
||||
{
|
||||
local_ip = listen_interface.to_v4();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// the local interface hasn't changed
|
||||
if (m_socket.is_open()
|
||||
&& m_socket.local_endpoint().address() == local_ip)
|
||||
return;
|
||||
|
||||
m_socket.close();
|
||||
|
||||
using namespace asio::ip::multicast;
|
||||
|
||||
m_socket.open(udp::v4());
|
||||
m_socket.set_option(datagram_socket::reuse_address(true));
|
||||
m_socket.bind(udp::endpoint(local_ip, 6771));
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << "local ip: " << local_ip << std::endl;
|
||||
#endif
|
||||
|
||||
m_socket.set_option(join_group(lsd_multicast_address));
|
||||
m_socket.set_option(outbound_interface(local_ip));
|
||||
m_socket.set_option(enable_loopback(true));
|
||||
m_socket.set_option(hops(255));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << "socket multicast error " << e.what()
|
||||
<< ". disabling local service discovery" << std::endl;
|
||||
#endif
|
||||
m_disabled = true;
|
||||
return;
|
||||
}
|
||||
m_disabled = false;
|
||||
|
||||
setup_receive();
|
||||
}
|
||||
|
||||
void lsd::announce(sha1_hash const& ih, int listen_port)
|
||||
{
|
||||
if (m_disabled) return;
|
||||
|
||||
std::stringstream btsearch;
|
||||
btsearch << "BT-SEARCH * HTTP/1.1\r\n"
|
||||
"Host: 239.192.152.143:6771\r\n"
|
||||
"Port: " << listen_port << "\r\n"
|
||||
"Infohash: " << ih << "\r\n"
|
||||
"\r\n\r\n";
|
||||
std::string const& msg = btsearch.str();
|
||||
|
||||
m_retry_count = 0;
|
||||
asio::error_code ec;
|
||||
m_socket.send_to(asio::buffer(msg.c_str(), msg.size() - 1)
|
||||
, lsd_multicast_endpoint, 0, ec);
|
||||
if (ec)
|
||||
{
|
||||
m_disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " ==> announce: ih: " << ih << " port: " << listen_port << std::endl;
|
||||
#endif
|
||||
|
||||
m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
|
||||
m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
|
||||
}
|
||||
|
||||
void lsd::resend_announce(asio::error_code const& e, std::string msg) try
|
||||
{
|
||||
if (e) return;
|
||||
|
||||
m_socket.send_to(asio::buffer(msg, msg.size() - 1)
|
||||
, lsd_multicast_endpoint);
|
||||
|
||||
++m_retry_count;
|
||||
if (m_retry_count >= 5)
|
||||
return;
|
||||
|
||||
m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
|
||||
m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
|
||||
}
|
||||
catch (std::exception&)
|
||||
{}
|
||||
|
||||
void lsd::on_announce(asio::error_code const& e
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
using namespace libtorrent::detail;
|
||||
if (e) return;
|
||||
|
||||
char* p = m_receive_buffer;
|
||||
char* end = m_receive_buffer + bytes_transferred;
|
||||
char* line = std::find(p, end, '\n');
|
||||
for (char* i = p; i < line; ++i) *i = std::tolower(*i);
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " <== announce: " << std::string(p, line) << std::endl;
|
||||
#endif
|
||||
if (line == end || (line - p >= 9 && std::memcmp("bt-search", p, 9)))
|
||||
{
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " *** assumed 'bt-search', ignoring" << std::endl;
|
||||
#endif
|
||||
setup_receive();
|
||||
return;
|
||||
}
|
||||
p = line + 1;
|
||||
int port = 0;
|
||||
sha1_hash ih(0);
|
||||
while (p != end)
|
||||
{
|
||||
line = std::find(p, end, '\n');
|
||||
if (line == end) break;
|
||||
*line = 0;
|
||||
for (char* i = p; i < line; ++i) *i = std::tolower(*i);
|
||||
if (line - p >= 5 && memcmp(p, "port:", 5) == 0)
|
||||
{
|
||||
p += 5;
|
||||
while (*p == ' ') ++p;
|
||||
port = atoi(p);
|
||||
}
|
||||
else if (line - p >= 9 && memcmp(p, "infohash:", 9) == 0)
|
||||
{
|
||||
p += 9;
|
||||
while (*p == ' ') ++p;
|
||||
if (line - p > 40) p[40] = 0;
|
||||
try { ih = boost::lexical_cast<sha1_hash>(p); }
|
||||
catch (std::exception&) {}
|
||||
}
|
||||
p = line + 1;
|
||||
}
|
||||
|
||||
if (!ih.is_all_zeros() && port != 0)
|
||||
{
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " *** incoming local announce " << m_remote.address()
|
||||
<< ":" << port << " ih: " << ih << std::endl;
|
||||
#endif
|
||||
// we got an announce, pass it on through the callback
|
||||
try { m_callback(tcp::endpoint(m_remote.address(), port), ih); }
|
||||
catch (std::exception&) {}
|
||||
}
|
||||
setup_receive();
|
||||
}
|
||||
|
||||
void lsd::setup_receive() try
|
||||
{
|
||||
assert(m_socket.is_open());
|
||||
m_socket.async_receive_from(asio::buffer(m_receive_buffer
|
||||
, sizeof(m_receive_buffer)), m_remote, bind(&lsd::on_announce, this, _1, _2));
|
||||
}
|
||||
catch (std::exception&)
|
||||
{}
|
||||
|
||||
void lsd::close()
|
||||
{
|
||||
m_socket.close();
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
@ -38,7 +40,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -56,8 +57,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/extensions/metadata_transfer.hpp"
|
||||
|
||||
using boost::posix_time::second_clock;
|
||||
|
||||
namespace libtorrent { namespace
|
||||
{
|
||||
int div_round_up(int numerator, int denominator)
|
||||
|
@ -107,7 +106,15 @@ namespace libtorrent { namespace
|
|||
{
|
||||
m_requested_metadata.resize(256, 0);
|
||||
}
|
||||
|
||||
|
||||
virtual void on_files_checked()
|
||||
{
|
||||
// if the torrent is a seed, copy the metadata from
|
||||
// the torrent before it is deallocated
|
||||
if (m_torrent.is_seed())
|
||||
metadata();
|
||||
}
|
||||
|
||||
virtual boost::shared_ptr<peer_plugin> new_connection(
|
||||
peer_connection* pc);
|
||||
|
||||
|
@ -212,6 +219,14 @@ namespace libtorrent { namespace
|
|||
m_metadata_size = total_size;
|
||||
}
|
||||
|
||||
void piece_pass(int)
|
||||
{
|
||||
// if we became a seed, copy the metadata from
|
||||
// the torrent before it is deallocated
|
||||
if (m_torrent.is_seed())
|
||||
metadata();
|
||||
}
|
||||
|
||||
private:
|
||||
torrent& m_torrent;
|
||||
|
||||
|
@ -243,12 +258,8 @@ namespace libtorrent { namespace
|
|||
: m_waiting_metadata_request(false)
|
||||
, m_message_index(0)
|
||||
, m_metadata_progress(0)
|
||||
, m_no_metadata(
|
||||
boost::gregorian::date(1970, boost::date_time::Jan, 1)
|
||||
, boost::posix_time::seconds(0))
|
||||
, m_metadata_request(
|
||||
boost::gregorian::date(1970, boost::date_time::Jan, 1)
|
||||
, boost::posix_time::seconds(0))
|
||||
, m_no_metadata(min_time())
|
||||
, m_metadata_request(min_time())
|
||||
, m_torrent(t)
|
||||
, m_pc(pc)
|
||||
, m_tp(tp)
|
||||
|
@ -411,7 +422,7 @@ namespace libtorrent { namespace
|
|||
}
|
||||
break;
|
||||
case 2: // have no data
|
||||
m_no_metadata = second_clock::universal_time();
|
||||
m_no_metadata = time_now();
|
||||
if (m_waiting_metadata_request)
|
||||
m_tp.cancel_metadata_request(m_last_metadata_request);
|
||||
m_waiting_metadata_request = false;
|
||||
|
@ -437,14 +448,13 @@ namespace libtorrent { namespace
|
|||
m_last_metadata_request = m_tp.metadata_request();
|
||||
write_metadata_request(m_last_metadata_request);
|
||||
m_waiting_metadata_request = true;
|
||||
m_metadata_request = second_clock::universal_time();
|
||||
m_metadata_request = time_now();
|
||||
}
|
||||
}
|
||||
|
||||
bool has_metadata() const
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
return second_clock::universal_time() - m_no_metadata > minutes(5);
|
||||
return time_now() - m_no_metadata > minutes(5);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -467,11 +477,11 @@ namespace libtorrent { namespace
|
|||
|
||||
// this is set to the current time each time we get a
|
||||
// "I don't have metadata" message.
|
||||
boost::posix_time::ptime m_no_metadata;
|
||||
ptime m_no_metadata;
|
||||
|
||||
// this is set to the time when we last sent
|
||||
// a request for metadata to this peer
|
||||
boost::posix_time::ptime m_metadata_request;
|
||||
ptime m_metadata_request;
|
||||
|
||||
// if we're waiting for a metadata request
|
||||
// this was the request we sent
|
||||
|
@ -485,6 +495,8 @@ namespace libtorrent { namespace
|
|||
boost::shared_ptr<peer_plugin> metadata_plugin::new_connection(
|
||||
peer_connection* pc)
|
||||
{
|
||||
bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
|
||||
if (!c) return boost::shared_ptr<peer_plugin>();
|
||||
return boost::shared_ptr<peer_plugin>(new metadata_peer_plugin(m_torrent, *pc, *this));
|
||||
}
|
||||
|
||||
|
|
393
libtorrent/src/natpmp.cpp
Normal file
393
libtorrent/src/natpmp.cpp
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/pch.hpp"
|
||||
|
||||
#include <libtorrent/natpmp.hpp>
|
||||
#include <libtorrent/io.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <asio/ip/host_name.hpp>
|
||||
|
||||
using boost::bind;
|
||||
using namespace libtorrent;
|
||||
|
||||
enum { num_mappings = 2 };
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
// defined in upnp.cpp
|
||||
bool is_local(address const& a);
|
||||
address_v4 guess_local_address(asio::io_service&);
|
||||
}
|
||||
|
||||
natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb)
|
||||
: m_callback(cb)
|
||||
, m_currently_mapping(-1)
|
||||
, m_retry_count(0)
|
||||
, m_socket(ios)
|
||||
, m_send_timer(ios)
|
||||
, m_refresh_timer(ios)
|
||||
, m_disabled(false)
|
||||
{
|
||||
m_mappings[0].protocol = 2; // tcp
|
||||
m_mappings[1].protocol = 1; // udp
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log.open("natpmp.log", std::ios::in | std::ios::out | std::ios::trunc);
|
||||
#endif
|
||||
rebind(listen_interface);
|
||||
}
|
||||
|
||||
void natpmp::rebind(address const& listen_interface) try
|
||||
{
|
||||
address_v4 local = address_v4::any();
|
||||
if (listen_interface.is_v4() && listen_interface != address_v4::any())
|
||||
{
|
||||
local = listen_interface.to_v4();
|
||||
}
|
||||
else
|
||||
{
|
||||
local = guess_local_address(m_socket.io_service());
|
||||
|
||||
if (local == address_v4::any())
|
||||
{
|
||||
throw std::runtime_error("local host is probably not on a NATed "
|
||||
"network. disabling NAT-PMP");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " local ip: " << local.to_string() << std::endl;
|
||||
#endif
|
||||
|
||||
if (!is_local(local))
|
||||
{
|
||||
// the local address seems to be an external
|
||||
// internet address. Assume it is not behind a NAT
|
||||
throw std::runtime_error("local IP is not on a local network");
|
||||
}
|
||||
|
||||
m_disabled = false;
|
||||
|
||||
// assume the router is located on the local
|
||||
// network as x.x.x.1
|
||||
udp::endpoint nat_endpoint(
|
||||
address_v4((local.to_ulong() & 0xffffff00) | 1), 5351);
|
||||
|
||||
if (nat_endpoint == m_nat_endpoint) return;
|
||||
|
||||
// TODO: find a better way to figure out the router IP
|
||||
m_nat_endpoint = nat_endpoint;
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
|
||||
#endif
|
||||
|
||||
m_socket.open(udp::v4());
|
||||
m_socket.bind(udp::endpoint(address_v4::any(), 0));
|
||||
|
||||
for (int i = 0; i < num_mappings; ++i)
|
||||
{
|
||||
if (m_mappings[i].local_port == 0)
|
||||
continue;
|
||||
refresh_mapping(i);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
m_disabled = true;
|
||||
std::stringstream msg;
|
||||
msg << "NAT-PMP disabled: " << e.what();
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << msg.str() << std::endl;
|
||||
#endif
|
||||
m_callback(0, 0, msg.str());
|
||||
};
|
||||
|
||||
void natpmp::set_mappings(int tcp, int udp)
|
||||
{
|
||||
if (m_disabled) return;
|
||||
update_mapping(0, tcp);
|
||||
update_mapping(1, udp);
|
||||
}
|
||||
|
||||
void natpmp::update_mapping(int i, int port)
|
||||
{
|
||||
natpmp::mapping& m = m_mappings[i];
|
||||
if (port <= 0) return;
|
||||
if (m.local_port != port)
|
||||
m.need_update = true;
|
||||
|
||||
m.local_port = port;
|
||||
// prefer the same external port as the local port
|
||||
if (m.external_port == 0) m.external_port = port;
|
||||
|
||||
if (m_currently_mapping == -1)
|
||||
{
|
||||
// the socket is not currently in use
|
||||
// send out a mapping request
|
||||
m_retry_count = 0;
|
||||
send_map_request(i);
|
||||
m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
|
||||
, m_remote, bind(&natpmp::on_reply, this, _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void natpmp::send_map_request(int i) try
|
||||
{
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
assert(m_currently_mapping == -1
|
||||
|| m_currently_mapping == i);
|
||||
m_currently_mapping = i;
|
||||
mapping& m = m_mappings[i];
|
||||
char buf[12];
|
||||
char* out = buf;
|
||||
write_uint8(0, out); // NAT-PMP version
|
||||
write_uint8(m.protocol, out); // map "protocol"
|
||||
write_uint16(0, out); // reserved
|
||||
write_uint16(m.local_port, out); // private port
|
||||
write_uint16(m.external_port, out); // requested public port
|
||||
int ttl = m.external_port == 0 ? 0 : 3600;
|
||||
write_uint32(ttl, out); // port mapping lifetime
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " ==> port map request: " << (m.protocol == 1 ? "udp" : "tcp")
|
||||
<< " local: " << m.local_port << " external: " << m.external_port
|
||||
<< " ttl: " << ttl << std::endl;
|
||||
#endif
|
||||
|
||||
m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint);
|
||||
// linear back-off instead of exponential
|
||||
++m_retry_count;
|
||||
m_send_timer.expires_from_now(milliseconds(250 * m_retry_count));
|
||||
m_send_timer.async_wait(bind(&natpmp::resend_request, this, i, _1));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::string err = e.what();
|
||||
};
|
||||
|
||||
void natpmp::resend_request(int i, asio::error_code const& e)
|
||||
{
|
||||
if (e) return;
|
||||
if (m_currently_mapping != i) return;
|
||||
if (m_retry_count >= 9)
|
||||
{
|
||||
m_mappings[i].need_update = false;
|
||||
// try again in two hours
|
||||
m_mappings[i].expires = time_now() + hours(2);
|
||||
return;
|
||||
}
|
||||
send_map_request(i);
|
||||
}
|
||||
|
||||
void natpmp::on_reply(asio::error_code const& e
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
using namespace libtorrent::detail;
|
||||
if (e) return;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (m_remote != m_nat_endpoint)
|
||||
{
|
||||
m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
|
||||
, m_remote, bind(&natpmp::on_reply, this, _1, _2));
|
||||
return;
|
||||
}
|
||||
|
||||
m_send_timer.cancel();
|
||||
|
||||
assert(m_currently_mapping >= 0);
|
||||
int i = m_currently_mapping;
|
||||
mapping& m = m_mappings[i];
|
||||
|
||||
char* in = m_response_buffer;
|
||||
int version = read_uint8(in);
|
||||
int cmd = read_uint8(in);
|
||||
int result = read_uint16(in);
|
||||
int time = read_uint32(in);
|
||||
int private_port = read_uint16(in);
|
||||
int public_port = read_uint16(in);
|
||||
int lifetime = read_uint32(in);
|
||||
|
||||
(void)time; // to remove warning
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << time_now_string()
|
||||
<< " <== port map response: " << (cmd - 128 == 1 ? "udp" : "tcp")
|
||||
<< " local: " << private_port << " external: " << public_port
|
||||
<< " ttl: " << lifetime << std::endl;
|
||||
#endif
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
if (version != 0)
|
||||
{
|
||||
m_log << "*** unexpected version: " << version << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
if (private_port != m.local_port)
|
||||
{
|
||||
m_log << "*** unexpected local port: " << private_port << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
if (cmd != 128 + m.protocol)
|
||||
{
|
||||
m_log << "*** unexpected protocol: " << (cmd - 128) << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (public_port == 0 || lifetime == 0)
|
||||
{
|
||||
// this means the mapping was
|
||||
// successfully closed
|
||||
m.local_port = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m.expires = time_now() + seconds(int(lifetime * 0.7f));
|
||||
m.external_port = public_port;
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << "*** ERROR: " << result << std::endl;
|
||||
#endif
|
||||
std::stringstream errmsg;
|
||||
errmsg << "NAT router reports error (" << result << ") ";
|
||||
switch (result)
|
||||
{
|
||||
case 1: errmsg << "Unsupported protocol version"; break;
|
||||
case 2: errmsg << "Not authorized to create port map (enable NAT-PMP on your router)"; break;
|
||||
case 3: errmsg << "Network failure"; break;
|
||||
case 4: errmsg << "Out of resources"; break;
|
||||
case 5: errmsg << "Unsupported opcode"; break;
|
||||
}
|
||||
throw std::runtime_error(errmsg.str());
|
||||
}
|
||||
|
||||
// don't report when we remove mappings
|
||||
if (m.local_port != 0)
|
||||
{
|
||||
int tcp_port = 0;
|
||||
int udp_port = 0;
|
||||
if (m.protocol == 1) udp_port = m.external_port;
|
||||
else tcp_port = public_port;
|
||||
m_callback(tcp_port, udp_port, "");
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
// try again in two hours
|
||||
m_mappings[m_currently_mapping].expires = time_now() + hours(2);
|
||||
m_callback(0, 0, e.what());
|
||||
}
|
||||
int i = m_currently_mapping;
|
||||
m_currently_mapping = -1;
|
||||
m_mappings[i].need_update = false;
|
||||
m_send_timer.cancel();
|
||||
update_expiration_timer();
|
||||
try_next_mapping(i);
|
||||
}
|
||||
|
||||
void natpmp::update_expiration_timer()
|
||||
{
|
||||
ptime now = time_now();
|
||||
ptime min_expire = now + seconds(3600);
|
||||
int min_index = -1;
|
||||
for (int i = 0; i < num_mappings; ++i)
|
||||
if (m_mappings[i].expires < min_expire
|
||||
&& m_mappings[i].local_port != 0)
|
||||
{
|
||||
min_expire = m_mappings[i].expires;
|
||||
min_index = i;
|
||||
}
|
||||
|
||||
if (min_index >= 0)
|
||||
{
|
||||
m_refresh_timer.expires_from_now(min_expire - now);
|
||||
m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, this, _1, min_index));
|
||||
}
|
||||
}
|
||||
|
||||
void natpmp::mapping_expired(asio::error_code const& e, int i)
|
||||
{
|
||||
if (e) return;
|
||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||
m_log << "*** mapping " << i << " expired, updating" << std::endl;
|
||||
#endif
|
||||
refresh_mapping(i);
|
||||
}
|
||||
|
||||
void natpmp::refresh_mapping(int i)
|
||||
{
|
||||
m_mappings[i].need_update = true;
|
||||
if (m_currently_mapping == -1)
|
||||
{
|
||||
// the socket is not currently in use
|
||||
// send out a mapping request
|
||||
m_retry_count = 0;
|
||||
send_map_request(i);
|
||||
m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
|
||||
, m_remote, bind(&natpmp::on_reply, this, _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void natpmp::try_next_mapping(int i)
|
||||
{
|
||||
++i;
|
||||
if (i >= num_mappings) i = 0;
|
||||
if (m_mappings[i].need_update)
|
||||
refresh_mapping(i);
|
||||
}
|
||||
|
||||
void natpmp::close()
|
||||
{
|
||||
if (m_disabled) return;
|
||||
for (int i = 0; i < num_mappings; ++i)
|
||||
{
|
||||
if (m_mappings[i].local_port == 0)
|
||||
continue;
|
||||
m_mappings[i].external_port = 0;
|
||||
refresh_mapping(i);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -30,27 +30,29 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/peer_connection.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "libtorrent/peer_connection.hpp"
|
||||
#include "libtorrent/web_peer_connection.hpp"
|
||||
#include "libtorrent/policy.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
|
@ -58,7 +60,6 @@ namespace libtorrent
|
|||
class peer_connection;
|
||||
}
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using boost::bind;
|
||||
|
||||
namespace
|
||||
|
@ -185,7 +186,9 @@ namespace libtorrent
|
|||
std::vector<piece_block> interesting_pieces;
|
||||
interesting_pieces.reserve(100);
|
||||
|
||||
bool prefer_whole_pieces = c.prefer_whole_pieces();
|
||||
bool prefer_whole_pieces = c.prefer_whole_pieces()
|
||||
|| c.on_parole();
|
||||
|
||||
if (!prefer_whole_pieces)
|
||||
{
|
||||
prefer_whole_pieces = c.statistics().download_payload_rate()
|
||||
|
@ -197,8 +200,13 @@ namespace libtorrent
|
|||
// the number of blocks we want, but it will try to make the picked
|
||||
// blocks be from whole pieces, possibly by returning more blocks
|
||||
// than we requested.
|
||||
assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
|
||||
|| c.proxy() == c.get_socket()->remote_endpoint());
|
||||
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||
|
||||
piece_picker::piece_state_t state;
|
||||
peer_connection::peer_speed_t speed = c.peer_speed();
|
||||
if (speed == peer_connection::fast) state = piece_picker::fast;
|
||||
else if (speed == peer_connection::medium) state = piece_picker::medium;
|
||||
else state = piece_picker::slow;
|
||||
|
||||
// picks the interesting pieces from this peer
|
||||
// the integer is the number of pieces that
|
||||
|
@ -209,7 +217,7 @@ namespace libtorrent
|
|||
// for this peer. If we're downloading one piece in 20 seconds
|
||||
// then use this mode.
|
||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.remote());
|
||||
, num_requests, prefer_whole_pieces, c.remote(), state);
|
||||
|
||||
// this vector is filled with the interesting pieces
|
||||
// that some other peer is currently downloading
|
||||
|
@ -375,16 +383,16 @@ namespace libtorrent
|
|||
: m_torrent(t)
|
||||
, m_num_unchoked(0)
|
||||
, m_available_free_upload(0)
|
||||
, m_last_optimistic_disconnect(boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||
, m_last_optimistic_disconnect(min_time())
|
||||
{ assert(t); }
|
||||
// finds the peer that has the worst download rate
|
||||
// and returns it. May return 0 if all peers are
|
||||
// choked.
|
||||
policy::peer* policy::find_choke_candidate()
|
||||
policy::iterator policy::find_choke_candidate()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
peer* worst_peer = 0;
|
||||
iterator worst_peer = m_peers.end();
|
||||
size_type min_weight = std::numeric_limits<int>::min();
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -393,7 +401,7 @@ namespace libtorrent
|
|||
|
||||
// TODO: make this selection better
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
|
@ -406,7 +414,7 @@ namespace libtorrent
|
|||
if (c->is_disconnecting()) continue;
|
||||
// if the peer isn't interested, just choke it
|
||||
if (!c->is_peer_interested())
|
||||
return &(*i);
|
||||
return i;
|
||||
|
||||
size_type diff = i->total_download()
|
||||
- i->total_upload();
|
||||
|
@ -415,35 +423,32 @@ namespace libtorrent
|
|||
+ diff
|
||||
+ ((c->is_interesting() && c->has_peer_choked())?-10:10)*1024;
|
||||
|
||||
if (weight >= min_weight && worst_peer) continue;
|
||||
if (weight >= min_weight && worst_peer != m_peers.end()) continue;
|
||||
|
||||
min_weight = weight;
|
||||
worst_peer = &(*i);
|
||||
worst_peer = i;
|
||||
continue;
|
||||
}
|
||||
assert(unchoked_counter == 0);
|
||||
return worst_peer;
|
||||
}
|
||||
|
||||
policy::peer* policy::find_unchoke_candidate()
|
||||
policy::iterator policy::find_unchoke_candidate()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
// if all of our peers are unchoked, there's
|
||||
// no left to unchoke
|
||||
if (m_num_unchoked == m_torrent->num_peers())
|
||||
return 0;
|
||||
return m_peers.end();
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
peer* unchoke_peer = 0;
|
||||
ptime min_time(date(9999,Jan,1));
|
||||
iterator unchoke_peer = m_peers.end();
|
||||
ptime min_time = libtorrent::min_time();
|
||||
float max_down_speed = 0.f;
|
||||
|
||||
// TODO: make this selection better
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
|
@ -457,81 +462,93 @@ namespace libtorrent
|
|||
|
||||
min_time = i->last_optimistically_unchoked;
|
||||
max_down_speed = c->statistics().download_rate();
|
||||
unchoke_peer = &(*i);
|
||||
unchoke_peer = i;
|
||||
}
|
||||
return unchoke_peer;
|
||||
}
|
||||
|
||||
policy::peer* policy::find_disconnect_candidate()
|
||||
policy::iterator policy::find_disconnect_candidate()
|
||||
{
|
||||
peer *disconnect_peer = 0;
|
||||
INVARIANT_CHECK;
|
||||
|
||||
iterator disconnect_peer = m_peers.end();
|
||||
double slowest_transfer_rate = std::numeric_limits<double>::max();
|
||||
|
||||
boost::posix_time::ptime local_time
|
||||
= second_clock::universal_time();
|
||||
ptime now = time_now();
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
if(c == 0)
|
||||
continue;
|
||||
if(c->is_disconnecting())
|
||||
if (c == 0) continue;
|
||||
if (c->is_disconnecting()) continue;
|
||||
|
||||
// never disconnect an interesting peer if we have a candidate that
|
||||
// isn't interesting
|
||||
if (disconnect_peer != m_peers.end()
|
||||
&& c->is_interesting()
|
||||
&& !disconnect_peer->connection->is_interesting())
|
||||
continue;
|
||||
|
||||
double transferred_amount
|
||||
= (double)c->statistics().total_payload_download();
|
||||
|
||||
boost::posix_time::time_duration connected_time
|
||||
= local_time - i->connected;
|
||||
time_duration connected_time = now - i->connected;
|
||||
|
||||
double connected_time_in_seconds
|
||||
= connected_time.seconds()
|
||||
+ connected_time.minutes()*60.0
|
||||
+ connected_time.hours()*60.0*60.0;
|
||||
double connected_time_in_seconds = total_seconds(connected_time);
|
||||
|
||||
double transfer_rate
|
||||
= transferred_amount / (connected_time_in_seconds+1);
|
||||
= transferred_amount / (connected_time_in_seconds + 1);
|
||||
|
||||
if (transfer_rate <= slowest_transfer_rate)
|
||||
// prefer to disconnect uninteresting peers, and secondly slow peers
|
||||
if (transfer_rate <= slowest_transfer_rate
|
||||
|| (disconnect_peer != m_peers.end()
|
||||
&& disconnect_peer->connection->is_interesting()
|
||||
&& !c->is_interesting()))
|
||||
{
|
||||
slowest_transfer_rate = transfer_rate;
|
||||
disconnect_peer = &(*i);
|
||||
disconnect_peer = i;
|
||||
}
|
||||
}
|
||||
return disconnect_peer;
|
||||
}
|
||||
|
||||
policy::peer *policy::find_connect_candidate()
|
||||
policy::iterator policy::find_connect_candidate()
|
||||
{
|
||||
boost::posix_time::ptime local_time=second_clock::universal_time();
|
||||
boost::posix_time::ptime ptime(local_time);
|
||||
policy::peer* candidate =0;
|
||||
INVARIANT_CHECK;
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
ptime now = time_now();
|
||||
ptime min_connect_time(now);
|
||||
iterator candidate = m_peers.end();
|
||||
|
||||
int max_failcount = m_torrent->settings().max_failcount;
|
||||
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
||||
|
||||
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
|
||||
{
|
||||
if(i->connection) continue;
|
||||
if(i->banned) continue;
|
||||
if(i->type == peer::not_connectable) continue;
|
||||
if (i->connection) continue;
|
||||
if (i->banned) continue;
|
||||
if (i->type == peer::not_connectable) continue;
|
||||
if (i->seed && m_torrent->is_seed()) continue;
|
||||
if (i->failcount >= max_failcount) continue;
|
||||
if (now - i->connected < seconds(i->failcount * min_reconnect_time))
|
||||
continue;
|
||||
|
||||
assert(i->connected <= local_time);
|
||||
assert(i->connected <= now);
|
||||
|
||||
boost::posix_time::ptime next_connect = i->connected;
|
||||
|
||||
if (next_connect <= ptime)
|
||||
if (i->connected <= min_connect_time)
|
||||
{
|
||||
ptime = next_connect;
|
||||
candidate = &(*i);
|
||||
min_connect_time = i->connected;
|
||||
candidate = i;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ptime <= local_time);
|
||||
assert(min_connect_time <= now);
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
policy::peer* policy::find_seed_choke_candidate()
|
||||
policy::iterator policy::find_seed_choke_candidate()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
|
@ -539,26 +556,23 @@ namespace libtorrent
|
|||
// first choice candidate.
|
||||
// it is a candidate we owe nothing to and which has been unchoked
|
||||
// the longest.
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
peer* candidate = 0;
|
||||
iterator candidate = m_peers.end();
|
||||
|
||||
// not valid when candidate == 0
|
||||
ptime last_unchoke = ptime(date(1970, Jan, 1));
|
||||
ptime last_unchoke = min_time();
|
||||
|
||||
// second choice candidate.
|
||||
// if there is no first choice candidate, this candidate will be chosen.
|
||||
// it is the candidate that we owe the least to.
|
||||
peer* second_candidate = 0;
|
||||
iterator second_candidate = m_peers.end();
|
||||
size_type lowest_share_diff = 0; // not valid when secondCandidate==0
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
// ignore peers that are choked or
|
||||
// whose connection is closed
|
||||
// ignore peers that are choked or
|
||||
// whose connection is closed
|
||||
if (c == 0) continue;
|
||||
|
||||
if (c->is_choked()) continue;
|
||||
|
@ -568,36 +582,36 @@ namespace libtorrent
|
|||
|
||||
// select as second candidate the one that we owe the least
|
||||
// to
|
||||
if (!second_candidate || share_diff <= lowest_share_diff)
|
||||
if (second_candidate == m_peers.end()
|
||||
|| share_diff <= lowest_share_diff)
|
||||
{
|
||||
lowest_share_diff = share_diff;
|
||||
second_candidate = &(*i);
|
||||
second_candidate = i;
|
||||
}
|
||||
|
||||
// select as first candidate the one that we don't owe anything to
|
||||
// and has been waiting for an unchoke the longest
|
||||
if (share_diff > 0) continue;
|
||||
if (!candidate || last_unchoke > i->last_optimistically_unchoked)
|
||||
if (candidate == m_peers.end()
|
||||
|| last_unchoke > i->last_optimistically_unchoked)
|
||||
{
|
||||
last_unchoke = i->last_optimistically_unchoked;
|
||||
candidate = &(*i);
|
||||
candidate = i;
|
||||
}
|
||||
}
|
||||
if (candidate) return candidate;
|
||||
if (second_candidate) return second_candidate;
|
||||
assert(false);
|
||||
return 0;
|
||||
if (candidate != m_peers.end()) return candidate;
|
||||
assert(second_candidate != m_peers.end());
|
||||
return second_candidate;
|
||||
}
|
||||
|
||||
policy::peer* policy::find_seed_unchoke_candidate()
|
||||
policy::iterator policy::find_seed_unchoke_candidate()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
peer* candidate = 0;
|
||||
boost::posix_time::ptime last_unchoke
|
||||
= second_clock::universal_time();
|
||||
iterator candidate = m_peers.end();
|
||||
ptime last_unchoke = time_now();
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
|
@ -607,7 +621,7 @@ namespace libtorrent
|
|||
if (c->is_disconnecting()) continue;
|
||||
if (last_unchoke < i->last_optimistically_unchoked) continue;
|
||||
last_unchoke = i->last_optimistically_unchoked;
|
||||
candidate = &(*i);
|
||||
candidate = i;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
@ -616,24 +630,23 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
peer* p = find_seed_unchoke_candidate();
|
||||
if (p != 0)
|
||||
iterator p = find_seed_unchoke_candidate();
|
||||
if (p != m_peers.end())
|
||||
{
|
||||
assert(p->connection->is_choked());
|
||||
p->connection->send_unchoke();
|
||||
p->last_optimistically_unchoked
|
||||
= second_clock::universal_time();
|
||||
p->last_optimistically_unchoked = time_now();
|
||||
++m_num_unchoked;
|
||||
}
|
||||
return p != 0;
|
||||
return p != m_peers.end();
|
||||
}
|
||||
|
||||
void policy::seed_choke_one_peer()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
peer* p = find_seed_choke_candidate();
|
||||
if (p != 0)
|
||||
iterator p = find_seed_choke_candidate();
|
||||
if (p != m_peers.end())
|
||||
{
|
||||
assert(!p->connection->is_choked());
|
||||
p->connection->send_choke();
|
||||
|
@ -647,14 +660,22 @@ namespace libtorrent
|
|||
|
||||
if (m_torrent->is_paused()) return;
|
||||
|
||||
using namespace boost::posix_time;
|
||||
|
||||
ptime now = time_now();
|
||||
// remove old disconnected peers from the list
|
||||
m_peers.erase(
|
||||
std::remove_if(m_peers.begin()
|
||||
, m_peers.end()
|
||||
, old_disconnected_peer())
|
||||
, m_peers.end());
|
||||
for (iterator i = m_peers.begin(); i != m_peers.end();)
|
||||
{
|
||||
// this timeout has to be customizable!
|
||||
if (i->connection == 0
|
||||
&& i->connected != min_time()
|
||||
&& now - i->connected > minutes(120))
|
||||
{
|
||||
m_peers.erase(i++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// maintain the number of connections
|
||||
|
@ -664,8 +685,8 @@ namespace libtorrent
|
|||
// that are currently in the process of disconnecting
|
||||
int num_connected_peers = 0;
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
if (i->connection && !i->connection->is_disconnecting())
|
||||
++num_connected_peers;
|
||||
|
@ -680,8 +701,9 @@ namespace libtorrent
|
|||
{
|
||||
// every minute, disconnect the worst peer in hope of finding a better peer
|
||||
|
||||
boost::posix_time::ptime local_time = second_clock::universal_time();
|
||||
if (m_last_optimistic_disconnect + boost::posix_time::seconds(120) <= local_time)
|
||||
ptime local_time = time_now();
|
||||
if (m_last_optimistic_disconnect + seconds(120) <= local_time
|
||||
&& find_connect_candidate() != m_peers.end())
|
||||
{
|
||||
m_last_optimistic_disconnect = local_time;
|
||||
--max_connections; // this will have the effect of disconnecting the worst peer
|
||||
|
@ -690,7 +712,7 @@ namespace libtorrent
|
|||
else
|
||||
{
|
||||
// don't do a disconnect earlier than 1 minute after some peer was connected
|
||||
m_last_optimistic_disconnect = second_clock::universal_time();
|
||||
m_last_optimistic_disconnect = time_now();
|
||||
}
|
||||
|
||||
while (num_connected_peers > max_connections)
|
||||
|
@ -702,13 +724,6 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
while (m_torrent->num_peers() < m_torrent->m_connections_quota.given)
|
||||
{
|
||||
if (!connect_one_peer())
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------
|
||||
// upload shift
|
||||
// ------------------------
|
||||
|
@ -749,10 +764,10 @@ namespace libtorrent
|
|||
{
|
||||
do
|
||||
{
|
||||
peer* p = find_seed_choke_candidate();
|
||||
iterator p = find_seed_choke_candidate();
|
||||
--m_num_unchoked;
|
||||
assert(p != 0);
|
||||
if (p == 0) break;
|
||||
assert(p != m_peers.end());
|
||||
if (p == m_peers.end()) break;
|
||||
|
||||
assert(!p->connection->is_choked());
|
||||
p->connection->send_choke();
|
||||
|
@ -765,8 +780,8 @@ namespace libtorrent
|
|||
// TODO: This rotation should happen
|
||||
// far less frequent than this!
|
||||
assert(m_num_unchoked <= m_torrent->num_peers());
|
||||
peer* p = find_seed_unchoke_candidate();
|
||||
if (p)
|
||||
iterator p = find_seed_unchoke_candidate();
|
||||
if (p != m_peers.end())
|
||||
{
|
||||
assert(p->connection->is_choked());
|
||||
seed_choke_one_peer();
|
||||
|
@ -795,7 +810,7 @@ namespace libtorrent
|
|||
if (m_torrent->ratio() != 0)
|
||||
{
|
||||
// choke peers that have leeched too much without giving anything back
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
|
@ -823,9 +838,9 @@ namespace libtorrent
|
|||
{
|
||||
do
|
||||
{
|
||||
peer* p = find_choke_candidate();
|
||||
if (!p) break;
|
||||
assert(p);
|
||||
iterator p = find_choke_candidate();
|
||||
if (p == m_peers.end()) break;
|
||||
assert(p != m_peers.end());
|
||||
assert(!p->connection->is_choked());
|
||||
p->connection->send_choke();
|
||||
--m_num_unchoked;
|
||||
|
@ -838,8 +853,8 @@ namespace libtorrent
|
|||
// TODO: This rotation should happen
|
||||
// far less frequent than this!
|
||||
assert(m_num_unchoked <= m_torrent->num_peers());
|
||||
peer* p = find_unchoke_candidate();
|
||||
if (p)
|
||||
iterator p = find_unchoke_candidate();
|
||||
if (p != m_peers.end())
|
||||
{
|
||||
assert(p->connection->is_choked());
|
||||
choke_one_peer();
|
||||
|
@ -856,30 +871,6 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void policy::ban_peer(const peer_connection& c)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
std::vector<peer>::iterator i = std::find_if(
|
||||
m_peers.begin()
|
||||
, m_peers.end()
|
||||
, match_peer_connection(c));
|
||||
|
||||
if (i == m_peers.end())
|
||||
{
|
||||
// this is probably an http seed
|
||||
if (web_peer_connection const* p = dynamic_cast<web_peer_connection const*>(&c))
|
||||
{
|
||||
m_torrent->remove_url_seed(p->url());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
i->type = peer::not_connectable;
|
||||
i->ip.port(0);
|
||||
i->banned = true;
|
||||
}
|
||||
|
||||
void policy::new_connection(peer_connection& c)
|
||||
{
|
||||
assert(!c.is_local());
|
||||
|
@ -892,8 +883,7 @@ namespace libtorrent
|
|||
|
||||
// TODO: only allow _one_ connection to use this
|
||||
// override at a time
|
||||
assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
|
||||
|| c.proxy() == c.get_socket()->remote_endpoint());
|
||||
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||
|
||||
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
|
||||
&& c.remote().address() != m_torrent->current_tracker().address())
|
||||
|
@ -908,7 +898,7 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
std::vector<peer>::iterator i;
|
||||
iterator i;
|
||||
|
||||
if (m_torrent->settings().allow_multiple_connections_per_ip)
|
||||
{
|
||||
|
@ -944,46 +934,43 @@ namespace libtorrent
|
|||
"connection in favour of this one");
|
||||
#endif
|
||||
i->connection->disconnect();
|
||||
i->connection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
// we don't have ny info about this peer.
|
||||
// add a new entry
|
||||
assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
|
||||
|| c.proxy() == c.get_socket()->remote_endpoint());
|
||||
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||
|
||||
peer p(c.remote(), peer::not_connectable);
|
||||
peer p(c.remote(), peer::not_connectable, 0);
|
||||
m_peers.push_back(p);
|
||||
i = m_peers.end()-1;
|
||||
i = boost::prior(m_peers.end());
|
||||
}
|
||||
|
||||
c.set_peer_info(&*i);
|
||||
assert(i->connection == 0);
|
||||
c.add_stat(i->prev_amount_download, i->prev_amount_upload);
|
||||
i->prev_amount_download = 0;
|
||||
i->prev_amount_upload = 0;
|
||||
i->connection = &c;
|
||||
assert(i->connection);
|
||||
i->connected = second_clock::universal_time();
|
||||
m_last_optimistic_disconnect = second_clock::universal_time();
|
||||
i->connected = time_now();
|
||||
m_last_optimistic_disconnect = time_now();
|
||||
}
|
||||
|
||||
void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid)
|
||||
void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid
|
||||
, int src, char flags)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
// just ignore the obviously invalid entries from the tracker
|
||||
// just ignore the obviously invalid entries
|
||||
if(remote.address() == address() || remote.port() == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
std::vector<peer>::iterator i;
|
||||
iterator i;
|
||||
|
||||
if (m_torrent->settings().allow_multiple_connections_per_ip)
|
||||
{
|
||||
|
@ -997,21 +984,38 @@ namespace libtorrent
|
|||
, match_peer_ip(remote));
|
||||
}
|
||||
|
||||
bool just_added = false;
|
||||
|
||||
if (i == m_peers.end())
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
aux::session_impl& ses = m_torrent->session();
|
||||
|
||||
// if the IP is blocked, don't add it
|
||||
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
|
||||
{
|
||||
if (ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
|
||||
, "blocked peer not added to peer list"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// we don't have any info about this peer.
|
||||
// add a new entry
|
||||
peer p(remote, peer::connectable);
|
||||
peer p(remote, peer::connectable, src);
|
||||
m_peers.push_back(p);
|
||||
// the iterator is invalid
|
||||
// because of the push_back()
|
||||
i = m_peers.end() - 1;
|
||||
just_added = true;
|
||||
i = boost::prior(m_peers.end());
|
||||
if (flags & 0x02) p.seed = true;
|
||||
|
||||
// try to send a DHT ping to this peer
|
||||
// as well, to figure out if it supports
|
||||
// DHT (uTorrent and BitComet doesn't
|
||||
// advertise support)
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
udp::endpoint node(remote.address(), remote.port());
|
||||
m_torrent->session().add_dht_node(node);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1021,6 +1025,16 @@ namespace libtorrent
|
|||
// not known, so save it. Client may also have changed port
|
||||
// for some reason.
|
||||
i->ip = remote;
|
||||
i->source |= src;
|
||||
|
||||
// if this peer has failed before, decrease the
|
||||
// counter to allow it another try, since somebody
|
||||
// else is appearantly able to connect to it
|
||||
// if it comes from the DHT it might be stale though
|
||||
if (i->failcount > 0 && src != peer_info::dht)
|
||||
--i->failcount;
|
||||
|
||||
if (flags & 0x02) i->seed = true;
|
||||
|
||||
if (i->connection)
|
||||
{
|
||||
|
@ -1038,22 +1052,6 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (i->banned) return;
|
||||
|
||||
if (m_torrent->num_peers() < m_torrent->m_connections_quota.given
|
||||
&& !m_torrent->is_paused())
|
||||
{
|
||||
if (!connect_peer(&*i) && just_added)
|
||||
{
|
||||
// if this peer was just added, and it
|
||||
// failed to connect. Remove it from the list
|
||||
// (to keep it in sync with the session's list)
|
||||
assert(i == m_peers.end() - 1);
|
||||
m_peers.erase(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
|
@ -1081,7 +1079,7 @@ namespace libtorrent
|
|||
if (successfully_verified)
|
||||
{
|
||||
// have all peers update their interested-flag
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
if (i->connection == 0) continue;
|
||||
|
@ -1089,21 +1087,7 @@ namespace libtorrent
|
|||
if (!i->connection->is_interesting()) continue;
|
||||
if (!i->connection->has_piece(index)) continue;
|
||||
|
||||
bool interested = false;
|
||||
const std::vector<bool>& peer_has = i->connection->get_bitfield();
|
||||
const std::vector<bool>& we_have = m_torrent->pieces();
|
||||
assert(we_have.size() == peer_has.size());
|
||||
for (int j = 0; j != (int)we_have.size(); ++j)
|
||||
{
|
||||
if (!we_have[j] && peer_has[j])
|
||||
{
|
||||
interested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!interested)
|
||||
i->connection->send_not_interested();
|
||||
assert(i->connection->is_interesting() == interested);
|
||||
i->connection->update_interest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1192,22 +1176,26 @@ namespace libtorrent
|
|||
|
||||
bool policy::unchoke_one_peer()
|
||||
{
|
||||
peer* p = find_unchoke_candidate();
|
||||
if (p == 0) return false;
|
||||
INVARIANT_CHECK;
|
||||
|
||||
iterator p = find_unchoke_candidate();
|
||||
if (p == m_peers.end()) return false;
|
||||
assert(p->connection);
|
||||
assert(!p->connection->is_disconnecting());
|
||||
|
||||
assert(p->connection->is_choked());
|
||||
p->connection->send_unchoke();
|
||||
p->last_optimistically_unchoked = second_clock::universal_time();
|
||||
p->last_optimistically_unchoked = time_now();
|
||||
++m_num_unchoked;
|
||||
return true;
|
||||
}
|
||||
|
||||
void policy::choke_one_peer()
|
||||
{
|
||||
peer* p = find_choke_candidate();
|
||||
if (p == 0) return;
|
||||
INVARIANT_CHECK;
|
||||
|
||||
iterator p = find_choke_candidate();
|
||||
if (p == m_peers.end()) return;
|
||||
assert(p->connection);
|
||||
assert(!p->connection->is_disconnecting());
|
||||
assert(!p->connection->is_choked());
|
||||
|
@ -1217,42 +1205,42 @@ namespace libtorrent
|
|||
|
||||
bool policy::connect_one_peer()
|
||||
{
|
||||
if(m_torrent->num_peers() >= m_torrent->m_connections_quota.given)
|
||||
return false;
|
||||
peer* p = find_connect_candidate();
|
||||
if (p == 0) return false;
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(m_torrent->want_more_peers());
|
||||
|
||||
iterator p = find_connect_candidate();
|
||||
if (p == m_peers.end()) return false;
|
||||
|
||||
assert(!p->banned);
|
||||
assert(!p->connection);
|
||||
assert(p->type == peer::connectable);
|
||||
|
||||
return connect_peer(p);
|
||||
}
|
||||
|
||||
bool policy::connect_peer(peer *p)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
try
|
||||
{
|
||||
assert(!p->connection);
|
||||
p->connection = &m_torrent->connect_to_peer(p->ip);
|
||||
assert(p->connection);
|
||||
p->connected = m_last_optimistic_disconnect = time_now();
|
||||
p->connection = m_torrent->connect_to_peer(&*p);
|
||||
if (p->connection == 0) return false;
|
||||
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
|
||||
p->prev_amount_download = 0;
|
||||
p->prev_amount_upload = 0;
|
||||
p->connected =
|
||||
m_last_optimistic_disconnect =
|
||||
second_clock::universal_time();
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{}
|
||||
return false;
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*m_torrent->session().m_logger) << "*** CONNECTION FAILED '"
|
||||
<< e.what() << "'\n";
|
||||
#endif
|
||||
++p->failcount;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool policy::disconnect_one_peer()
|
||||
{
|
||||
peer *p = find_disconnect_candidate();
|
||||
if(!p)
|
||||
iterator p = find_disconnect_candidate();
|
||||
if (p == m_peers.end())
|
||||
return false;
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
(*p->connection->m_logger) << "*** CLOSING CONNECTION 'too many connections'\n";
|
||||
|
@ -1270,7 +1258,7 @@ namespace libtorrent
|
|||
// assert(c.is_disconnecting());
|
||||
bool unchoked = false;
|
||||
|
||||
std::vector<peer>::iterator i = std::find_if(
|
||||
iterator i = std::find_if(
|
||||
m_peers.begin()
|
||||
, m_peers.end()
|
||||
, match_peer_connection(c));
|
||||
|
@ -1278,17 +1266,18 @@ namespace libtorrent
|
|||
// if we couldn't find the connection in our list, just ignore it.
|
||||
if (i == m_peers.end()) return;
|
||||
assert(i->connection == &c);
|
||||
i->connection = 0;
|
||||
|
||||
i->connected = second_clock::universal_time();
|
||||
if (!i->connection->is_choked() && !m_torrent->is_aborted())
|
||||
i->connected = time_now();
|
||||
if (!c.is_choked() && !m_torrent->is_aborted())
|
||||
{
|
||||
unchoked = true;
|
||||
}
|
||||
|
||||
if (c.failed())
|
||||
{
|
||||
i->type = peer::not_connectable;
|
||||
i->ip.port(0);
|
||||
++i->failcount;
|
||||
i->connected = time_now();
|
||||
}
|
||||
|
||||
// if the share ratio is 0 (infinite), the
|
||||
|
@ -1296,13 +1285,12 @@ namespace libtorrent
|
|||
// because it isn't necessary.
|
||||
if (m_torrent->ratio() != 0.f)
|
||||
{
|
||||
assert(i->connection->associated_torrent().lock().get() == m_torrent);
|
||||
assert(i->connection->share_diff() < std::numeric_limits<size_type>::max());
|
||||
m_available_free_upload += i->connection->share_diff();
|
||||
assert(c.associated_torrent().lock().get() == m_torrent);
|
||||
assert(c.share_diff() < std::numeric_limits<size_type>::max());
|
||||
m_available_free_upload += c.share_diff();
|
||||
}
|
||||
i->prev_amount_download += c.statistics().total_payload_download();
|
||||
i->prev_amount_upload += c.statistics().total_payload_upload();
|
||||
i->connection = 0;
|
||||
|
||||
if (unchoked)
|
||||
{
|
||||
|
@ -1334,9 +1322,10 @@ namespace libtorrent
|
|||
#ifndef NDEBUG
|
||||
bool policy::has_connection(const peer_connection* c)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(c);
|
||||
assert((c->proxy() == tcp::endpoint() && c->remote() == c->get_socket()->remote_endpoint())
|
||||
|| c->proxy() == c->get_socket()->remote_endpoint());
|
||||
assert(c->remote() == c->get_socket()->remote_endpoint());
|
||||
|
||||
return std::find_if(
|
||||
m_peers.begin()
|
||||
|
@ -1353,12 +1342,17 @@ namespace libtorrent
|
|||
int total_connections = 0;
|
||||
int nonempty_connections = 0;
|
||||
|
||||
|
||||
for (std::vector<peer>::const_iterator i = m_peers.begin();
|
||||
std::set<address> unique_test;
|
||||
for (const_iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
||||
assert(unique_test.find(i->ip.address()) == unique_test.end());
|
||||
unique_test.insert(i->ip.address());
|
||||
++total_connections;
|
||||
if (!i->connection) continue;
|
||||
assert(i->connection->peer_info_struct() == 0
|
||||
|| i->connection->peer_info_struct() == &*i);
|
||||
++nonempty_connections;
|
||||
if (!i->connection->is_disconnecting())
|
||||
++connected_peers;
|
||||
|
@ -1386,30 +1380,30 @@ namespace libtorrent
|
|||
// When there's an outgoing connection, it will first
|
||||
// be added to the torrent and then to the policy.
|
||||
// that's why the two second cases are in there.
|
||||
|
||||
/*
|
||||
assert(connected_peers == num_torrent_peers
|
||||
|| (connected_peers == num_torrent_peers + 1
|
||||
&& connected_peers > 0)
|
||||
|| (connected_peers + 1 == num_torrent_peers
|
||||
&& num_torrent_peers > 0));
|
||||
|
||||
// TODO: Make sure the number of peers in m_torrent is equal
|
||||
// to the number of connected peers in m_peers.
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t)
|
||||
policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t, int src)
|
||||
: ip(ip_)
|
||||
, type(t)
|
||||
, last_optimistically_unchoked(
|
||||
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||
, connected(boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||
, failcount(0)
|
||||
, seed(false)
|
||||
, last_optimistically_unchoked(min_time())
|
||||
, connected(min_time())
|
||||
, prev_amount_upload(0)
|
||||
, prev_amount_download(0)
|
||||
, banned(false)
|
||||
, source(src)
|
||||
, connection(0)
|
||||
{
|
||||
assert(connected < second_clock::universal_time());
|
||||
assert(connected < time_now());
|
||||
}
|
||||
|
||||
size_type policy::peer::total_download() const
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
@ -73,7 +75,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/kademlia/dht_tracker.hpp"
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using boost::shared_ptr;
|
||||
using boost::weak_ptr;
|
||||
using boost::bind;
|
||||
|
@ -87,9 +88,11 @@ namespace libtorrent
|
|||
{
|
||||
filesystem_init::filesystem_init()
|
||||
{
|
||||
#if BOOST_VERSION < 103400
|
||||
using namespace boost::filesystem;
|
||||
if (path::default_name_check_writable())
|
||||
path::default_name_check(no_check);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,10 +170,11 @@ namespace libtorrent
|
|||
, boost::filesystem::path const& save_path
|
||||
, entry const& resume_data
|
||||
, bool compact_mode
|
||||
, int block_size)
|
||||
, int block_size
|
||||
, storage_constructor_type sc)
|
||||
{
|
||||
return m_impl->add_torrent(ti, save_path, resume_data
|
||||
, compact_mode, block_size);
|
||||
, compact_mode, block_size, sc);
|
||||
}
|
||||
|
||||
torrent_handle session::add_torrent(
|
||||
|
@ -180,10 +184,11 @@ namespace libtorrent
|
|||
, boost::filesystem::path const& save_path
|
||||
, entry const& e
|
||||
, bool compact_mode
|
||||
, int block_size)
|
||||
, int block_size
|
||||
, storage_constructor_type sc)
|
||||
{
|
||||
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
|
||||
, compact_mode, block_size);
|
||||
, compact_mode, block_size, sc);
|
||||
}
|
||||
|
||||
void session::remove_torrent(const torrent_handle& h)
|
||||
|
@ -257,6 +262,49 @@ namespace libtorrent
|
|||
return m_impl->settings();
|
||||
}
|
||||
|
||||
void session::set_peer_proxy(proxy_settings const& s)
|
||||
{
|
||||
m_impl->set_peer_proxy(s);
|
||||
}
|
||||
|
||||
void session::set_web_seed_proxy(proxy_settings const& s)
|
||||
{
|
||||
m_impl->set_web_seed_proxy(s);
|
||||
}
|
||||
|
||||
void session::set_tracker_proxy(proxy_settings const& s)
|
||||
{
|
||||
m_impl->set_tracker_proxy(s);
|
||||
}
|
||||
|
||||
proxy_settings const& session::peer_proxy() const
|
||||
{
|
||||
return m_impl->peer_proxy();
|
||||
}
|
||||
|
||||
proxy_settings const& session::web_seed_proxy() const
|
||||
{
|
||||
return m_impl->web_seed_proxy();
|
||||
}
|
||||
|
||||
proxy_settings const& session::tracker_proxy() const
|
||||
{
|
||||
return m_impl->tracker_proxy();
|
||||
}
|
||||
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
void session::set_dht_proxy(proxy_settings const& s)
|
||||
{
|
||||
m_impl->set_dht_proxy(s);
|
||||
}
|
||||
|
||||
proxy_settings const& session::dht_proxy() const
|
||||
{
|
||||
return m_impl->dht_proxy();
|
||||
}
|
||||
#endif
|
||||
|
||||
void session::set_max_uploads(int limit)
|
||||
{
|
||||
m_impl->set_max_uploads(limit);
|
||||
|
@ -312,5 +360,9 @@ namespace libtorrent
|
|||
m_impl->set_severity_level(s);
|
||||
}
|
||||
|
||||
connection_queue& session::get_connection_queue()
|
||||
{
|
||||
return m_impl->m_half_open;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,8 @@ By Steve Reid <sreid@sea-to-sky.net>
|
|||
changelog at the end of the file.
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -23,16 +25,16 @@ using boost::uint8_t;
|
|||
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
struct TORRENT_EXPORT SHA1_CTX
|
||||
struct TORRENT_EXPORT SHA_CTX
|
||||
{
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
uint8_t buffer[64];
|
||||
};
|
||||
|
||||
TORRENT_EXPORT void SHA1Init(SHA1_CTX* context);
|
||||
TORRENT_EXPORT void SHA1Update(SHA1_CTX* context, uint8_t const* data, uint32_t len);
|
||||
TORRENT_EXPORT void SHA1Final(SHA1_CTX* context, uint8_t* digest);
|
||||
TORRENT_EXPORT void SHA1_Init(SHA_CTX* context);
|
||||
TORRENT_EXPORT void SHA1_Update(SHA_CTX* context, uint8_t const* data, uint32_t len);
|
||||
TORRENT_EXPORT void SHA1_Final(uint8_t* digest, SHA_CTX* context);
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -123,7 +125,7 @@ namespace
|
|||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
void SHAPrintContext(SHA1_CTX *context, char *msg)
|
||||
void SHAPrintContext(SHA_CTX *context, char *msg)
|
||||
{
|
||||
using namespace std;
|
||||
printf("%s (%d,%d) %x %x %x %x %x\n"
|
||||
|
@ -134,7 +136,7 @@ namespace
|
|||
}
|
||||
|
||||
template <class BlkFun>
|
||||
void internal_update(SHA1_CTX* context, uint8_t const* data, uint32_t len)
|
||||
void internal_update(SHA_CTX* context, uint8_t const* data, uint32_t len)
|
||||
{
|
||||
using namespace std;
|
||||
uint32_t i, j; // JHB
|
||||
|
@ -174,7 +176,7 @@ namespace
|
|||
|
||||
// SHA1Init - Initialize new context
|
||||
|
||||
void SHA1Init(SHA1_CTX* context)
|
||||
void SHA1_Init(SHA_CTX* context)
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
context->state[0] = 0x67452301;
|
||||
|
@ -188,7 +190,7 @@ void SHA1Init(SHA1_CTX* context)
|
|||
|
||||
// Run your data through this.
|
||||
|
||||
void SHA1Update(SHA1_CTX* context, uint8_t const* data, uint32_t len)
|
||||
void SHA1_Update(SHA_CTX* context, uint8_t const* data, uint32_t len)
|
||||
{
|
||||
#if defined __BIG_ENDIAN__
|
||||
internal_update<big_endian_blk0>(context, data, len);
|
||||
|
@ -207,7 +209,7 @@ void SHA1Update(SHA1_CTX* context, uint8_t const* data, uint32_t len)
|
|||
|
||||
// Add padding and return the message digest.
|
||||
|
||||
void SHA1Final(SHA1_CTX* context, uint8_t* digest)
|
||||
void SHA1_Final(uint8_t* digest, SHA_CTX* context)
|
||||
{
|
||||
uint8_t finalcount[8];
|
||||
|
||||
|
@ -219,10 +221,10 @@ void SHA1Final(SHA1_CTX* context, uint8_t* digest)
|
|||
>> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
|
||||
SHA1Update(context, (uint8_t const*)"\200", 1);
|
||||
SHA1_Update(context, (uint8_t const*)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448)
|
||||
SHA1Update(context, (uint8_t const*)"\0", 1);
|
||||
SHA1Update(context, finalcount, 8); // Should cause a SHA1Transform()
|
||||
SHA1_Update(context, (uint8_t const*)"\0", 1);
|
||||
SHA1_Update(context, finalcount, 8); // Should cause a SHA1Transform()
|
||||
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
|
@ -299,6 +301,7 @@ By Arvid Norberg <arvidn@sourceforge.net>
|
|||
4- using anonymous namespace to avoid external
|
||||
linkage on internal functions
|
||||
5- using standard C++ includes
|
||||
6- made API compatible with openssl
|
||||
|
||||
still 100% PD
|
||||
*/
|
||||
|
|
315
libtorrent/src/socks5_stream.cpp
Normal file
315
libtorrent/src/socks5_stream.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2007, 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 "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/socks5_stream.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e || i == tcp::resolver::iterator())
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
m_sock.async_connect(i->endpoint(), boost::bind(
|
||||
&socks5_stream::connected, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace libtorrent::detail;
|
||||
// send SOCKS5 authentication methods
|
||||
m_buffer.resize(m_user.empty()?3:4);
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(5, p); // SOCKS VERSION 5
|
||||
if (m_user.empty())
|
||||
{
|
||||
write_uint8(1, p); // 1 authentication method (no auth)
|
||||
write_uint8(0, p); // no authentication
|
||||
}
|
||||
else
|
||||
{
|
||||
write_uint8(2, p); // 2 authentication methods
|
||||
write_uint8(0, p); // no authentication
|
||||
write_uint8(2, p); // username/password
|
||||
}
|
||||
asio::async_write(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::handshake1, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer.resize(2);
|
||||
asio::async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::handshake2, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
char* p = &m_buffer[0];
|
||||
int version = read_uint8(p);
|
||||
int method = read_uint8(p);
|
||||
|
||||
if (version < 5)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (method == 0)
|
||||
{
|
||||
socks_connect(h);
|
||||
}
|
||||
else if (method == 2)
|
||||
{
|
||||
if (m_user.empty())
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
// start sub-negotiation
|
||||
m_buffer.resize(m_user.size() + m_password.size() + 3);
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(1, p);
|
||||
write_uint8(m_user.size(), p);
|
||||
write_string(m_user, p);
|
||||
write_uint8(m_password.size(), p);
|
||||
write_string(m_password, p);
|
||||
asio::async_write(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::handshake3, this, _1, h));
|
||||
}
|
||||
else
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void socks5_stream::handshake3(asio::error_code const& e
|
||||
, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer.resize(2);
|
||||
asio::async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::handshake4, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::handshake4(asio::error_code const& e
|
||||
, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
char* p = &m_buffer[0];
|
||||
int version = read_uint8(p);
|
||||
int status = read_uint8(p);
|
||||
|
||||
if (version != 1)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
}
|
||||
|
||||
void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
// send SOCKS5 connect command
|
||||
m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(5, p); // SOCKS VERSION 5
|
||||
write_uint8(1, p); // CONNECT command
|
||||
write_uint8(0, p); // reserved
|
||||
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
||||
write_address(m_remote_endpoint.address(), p);
|
||||
write_uint16(m_remote_endpoint.port(), p);
|
||||
assert(p - &m_buffer[0] == int(m_buffer.size()));
|
||||
|
||||
asio::async_write(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::connect1, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer.resize(6 + 4); // assume an IPv4 address
|
||||
asio::async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::connect2, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
// send SOCKS5 connect command
|
||||
char* p = &m_buffer[0];
|
||||
int version = read_uint8(p);
|
||||
if (version < 5)
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
int response = read_uint8(p);
|
||||
if (response != 0)
|
||||
{
|
||||
asio::error_code e = asio::error::fault;
|
||||
switch (response)
|
||||
{
|
||||
case 1: e = asio::error::fault; break;
|
||||
case 2: e = asio::error::no_permission; break;
|
||||
case 3: e = asio::error::network_unreachable; break;
|
||||
case 4: e = asio::error::host_unreachable; break;
|
||||
case 5: e = asio::error::connection_refused; break;
|
||||
case 6: e = asio::error::timed_out; break;
|
||||
case 7: e = asio::error::operation_not_supported; break;
|
||||
case 8: e = asio::error::address_family_not_supported; break;
|
||||
}
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
p += 1; // reserved
|
||||
int atyp = read_uint8(p);
|
||||
// we ignore the proxy IP it was bound to
|
||||
if (atyp == 1)
|
||||
{
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
return;
|
||||
}
|
||||
int skip_bytes = 0;
|
||||
if (atyp == 4)
|
||||
{
|
||||
skip_bytes = 12;
|
||||
}
|
||||
else if (atyp == 3)
|
||||
{
|
||||
skip_bytes = read_uint8(p) - 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*h)(asio::error::operation_not_supported);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
m_buffer.resize(skip_bytes);
|
||||
|
||||
asio::async_read(m_sock, asio::buffer(m_buffer)
|
||||
, boost::bind(&socks5_stream::connect3, this, _1, h));
|
||||
}
|
||||
|
||||
void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
(*h)(e);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,11 +35,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// per second and one (low pass-filter) for rates < 1
|
||||
// packet per second.
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libtorrent/stat.hpp"
|
||||
#include "libtorrent/invariant_check.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER <= 1200
|
||||
#define for if (false) {} else for
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
@ -179,6 +181,13 @@ namespace libtorrent
|
|||
, bind(&torrent::set_upload_limit, _1, limit));
|
||||
}
|
||||
|
||||
int torrent_handle::upload_limit() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
return call_member<int>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::upload_limit, _1));
|
||||
}
|
||||
|
||||
void torrent_handle::set_download_limit(int limit) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -189,6 +198,13 @@ namespace libtorrent
|
|||
, bind(&torrent::set_download_limit, _1, limit));
|
||||
}
|
||||
|
||||
int torrent_handle::download_limit() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
return call_member<int>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::download_limit, _1));
|
||||
}
|
||||
|
||||
bool torrent_handle::move_storage(
|
||||
boost::filesystem::path const& save_path) const
|
||||
{
|
||||
|
@ -328,6 +344,57 @@ namespace libtorrent
|
|||
, bind(&torrent::set_sequenced_download_threshold, _1, threshold));
|
||||
}
|
||||
|
||||
std::string torrent_handle::name() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
return call_member<std::string>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::name, _1));
|
||||
}
|
||||
|
||||
|
||||
void torrent_handle::piece_priority(int index, int priority) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
call_member<void>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::set_piece_priority, _1, index, priority));
|
||||
}
|
||||
|
||||
int torrent_handle::piece_priority(int index) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
return call_member<int>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::piece_priority, _1, index));
|
||||
}
|
||||
|
||||
void torrent_handle::prioritize_pieces(std::vector<int> const& pieces) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
call_member<void>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::prioritize_pieces, _1, boost::cref(pieces)));
|
||||
}
|
||||
|
||||
std::vector<int> torrent_handle::piece_priorities() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
std::vector<int> ret;
|
||||
call_member<void>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::piece_priorities, _1, boost::ref(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void torrent_handle::prioritize_files(std::vector<int> const& files) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
call_member<void>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::prioritize_files, _1, boost::cref(files)));
|
||||
}
|
||||
|
||||
// ============ start deprecation ===============
|
||||
|
||||
void torrent_handle::filter_piece(int index, bool filter) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -339,7 +406,7 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
call_member<void>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::filter_pieces, _1, pieces));
|
||||
, bind(&torrent::filter_pieces, _1, boost::cref(pieces)));
|
||||
}
|
||||
|
||||
bool torrent_handle::is_piece_filtered(int index) const
|
||||
|
@ -349,13 +416,6 @@ namespace libtorrent
|
|||
, bind(&torrent::is_piece_filtered, _1, index));
|
||||
}
|
||||
|
||||
std::string torrent_handle::name() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
return call_member<std::string>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::name, _1));
|
||||
}
|
||||
|
||||
std::vector<bool> torrent_handle::filtered_pieces() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -372,6 +432,9 @@ namespace libtorrent
|
|||
, bind(&torrent::filter_files, _1, files));
|
||||
}
|
||||
|
||||
// ============ end deprecation ===============
|
||||
|
||||
|
||||
std::vector<announce_entry> const& torrent_handle::trackers() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -448,6 +511,8 @@ namespace libtorrent
|
|||
ret["file-format"] = "libtorrent resume file";
|
||||
ret["file-version"] = 1;
|
||||
|
||||
ret["allocation"] = t->filesystem().compact_allocation()?"compact":"full";
|
||||
|
||||
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
||||
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
||||
|
||||
|
@ -477,7 +542,7 @@ namespace libtorrent
|
|||
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
||||
= q.begin(); i != q.end(); ++i)
|
||||
{
|
||||
if (i->finished_blocks.count() == 0) continue;
|
||||
if (i->finished == 0) continue;
|
||||
|
||||
entry piece_struct(entry::dictionary_t);
|
||||
|
||||
|
@ -492,7 +557,7 @@ namespace libtorrent
|
|||
{
|
||||
unsigned char v = 0;
|
||||
for (int k = 0; k < 8; ++k)
|
||||
v |= i->finished_blocks[j*8+k]?(1 << k):0;
|
||||
v |= i->info[j*8+k].finished?(1 << k):0;
|
||||
bitmask.insert(bitmask.end(), v);
|
||||
}
|
||||
piece_struct["bitmask"] = bitmask;
|
||||
|
@ -502,7 +567,7 @@ namespace libtorrent
|
|||
= t->filesystem().piece_crc(
|
||||
t->filesystem().slot_for_piece(i->index)
|
||||
, t->block_size()
|
||||
, i->finished_blocks);
|
||||
, i->info);
|
||||
|
||||
piece_struct["adler32"] = adler;
|
||||
|
||||
|
@ -537,19 +602,7 @@ namespace libtorrent
|
|||
peer_list.push_back(peer);
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
= get_filesizes(t->torrent_file(), t->save_path());
|
||||
|
||||
ret["file sizes"] = entry::list_type();
|
||||
entry::list_type& fl = ret["file sizes"].list();
|
||||
for (std::vector<std::pair<size_type, std::time_t> >::iterator i
|
||||
= file_sizes.begin(), end(file_sizes.end()); i != end; ++i)
|
||||
{
|
||||
entry::list_type p;
|
||||
p.push_back(entry(i->first));
|
||||
p.push_back(entry(i->second));
|
||||
fl.push_back(entry(p));
|
||||
}
|
||||
t->filesystem().write_resume_data(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -563,7 +616,7 @@ namespace libtorrent
|
|||
, bind(&torrent::save_path, _1));
|
||||
}
|
||||
|
||||
void torrent_handle::connect_peer(tcp::endpoint const& adr) const
|
||||
void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
|
@ -587,7 +640,7 @@ namespace libtorrent
|
|||
|
||||
peer_id id;
|
||||
std::fill(id.begin(), id.end(), 0);
|
||||
t->get_policy().peer_from_tracker(adr, id);
|
||||
t->get_policy().peer_from_tracker(adr, id, source, 0);
|
||||
}
|
||||
|
||||
void torrent_handle::force_reannounce(
|
||||
|
@ -601,9 +654,8 @@ namespace libtorrent
|
|||
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||
if (!t) throw_invalid_handle();
|
||||
|
||||
using boost::posix_time::second_clock;
|
||||
t->force_tracker_request(second_clock::universal_time()
|
||||
+ duration);
|
||||
t->force_tracker_request(time_now()
|
||||
+ seconds(duration.total_seconds()));
|
||||
}
|
||||
|
||||
void torrent_handle::force_reannounce() const
|
||||
|
@ -632,6 +684,7 @@ namespace libtorrent
|
|||
, bind(&torrent::set_ratio, _1, ratio));
|
||||
}
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void torrent_handle::resolve_countries(bool r)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -645,6 +698,7 @@ namespace libtorrent
|
|||
return call_member<bool>(m_ses, m_chk, m_info_hash
|
||||
, bind(&torrent::resolving_countries, _1));
|
||||
}
|
||||
#endif
|
||||
|
||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
|
||||
{
|
||||
|
@ -671,8 +725,10 @@ namespace libtorrent
|
|||
peer_info& p = v.back();
|
||||
|
||||
peer->get_peer_info(p);
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
if (t->resolving_countries())
|
||||
t->resolve_peer_country(intrusive_ptr<peer_connection>(peer));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,15 +756,16 @@ namespace libtorrent
|
|||
= q.begin(); i != q.end(); ++i)
|
||||
{
|
||||
partial_piece_info pi;
|
||||
pi.finished_blocks = i->finished_blocks;
|
||||
pi.requested_blocks = i->requested_blocks;
|
||||
for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j)
|
||||
pi.piece_state = (partial_piece_info::state_t)i->state;
|
||||
pi.blocks_in_piece = p.blocks_in_piece(i->index);
|
||||
for (int j = 0; j < pi.blocks_in_piece; ++j)
|
||||
{
|
||||
pi.peer[j] = i->info[j].peer;
|
||||
pi.num_downloads[j] = i->info[j].num_downloads;
|
||||
pi.finished_blocks[j] = i->info[j].finished;
|
||||
pi.requested_blocks[j] = i->info[j].requested;
|
||||
}
|
||||
pi.piece_index = i->index;
|
||||
pi.blocks_in_piece = p.blocks_in_piece(i->index);
|
||||
queue.push_back(pi);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
@ -43,7 +45,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian_types.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
@ -57,6 +58,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/entry.hpp"
|
||||
|
||||
namespace pt = boost::posix_time;
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
using namespace libtorrent;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
|
@ -213,15 +217,16 @@ namespace
|
|||
namespace libtorrent
|
||||
{
|
||||
|
||||
using namespace boost::gregorian;
|
||||
using namespace boost::posix_time;
|
||||
|
||||
// standard constructor that parses a torrent file
|
||||
torrent_info::torrent_info(const entry& torrent_file)
|
||||
: m_creation_date(date(not_a_date_time))
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -240,24 +245,32 @@ namespace libtorrent
|
|||
torrent_info::torrent_info(sha1_hash const& info_hash)
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash(info_hash)
|
||||
, m_name()
|
||||
, m_creation_date(second_clock::universal_time())
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
torrent_info::torrent_info()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash(0)
|
||||
, m_name()
|
||||
, m_creation_date(second_clock::universal_time())
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -277,15 +290,15 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
#endif
|
||||
assert(!m_half_metadata);
|
||||
m_piece_length = size;
|
||||
|
||||
|
||||
int num_pieces = static_cast<int>(
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(num_pieces);
|
||||
for (int i = old_num_pieces; i < num_pieces; ++i)
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
for (int i = old_num_pieces; i < m_num_pieces; ++i)
|
||||
{
|
||||
m_piece_hash[i].clear();
|
||||
}
|
||||
|
@ -343,14 +356,14 @@ namespace libtorrent
|
|||
// we want this division to round upwards, that's why we have the
|
||||
// extra addition
|
||||
|
||||
int num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
m_piece_hash.resize(num_pieces);
|
||||
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
const std::string& hash_string = info["pieces"].string();
|
||||
|
||||
if ((int)hash_string.length() != num_pieces * 20)
|
||||
if ((int)hash_string.length() != m_num_pieces * 20)
|
||||
throw invalid_torrent_file();
|
||||
|
||||
for (int i = 0; i < num_pieces; ++i)
|
||||
for (int i = 0; i < m_num_pieces; ++i)
|
||||
std::copy(
|
||||
hash_string.begin() + i*20
|
||||
, hash_string.begin() + (i+1)*20
|
||||
|
@ -453,8 +466,8 @@ namespace libtorrent
|
|||
// extract creation date
|
||||
try
|
||||
{
|
||||
m_creation_date = ptime(date(1970, Jan, 1))
|
||||
+ seconds(long(torrent_file["creation date"].integer()));
|
||||
m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1))
|
||||
+ pt::seconds(long(torrent_file["creation date"].integer()));
|
||||
}
|
||||
catch (type_error) {}
|
||||
|
||||
|
@ -492,14 +505,14 @@ namespace libtorrent
|
|||
parse_info_section(torrent_file["info"]);
|
||||
}
|
||||
|
||||
boost::optional<ptime>
|
||||
boost::optional<pt::ptime>
|
||||
torrent_info::creation_date() const
|
||||
{
|
||||
if (m_creation_date != ptime(date(not_a_date_time)))
|
||||
if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
|
||||
{
|
||||
return boost::optional<ptime>(m_creation_date);
|
||||
return boost::optional<pt::ptime>(m_creation_date);
|
||||
}
|
||||
return boost::optional<ptime>();
|
||||
return boost::optional<pt::ptime>();
|
||||
}
|
||||
|
||||
void torrent_info::add_tracker(std::string const& url, int tier)
|
||||
|
@ -549,12 +562,12 @@ namespace libtorrent
|
|||
if (m_piece_length == 0)
|
||||
m_piece_length = 256 * 1024;
|
||||
|
||||
int num_pieces = static_cast<int>(
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(num_pieces);
|
||||
if (num_pieces > old_num_pieces)
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
if (m_num_pieces > old_num_pieces)
|
||||
std::for_each(m_piece_hash.begin() + old_num_pieces
|
||||
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
|
||||
}
|
||||
|
@ -637,9 +650,6 @@ namespace libtorrent
|
|||
{
|
||||
assert(m_piece_length > 0);
|
||||
|
||||
using namespace boost::gregorian;
|
||||
using namespace boost::posix_time;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
if ((m_urls.empty() && m_nodes.empty()) || m_files.empty())
|
||||
|
@ -694,7 +704,7 @@ namespace libtorrent
|
|||
dict["comment"] = m_comment;
|
||||
|
||||
dict["creation date"] =
|
||||
(m_creation_date - ptime(date(1970, Jan, 1))).total_seconds();
|
||||
(m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds();
|
||||
|
||||
if (!m_created_by.empty())
|
||||
dict["created by"] = m_created_by;
|
||||
|
@ -738,6 +748,18 @@ namespace libtorrent
|
|||
assert(false);
|
||||
}
|
||||
|
||||
void torrent_info::seed_free()
|
||||
{
|
||||
std::vector<std::string>().swap(m_url_seeds);
|
||||
nodes_t().swap(m_nodes);
|
||||
std::vector<sha1_hash>().swap(m_piece_hash);
|
||||
#ifndef NDEBUG
|
||||
m_half_metadata = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------- start deprecation -------
|
||||
|
||||
void torrent_info::print(std::ostream& os) const
|
||||
{
|
||||
os << "trackers:\n";
|
||||
|
@ -748,8 +770,8 @@ namespace libtorrent
|
|||
}
|
||||
if (!m_comment.empty())
|
||||
os << "comment: " << m_comment << "\n";
|
||||
if (m_creation_date != ptime(date(not_a_date_time)))
|
||||
os << "creation date: " << to_simple_string(m_creation_date) << "\n";
|
||||
// if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
|
||||
// os << "creation date: " << to_simple_string(m_creation_date) << "\n";
|
||||
os << "private: " << (m_private?"yes":"no") << "\n";
|
||||
os << "number of pieces: " << num_pieces() << "\n";
|
||||
os << "piece length: " << piece_length() << "\n";
|
||||
|
@ -758,6 +780,8 @@ namespace libtorrent
|
|||
os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n";
|
||||
}
|
||||
|
||||
// ------- end deprecation -------
|
||||
|
||||
size_type torrent_info::piece_size(int index) const
|
||||
{
|
||||
assert(index >= 0 && index < num_pieces());
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
|
@ -79,11 +81,6 @@ namespace
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
using boost::posix_time::second_clock;
|
||||
using boost::posix_time::seconds;
|
||||
using boost::posix_time::ptime;
|
||||
using boost::posix_time::time_duration;
|
||||
|
||||
// returns -1 if gzip header is invalid or the header size in bytes
|
||||
int gzip_header(const char* buf, int size)
|
||||
{
|
||||
|
@ -316,8 +313,8 @@ namespace libtorrent
|
|||
|
||||
timeout_handler::timeout_handler(asio::strand& str)
|
||||
: m_strand(str)
|
||||
, m_start_time(second_clock::universal_time())
|
||||
, m_read_time(second_clock::universal_time())
|
||||
, m_start_time(time_now())
|
||||
, m_read_time(time_now())
|
||||
, m_timeout(str.io_service())
|
||||
, m_completion_timeout(0)
|
||||
, m_read_timeout(0)
|
||||
|
@ -328,8 +325,8 @@ namespace libtorrent
|
|||
{
|
||||
m_completion_timeout = completion_timeout;
|
||||
m_read_timeout = read_timeout;
|
||||
m_start_time = second_clock::universal_time();
|
||||
m_read_time = second_clock::universal_time();
|
||||
m_start_time = time_now();
|
||||
m_read_time = time_now();
|
||||
|
||||
m_timeout.expires_at(std::min(
|
||||
m_read_time + seconds(m_read_timeout)
|
||||
|
@ -340,7 +337,7 @@ namespace libtorrent
|
|||
|
||||
void timeout_handler::restart_read_timeout()
|
||||
{
|
||||
m_read_time = second_clock::universal_time();
|
||||
m_read_time = time_now();
|
||||
}
|
||||
|
||||
void timeout_handler::cancel()
|
||||
|
@ -354,14 +351,14 @@ namespace libtorrent
|
|||
if (error) return;
|
||||
if (m_completion_timeout == 0) return;
|
||||
|
||||
ptime now(second_clock::universal_time());
|
||||
ptime now(time_now());
|
||||
time_duration receive_timeout = now - m_read_time;
|
||||
time_duration completion_timeout = now - m_start_time;
|
||||
|
||||
if (m_read_timeout
|
||||
< receive_timeout.total_seconds()
|
||||
< total_seconds(receive_timeout)
|
||||
|| m_completion_timeout
|
||||
< completion_timeout.total_seconds())
|
||||
< total_seconds(completion_timeout))
|
||||
{
|
||||
on_timeout();
|
||||
return;
|
||||
|
@ -427,11 +424,13 @@ namespace libtorrent
|
|||
|
||||
m_connections.erase(i);
|
||||
}
|
||||
|
||||
tuple<std::string, std::string, int, std::string>
|
||||
|
||||
// returns protocol, auth, hostname, port, path
|
||||
tuple<std::string, std::string, std::string, int, std::string>
|
||||
parse_url_components(std::string url)
|
||||
{
|
||||
std::string hostname; // hostname only
|
||||
std::string auth; // user:pass
|
||||
std::string protocol; // should be http
|
||||
int port = 80;
|
||||
|
||||
|
@ -442,7 +441,7 @@ namespace libtorrent
|
|||
++start;
|
||||
std::string::iterator end
|
||||
= std::find(url.begin(), url.end(), ':');
|
||||
protocol = std::string(start, end);
|
||||
protocol.assign(start, end);
|
||||
|
||||
if (end == url.end()) throw std::runtime_error("invalid url");
|
||||
++end;
|
||||
|
@ -454,7 +453,20 @@ namespace libtorrent
|
|||
++end;
|
||||
start = end;
|
||||
|
||||
std::string::iterator at = std::find(start, url.end(), '@');
|
||||
std::string::iterator colon = std::find(start, url.end(), ':');
|
||||
end = std::find(start, url.end(), '/');
|
||||
|
||||
if (at != url.end()
|
||||
&& colon != url.end()
|
||||
&& colon < at
|
||||
&& at < end)
|
||||
{
|
||||
auth.assign(start, at);
|
||||
start = at;
|
||||
++start;
|
||||
}
|
||||
|
||||
std::string::iterator port_pos
|
||||
= std::find(start, url.end(), ':');
|
||||
|
||||
|
@ -478,12 +490,13 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
start = end;
|
||||
return make_tuple(protocol, hostname, port
|
||||
return make_tuple(protocol, auth, hostname, port
|
||||
, std::string(start, url.end()));
|
||||
}
|
||||
|
||||
void tracker_manager::queue_request(
|
||||
asio::strand& str
|
||||
, connection_queue& cc
|
||||
, tracker_request req
|
||||
, std::string const& auth
|
||||
, address bind_infc
|
||||
|
@ -494,6 +507,10 @@ namespace libtorrent
|
|||
if (req.event == tracker_request::stopped)
|
||||
req.num_want = 0;
|
||||
|
||||
assert(!m_abort || req.event == tracker_request::stopped);
|
||||
if (m_abort && req.event != tracker_request::stopped)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
std::string protocol;
|
||||
|
@ -501,7 +518,9 @@ namespace libtorrent
|
|||
int port;
|
||||
std::string request_string;
|
||||
|
||||
boost::tie(protocol, hostname, port, request_string)
|
||||
using boost::tuples::ignore;
|
||||
// TODO: should auth be used here?
|
||||
boost::tie(protocol, ignore, hostname, port, request_string)
|
||||
= parse_url_components(req.url);
|
||||
|
||||
boost::intrusive_ptr<tracker_connection> con;
|
||||
|
@ -510,6 +529,7 @@ namespace libtorrent
|
|||
{
|
||||
con = new http_tracker_connection(
|
||||
str
|
||||
, cc
|
||||
, *this
|
||||
, req
|
||||
, hostname
|
||||
|
@ -518,6 +538,7 @@ namespace libtorrent
|
|||
, bind_infc
|
||||
, c
|
||||
, m_settings
|
||||
, m_proxy
|
||||
, auth);
|
||||
}
|
||||
else if (protocol == "udp")
|
||||
|
@ -555,6 +576,7 @@ namespace libtorrent
|
|||
// 'event=stopped'-requests)
|
||||
mutex_t::scoped_lock l(m_mutex);
|
||||
|
||||
m_abort = true;
|
||||
tracker_connections_t keep_connections;
|
||||
|
||||
for (tracker_connections_t::const_iterator i =
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
|
@ -65,7 +67,6 @@ namespace
|
|||
};
|
||||
}
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using boost::bind;
|
||||
using boost::lexical_cast;
|
||||
|
||||
|
|
1038
libtorrent/src/upnp.cpp
Normal file
1038
libtorrent/src/upnp.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
@ -58,6 +60,18 @@ namespace libtorrent { namespace
|
|||
max_peer_entries = 100
|
||||
};
|
||||
|
||||
bool send_peer(peer_connection const& p)
|
||||
{
|
||||
// don't send out peers that we haven't connected to
|
||||
// (that have connected to us)
|
||||
if (!p.is_local()) return false;
|
||||
// don't send out peers that we haven't successfully connected to
|
||||
if (p.is_connecting()) return false;
|
||||
// ut pex does not support IPv6
|
||||
if (!p.remote().address().is_v4()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ut_pex_plugin: torrent_plugin
|
||||
{
|
||||
ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(0) {}
|
||||
|
@ -79,61 +93,56 @@ namespace libtorrent { namespace
|
|||
if (++m_1_minute < 60) return;
|
||||
|
||||
m_1_minute = 0;
|
||||
std::list<tcp::endpoint> cs;
|
||||
for (torrent::peer_iterator i = m_torrent.begin()
|
||||
, end(m_torrent.end()); i != end; ++i)
|
||||
{
|
||||
// don't send out peers that we haven't connected to
|
||||
// (that have connected to us)
|
||||
if (!i->second->is_local()) continue;
|
||||
// don't send out peers that we haven't successfully connected to
|
||||
if (i->second->is_connecting()) continue;
|
||||
cs.push_back(i->first);
|
||||
}
|
||||
std::list<tcp::endpoint> added_peers, dropped_peers;
|
||||
|
||||
std::set_difference(cs.begin(), cs.end(), m_old_peers.begin()
|
||||
, m_old_peers.end(), std::back_inserter(added_peers));
|
||||
std::set_difference(m_old_peers.begin(), m_old_peers.end()
|
||||
, cs.begin(), cs.end(), std::back_inserter(dropped_peers));
|
||||
m_old_peers = cs;
|
||||
|
||||
unsigned int num_peers = max_peer_entries;
|
||||
|
||||
std::string pla, pld, plf;
|
||||
entry pex;
|
||||
std::string& pla = pex["added"].string();
|
||||
std::string& pld = pex["dropped"].string();
|
||||
std::string& plf = pex["added.f"].string();
|
||||
std::back_insert_iterator<std::string> pla_out(pla);
|
||||
std::back_insert_iterator<std::string> pld_out(pld);
|
||||
std::back_insert_iterator<std::string> plf_out(plf);
|
||||
|
||||
// TODO: use random selection in case added_peers.size() > num_peers
|
||||
for (std::list<tcp::endpoint>::const_iterator i = added_peers.begin()
|
||||
, end(added_peers.end());i != end; ++i)
|
||||
{
|
||||
if (!i->address().is_v4()) continue;
|
||||
detail::write_endpoint(*i, pla_out);
|
||||
// no supported flags to set yet
|
||||
// 0x01 - peer supports encryption
|
||||
detail::write_uint8(0, plf_out);
|
||||
std::set<tcp::endpoint> dropped;
|
||||
m_old_peers.swap(dropped);
|
||||
|
||||
if (--num_peers == 0) break;
|
||||
int num_added = 0;
|
||||
for (torrent::peer_iterator i = m_torrent.begin()
|
||||
, end(m_torrent.end()); i != end; ++i)
|
||||
{
|
||||
if (!send_peer(*i->second)) continue;
|
||||
|
||||
m_old_peers.insert(i->first);
|
||||
|
||||
std::set<tcp::endpoint>::iterator di = dropped.find(i->first);
|
||||
if (di == dropped.end())
|
||||
{
|
||||
// don't write too big of a package
|
||||
if (num_added >= max_peer_entries) continue;
|
||||
|
||||
// i->first was added since the last time
|
||||
detail::write_endpoint(i->first, pla_out);
|
||||
// no supported flags to set yet
|
||||
// 0x01 - peer supports encryption
|
||||
// 0x02 - peer is a seed
|
||||
int flags = i->second->is_seed() ? 2 : 0;
|
||||
detail::write_uint8(flags, plf_out);
|
||||
++num_added;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this was in the previous message
|
||||
// so, it wasn't dropped
|
||||
dropped.erase(di);
|
||||
}
|
||||
}
|
||||
|
||||
num_peers = max_peer_entries;
|
||||
// TODO: use random selection in case dropped_peers.size() > num_peers
|
||||
for (std::list<tcp::endpoint>::const_iterator i = dropped_peers.begin()
|
||||
, end(dropped_peers.end());i != end; ++i)
|
||||
for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
|
||||
, end(dropped.end());i != end; ++i)
|
||||
{
|
||||
if (!i->address().is_v4()) continue;
|
||||
detail::write_endpoint(*i, pld_out);
|
||||
|
||||
if (--num_peers == 0) break;
|
||||
}
|
||||
|
||||
entry pex(entry::dictionary_t);
|
||||
pex["added"] = pla;
|
||||
pex["dropped"] = pld;
|
||||
pex["added.f"] = plf;
|
||||
|
||||
m_ut_pex_msg.clear();
|
||||
bencode(std::back_inserter(m_ut_pex_msg), pex);
|
||||
}
|
||||
|
@ -141,7 +150,7 @@ namespace libtorrent { namespace
|
|||
private:
|
||||
torrent& m_torrent;
|
||||
|
||||
std::list<tcp::endpoint> m_old_peers;
|
||||
std::set<tcp::endpoint> m_old_peers;
|
||||
int m_1_minute;
|
||||
std::vector<char> m_ut_pex_msg;
|
||||
};
|
||||
|
@ -155,6 +164,7 @@ namespace libtorrent { namespace
|
|||
, m_tp(tp)
|
||||
, m_1_minute(0)
|
||||
, m_message_index(0)
|
||||
, m_first_time(true)
|
||||
{}
|
||||
|
||||
virtual void add_handshake(entry& h)
|
||||
|
@ -180,6 +190,7 @@ namespace libtorrent { namespace
|
|||
}
|
||||
|
||||
virtual bool on_extended(int length, int msg, buffer::const_interval body)
|
||||
try
|
||||
{
|
||||
if (msg != extension_index) return false;
|
||||
if (m_message_index == 0) return false;
|
||||
|
@ -189,29 +200,31 @@ namespace libtorrent { namespace
|
|||
|
||||
if (body.left() < length) return true;
|
||||
|
||||
// in case we are a seed we do not use the peers
|
||||
// from the pex message to prevent us from
|
||||
// overloading ourself
|
||||
if (m_torrent.is_seed()) return true;
|
||||
|
||||
entry Pex = bdecode(body.begin, body.end);
|
||||
entry* PeerList = Pex.find_key("added");
|
||||
entry pex_msg = bdecode(body.begin, body.end);
|
||||
std::string const& peers = pex_msg["added"].string();
|
||||
std::string const& peer_flags = pex_msg["added.f"].string();
|
||||
|
||||
if (!PeerList) return true;
|
||||
std::string const& peers = PeerList->string();
|
||||
int num_peers = peers.length() / 6;
|
||||
char const* in = peers.c_str();
|
||||
char const* fin = peer_flags.c_str();
|
||||
|
||||
peer_id pid;
|
||||
pid.clear();
|
||||
if (int(peer_flags.size()) != num_peers)
|
||||
return true;
|
||||
|
||||
peer_id pid(0);
|
||||
policy& p = m_torrent.get_policy();
|
||||
for (int i = 0; i < num_peers; ++i)
|
||||
{
|
||||
tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
|
||||
if (!m_torrent.connection_for(adr)) p.peer_from_tracker(adr, pid);
|
||||
char flags = detail::read_uint8(fin);
|
||||
p.peer_from_tracker(adr, pid, peer_info::pex, flags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// the peers second tick
|
||||
// every minute we send a pex message
|
||||
|
@ -220,15 +233,66 @@ namespace libtorrent { namespace
|
|||
if (!m_message_index) return; // no handshake yet
|
||||
if (++m_1_minute <= 60) return;
|
||||
|
||||
send_ut_peer_list();
|
||||
if (m_first_time)
|
||||
{
|
||||
send_ut_peer_list();
|
||||
m_first_time = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_ut_peer_diff();
|
||||
}
|
||||
m_1_minute = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void send_ut_peer_diff()
|
||||
{
|
||||
std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();
|
||||
|
||||
buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
|
||||
|
||||
detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
|
||||
detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
|
||||
detail::write_uint8(m_message_index, i.begin);
|
||||
std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
|
||||
i.begin += pex_msg.size();
|
||||
|
||||
assert(i.begin == i.end);
|
||||
m_pc.setup_send();
|
||||
}
|
||||
|
||||
void send_ut_peer_list()
|
||||
{
|
||||
std::vector<char>& pex_msg = m_tp.get_ut_pex_msg();
|
||||
entry pex;
|
||||
// leave the dropped string empty
|
||||
pex["dropped"].string();
|
||||
std::string& pla = pex["added"].string();
|
||||
std::string& plf = pex["added.f"].string();
|
||||
std::back_insert_iterator<std::string> pla_out(pla);
|
||||
std::back_insert_iterator<std::string> plf_out(plf);
|
||||
|
||||
int num_added = 0;
|
||||
for (torrent::peer_iterator i = m_torrent.begin()
|
||||
, end(m_torrent.end()); i != end; ++i)
|
||||
{
|
||||
if (!send_peer(*i->second)) continue;
|
||||
|
||||
// don't write too big of a package
|
||||
if (num_added >= max_peer_entries) continue;
|
||||
|
||||
// i->first was added since the last time
|
||||
detail::write_endpoint(i->first, pla_out);
|
||||
// no supported flags to set yet
|
||||
// 0x01 - peer supports encryption
|
||||
// 0x02 - peer is a seed
|
||||
int flags = i->second->is_seed() ? 2 : 0;
|
||||
detail::write_uint8(flags, plf_out);
|
||||
++num_added;
|
||||
}
|
||||
std::vector<char> pex_msg;
|
||||
bencode(std::back_inserter(pex_msg), pex);
|
||||
|
||||
buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
|
||||
|
||||
|
@ -247,10 +311,18 @@ namespace libtorrent { namespace
|
|||
ut_pex_plugin& m_tp;
|
||||
int m_1_minute;
|
||||
int m_message_index;
|
||||
|
||||
// this is initialized to true, and set to
|
||||
// false after the first pex message has been sent.
|
||||
// it is used to know if a diff message or a full
|
||||
// message should be sent.
|
||||
bool m_first_time;
|
||||
};
|
||||
|
||||
boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
|
||||
{
|
||||
bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
|
||||
if (!c) return boost::shared_ptr<peer_plugin>();
|
||||
return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
|
||||
, *pc, *this));
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
@ -48,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/version.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using boost::bind;
|
||||
using boost::shared_ptr;
|
||||
using libtorrent::aux::session_impl;
|
||||
|
@ -58,11 +59,11 @@ namespace libtorrent
|
|||
web_peer_connection::web_peer_connection(
|
||||
session_impl& ses
|
||||
, boost::weak_ptr<torrent> t
|
||||
, boost::shared_ptr<stream_socket> s
|
||||
, boost::shared_ptr<socket_type> s
|
||||
, tcp::endpoint const& remote
|
||||
, tcp::endpoint const& proxy
|
||||
, std::string const& url)
|
||||
: peer_connection(ses, t, s, remote, proxy)
|
||||
, std::string const& url
|
||||
, policy::peer* peerinfo)
|
||||
: peer_connection(ses, t, s, remote, peerinfo)
|
||||
, m_url(url)
|
||||
, m_first_request(true)
|
||||
{
|
||||
|
@ -93,9 +94,12 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
std::string protocol;
|
||||
boost::tie(protocol, m_host, m_port, m_path)
|
||||
boost::tie(protocol, m_auth, m_host, m_port, m_path)
|
||||
= parse_url_components(url);
|
||||
|
||||
|
||||
if (!m_auth.empty())
|
||||
m_auth = base64encode(m_auth);
|
||||
|
||||
m_server_string = "URL seed @ ";
|
||||
m_server_string += m_host;
|
||||
}
|
||||
|
@ -106,17 +110,31 @@ namespace libtorrent
|
|||
boost::optional<piece_block_progress>
|
||||
web_peer_connection::downloading_piece_progress() const
|
||||
{
|
||||
if (!m_parser.header_finished() || m_requests.empty())
|
||||
if (m_requests.empty())
|
||||
return boost::optional<piece_block_progress>();
|
||||
|
||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||
assert(t);
|
||||
|
||||
buffer::const_interval http_body = m_parser.get_body();
|
||||
piece_block_progress ret;
|
||||
|
||||
ret.piece_index = m_requests.front().piece;
|
||||
ret.bytes_downloaded = http_body.left() % t->block_size();
|
||||
if (!m_piece.empty())
|
||||
{
|
||||
ret.bytes_downloaded = int(m_piece.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_parser.header_finished())
|
||||
{
|
||||
ret.bytes_downloaded = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int receive_buffer_size = receive_buffer().left() - m_parser.body_start();
|
||||
ret.bytes_downloaded = receive_buffer_size % t->block_size();
|
||||
}
|
||||
}
|
||||
ret.block_index = (m_requests.front().start + ret.bytes_downloaded) / t->block_size();
|
||||
ret.full_block_bytes = t->block_size();
|
||||
const int last_piece = t->torrent_file().num_pieces() - 1;
|
||||
|
@ -136,8 +154,8 @@ namespace libtorrent
|
|||
t->torrent_file().num_pieces(), true));
|
||||
// it is always possible to request pieces
|
||||
incoming_unchoke();
|
||||
|
||||
reset_recv_buffer(t->torrent_file().piece_length() + 1024 * 2);
|
||||
|
||||
reset_recv_buffer(t->block_size() + 1024);
|
||||
}
|
||||
|
||||
void web_peer_connection::write_request(peer_request const& r)
|
||||
|
@ -156,6 +174,7 @@ namespace libtorrent
|
|||
torrent_info const& info = t->torrent_file();
|
||||
|
||||
std::string request;
|
||||
request.reserve(400);
|
||||
|
||||
int size = r.length;
|
||||
const int block_size = t->block_size();
|
||||
|
@ -168,9 +187,9 @@ namespace libtorrent
|
|||
size -= request_size;
|
||||
}
|
||||
|
||||
bool using_proxy = false;
|
||||
if (!m_ses.settings().proxy_ip.empty())
|
||||
using_proxy = true;
|
||||
proxy_settings const& ps = m_ses.web_seed_proxy();
|
||||
bool using_proxy = ps.type == proxy_settings::http
|
||||
|| ps.type == proxy_settings::http_pw;
|
||||
|
||||
if (single_file_request)
|
||||
{
|
||||
|
@ -186,11 +205,15 @@ namespace libtorrent
|
|||
request += "\r\nUser-Agent: ";
|
||||
request += m_ses.settings().user_agent;
|
||||
}
|
||||
if (using_proxy && !m_ses.settings().proxy_login.empty())
|
||||
if (!m_auth.empty())
|
||||
{
|
||||
request += "\r\nAuthorization: Basic ";
|
||||
request += m_auth;
|
||||
}
|
||||
if (ps.type == proxy_settings::http_pw)
|
||||
{
|
||||
request += "\r\nProxy-Authorization: Basic ";
|
||||
request += base64encode(m_ses.settings().proxy_login + ":"
|
||||
+ m_ses.settings().proxy_password);
|
||||
request += base64encode(ps.username + ":" + ps.password);
|
||||
}
|
||||
if (using_proxy)
|
||||
{
|
||||
|
@ -239,11 +262,15 @@ namespace libtorrent
|
|||
request += "\r\nUser-Agent: ";
|
||||
request += m_ses.settings().user_agent;
|
||||
}
|
||||
if (using_proxy && !m_ses.settings().proxy_login.empty())
|
||||
if (!m_auth.empty())
|
||||
{
|
||||
request += "\r\nAuthorization: Basic ";
|
||||
request += m_auth;
|
||||
}
|
||||
if (ps.type == proxy_settings::http_pw)
|
||||
{
|
||||
request += "\r\nProxy-Authorization: Basic ";
|
||||
request += base64encode(m_ses.settings().proxy_login + ":"
|
||||
+ m_ses.settings().proxy_password);
|
||||
request += base64encode(ps.username + ":" + ps.password);
|
||||
}
|
||||
if (using_proxy)
|
||||
{
|
||||
|
@ -257,6 +284,7 @@ namespace libtorrent
|
|||
request += "\r\nConnection: keep-alive";
|
||||
request += "\r\n\r\n";
|
||||
m_first_request = false;
|
||||
assert(f.file_index >= 0);
|
||||
m_file_requests.push_back(f.file_index);
|
||||
}
|
||||
}
|
||||
|
@ -301,36 +329,45 @@ namespace libtorrent
|
|||
int payload;
|
||||
int protocol;
|
||||
bool header_finished = m_parser.header_finished();
|
||||
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
|
||||
m_statistics.received_bytes(payload, protocol);
|
||||
|
||||
assert(recv_buffer.left() <= packet_size());
|
||||
assert (recv_buffer.left() < packet_size()
|
||||
|| m_parser.finished());
|
||||
|
||||
// this means the entire status line hasn't been received yet
|
||||
if (m_parser.status_code() == -1) break;
|
||||
|
||||
// if the status code is not one of the accepted ones, abort
|
||||
if (m_parser.status_code() != 206 // partial content
|
||||
&& m_parser.status_code() != 200 // OK
|
||||
&& !(m_parser.status_code() >= 300 // redirect
|
||||
&& m_parser.status_code() < 400))
|
||||
if (!header_finished)
|
||||
{
|
||||
// we should not try this server again.
|
||||
t->remove_url_seed(m_url);
|
||||
std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
|
||||
+ " " + m_parser.message();
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url()
|
||||
, error_msg));
|
||||
}
|
||||
throw std::runtime_error(error_msg);
|
||||
}
|
||||
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
|
||||
m_statistics.received_bytes(payload, protocol);
|
||||
|
||||
if (!m_parser.header_finished()) break;
|
||||
assert(recv_buffer.left() == 0 || *recv_buffer.begin == 'H');
|
||||
|
||||
assert(recv_buffer.left() <= packet_size());
|
||||
|
||||
// this means the entire status line hasn't been received yet
|
||||
if (m_parser.status_code() == -1) break;
|
||||
|
||||
// if the status code is not one of the accepted ones, abort
|
||||
if (m_parser.status_code() != 206 // partial content
|
||||
&& m_parser.status_code() != 200 // OK
|
||||
&& !(m_parser.status_code() >= 300 // redirect
|
||||
&& m_parser.status_code() < 400))
|
||||
{
|
||||
// we should not try this server again.
|
||||
t->remove_url_seed(m_url);
|
||||
std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
|
||||
+ " " + m_parser.message();
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url()
|
||||
, error_msg));
|
||||
}
|
||||
throw std::runtime_error(error_msg);
|
||||
}
|
||||
if (!m_parser.header_finished()) break;
|
||||
|
||||
m_body_start = m_parser.body_start();
|
||||
m_received_body = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_statistics.received_bytes(bytes_transferred, 0);
|
||||
}
|
||||
|
||||
// we just completed reading the header
|
||||
if (!header_finished)
|
||||
|
@ -385,9 +422,13 @@ namespace libtorrent
|
|||
m_server_string += ")";
|
||||
}
|
||||
|
||||
m_body_start = m_parser.body_start();
|
||||
m_received_body = 0;
|
||||
}
|
||||
|
||||
buffer::const_interval http_body = m_parser.get_body();
|
||||
recv_buffer.begin += m_body_start;
|
||||
// we only received the header, no data
|
||||
if (recv_buffer.left() == 0) break;
|
||||
|
||||
size_type range_start;
|
||||
size_type range_end;
|
||||
|
@ -428,19 +469,17 @@ namespace libtorrent
|
|||
, range_end - range_start);
|
||||
|
||||
peer_request front_request = m_requests.front();
|
||||
|
||||
if (in_range.piece != front_request.piece
|
||||
|| in_range.start > front_request.start + int(m_piece.size()))
|
||||
{
|
||||
throw std::runtime_error("invalid range in HTTP response");
|
||||
}
|
||||
|
||||
front_request = m_requests.front();
|
||||
|
||||
// skip the http header and the blocks we've already read. The
|
||||
// http_body.begin is now in sync with the request at the front
|
||||
// of the request queue
|
||||
assert(in_range.start - int(m_piece.size()) <= front_request.start);
|
||||
http_body.begin += front_request.start - in_range.start + int(m_piece.size());
|
||||
|
||||
// the http response body consists of 3 parts
|
||||
// 1. the middle of a block or the ending of a block
|
||||
|
@ -463,41 +502,54 @@ namespace libtorrent
|
|||
// (if it completed) call incoming_piece() with
|
||||
// m_piece as buffer.
|
||||
|
||||
m_piece.reserve(info.piece_length());
|
||||
int copy_size = std::min(front_request.length - int(m_piece.size())
|
||||
, http_body.left());
|
||||
std::copy(http_body.begin, http_body.begin + copy_size, std::back_inserter(m_piece));
|
||||
assert(int(m_piece.size()) <= front_request.length);
|
||||
http_body.begin += copy_size;
|
||||
int piece_size = int(m_piece.size());
|
||||
if (piece_size < front_request.length)
|
||||
return;
|
||||
int copy_size = std::min(std::min(front_request.length - piece_size
|
||||
, recv_buffer.left()), int(range_end - range_start - m_received_body));
|
||||
m_piece.resize(piece_size + copy_size);
|
||||
assert(copy_size > 0);
|
||||
std::memcpy(&m_piece[0] + piece_size, recv_buffer.begin, copy_size);
|
||||
assert(int(m_piece.size()) <= front_request.length);
|
||||
recv_buffer.begin += copy_size;
|
||||
m_received_body += copy_size;
|
||||
m_body_start += copy_size;
|
||||
assert(m_received_body <= range_end - range_start);
|
||||
assert(int(m_piece.size()) <= front_request.length);
|
||||
if (int(m_piece.size()) == front_request.length)
|
||||
{
|
||||
// each call to incoming_piece() may result in us becoming
|
||||
// a seed. If we become a seed, all seeds we're connected to
|
||||
// will be disconnected, including this web seed. We need to
|
||||
// check for the disconnect condition after the call.
|
||||
|
||||
// each call to incoming_piece() may result in us becoming
|
||||
// a seed. If we become a seed, all seeds we're connected to
|
||||
// will be disconnected, including this web seed. We need to
|
||||
// check for the disconnect condition after the call.
|
||||
|
||||
m_requests.pop_front();
|
||||
incoming_piece(front_request, &m_piece[0]);
|
||||
if (associated_torrent().expired()) return;
|
||||
m_piece.clear();
|
||||
m_requests.pop_front();
|
||||
incoming_piece(front_request, &m_piece[0]);
|
||||
if (associated_torrent().expired()) return;
|
||||
cut_receive_buffer(m_body_start, t->block_size() + 1024);
|
||||
m_body_start = 0;
|
||||
recv_buffer = receive_buffer();
|
||||
assert(m_received_body <= range_end - range_start);
|
||||
m_piece.clear();
|
||||
assert(m_piece.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// report all received blocks to the bittorrent engine
|
||||
while (!m_requests.empty()
|
||||
&& range_contains(in_range, m_requests.front())
|
||||
&& http_body.left() >= m_requests.front().length)
|
||||
&& recv_buffer.left() >= m_requests.front().length)
|
||||
{
|
||||
peer_request r = m_requests.front();
|
||||
m_requests.pop_front();
|
||||
assert(http_body.begin == recv_buffer.begin + m_parser.body_start()
|
||||
+ r.start - in_range.start);
|
||||
assert(http_body.left() >= r.length);
|
||||
assert(recv_buffer.left() >= r.length);
|
||||
|
||||
incoming_piece(r, http_body.begin);
|
||||
incoming_piece(r, recv_buffer.begin);
|
||||
if (associated_torrent().expired()) return;
|
||||
http_body.begin += r.length;
|
||||
m_received_body += r.length;
|
||||
assert(receive_buffer().begin + m_body_start == recv_buffer.begin);
|
||||
assert(m_received_body <= range_end - range_start);
|
||||
cut_receive_buffer(r.length + m_body_start, t->block_size() + 1024);
|
||||
m_body_start = 0;
|
||||
recv_buffer = receive_buffer();
|
||||
}
|
||||
|
||||
if (!m_requests.empty())
|
||||
|
@ -506,24 +558,34 @@ namespace libtorrent
|
|||
> m_requests.front().start + int(m_piece.size());
|
||||
|
||||
if (in_range.start + in_range.length < m_requests.front().start + m_requests.front().length
|
||||
&& m_parser.finished())
|
||||
&& (m_received_body + recv_buffer.left() >= range_end - range_start))
|
||||
{
|
||||
m_piece.reserve(info.piece_length());
|
||||
int copy_size = std::min(m_requests.front().length - int(m_piece.size())
|
||||
, http_body.left());
|
||||
std::copy(http_body.begin, http_body.begin + copy_size, std::back_inserter(m_piece));
|
||||
http_body.begin += copy_size;
|
||||
int piece_size = int(m_piece.size());
|
||||
int copy_size = std::min(std::min(m_requests.front().length - piece_size
|
||||
, recv_buffer.left()), int(range_end - range_start - m_received_body));
|
||||
assert(copy_size >= 0);
|
||||
if (copy_size > 0)
|
||||
{
|
||||
m_piece.resize(piece_size + copy_size);
|
||||
std::memcpy(&m_piece[0] + piece_size, recv_buffer.begin, copy_size);
|
||||
recv_buffer.begin += copy_size;
|
||||
m_received_body += copy_size;
|
||||
m_body_start += copy_size;
|
||||
}
|
||||
assert(m_received_body == range_end - range_start);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_parser.finished())
|
||||
assert(m_received_body <= range_end - range_start);
|
||||
if (m_received_body == range_end - range_start)
|
||||
{
|
||||
cut_receive_buffer(recv_buffer.begin - receive_buffer().begin
|
||||
, t->block_size() + 1024);
|
||||
recv_buffer = receive_buffer();
|
||||
m_file_requests.pop_front();
|
||||
assert(http_body.left() == 0);
|
||||
m_parser.reset();
|
||||
assert(recv_buffer.end == http_body.end || *http_body.end == 'H');
|
||||
cut_receive_buffer(http_body.end - recv_buffer.begin
|
||||
, t->torrent_file().piece_length() + 1024 * 2);
|
||||
m_body_start = 0;
|
||||
m_received_body = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -540,9 +602,11 @@ namespace libtorrent
|
|||
p.payload_up_speed = statistics().upload_payload_rate();
|
||||
p.pid = pid();
|
||||
p.ip = remote();
|
||||
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
p.country[0] = m_country[0];
|
||||
p.country[1] = m_country[1];
|
||||
#endif
|
||||
|
||||
p.total_download = statistics().total_payload_download();
|
||||
p.total_upload = statistics().total_payload_upload();
|
||||
|
@ -593,6 +657,8 @@ namespace libtorrent
|
|||
|
||||
p.client = m_server_string;
|
||||
p.connection_type = peer_info::web_seed;
|
||||
p.source = 0;
|
||||
p.failcount = 0;
|
||||
}
|
||||
|
||||
bool web_peer_connection::in_handshake() const
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
$Id: Changelog.txt,v 1.27 2007/03/01 22:29:48 nanard Exp $
|
||||
miniUPnP client Changelog.
|
||||
|
||||
2007/03/01:
|
||||
Small typo fix...
|
||||
|
||||
2007/01/30:
|
||||
Now parsing the HTTP header from SOAP responses in order to
|
||||
get content-length value.
|
||||
|
||||
2007/01/29:
|
||||
Fixed the Soap Query to speedup the HTTP request.
|
||||
added some Win32 DLL stuff...
|
||||
|
||||
2007/01/27:
|
||||
Fixed some WIN32 compatibility issues
|
||||
|
||||
2006/12/14:
|
||||
Added UPNPIGD_IsConnected() function in miniupnp.c/.h
|
||||
Added UPNP_GetValidIGD() in miniupnp.c/.h
|
||||
cleaned upnpc.c main(). now using UPNP_GetValidIGD()
|
||||
|
||||
2006/12/07:
|
||||
Version 1.0-RC1 released
|
||||
|
||||
2006/12/03:
|
||||
Minor changes to compile under SunOS/Solaris
|
||||
|
||||
2006/11/30:
|
||||
made a minixml parser validator program
|
||||
updated minixml to handle attributes correctly
|
||||
|
||||
2006/11/22:
|
||||
Added a -r option to the upnpc sample thanks to Alexander Hubmann.
|
||||
|
||||
2006/11/19:
|
||||
Cleanup code to make it more ANSI C compliant
|
||||
|
||||
2006/11/10:
|
||||
detect and display local lan address.
|
||||
|
||||
2006/11/04:
|
||||
Packets and Bytes Sent/Received are now unsigned int.
|
||||
|
||||
2006/11/01:
|
||||
Bug fix thanks to Giuseppe D'Angelo
|
||||
|
||||
2006/10/31:
|
||||
C++ compatibility for .h files.
|
||||
Added a way to get ip Address on the LAN used to reach the IGD.
|
||||
|
||||
2006/10/25:
|
||||
Added M-SEARCH to the services in the discovery process.
|
||||
|
||||
2006/10/22:
|
||||
updated the Makefile to use makedepend, added a "make install"
|
||||
update Makefile
|
||||
|
||||
2006/10/20:
|
||||
fixing the description url parsing thanks to patch sent by
|
||||
Wayne Dawe.
|
||||
Fixed/translated some comments.
|
||||
Implemented a better discover process, first looking
|
||||
for IGD then for root devices (as some devices only reply to
|
||||
M-SEARCH for root devices).
|
||||
|
||||
2006/09/02:
|
||||
added freeUPNPDevlist() function.
|
||||
|
||||
2006/08/04:
|
||||
More command line arguments checking
|
||||
|
||||
2006/08/01:
|
||||
Added the .bat file to compile under Win32 with minGW32
|
||||
|
||||
2006/07/31:
|
||||
Fixed the rootdesc parser (igd_desc_parse.c)
|
||||
|
||||
2006/07/20:
|
||||
parseMSEARCHReply() is now returning the ST: line as well
|
||||
starting changes to detect several UPnP devices on the network
|
||||
|
||||
2006/07/19:
|
||||
using GetCommonLinkProperties to get down/upload bitrate
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
# $Id: Makefile,v 1.21 2007/03/02 10:45:52 nanard Exp $
|
||||
# MiniUPnP Project
|
||||
# http://miniupnp.free.fr/
|
||||
# (c) 2005-2006 Thomas Bernard
|
||||
CC = gcc
|
||||
#AR = gar
|
||||
CFLAGS = -O -Wall -g -DDEBUG
|
||||
#CFLAGS = -O -Wall -DNDEBUG
|
||||
INSTALL = install
|
||||
#following libs are needed on Solaris
|
||||
#LDLIBS=-lsocket -lnsl -lresolv
|
||||
|
||||
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
|
||||
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
|
||||
minixmlvalid.c
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
# HEADERS to install
|
||||
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
|
||||
upnpreplyparse.h
|
||||
LIBRARY = libminiupnpc.a
|
||||
EXECUTABLES = upnpc testminixml minixmlvalid
|
||||
|
||||
INSTALLPREFIX = /usr
|
||||
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
|
||||
INSTALLDIRLIB = $(INSTALLPREFIX)/lib
|
||||
|
||||
.PHONY: install clean depend all
|
||||
|
||||
all: validateminixml $(LIBRARY) $(EXECUTABLES)
|
||||
|
||||
validateminixml: minixmlvalid
|
||||
@echo "minixml validation test"
|
||||
./minixmlvalid
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
$(RM) $(LIBRARY) $(EXECUTABLES) $(OBJS)
|
||||
|
||||
install: $(LIBRARY)
|
||||
$(INSTALL) -d $(INSTALLDIRINC)
|
||||
$(INSTALL) --mode=644 $(HEADERS) $(INSTALLDIRINC)
|
||||
$(INSTALL) --mode=644 $(LIBRARY) $(INSTALLDIRLIB)
|
||||
|
||||
cleaninstall:
|
||||
$(RM) -r $(INSTALLDIRINC)
|
||||
$(RM) $(INSTALLDIRLIB)/$(LIBRARY)
|
||||
|
||||
depend:
|
||||
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||
|
||||
libminiupnpc.a: miniwget.o minixml.o igd_desc_parse.o minisoap.o miniupnpc.o upnpreplyparse.o upnpcommands.o
|
||||
$(AR) crs $@ $?
|
||||
|
||||
upnpc: upnpc.o libminiupnpc.a
|
||||
|
||||
testminixml: minixml.o igd_desc_parse.o testminixml.o
|
||||
|
||||
minixmlvalid: minixml.o minixmlvalid.o
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
igd_desc_parse.o: igd_desc_parse.h
|
||||
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h miniwget.h minisoap.h
|
||||
miniupnpc.o: minixml.h upnpcommands.h upnpreplyparse.h
|
||||
minixml.o: minixml.h
|
||||
minisoap.o: minisoap.h
|
||||
miniwget.o: miniupnpc.h declspec.h igd_desc_parse.h
|
||||
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h
|
||||
upnpc.o: upnpreplyparse.h
|
||||
upnpcommands.o: upnpcommands.h upnpreplyparse.h miniupnpc.h declspec.h
|
||||
upnpcommands.o: igd_desc_parse.h
|
||||
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||
testminixml.o: minixml.h igd_desc_parse.h
|
||||
minixmlvalid.o: minixml.h
|
|
@ -1,35 +0,0 @@
|
|||
# $Id: Makefile.mingw,v 1.4 2006/11/08 22:07:47 nanard Exp $
|
||||
CC = gcc
|
||||
#CFLAGS = -Wall -g -DDEBUG
|
||||
CFLAGS = -Wall -Os -DNDEBUG
|
||||
LDLIBS = -lws2_32
|
||||
# -lwsock32
|
||||
|
||||
all: upnpc testminixml libminiupnpc.a
|
||||
|
||||
clean:
|
||||
del upnpc testminixml *.o
|
||||
|
||||
libminiupnpc.a: miniwget.o minixml.o igd_desc_parse.o minisoap.o miniupnpc.o upnpreplyparse.o upnpcommands.o
|
||||
$(AR) cr $@ $?
|
||||
|
||||
upnpc: upnpc.o libminiupnpc.a
|
||||
|
||||
minixml.o: minixml.c minixml.h
|
||||
|
||||
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h
|
||||
|
||||
miniwget.o: miniwget.c miniwget.h
|
||||
|
||||
minisoap.o: minisoap.c minisoap.h
|
||||
|
||||
miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h
|
||||
|
||||
igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h
|
||||
|
||||
testminixml: minixml.o igd_desc_parse.o testminixml.c
|
||||
|
||||
upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
|
||||
|
||||
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
Project: miniupnp
|
||||
Project web page: http://miniupnp.free.fr/
|
||||
Author: Thomas Bernard
|
||||
Copyright (c) 2005 Thomas Bernard
|
||||
This software is subject to the conditions detailed in the
|
||||
LICENCE file provided within this distribution.
|
||||
|
||||
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
|
||||
Its licence is included in the header of the file.
|
||||
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
|
||||
|
||||
* miniupnp Client *
|
||||
|
||||
To compile, simply run 'gmake' (could be 'make').
|
||||
Under win32, to compile with MinGW, type "mingw32make.bat".
|
||||
The compilation is known to work under linux, FreeBSD,
|
||||
OpenBSD, MacOS X and cygwin.
|
||||
To install the library and headers on the system use :
|
||||
> su
|
||||
> make install
|
||||
> exit
|
||||
|
||||
upnpc.c is a sample client using the libminiupnpc.
|
||||
To use the libminiupnpc in your application, link it with
|
||||
libminiupnpc.a and use the following functions found in miniupnpc.h,
|
||||
upnpcommands.h and miniwget.h :
|
||||
- upnpDiscover()
|
||||
- miniwget()
|
||||
- parserootdesc()
|
||||
- GetUPNPUrls()
|
||||
- UPNP_* (calling UPNP methods)
|
||||
|
||||
Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
|
||||
and -lminiupnpc for the link
|
||||
|
||||
Feel free to contact me if you have any problem :
|
||||
e-mail : miniupnp@free.fr
|
||||
|
||||
If you are using libminiupnpc in your application, please
|
||||
send me an email !
|
||||
|
||||
|
|
@ -1,531 +0,0 @@
|
|||
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
||||
#else
|
||||
#define _Q_INVALIDATE(a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#ifdef SLIST_ENTRY
|
||||
#undef SLIST_ENTRY
|
||||
#endif
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_END(head) NULL
|
||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != SLIST_END(head); \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
\
|
||||
while (curelm->field.sle_next != (elm)) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
_Q_INVALIDATE((elm)->field.sle_next); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List access methods
|
||||
*/
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_END(head) NULL
|
||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for((var) = LIST_FIRST(head); \
|
||||
(var)!= LIST_END(head); \
|
||||
(var) = LIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST(head) = LIST_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = \
|
||||
&(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_END(head) NULL
|
||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define TAILQ_EMPTY(head) \
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef __DECLSPEC_H__
|
||||
#define __DECLSPEC_H__
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LIBSPEC
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
/* $Id: igd_desc_parse.c,v 1.7 2006/11/19 22:32:33 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */
|
||||
void IGDstartelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
memcpy( datas->cureltname, name, l);
|
||||
datas->cureltname[l] = '\0';
|
||||
datas->level++;
|
||||
}
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
void IGDendelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
datas->level--;
|
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
/*datas->state++; */
|
||||
/*
|
||||
if( datas->state < 1
|
||||
&& !strcmp(datas->servicetype,
|
||||
// "urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||
datas->state ++;
|
||||
*/
|
||||
if(0==strcmp(datas->servicetype_CIF,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||
datas->state = 2;
|
||||
if(0==strcmp(datas->servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||
datas->state = 3;
|
||||
/* if(0==strcmp(datas->servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1") )
|
||||
datas->state = 4; */
|
||||
}
|
||||
}
|
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */
|
||||
void IGDdata(void * d, const char * data, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
char * dstmember = 0;
|
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */
|
||||
if( !strcmp(datas->cureltname, "URLBase") )
|
||||
dstmember = datas->urlbase;
|
||||
else if(datas->state<=1)
|
||||
{
|
||||
if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->servicetype_CIF;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->controlurl_CIF;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->eventsuburl_CIF;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->scpdurl_CIF;
|
||||
else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_CIF;
|
||||
}
|
||||
else if(datas->state==2)
|
||||
{
|
||||
if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->servicetype;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->controlurl;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->eventsuburl;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->scpdurl;
|
||||
else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype;
|
||||
}
|
||||
if(dstmember)
|
||||
{
|
||||
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(dstmember, data, l);
|
||||
dstmember[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void printIGD(struct IGDdatas * d)
|
||||
{
|
||||
printf("urlbase = %s\n", d->urlbase);
|
||||
printf("WAN Device (Common interface config) :\n");
|
||||
printf(" deviceType = %s\n", d->devicetype_CIF);
|
||||
printf(" serviceType = %s\n", d->servicetype_CIF);
|
||||
printf(" controlURL = %s\n", d->controlurl_CIF);
|
||||
printf(" eventSubURL = %s\n", d->eventsuburl_CIF);
|
||||
printf(" SCPDURL = %s\n", d->scpdurl_CIF);
|
||||
printf("WAN Connection Device :\n");
|
||||
printf(" deviceType = %s\n", d->devicetype);
|
||||
printf(" servicetype = %s\n", d->servicetype);
|
||||
printf(" controlURL = %s\n", d->controlurl);
|
||||
printf(" eventSubURL = %s\n", d->eventsuburl);
|
||||
printf(" SCPDURL = %s\n", d->scpdurl);
|
||||
}
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/* $Id: igd_desc_parse.h,v 1.4 2006/07/06 00:05:11 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef __IGD_DESC_PARSE_H__
|
||||
#define __IGD_DESC_PARSE_H__
|
||||
|
||||
/* Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices */
|
||||
#define MINIUPNPC_URL_MAXSIZE (64)
|
||||
struct IGDdatas {
|
||||
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||
int level;
|
||||
int state;
|
||||
char controlurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||
char eventsuburl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||
char scpdurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||
char servicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||
char devicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||
char devicetype[MINIUPNPC_URL_MAXSIZE];
|
||||
};
|
||||
|
||||
void IGDstartelt(void *, const char *, int);
|
||||
void IGDendelt(void *, const char *, int);
|
||||
void IGDdata(void *, const char *, int);
|
||||
void printIGD(struct IGDdatas *);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
mingw32-make -f Makefile.mingw
|
||||
if errorlevel 1 goto end
|
||||
strip upnpc.exe
|
||||
upx --best upnpc.exe
|
||||
:end
|
|
@ -1,73 +0,0 @@
|
|||
/* $Id: minisoap.c,v 1.10 2007/01/29 20:05:07 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
*
|
||||
* Minimal SOAP implementation for UPnP protocol.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include "minisoap.h"
|
||||
|
||||
/* only for malloc */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* httpWrite sends the headers and the body to the socket
|
||||
* and returns the number of bytes sent */
|
||||
static int
|
||||
httpWrite(int fd, const char * body, int bodysize,
|
||||
const char * headers, int headerssize)
|
||||
{
|
||||
int n = 0;
|
||||
/*n = write(fd, headers, headerssize);*/
|
||||
/*if(bodysize>0)
|
||||
n += write(fd, body, bodysize);*/
|
||||
/* Note : my old linksys router only took into account
|
||||
* soap request that are sent into only one packet */
|
||||
char * p;
|
||||
p = malloc(headerssize+bodysize);
|
||||
memcpy(p, headers, headerssize);
|
||||
memcpy(p+headerssize, body, bodysize);
|
||||
/*n = write(fd, p, headerssize+bodysize);*/
|
||||
n = send(fd, p, headerssize+bodysize, 0);
|
||||
shutdown(fd, SHUT_WR); /*SD_SEND*/
|
||||
free(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* self explanatory */
|
||||
int soapPostSubmit(int fd,
|
||||
const char * url,
|
||||
const char * host,
|
||||
unsigned short port,
|
||||
const char * action,
|
||||
const char * body)
|
||||
{
|
||||
int bodysize;
|
||||
char headerbuf[1024];
|
||||
int headerssize;
|
||||
bodysize = (int)strlen(body);
|
||||
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
"HOST: %s:%d\r\n"
|
||||
"Content-length: %d\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"SOAPAction: \"%s\"\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"\r\n",
|
||||
url, host, port, bodysize, action);
|
||||
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/* $Id: minisoap.h,v 1.3 2006/11/19 22:32:34 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
#ifndef __MINISOAP_H__
|
||||
#define __MINISOAP_H__
|
||||
|
||||
/*int httpWrite(int, const char *, int, const char *);*/
|
||||
int soapPostSubmit(int, const char *, const char *, unsigned short,
|
||||
const char *, const char *);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,659 +0,0 @@
|
|||
/* $Id: miniupnpc.c,v 1.38 2007/03/01 22:29:49 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp memicmp
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <netdb.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
#include "miniupnpc.h"
|
||||
#include "miniwget.h"
|
||||
#include "minisoap.h"
|
||||
#include "minixml.h"
|
||||
#include "upnpcommands.h"
|
||||
|
||||
/* Uncomment the following to transmit the msearch from the same port
|
||||
* as the UPnP multicast port. With WinXP this seems to result in the
|
||||
* responses to the msearch being lost, thus if things dont work then
|
||||
* comment this out. */
|
||||
/* #define TX_FROM_UPNP_PORT */
|
||||
|
||||
#ifdef WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
/* root description parsing */
|
||||
void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
/* xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
#ifndef NDEBUG
|
||||
printIGD(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Content-length: nnn */
|
||||
static int getcontentlenfromline(const char * p, int n)
|
||||
{
|
||||
static const char contlenstr[] = "content-length";
|
||||
const char * p2 = contlenstr;
|
||||
int a = 0;
|
||||
while(*p2)
|
||||
{
|
||||
if(n==0)
|
||||
return -1;
|
||||
if(*p2 != *p && *p2 != (*p + 32))
|
||||
return -1;
|
||||
p++; p2++; n--;
|
||||
}
|
||||
if(n==0)
|
||||
return -1;
|
||||
if(*p != ':')
|
||||
return -1;
|
||||
p++; n--;
|
||||
while(*p == ' ')
|
||||
{
|
||||
if(n==0)
|
||||
return -1;
|
||||
p++; n--;
|
||||
}
|
||||
while(*p >= '0' && *p <= '9')
|
||||
{
|
||||
if(n==0)
|
||||
return -1;
|
||||
a = (a * 10) + (*p - '0');
|
||||
p++; n--;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static void
|
||||
getContentLengthAndHeaderLength(char * p, int n,
|
||||
int * contentlen, int * headerlen)
|
||||
{
|
||||
char * line;
|
||||
int linelen;
|
||||
int r;
|
||||
line = p;
|
||||
while(line < p + n)
|
||||
{
|
||||
linelen = 0;
|
||||
while(line[linelen] != '\r' && line[linelen] != '\r')
|
||||
{
|
||||
if(line+linelen >= p+n)
|
||||
return;
|
||||
linelen++;
|
||||
}
|
||||
r = getcontentlenfromline(line, linelen);
|
||||
if(r>0)
|
||||
*contentlen = r;
|
||||
line = line + linelen + 2;
|
||||
if(line[0] == '\r' && line[1] == '\n')
|
||||
{
|
||||
*headerlen = (line - p) + 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* simpleUPnPcommand :
|
||||
* not so simple !
|
||||
* */
|
||||
int simpleUPnPcommand(int s, const char * url, const char * service,
|
||||
const char * action, struct UPNParg * args,
|
||||
char * buffer, int * bufsize)
|
||||
{
|
||||
struct sockaddr_in dest;
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port = 0;
|
||||
char * path;
|
||||
char soapact[128];
|
||||
char soapbody[2048];
|
||||
int soapbodylen;
|
||||
char * buf;
|
||||
int buffree;
|
||||
int n;
|
||||
int contentlen, headerlen; /* for the response */
|
||||
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
||||
if(args==NULL)
|
||||
{
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<SOAP-ENV:Envelope "
|
||||
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<SOAP-ENV:Body>"
|
||||
"<m:%s xmlns:m=\"%s\"/>"
|
||||
"</SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
||||
"\r\n", action, service);
|
||||
}
|
||||
else
|
||||
{
|
||||
char * p;
|
||||
const char * pe, * pv;
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<SOAP-ENV:Envelope "
|
||||
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<SOAP-ENV:Body>"
|
||||
"<m:%s xmlns:m=\"%s\">",
|
||||
action, service);
|
||||
p = soapbody + soapbodylen;
|
||||
while(args->elt)
|
||||
{
|
||||
/* check that we are never overflowing the string... */
|
||||
if(soapbody + sizeof(soapbody) <= p + 100)
|
||||
{
|
||||
/* we keep a margin of at least 100 bytes */
|
||||
*bufsize = 0;
|
||||
return -1;
|
||||
}
|
||||
*(p++) = '<';
|
||||
pe = args->elt;
|
||||
while(*pe)
|
||||
*(p++) = *(pe++);
|
||||
*(p++) = '>';
|
||||
if((pv = args->val))
|
||||
{
|
||||
while(*pv)
|
||||
*(p++) = *(pv++);
|
||||
}
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
pe = args->elt;
|
||||
while(*pe)
|
||||
*(p++) = *(pe++);
|
||||
*(p++) = '>';
|
||||
args++;
|
||||
}
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
*(p++) = 'm';
|
||||
*(p++) = ':';
|
||||
pe = action;
|
||||
while(*pe)
|
||||
*(p++) = *(pe++);
|
||||
strncpy(p, "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n",
|
||||
soapbody + sizeof(soapbody) - p);
|
||||
}
|
||||
if(!parseURL(url, hostname, &port, &path)) return -1;
|
||||
if(s<0)
|
||||
{
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(port);
|
||||
dest.sin_addr.s_addr = inet_addr(hostname);
|
||||
if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
*bufsize = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);
|
||||
|
||||
contentlen = -1;
|
||||
headerlen = -1;
|
||||
buf = buffer;
|
||||
buffree = *bufsize;
|
||||
*bufsize = 0;
|
||||
while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {
|
||||
buffree -= n;
|
||||
buf += n;
|
||||
*bufsize += n;
|
||||
getContentLengthAndHeaderLength(buffer, *bufsize,
|
||||
&contentlen, &headerlen);
|
||||
#ifdef DEBUG
|
||||
printf("n=%d bufsize=%d ContLen=%d HeadLen=%d\n",
|
||||
n, *bufsize, contentlen, headerlen);
|
||||
#endif
|
||||
if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)
|
||||
break;
|
||||
}
|
||||
|
||||
closesocket(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
static void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0;
|
||||
a = i; /* start of the line */
|
||||
b = 0;
|
||||
while(i<size)
|
||||
{
|
||||
switch(reply[i])
|
||||
{
|
||||
case ':':
|
||||
if(b==0)
|
||||
{
|
||||
b = i; /* end of the "header" */
|
||||
/*for(j=a; j<b; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0)
|
||||
{
|
||||
/*for(j=b+1; j<i; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
do { b++; } while(reply[b]==' ');
|
||||
if(0==strncasecmp(reply+a, "location", 8))
|
||||
{
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "st", 2))
|
||||
{
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* port upnp discover : SSDP protocol */
|
||||
#define PORT (1900)
|
||||
#define UPNP_MCAST_ADDR "239.255.255.250"
|
||||
|
||||
/* upnpDiscover() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll) */
|
||||
struct UPNPDev * upnpDiscover(int delay)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
int opt = 1;
|
||||
static const char MSearchMsgFmt[] =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: " UPNP_MCAST_ADDR ":" "1900" "\r\n"
|
||||
"ST: %s\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: 3\r\n"
|
||||
"\r\n";
|
||||
static const char * const deviceList[] = {
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
0
|
||||
};
|
||||
int deviceIndex = 0;
|
||||
char bufr[1536]; /* reception and emission buffer */
|
||||
int sudp;
|
||||
int n;
|
||||
struct sockaddr_in sockudp_r, sockudp_w;
|
||||
|
||||
#ifdef WIN32
|
||||
sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#else
|
||||
sudp = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
/* reception */
|
||||
memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
|
||||
sockudp_r.sin_family = AF_INET;
|
||||
#ifdef TX_FROM_UPNP_PORT
|
||||
sockudp_r.sin_port = htons(PORT);
|
||||
#endif
|
||||
sockudp_r.sin_addr.s_addr = INADDR_ANY;
|
||||
/* emission */
|
||||
memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
|
||||
sockudp_w.sin_family = AF_INET;
|
||||
sockudp_w.sin_port = htons(PORT);
|
||||
sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
|
||||
|
||||
#ifdef WIN32
|
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
|
||||
#else
|
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
|
||||
#endif
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
|
||||
if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("bind");
|
||||
closesocket(sudp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* receiving SSDP response packet */
|
||||
for(n = 0;;)
|
||||
{
|
||||
if(n == 0)
|
||||
{
|
||||
/* sending the SSDP M-SEARCH packet */
|
||||
n = snprintf(bufr, sizeof(bufr),
|
||||
MSearchMsgFmt, deviceList[deviceIndex++]);
|
||||
/*printf("Sending %s", bufr);*/
|
||||
n = sendto(sudp, bufr, n, 0,
|
||||
(struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
|
||||
if (n < 0) {
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
closesocket(sudp);
|
||||
return devlist;
|
||||
}
|
||||
}
|
||||
/* Waiting for SSDP REPLY packet to M-SEARCH */
|
||||
n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
|
||||
if (n < 0) {
|
||||
/* error */
|
||||
closesocket(sudp);
|
||||
return devlist;
|
||||
} else if (n == 0) {
|
||||
/* no data or Time Out */
|
||||
if (devlist || (deviceList[deviceIndex] == 0)) {
|
||||
/* no more device type to look for... */
|
||||
closesocket(sudp);
|
||||
return devlist;
|
||||
}
|
||||
} else {
|
||||
const char * descURL=NULL;
|
||||
int urlsize=0;
|
||||
const char * st=NULL;
|
||||
int stsize=0;
|
||||
/*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
|
||||
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
|
||||
if(st&&descURL)
|
||||
{
|
||||
/*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
|
||||
stsize, st, urlsize, descURL); */
|
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
|
||||
tmp->pNext = devlist;
|
||||
tmp->descURL = tmp->buffer;
|
||||
tmp->st = tmp->buffer + 1 + urlsize;
|
||||
memcpy(tmp->buffer, descURL, urlsize);
|
||||
tmp->buffer[urlsize] = '\0';
|
||||
memcpy(tmp->buffer + urlsize + 1, st, stsize);
|
||||
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||
devlist = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */
|
||||
void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
{
|
||||
struct UPNPDev * next;
|
||||
while(devlist)
|
||||
{
|
||||
next = devlist->pNext;
|
||||
free(devlist);
|
||||
devlist = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
url_cpy_or_cat(char * dst, const char * src, int n)
|
||||
{
|
||||
if( (src[0] == 'h')
|
||||
&&(src[1] == 't')
|
||||
&&(src[2] == 't')
|
||||
&&(src[3] == 'p')
|
||||
&&(src[4] == ':')
|
||||
&&(src[5] == '/')
|
||||
&&(src[6] == '/'))
|
||||
{
|
||||
strncpy(dst, src, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(src[0] != '/')
|
||||
strncat(dst, "/", n-1);
|
||||
strncat(dst, src, n-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL)
|
||||
{
|
||||
char * p;
|
||||
int n1, n2, n3;
|
||||
n1 = strlen(data->urlbase);
|
||||
if(n1==0)
|
||||
n1 = strlen(descURL);
|
||||
n1++;
|
||||
n2 = n1; n3 = n1;
|
||||
n1 += strlen(data->scpdurl);
|
||||
n2 += strlen(data->controlurl);
|
||||
n3 += strlen(data->controlurl_CIF);
|
||||
|
||||
urls->ipcondescURL = (char *)malloc(n1);
|
||||
urls->controlURL = (char *)malloc(n2);
|
||||
urls->controlURL_CIF = (char *)malloc(n3);
|
||||
/* maintenant on chope la desc du WANIPConnection */
|
||||
if(data->urlbase[0] != '\0')
|
||||
strncpy(urls->ipcondescURL, data->urlbase, n1);
|
||||
else
|
||||
strncpy(urls->ipcondescURL, descURL, n1);
|
||||
p = strchr(urls->ipcondescURL+7, '/');
|
||||
if(p) p[0] = '\0';
|
||||
strncpy(urls->controlURL, urls->ipcondescURL, n2);
|
||||
strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
|
||||
|
||||
url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
|
||||
|
||||
url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
|
||||
|
||||
url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
|
||||
strlen(urls->ipcondescURL), n1);
|
||||
printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
|
||||
strlen(urls->controlURL), n2);
|
||||
printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
|
||||
strlen(urls->controlURL_CIF), n3);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
FreeUPNPUrls(struct UPNPUrls * urls)
|
||||
{
|
||||
if(!urls)
|
||||
return;
|
||||
free(urls->controlURL);
|
||||
urls->controlURL = 0;
|
||||
free(urls->ipcondescURL);
|
||||
urls->ipcondescURL = 0;
|
||||
free(urls->controlURL_CIF);
|
||||
urls->controlURL_CIF = 0;
|
||||
}
|
||||
|
||||
|
||||
int ReceiveData(int socket, char * data, int length, int timeout)
|
||||
{
|
||||
int n;
|
||||
#ifndef WIN32
|
||||
struct pollfd fds[1]; /* for the poll */
|
||||
fds[0].fd = socket;
|
||||
fds[0].events = POLLIN;
|
||||
n = poll(fds, 1, timeout);
|
||||
if(n < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("poll");
|
||||
return -1;
|
||||
}
|
||||
else if(n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
fd_set socketSet;
|
||||
TIMEVAL timeval;
|
||||
FD_ZERO(&socketSet);
|
||||
FD_SET(socket, &socketSet);
|
||||
timeval.tv_sec = timeout / 1000;
|
||||
timeval.tv_usec = (timeout % 1000) * 1000;
|
||||
n = select(0, &socketSet, NULL, NULL, &timeval);
|
||||
if(n < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("poll");
|
||||
return -1;
|
||||
}
|
||||
else if(n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
n = recv(socket, data, length, 0);
|
||||
if(n<0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("recv");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||
{
|
||||
char status[64];
|
||||
unsigned int uptime;
|
||||
status[0] = '\0';
|
||||
UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime);
|
||||
if(0 == strcmp("Connected", status))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values :
|
||||
* 0 = NO IGD found
|
||||
* 1 = A valid connected IGD has been found
|
||||
* 2 = A valid IGD has been found but it reported as
|
||||
* not connected
|
||||
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||
*
|
||||
* In any non zero return case, the urls and data structures
|
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen)
|
||||
{
|
||||
char * descXML;
|
||||
int descXMLsize = 0;
|
||||
struct UPNPDev * dev;
|
||||
int ndev = 0;
|
||||
int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
|
||||
if(!devlist)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Empty devlist\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
for(state = 1; state <= 3; state++)
|
||||
{
|
||||
for(dev = devlist; dev; dev = dev->pNext)
|
||||
{
|
||||
/* we should choose an internet gateway device.
|
||||
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
|
||||
if((state >= 3) || strstr(dev->st, "InternetGatewayDevice"))
|
||||
{
|
||||
descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
|
||||
lanaddr, lanaddrlen);
|
||||
if(descXML)
|
||||
{
|
||||
ndev++;
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(descXML, descXMLsize, data);
|
||||
free(descXML);
|
||||
descXML = NULL;
|
||||
GetUPNPUrls(urls, data, dev->descURL);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL,
|
||||
UPNPIGD_IsConnected(urls, data));
|
||||
#endif
|
||||
if((state >= 2) || UPNPIGD_IsConnected(urls, data))
|
||||
return state;
|
||||
FreeUPNPUrls(urls);
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
{
|
||||
printf("error getting XML description %s\n", dev->descURL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/* $Id: miniupnpc.h,v 1.13 2007/01/29 20:27:23 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2006 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef __MINIUPNPC_H__
|
||||
#define __MINIUPNPC_H__
|
||||
|
||||
#include "declspec.h"
|
||||
#include "igd_desc_parse.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct UPNParg { const char * elt; const char * val; };
|
||||
|
||||
int simpleUPnPcommand(int, const char *, const char *,
|
||||
const char *, struct UPNParg *,
|
||||
char *, int *);
|
||||
|
||||
struct UPNPDev {
|
||||
struct UPNPDev * pNext;
|
||||
char * descURL;
|
||||
char * st;
|
||||
char buffer[2];
|
||||
};
|
||||
|
||||
/* discover UPnP devices on the network */
|
||||
LIBSPEC struct UPNPDev * upnpDiscover(int);
|
||||
/* free returned list from above function */
|
||||
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
|
||||
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||
|
||||
/* structure used to get fast access to urls
|
||||
* controlURL: controlURL of the WANIPConnection
|
||||
* ipcondescURL: url of the description of the WANIPConnection
|
||||
* controlURL_CIF: controlURL of the WANCOmmonInterfaceConfig
|
||||
*/
|
||||
struct UPNPUrls {
|
||||
char * controlURL;
|
||||
char * ipcondescURL;
|
||||
char * controlURL_CIF;
|
||||
};
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values :
|
||||
* 0 = NO IGD found
|
||||
* 1 = A valid connected IGD has been found
|
||||
* 2 = A valid IGD has been found but it reported as
|
||||
* not connected
|
||||
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||
*
|
||||
* In any non zero return case, the urls and data structures
|
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen);
|
||||
|
||||
LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);
|
||||
|
||||
LIBSPEC void FreeUPNPUrls(struct UPNPUrls *);
|
||||
|
||||
/* Reads data from the specified socket.
|
||||
* Returns the number of bytes read if successful, zero if no bytes were
|
||||
* read or if we timed out. Returns negative if there was an error. */
|
||||
int ReceiveData(int socket, char * data, int length, int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
/* $Id: miniwget.c,v 1.17 2006/12/03 17:22:09 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "miniupnpc.h"
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#define snprintf _snprintf
|
||||
#define herror
|
||||
#define socklen_t int
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#define closesocket close
|
||||
#endif
|
||||
/* for MIN() macro : */
|
||||
#if defined(__sun) || defined(sun)
|
||||
#include <utility.h>
|
||||
#endif
|
||||
|
||||
/* miniwget2() :
|
||||
* */
|
||||
static void *
|
||||
miniwget2(const char * url, const char * host,
|
||||
unsigned short port, const char * path,
|
||||
int * size, char * addr_str, int addr_str_len)
|
||||
{
|
||||
char buf[2048];
|
||||
int s;
|
||||
struct sockaddr_in dest;
|
||||
struct hostent *hp;
|
||||
*size = 0;
|
||||
hp = gethostbyname(host);
|
||||
if(hp==NULL)
|
||||
{
|
||||
herror(host);
|
||||
return NULL;
|
||||
}
|
||||
memcpy((char *)&dest.sin_addr, hp->h_addr, hp->h_length);
|
||||
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(port);
|
||||
if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
|
||||
{
|
||||
perror("connect");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get address for caller ! */
|
||||
if(addr_str)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t len;
|
||||
|
||||
len = sizeof(saddr);
|
||||
getsockname(s, (struct sockaddr *)&saddr, &len);
|
||||
#ifndef WIN32
|
||||
inet_ntop(AF_INET, &saddr.sin_addr, addr_str, addr_str_len);
|
||||
#else
|
||||
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
|
||||
* But his function make a string with the port : nn.nn.nn.nn:port */
|
||||
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
|
||||
NULL, addr_str, (DWORD *)&addr_str_len))
|
||||
{
|
||||
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
|
||||
}*/
|
||||
strncpy(addr_str, inet_ntoa(saddr.sin_addr), addr_str_len);
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
printf("address miniwget : %s\n", addr_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
snprintf(buf, 2048,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"\r\n",
|
||||
path, host, port);
|
||||
/*write(s, buf, strlen(buf));*/
|
||||
send(s, buf, strlen(buf), 0);
|
||||
{
|
||||
int n, headers=1;
|
||||
char * respbuffer = NULL;
|
||||
int allreadyread = 0;
|
||||
/*while((n = recv(s, buf, 2048, 0)) > 0)*/
|
||||
while((n = ReceiveData(s, buf, 2048, 5000)) > 0)
|
||||
{
|
||||
if(headers)
|
||||
{
|
||||
int i=0;
|
||||
while(i<n-3)
|
||||
{
|
||||
if(buf[i]=='\r' && buf[i+1]=='\n'
|
||||
&& buf[i+2]=='\r' && buf[i+3]=='\n')
|
||||
{
|
||||
headers = 0; /* end */
|
||||
if(i<n-4)
|
||||
{
|
||||
respbuffer = (char *)realloc((void *)respbuffer,
|
||||
allreadyread+(n-i-4));
|
||||
memcpy(respbuffer+allreadyread, buf + i + 4, n-i-4);
|
||||
allreadyread += (n-i-4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
respbuffer = (char *)realloc((void *)respbuffer,
|
||||
allreadyread+n);
|
||||
memcpy(respbuffer+allreadyread, buf, n);
|
||||
allreadyread += n;
|
||||
}
|
||||
}
|
||||
*size = allreadyread;
|
||||
#ifndef NDEBUG
|
||||
printf("%d bytes read\n", *size);
|
||||
#endif
|
||||
closesocket(s);
|
||||
return respbuffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* parseURL()
|
||||
* arguments :
|
||||
* url : source string not modified
|
||||
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
|
||||
* port : port (destination)
|
||||
* path : pointer to the path part of the URL
|
||||
*
|
||||
* Return values :
|
||||
* 0 - Failure
|
||||
* 1 - Success */
|
||||
int parseURL(const char * url, char * hostname, unsigned short * port, char * * path)
|
||||
{
|
||||
char * p1, *p2, *p3;
|
||||
p1 = strstr(url, "://");
|
||||
if(!p1)
|
||||
return 0;
|
||||
p1 += 3;
|
||||
if( (url[0]!='h') || (url[1]!='t')
|
||||
||(url[2]!='t') || (url[3]!='p'))
|
||||
return 0;
|
||||
p2 = strchr(p1, ':');
|
||||
p3 = strchr(p1, '/');
|
||||
if(!p3)
|
||||
return 0;
|
||||
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||
if(!p2 || (p2>p3))
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||
*port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||
{
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void * miniwget(const char * url, int * size)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/chemin */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(!parseURL(url, hostname, &port, &path))
|
||||
return NULL;
|
||||
return miniwget2(url, hostname, port, path, size, 0, 0);
|
||||
}
|
||||
|
||||
void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/chemin */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(addr)
|
||||
addr[0] = '\0';
|
||||
if(!parseURL(url, hostname, &port, &path))
|
||||
return NULL;
|
||||
return miniwget2(url, hostname, port, path, size, addr, addrlen);
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/* $Id: miniwget.h,v 1.5 2007/01/29 20:27:23 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef __MINIWGET_H__
|
||||
#define __MINIWGET_H__
|
||||
|
||||
#include "declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBSPEC void * miniwget(const char *, int *);
|
||||
|
||||
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int);
|
||||
|
||||
int parseURL(const char *, char *, unsigned short *, char * *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
/* $Id: minixml.c,v 1.5 2007/01/27 14:20:00 nanard Exp $ */
|
||||
/* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2006, Thomas BERNARD
|
||||
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.
|
||||
* The name of the author may not 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 "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef __MINIXML_H__
|
||||
#define __MINIXML_H__
|
||||
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/* $Id: minixmlvalid.c,v 1.2 2006/11/30 11:31:55 nanard Exp $ */
|
||||
/* MiniUPnP Project
|
||||
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
* minixmlvalid.c :
|
||||
* validation program for the minixml parser
|
||||
*
|
||||
* (c) 2006 Thomas Bernard */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* xml event structure */
|
||||
struct event {
|
||||
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
|
||||
const char * data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct eventlist {
|
||||
int n;
|
||||
struct event * events;
|
||||
};
|
||||
|
||||
/* compare 2 xml event lists
|
||||
* return 0 if the two lists are equals */
|
||||
int evtlistcmp(struct eventlist * a, struct eventlist * b)
|
||||
{
|
||||
int i;
|
||||
struct event * ae, * be;
|
||||
if(a->n != b->n)
|
||||
return 1;
|
||||
for(i=0; i<a->n; i++)
|
||||
{
|
||||
ae = a->events + i;
|
||||
be = b->events + i;
|
||||
if( (ae->type != be->type)
|
||||
||(ae->len != be->len)
|
||||
||memcmp(ae->data, be->data, ae->len))
|
||||
{
|
||||
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
|
||||
ae->type, ae->len, ae->data,
|
||||
be->type, be->len, be->data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test data */
|
||||
static const char xmldata[] =
|
||||
"<xmlroot>\n"
|
||||
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
|
||||
"character data"
|
||||
"</elt1> \n \t"
|
||||
"<elt1b/>"
|
||||
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b>chardata2</elt2b></elt2a>"
|
||||
"</xmlroot>";
|
||||
|
||||
static const struct event evtref[] =
|
||||
{
|
||||
{ELTSTART, "xmlroot", 7},
|
||||
{ELTSTART, "elt1", 4},
|
||||
/* attributes */
|
||||
{CHARDATA, "character data", 14},
|
||||
{ELTEND, "elt1", 4},
|
||||
{ELTSTART, "elt1b", 5},
|
||||
{ELTSTART, "elt2a", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, "chardata1", 9},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, "chardata2", 9},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTEND, "elt2a", 5},
|
||||
{ELTEND, "xmlroot", 7}
|
||||
};
|
||||
|
||||
void startelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("startelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTSTART;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void endelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("endelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTEND;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void chardata(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("chardata : '%.*s'\n", l, p);*/
|
||||
evt->type = CHARDATA;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
int testxmlparser(const char * xml, int size)
|
||||
{
|
||||
int r;
|
||||
struct eventlist evtlist;
|
||||
struct eventlist evtlistref;
|
||||
struct xmlparser parser;
|
||||
evtlist.n = 0;
|
||||
evtlist.events = malloc(sizeof(struct event)*100);
|
||||
memset(&parser, 0, sizeof(parser));
|
||||
parser.xmlstart = xml;
|
||||
parser.xmlsize = size;
|
||||
parser.data = &evtlist;
|
||||
parser.starteltfunc = startelt;
|
||||
parser.endeltfunc = endelt;
|
||||
parser.datafunc = chardata;
|
||||
parsexml(&parser);
|
||||
printf("%d events\n", evtlist.n);
|
||||
/* compare */
|
||||
evtlistref.n = sizeof(evtref)/sizeof(struct event);
|
||||
evtlistref.events = (struct event *)evtref;
|
||||
r = evtlistcmp(&evtlistref, &evtlist);
|
||||
free(evtlist.events);
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int r;
|
||||
r = testxmlparser(xmldata, sizeof(xmldata)-1);
|
||||
if(r)
|
||||
printf("minixml validation test failed\n");
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* $Id: testminixml.c,v 1.6 2006/11/19 22:32:35 nanard Exp $
|
||||
* testminixml.c
|
||||
* test program for the "minixml" functions.
|
||||
* Author : Thomas Bernard.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
#include "igd_desc_parse.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define NO_BZERO
|
||||
#endif
|
||||
|
||||
#ifdef NO_BZERO
|
||||
#define bzero(p, n) memset(p, 0, n)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
void printeltname1(void * d, const char * name, int l)
|
||||
{
|
||||
int i;
|
||||
printf("element ");
|
||||
for(i=0;i<l;i++)
|
||||
putchar(name[i]);
|
||||
}
|
||||
void printeltname2(void * d, const char * name, int l)
|
||||
{
|
||||
int i;
|
||||
putchar('/');
|
||||
for(i=0;i<l;i++)
|
||||
putchar(name[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
void printdata(void *d, const char * data, int l)
|
||||
{
|
||||
int i;
|
||||
printf("data : ");
|
||||
for(i=0;i<l;i++)
|
||||
putchar(data[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void burptest(const char * buffer, int bufsize)
|
||||
{
|
||||
struct IGDdatas data;
|
||||
struct xmlparser parser;
|
||||
/*objet IGDdatas */
|
||||
bzero(&data, sizeof(struct IGDdatas));
|
||||
/* objet xmlparser */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = &data;
|
||||
/*parser.starteltfunc = printeltname1;
|
||||
parser.endeltfunc = printeltname2;
|
||||
parser.datafunc = printdata; */
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parsexml(&parser);
|
||||
printIGD(&data);
|
||||
}
|
||||
|
||||
/* ----- main ---- */
|
||||
#define XML_MAX_SIZE (8192)
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
FILE * f;
|
||||
char buffer[XML_MAX_SIZE];
|
||||
int bufsize;
|
||||
if(argc<2)
|
||||
{
|
||||
printf("usage:\t%s file.xml\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
f = fopen(argv[1], "r");
|
||||
if(!f)
|
||||
{
|
||||
printf("cannot open file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
bufsize = (int)fread(buffer, 1, XML_MAX_SIZE, f);
|
||||
fclose(f);
|
||||
burptest(buffer, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,293 +0,0 @@
|
|||
/* $Id: upnpc.c,v 1.49 2007/01/27 14:20:01 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#include "miniwget.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
|
||||
/* protofix() checks if protocol is "UDP" or "TCP"
|
||||
* returns NULL if not */
|
||||
const char * protofix(const char * proto)
|
||||
{
|
||||
static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
|
||||
static const char proto_udp[4] = { 'U', 'D', 'P', 0};
|
||||
int i, b;
|
||||
for(i=0, b=1; i<4; i++)
|
||||
b = b && ( (proto[i] == proto_tcp[i])
|
||||
|| (proto[i] == (proto_tcp[i] | 32)) );
|
||||
if(b)
|
||||
return proto_tcp;
|
||||
for(i=0, b=1; i<4; i++)
|
||||
b = b && ( (proto[i] == proto_udp[i])
|
||||
|| (proto[i] == (proto_udp[i] | 32)) );
|
||||
if(b)
|
||||
return proto_udp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DisplayInfos(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
char connectionType[64];
|
||||
char status[64];
|
||||
unsigned int uptime;
|
||||
unsigned int brUp, brDown;
|
||||
UPNP_GetConnectionTypeInfo(urls->controlURL,
|
||||
data->servicetype,
|
||||
connectionType);
|
||||
if(connectionType[0])
|
||||
printf("Connection Type : %s\n", connectionType);
|
||||
else
|
||||
printf("GetConnectionTypeInfo failed.\n");
|
||||
UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime);
|
||||
printf("Status : %s, uptime=%u\n", status, uptime);
|
||||
UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->servicetype_CIF,
|
||||
&brDown, &brUp);
|
||||
printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp);
|
||||
}
|
||||
|
||||
static void GetConnectionStatus(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||
DisplayInfos(urls, data);
|
||||
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->servicetype_CIF);
|
||||
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->servicetype_CIF);
|
||||
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->servicetype_CIF);
|
||||
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->servicetype_CIF);
|
||||
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||
}
|
||||
|
||||
static void ListRedirections(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data)
|
||||
{
|
||||
int r;
|
||||
int i = 0;
|
||||
char index[6];
|
||||
char intClient[16];
|
||||
char intPort[6];
|
||||
char extPort[6];
|
||||
char protocol[4];
|
||||
char desc[80];
|
||||
char enabled[6];
|
||||
char rHost[64];
|
||||
char duration[16];
|
||||
/*unsigned int num=0;
|
||||
UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
|
||||
printf("PortMappingNumberOfEntries : %u\n", num);*/
|
||||
do {
|
||||
snprintf(index, 6, "%d", i);
|
||||
rHost[0] = '\0'; enabled[0] = '\0';
|
||||
duration[0] = '\0'; desc[0] = '\0';
|
||||
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||
r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->servicetype,
|
||||
index,
|
||||
extPort, intClient, intPort,
|
||||
protocol, desc, enabled,
|
||||
rHost, duration);
|
||||
if(r==0)
|
||||
printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
|
||||
" desc='%s' rHost='%s'\n",
|
||||
i, protocol, extPort, intClient, intPort,
|
||||
enabled, duration,
|
||||
desc, rHost);
|
||||
i++;
|
||||
} while(r==0);
|
||||
}
|
||||
|
||||
/* Test function
|
||||
* 1 - get connection type
|
||||
* 2 - get extenal ip address
|
||||
* 3 - Add port mapping
|
||||
* 4 - get this port mapping from the IGD */
|
||||
static void SetRedirectAndTest(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * iaddr,
|
||||
const char * iport,
|
||||
const char * eport,
|
||||
const char * proto)
|
||||
{
|
||||
char externalIPAddress[16];
|
||||
char intClient[16];
|
||||
char intPort[6];
|
||||
int r;
|
||||
|
||||
if(!iaddr || !iport || !eport || !proto)
|
||||
{
|
||||
fprintf(stderr, "Wrong arguments\n");
|
||||
return;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "invalid protocol\n");
|
||||
return;
|
||||
}
|
||||
|
||||
UPNP_GetExternalIPAddress(urls->controlURL,
|
||||
data->servicetype,
|
||||
externalIPAddress);
|
||||
if(externalIPAddress[0])
|
||||
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||
else
|
||||
printf("GetExternalIPAddress failed.\n");
|
||||
|
||||
r = UPNP_AddPortMapping(urls->controlURL, data->servicetype,
|
||||
eport, iport, iaddr, 0, proto);
|
||||
if(r==0)
|
||||
printf("AddPortMapping(%s, %s, %s) failed\n", eport, iport, iaddr);
|
||||
|
||||
UPNP_GetSpecificPortMappingEntry(urls->controlURL,
|
||||
data->servicetype,
|
||||
eport, proto,
|
||||
intClient, intPort);
|
||||
if(intClient[0])
|
||||
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
|
||||
else
|
||||
printf("GetSpecificPortMappingEntry failed.\n");
|
||||
|
||||
printf("external %s:%s is redirected to internal %s:%s\n",
|
||||
externalIPAddress, eport, intClient, intPort);
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveRedirect(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * eport,
|
||||
const char * proto)
|
||||
{
|
||||
if(!proto || !eport)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "protocol invalid\n");
|
||||
return;
|
||||
}
|
||||
UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto);
|
||||
}
|
||||
|
||||
|
||||
/* sample upnp client program */
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
char command = 0;
|
||||
struct UPNPDev * devlist;
|
||||
char lanaddr[16]; /* my ip address on the LAN */
|
||||
int i;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsaData;
|
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if(nResult != NO_ERROR)
|
||||
{
|
||||
fprintf(stderr, "WSAStartup() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
printf("upnpc : miniupnp test client. (c) 2006 Thomas Bernard\n");
|
||||
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
|
||||
"for more information.\n");
|
||||
if(argc>=2 && (argv[1][0] == '-'))
|
||||
command = argv[1][1];
|
||||
|
||||
if(!command || argc<2 || (command == 'a' && argc<6)
|
||||
|| (command == 'd' && argc<4)
|
||||
|| (command == 'r' && argc<4))
|
||||
{
|
||||
fprintf(stderr, "Usage :\t%s -a ip port external_port protocol\tAdd port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s -d external_port protocol\tDelete port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s -s\t\t\t\tGet Connection status\n", argv[0]);
|
||||
fprintf(stderr, " \t%s -l\t\t\t\tList redirections\n", argv[0]);
|
||||
fprintf(stderr, " \t%s -r port1 protocol1 [port2 protocol2] [...]\n\t\t\t\tAdd all redirections to the current host\n", argv[0]);
|
||||
fprintf(stderr, "\nprotocol is UDP or TCP\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
devlist = upnpDiscover(2000);
|
||||
if(devlist)
|
||||
{
|
||||
struct UPNPDev * device;
|
||||
struct UPNPUrls urls;
|
||||
struct IGDdatas data;
|
||||
printf("List of UPNP devices found on the network :\n");
|
||||
for(device = devlist; device; device = device->pNext)
|
||||
{
|
||||
printf("\n desc: %s\n st: %s\n",
|
||||
device->descURL, device->st);
|
||||
}
|
||||
putchar('\n');
|
||||
if(UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))
|
||||
{
|
||||
printf("Found valid IGD : %s\n", urls.controlURL);
|
||||
printf("Local LAN ip address : %s\n", lanaddr);
|
||||
#if 0
|
||||
printf("getting \"%s\"\n", urls.ipcondescURL);
|
||||
descXML = miniwget(urls.ipcondescURL, &descXMLsize);
|
||||
if(descXML)
|
||||
{
|
||||
/*fwrite(descXML, 1, descXMLsize, stdout);*/
|
||||
free(descXML); descXML = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case 'l':
|
||||
DisplayInfos(&urls, &data);
|
||||
ListRedirections(&urls, &data);
|
||||
break;
|
||||
case 'a':
|
||||
SetRedirectAndTest(&urls, &data, argv[2], argv[3], argv[4], argv[5]);
|
||||
break;
|
||||
case 'd':
|
||||
RemoveRedirect(&urls, &data, argv[2], argv[3]);
|
||||
break;
|
||||
case 's':
|
||||
GetConnectionStatus(&urls, &data);
|
||||
break;
|
||||
case 'r':
|
||||
for(i=2; i<argc-1; i+=2)
|
||||
{
|
||||
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
|
||||
SetRedirectAndTest(&urls, &data,
|
||||
lanaddr, argv[i], argv[i], argv[i+1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown switch -%c\n", command);
|
||||
}
|
||||
|
||||
FreeUPNPUrls(&urls);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
|
||||
}
|
||||
freeUPNPDevlist(devlist); devlist = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "No IGD UPnP Device found on the network !\n");
|
||||
}
|
||||
|
||||
/*puts("************* HOP ***************");*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,485 +0,0 @@
|
|||
/* $Id: upnpcommands.c,v 1.14 2006/11/19 22:32:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "upnpcommands.h"
|
||||
#include "miniupnpc.h"
|
||||
|
||||
static unsigned int
|
||||
my_atoui(const char * s)
|
||||
{
|
||||
return (unsigned int)strtoul(s, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* */
|
||||
unsigned int
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
unsigned int r = 0;
|
||||
char * p;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent");
|
||||
if(p)
|
||||
r = my_atoui(p);
|
||||
ClearNameValueList(&pdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* */
|
||||
unsigned int
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
unsigned int r = 0;
|
||||
char * p;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived");
|
||||
if(p)
|
||||
r = my_atoui(p);
|
||||
ClearNameValueList(&pdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* */
|
||||
unsigned int
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
unsigned int r = 0;
|
||||
char * p;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent");
|
||||
if(p)
|
||||
r = my_atoui(p);
|
||||
ClearNameValueList(&pdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* */
|
||||
unsigned int
|
||||
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
unsigned int r = 0;
|
||||
char * p;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived");
|
||||
if(p)
|
||||
r = my_atoui(p);
|
||||
ClearNameValueList(&pdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* UPNP_GetStatusInfo() call the corresponding UPNP method
|
||||
* returns the current status and uptime */
|
||||
void UPNP_GetStatusInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * status,
|
||||
unsigned int * uptime)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * p;
|
||||
char* up;
|
||||
|
||||
if(!status && !uptime)
|
||||
return;
|
||||
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetStatusInfo", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
up = GetValueFromNameValueList(&pdata, "NewUptime");
|
||||
p = GetValueFromNameValueList(&pdata, "NewConnectionStatus");
|
||||
|
||||
if(status)
|
||||
{
|
||||
if(p){
|
||||
strncpy(status, p, 64 );
|
||||
status[63] = '\0';
|
||||
}else
|
||||
status[0]= '\0';
|
||||
}
|
||||
|
||||
if(uptime){
|
||||
if(p)
|
||||
sscanf(up,"%u",uptime);
|
||||
else
|
||||
uptime = 0;
|
||||
}
|
||||
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
|
||||
/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
|
||||
* returns the connection type */
|
||||
void UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * connectionType)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * p;
|
||||
|
||||
if(!connectionType)
|
||||
return;
|
||||
|
||||
|
||||
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"GetConnectionTypeInfo", 0, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
p = GetValueFromNameValueList(&pdata, "NewConnectionType");
|
||||
/*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/
|
||||
/* PossibleConnectionTypes will have several values.... */
|
||||
if(connectionType)
|
||||
{
|
||||
if(p){
|
||||
strncpy(connectionType, p, 64 );
|
||||
connectionType[63] = '\0';
|
||||
} else
|
||||
connectionType[0] = '\0';
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
|
||||
/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method.
|
||||
* Returns 2 values: Downloadlink bandwidth and Uplink bandwidth.
|
||||
* One of the values can be null
|
||||
* Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
|
||||
* We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
|
||||
void UPNP_GetLinkLayerMaxBitRates(const char * controlURL, const char * servicetype, unsigned int * bitrateDown, unsigned int* bitrateUp)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * down;
|
||||
char* up;
|
||||
|
||||
if(!bitrateDown && !bitrateUp)
|
||||
return;
|
||||
|
||||
/* shouldn't we use GetCommonLinkProperties ? */
|
||||
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"GetCommonLinkProperties", 0, buffer, &bufsize);
|
||||
/*"GetLinkLayerMaxBitRates", 0, buffer, &bufsize);*/
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/
|
||||
/*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/
|
||||
down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate");
|
||||
up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate");
|
||||
/*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/
|
||||
/*GetValueFromNameValueList(&pdata, "NewPhysicalLinkSatus");*/
|
||||
|
||||
if(bitrateDown)
|
||||
{
|
||||
if(down)
|
||||
sscanf(down,"%u",bitrateDown);
|
||||
else
|
||||
*bitrateDown = 0;
|
||||
}
|
||||
|
||||
if(bitrateUp)
|
||||
{
|
||||
if(up)
|
||||
sscanf(up,"%u",bitrateUp);
|
||||
else
|
||||
*bitrateUp = 0;
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
|
||||
|
||||
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||
* if the third arg is not null the value is copied to it.
|
||||
* at least 16 bytes must be available */
|
||||
void UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * p;
|
||||
|
||||
if(!extIpAdd)
|
||||
return;
|
||||
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetExternalIPAddress", 0, buffer, &bufsize);
|
||||
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "GetExternalIPAddress", 0, buffer, &bufsize);*/
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
/*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/
|
||||
p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress");
|
||||
|
||||
if(p){
|
||||
strncpy(extIpAdd, p, 16 );
|
||||
extIpAdd[15] = '\0';
|
||||
}else
|
||||
extIpAdd[0] = '\0';
|
||||
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
|
||||
int
|
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto)
|
||||
{
|
||||
struct UPNParg * AddPortMappingArgs;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
struct NameValueParserData pdata;
|
||||
const char * resVal;
|
||||
int ret;
|
||||
|
||||
if(!inPort || !inClient)
|
||||
return 0;
|
||||
|
||||
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
|
||||
AddPortMappingArgs[0].elt = "NewRemoteHost";
|
||||
AddPortMappingArgs[1].elt = "NewExternalPort";
|
||||
AddPortMappingArgs[1].val = extPort;
|
||||
AddPortMappingArgs[2].elt = "NewProtocol";
|
||||
AddPortMappingArgs[2].val = proto;
|
||||
AddPortMappingArgs[3].elt = "NewInternalPort";
|
||||
AddPortMappingArgs[3].val = inPort;
|
||||
AddPortMappingArgs[4].elt = "NewInternalClient";
|
||||
AddPortMappingArgs[4].val = inClient;
|
||||
AddPortMappingArgs[5].elt = "NewEnabled";
|
||||
AddPortMappingArgs[5].val = "1";
|
||||
AddPortMappingArgs[6].elt = "NewPortMappingDescription";
|
||||
AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
|
||||
AddPortMappingArgs[7].elt = "NewLeaseDuration";
|
||||
AddPortMappingArgs[7].val = "0";
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "AddPortMapping", AddPortMappingArgs, buffer, &bufsize);
|
||||
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "AddPortMapping", AddPortMappingArgs, buffer, &bufsize);*/
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
/*buffer[bufsize] = '\0';*/
|
||||
/*puts(buffer);*/
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
resVal = GetValueFromNameValueList(&pdata, "errorCode");
|
||||
ret = resVal?0:1;
|
||||
/* Do something with resVal if not null ! */
|
||||
/*printf("AddPortMapping errorCode = '%s'\n", resVal); */
|
||||
free(AddPortMappingArgs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto)
|
||||
{
|
||||
/*struct NameValueParserData pdata;*/
|
||||
struct UPNParg * DeletePortMappingArgs;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
|
||||
if(!extPort)
|
||||
return;
|
||||
|
||||
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
|
||||
DeletePortMappingArgs[0].elt = "NewRemoteHost";
|
||||
DeletePortMappingArgs[1].elt = "NewExternalPort";
|
||||
DeletePortMappingArgs[1].val = extPort;
|
||||
DeletePortMappingArgs[2].elt = "NewProtocol";
|
||||
DeletePortMappingArgs[2].val = proto;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"DeletePortMapping",
|
||||
DeletePortMappingArgs, buffer, &bufsize);
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
free(DeletePortMappingArgs);
|
||||
}
|
||||
|
||||
int UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * index,
|
||||
char * extPort,
|
||||
char * intClient,
|
||||
char * intPort,
|
||||
char * protocol,
|
||||
char * desc,
|
||||
char * enabled,
|
||||
char * rHost,
|
||||
char * duration)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct UPNParg * GetPortMappingArgs;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * p;
|
||||
int r = -1;
|
||||
intClient[0] = '\0';
|
||||
intPort[0] = '\0';
|
||||
GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
|
||||
GetPortMappingArgs[0].elt = "NewPortMappingIndex";
|
||||
GetPortMappingArgs[0].val = index;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"GetGenericPortMappingEntry",
|
||||
GetPortMappingArgs, buffer, &bufsize);
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
p = GetValueFromNameValueList(&pdata, "NewRemoteHost");
|
||||
if(p && rHost)
|
||||
{
|
||||
strncpy(rHost, p, 64);
|
||||
rHost[63] = '\0';
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewExternalPort");
|
||||
if(p && extPort)
|
||||
{
|
||||
strncpy(extPort, p, 6);
|
||||
extPort[5] = '\0';
|
||||
r = 0;
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewProtocol");
|
||||
if(p && protocol)
|
||||
{
|
||||
strncpy(protocol, p, 4);
|
||||
protocol[3] = '\0';
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewInternalClient");
|
||||
if(p && intClient)
|
||||
{
|
||||
strncpy(intClient, p, 16);
|
||||
intClient[15] = '\0';
|
||||
r = 0;
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewInternalPort");
|
||||
if(p && intPort)
|
||||
{
|
||||
strncpy(intPort, p, 6);
|
||||
intPort[5] = '\0';
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewEnabled");
|
||||
if(p && enabled)
|
||||
{
|
||||
strncpy(enabled, p, 4);
|
||||
enabled[3] = '\0';
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
|
||||
if(p && desc)
|
||||
{
|
||||
strncpy(desc, p, 80);
|
||||
desc[79] = '\0';
|
||||
}
|
||||
p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
|
||||
if(p && duration)
|
||||
{
|
||||
strncpy(duration, p, 16);
|
||||
duration[15] = '\0';
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
free(GetPortMappingArgs);
|
||||
return r;
|
||||
}
|
||||
|
||||
void UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char* p;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype, "GetPortMappingNumberOfEntries", 0, buffer, &bufsize);
|
||||
#ifndef NDEBUG
|
||||
DisplayNameValueList(buffer, bufsize);
|
||||
#endif
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries");
|
||||
|
||||
if(numEntries && p)
|
||||
{
|
||||
sscanf(p,"%u",numEntries);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
|
||||
/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
|
||||
* the result is returned in the intClient and intPort strings
|
||||
* please provide 16 and 6 bytes of data */
|
||||
void
|
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * proto,
|
||||
char * intClient,
|
||||
char * intPort)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct UPNParg * GetPortMappingArgs;
|
||||
char buffer[4096];
|
||||
int bufsize = 4096;
|
||||
char * p;
|
||||
|
||||
if(!intPort && !intClient && !extPort)
|
||||
return;
|
||||
|
||||
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
|
||||
GetPortMappingArgs[0].elt = "NewRemoteHost";
|
||||
GetPortMappingArgs[1].elt = "NewExternalPort";
|
||||
GetPortMappingArgs[1].val = extPort;
|
||||
GetPortMappingArgs[2].elt = "NewProtocol";
|
||||
GetPortMappingArgs[2].val = proto;
|
||||
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"GetSpecificPortMappingEntry",
|
||||
GetPortMappingArgs, buffer, &bufsize);
|
||||
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "GetSpecificPortMappingEntry", AddPortMappingArgs, buffer, &bufsize); */
|
||||
/*DisplayNameValueList(buffer, bufsize);*/
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
p = GetValueFromNameValueList(&pdata, "NewInternalClient");
|
||||
|
||||
if(intClient)
|
||||
{
|
||||
if(p){
|
||||
strncpy(intClient, p, 16);
|
||||
intClient[15] = '\0';
|
||||
}else
|
||||
intClient[0] = '\0';
|
||||
}
|
||||
|
||||
p = GetValueFromNameValueList(&pdata, "NewInternalPort");
|
||||
if(intPort)
|
||||
{
|
||||
if(p){
|
||||
strncpy(intPort, p, 6);
|
||||
intPort[5] = '\0';
|
||||
}else
|
||||
intPort[0] = '\0';
|
||||
}
|
||||
|
||||
ClearNameValueList(&pdata);
|
||||
free(GetPortMappingArgs);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue