here we go...lt 0.13...upnp & natpmp support!

This commit is contained in:
Marcos Pinto 2007-05-25 19:59:20 +00:00
parent 3324d7afc7
commit 4722aa5796
107 changed files with 9717 additions and 6390 deletions

View file

@ -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
}

View file

@ -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)); }
};
}

View file

@ -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;

View file

@ -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:

View 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

View file

@ -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

View file

@ -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; }

View file

@ -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);

View file

@ -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> >

View file

@ -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;
};
}

View 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

View 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;
};
}

View file

@ -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;
};
}

View 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

View file

@ -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);
}
}
}

View file

@ -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:

View 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

View 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

View 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

View file

@ -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;

View file

@ -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

View file

@ -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.

View file

@ -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;
};
}

View file

@ -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;

View file

@ -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

View file

@ -59,6 +59,7 @@ namespace libtorrent
int dht_nodes;
int dht_node_cache;
int dht_torrents;
size_type dht_global_nodes;
#endif
};

View file

@ -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
{

View file

@ -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

View 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;
};
}

View file

@ -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;

View 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

View file

@ -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;
}

View file

@ -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

View file

@ -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
};
}

View file

@ -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;
};
}

View file

@ -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

View 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

View 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

View file

@ -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

View file

@ -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;
};
}

View 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

View file

@ -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@

View file

@ -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;
}

View file

@ -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

View file

@ -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); };
}

View file

@ -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);
}

View 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();
}
}

View file

@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/pch.hpp"
#include <algorithm>
#include <iomanip>
#include "libtorrent/entry.hpp"

View file

@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/pch.hpp"
#include <string>
#include <cassert>
#include <stdexcept>

View file

@ -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);

View file

@ -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)

View file

@ -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));

View 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;
}
}

View 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));
}
}

View file

@ -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);

View file

@ -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];

View 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;
}
}

View file

@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/pch.hpp"
#include "libtorrent/ip_filter.hpp"
#include <boost/utility.hpp>
//#include <iostream>

View file

@ -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
View 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();
}

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -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
*/

View 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);
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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());

View file

@ -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 =

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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));
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 !

View file

@ -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_ */

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -1,5 +0,0 @@
mingw32-make -f Makefile.mingw
if errorlevel 1 goto end
strip upnpc.exe
upx --best upnpc.exe
:end

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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