diff --git a/libtorrent/include/libtorrent/GeoIP.h b/libtorrent/include/libtorrent/GeoIP.h new file mode 100644 index 000000000..d493eccb9 --- /dev/null +++ b/libtorrent/include/libtorrent/GeoIP.h @@ -0,0 +1,180 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ +/* GeoIP.h + * + * Copyright (C) 2006 MaxMind LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GEOIP_H +#define GEOIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include /* for fstat */ +#include /* for fstat */ + +#define SEGMENT_RECORD_LENGTH 3 +#define STANDARD_RECORD_LENGTH 3 +#define ORG_RECORD_LENGTH 4 +#define MAX_RECORD_LENGTH 4 +#define NUM_DB_TYPES 20 + +typedef struct GeoIPTag { + FILE *GeoIPDatabase; + char *file_path; + unsigned char *cache; + unsigned char *index_cache; + unsigned int *databaseSegments; + char databaseType; + time_t mtime; + int flags; + off_t size; + char record_length; + int charset; /* 0 iso-8859-1 1 utf8 */ + int record_iter; /* used in GeoIP_next_record */ + int netmask; /* netmask of last lookup - set using depth in _GeoIP_seek_record */ +} GeoIP; + + +typedef enum { + GEOIP_CHARSET_ISO_8859_1 = 0, + GEOIP_CHARSET_UTF8 = 1 +} GeoIPCharset; + +typedef struct GeoIPRegionTag { + char country_code[3]; + char region[3]; +} GeoIPRegion; + +typedef enum { + GEOIP_STANDARD = 0, + GEOIP_MEMORY_CACHE = 1, + GEOIP_CHECK_CACHE = 2, + GEOIP_INDEX_CACHE = 4, + GEOIP_MMAP_CACHE = 8, +} GeoIPOptions; + +typedef enum { + GEOIP_COUNTRY_EDITION = 1, + GEOIP_REGION_EDITION_REV0 = 7, + GEOIP_CITY_EDITION_REV0 = 6, + GEOIP_ORG_EDITION = 5, + GEOIP_ISP_EDITION = 4, + GEOIP_CITY_EDITION_REV1 = 2, + GEOIP_REGION_EDITION_REV1 = 3, + GEOIP_PROXY_EDITION = 8, + GEOIP_ASNUM_EDITION = 9, + GEOIP_NETSPEED_EDITION = 10, + GEOIP_DOMAIN_EDITION = 11 +} GeoIPDBTypes; + +typedef enum { + GEOIP_ANON_PROXY = 1, + GEOIP_HTTP_X_FORWARDED_FOR_PROXY = 2, + GEOIP_HTTP_CLIENT_IP_PROXY = 3, +} GeoIPProxyTypes; + +typedef enum { + GEOIP_UNKNOWN_SPEED = 0, + GEOIP_DIALUP_SPEED = 1, + GEOIP_CABLEDSL_SPEED = 2, + GEOIP_CORPORATE_SPEED = 3, +} GeoIPNetspeedValues; + +extern char **GeoIPDBFileName; +extern const char * GeoIPDBDescription[NUM_DB_TYPES]; +extern const char *GeoIPCountryDBFileName; +extern const char *GeoIPRegionDBFileName; +extern const char *GeoIPCityDBFileName; +extern const char *GeoIPOrgDBFileName; +extern const char *GeoIPISPDBFileName; + +extern const char GeoIP_country_code[253][3]; +extern const char GeoIP_country_code3[253][4]; +extern const char * GeoIP_country_name[253]; +extern const char GeoIP_country_continent[253][3]; + +#ifdef DLL +#define GEOIP_API __declspec(dllexport) +#else +#define GEOIP_API +#endif /* DLL */ + +GEOIP_API void GeoIP_setup_custom_directory(char *dir); +GEOIP_API GeoIP* GeoIP_open_type (int type, int flags); +GEOIP_API GeoIP* GeoIP_new(int flags); +GEOIP_API GeoIP* GeoIP_open(const char * filename, int flags); +GEOIP_API int GeoIP_db_avail(int type); +GEOIP_API void GeoIP_delete(GeoIP* gi); +GEOIP_API const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_code_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr); +GEOIP_API const char *GeoIP_country_name_by_name (GeoIP* gi, const char *host); +GEOIP_API const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum); + +/* Deprecated - for backwards compatibility only */ +GEOIP_API int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr); +GEOIP_API int GeoIP_country_id_by_name (GeoIP* gi, const char *host); +GEOIP_API char *GeoIP_org_by_addr (GeoIP* gi, const char *addr); +GEOIP_API char *GeoIP_org_by_name (GeoIP* gi, const char *host); +/* End deprecated */ + +GEOIP_API int GeoIP_id_by_addr (GeoIP* gi, const char *addr); +GEOIP_API int GeoIP_id_by_name (GeoIP* gi, const char *host); +GEOIP_API int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum); + +GEOIP_API GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr); +GEOIP_API GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *host); +GEOIP_API GeoIPRegion * GeoIP_region_by_ipnum (GeoIP *gi, unsigned long ipnum); + +/* Warning - don't call this after GeoIP_assign_region_by_inetaddr calls */ +GEOIP_API void GeoIPRegion_delete (GeoIPRegion *gir); + +GEOIP_API void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *gir); + +/* Used to query GeoIP Organization, ISP and AS Number databases */ +GEOIP_API char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum); +GEOIP_API char *GeoIP_name_by_addr (GeoIP* gi, const char *addr); +GEOIP_API char *GeoIP_name_by_name (GeoIP* gi, const char *host); + +GEOIP_API char *GeoIP_database_info (GeoIP* gi); +GEOIP_API unsigned char GeoIP_database_edition (GeoIP* gi); + +GEOIP_API int GeoIP_charset (GeoIP* gi); +GEOIP_API int GeoIP_set_charset (GeoIP* gi, int charset); + +GEOIP_API int GeoIP_last_netmask (GeoIP* gi); + +/* Convert region code to region name */ +GEOIP_API const char * GeoIP_region_name_by_code(const char *country_code, const char *region_code); + +/* Get timezone from country and region code */ +GEOIP_API const char * GeoIP_time_zone_by_country_and_region(const char *country_code, const char *region_code); + +#ifdef __cplusplus +} +#endif + +#endif /* GEOIP_H */ diff --git a/libtorrent/include/libtorrent/alert.hpp b/libtorrent/include/libtorrent/alert.hpp new file mode 100644 index 000000000..ab8065f1f --- /dev/null +++ b/libtorrent/include/libtorrent/alert.hpp @@ -0,0 +1,168 @@ +/* + +Copyright (c) 2003, Arvid Norberg, Daniel Wallin +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_ALERT_HPP_INCLUDED +#define TORRENT_ALERT_HPP_INCLUDED + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/time.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +#ifndef TORRENT_MAX_ALERT_TYPES +#define TORRENT_MAX_ALERT_TYPES 15 +#endif + +namespace libtorrent { + + class TORRENT_EXPORT alert + { + public: + enum severity_t { debug, info, warning, critical, fatal, none }; + + alert(severity_t severity, const std::string& msg); + virtual ~alert(); + + // a timestamp is automatically created in the constructor + ptime timestamp() const; + + std::string const& msg() const; + + severity_t severity() const; + + virtual std::auto_ptr clone() const = 0; + + private: + std::string m_msg; + severity_t m_severity; + ptime m_timestamp; + }; + + class TORRENT_EXPORT alert_manager + { + public: + alert_manager(); + ~alert_manager(); + + void post_alert(const alert& alert_); + bool pending() const; + std::auto_ptr get(); + + void set_severity(alert::severity_t severity); + bool should_post(alert::severity_t severity) const; + + alert const* wait_for_alert(time_duration max_wait); + + private: + std::queue m_alerts; + alert::severity_t m_severity; + mutable boost::mutex m_mutex; + boost::condition m_condition; + }; + + struct TORRENT_EXPORT unhandled_alert : std::exception + { + unhandled_alert() {} + }; + + namespace detail { + + struct void_; + + template + void handle_alert_dispatch( + const std::auto_ptr& 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(alert_.get())); + else + handle_alert_dispatch(alert_, handler, typeid_ + , BOOST_PP_ENUM_SHIFTED_PARAMS( + TORRENT_MAX_ALERT_TYPES, p), (void_*)0); + } + + template + void handle_alert_dispatch( + const std::auto_ptr& 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 + struct TORRENT_EXPORT handle_alert + { + template + handle_alert(const std::auto_ptr& 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, _)); + + #undef ALERT_POINTER_TYPE + } + }; + +} // namespace libtorrent + +#endif // TORRENT_ALERT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp new file mode 100644 index 000000000..1fc8116ff --- /dev/null +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -0,0 +1,559 @@ +/* + +Copyright (c) 2003, 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_ALERT_TYPES_HPP_INCLUDED +#define TORRENT_ALERT_TYPES_HPP_INCLUDED + +#include "libtorrent/alert.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + struct TORRENT_EXPORT torrent_alert: alert + { + torrent_alert(torrent_handle const& h, alert::severity_t s + , std::string const& msg) + : alert(s, msg) + , handle(h) + {} + + torrent_handle handle; + }; + + struct TORRENT_EXPORT file_renamed_alert: torrent_alert + { + file_renamed_alert(torrent_handle const& h + , std::string const& name_ + , std::string const& msg) + : torrent_alert(h, alert::warning, msg) + , name(name_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new file_renamed_alert(*this)); } + + std::string name; + }; + + struct TORRENT_EXPORT tracker_alert: torrent_alert + { + tracker_alert(torrent_handle const& h + , std::string const& url_ + , alert::severity_t s + , std::string const& msg) + : torrent_alert(h, s, msg) + , url(url_) + {} + + std::string url; + }; + + struct TORRENT_EXPORT tracker_error_alert: tracker_alert + { + tracker_error_alert(torrent_handle const& h + , int times + , int status + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::warning, msg) + , times_in_row(times) + , status_code(status) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new tracker_error_alert(*this)); } + + int times_in_row; + int status_code; + }; + + struct TORRENT_EXPORT tracker_warning_alert: tracker_alert + { + tracker_warning_alert(torrent_handle const& h + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new tracker_warning_alert(*this)); } + }; + + struct TORRENT_EXPORT scrape_reply_alert: tracker_alert + { + scrape_reply_alert(torrent_handle const& h + , int incomplete_ + , int complete_ + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::info, msg) + , incomplete(incomplete_) + , complete(complete_) + {} + + int incomplete; + int complete; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_reply_alert(*this)); } + }; + + struct TORRENT_EXPORT scrape_failed_alert: tracker_alert + { + scrape_failed_alert(torrent_handle const& h + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_failed_alert(*this)); } + }; + + struct TORRENT_EXPORT tracker_reply_alert: tracker_alert + { + tracker_reply_alert(torrent_handle const& h + , int np + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::info, msg) + , num_peers(np) + {} + + int num_peers; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new tracker_reply_alert(*this)); } + }; + + struct TORRENT_EXPORT tracker_announce_alert: tracker_alert + { + tracker_announce_alert(torrent_handle const& h + , std::string const& url + , std::string const& msg) + : tracker_alert(h, url, alert::info, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new tracker_announce_alert(*this)); } + }; + + struct TORRENT_EXPORT hash_failed_alert: torrent_alert + { + hash_failed_alert( + torrent_handle const& h + , int index + , std::string const& msg) + : torrent_alert(h, alert::info, msg) + , piece_index(index) + { TORRENT_ASSERT(index >= 0);} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new hash_failed_alert(*this)); } + + int piece_index; + }; + + struct TORRENT_EXPORT peer_ban_alert: torrent_alert + { + peer_ban_alert(tcp::endpoint const& pip, torrent_handle h, std::string const& msg) + : torrent_alert(h, alert::info, msg) + , ip(pip) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new peer_ban_alert(*this)); } + + tcp::endpoint ip; + }; + + struct TORRENT_EXPORT peer_error_alert: alert + { + peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg) + : alert(alert::info, msg) + , ip(pip) + , pid(pid_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new peer_error_alert(*this)); } + + tcp::endpoint ip; + peer_id pid; + }; + + struct TORRENT_EXPORT peer_disconnected_alert: alert + { + peer_disconnected_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg) + : alert(alert::debug, msg) + , ip(pip) + , pid(pid_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new peer_disconnected_alert(*this)); } + + tcp::endpoint ip; + peer_id pid; + }; + + struct TORRENT_EXPORT invalid_request_alert: torrent_alert + { + invalid_request_alert( + peer_request const& r + , torrent_handle const& h + , tcp::endpoint const& sender + , peer_id const& pid_ + , std::string const& msg) + : torrent_alert(h, alert::debug, msg) + , ip(sender) + , request(r) + , pid(pid_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new invalid_request_alert(*this)); } + + tcp::endpoint ip; + peer_request request; + peer_id pid; + }; + + struct TORRENT_EXPORT torrent_finished_alert: torrent_alert + { + torrent_finished_alert( + const torrent_handle& h + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT piece_finished_alert: torrent_alert + { + piece_finished_alert( + const torrent_handle& h + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::debug, msg) + , piece_index(piece_num) + { TORRENT_ASSERT(piece_index >= 0);} + + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new piece_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_finished_alert: torrent_alert + { + block_finished_alert( + const torrent_handle& h + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::debug, msg) + , block_index(block_num) + , piece_index(piece_num) + { TORRENT_ASSERT(block_index >= 0 && piece_index >= 0);} + + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_finished_alert(*this)); } + }; + + struct TORRENT_EXPORT block_downloading_alert: torrent_alert + { + block_downloading_alert( + const torrent_handle& h + , char const* speedmsg + , int block_num + , int piece_num + , const std::string& msg) + : torrent_alert(h, alert::debug, msg) + , peer_speedmsg(speedmsg) + , block_index(block_num) + , piece_index(piece_num) + { TORRENT_ASSERT(block_index >= 0 && piece_index >= 0);} + + std::string peer_speedmsg; + int block_index; + int piece_index; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new block_downloading_alert(*this)); } + }; + + struct TORRENT_EXPORT storage_moved_alert: torrent_alert + { + storage_moved_alert(torrent_handle const& h, std::string const& path) + : torrent_alert(h, alert::warning, path) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new storage_moved_alert(*this)); } + }; + + struct TORRENT_EXPORT torrent_deleted_alert: torrent_alert + { + torrent_deleted_alert(torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_deleted_alert(*this)); } + }; + + struct TORRENT_EXPORT save_resume_data_alert: torrent_alert + { + save_resume_data_alert(boost::shared_ptr const& rd + , torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::warning, msg) + , resume_data(rd) + {} + + boost::shared_ptr resume_data; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new save_resume_data_alert(*this)); } + }; + + struct TORRENT_EXPORT torrent_paused_alert: torrent_alert + { + torrent_paused_alert(torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_paused_alert(*this)); } + }; + + struct TORRENT_EXPORT torrent_checked_alert: torrent_alert + { + torrent_checked_alert(torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::info, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_checked_alert(*this)); } + }; + + + struct TORRENT_EXPORT url_seed_alert: torrent_alert + { + url_seed_alert( + torrent_handle const& h + , const std::string& url_ + , const std::string& msg) + : torrent_alert(h, alert::warning, msg) + , url(url_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new url_seed_alert(*this)); } + + std::string url; + }; + + struct TORRENT_EXPORT file_error_alert: torrent_alert + { + file_error_alert( + std::string const& f + , const torrent_handle& h + , const std::string& msg) + : torrent_alert(h, alert::fatal, msg) + , file(f) + {} + + std::string file; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new file_error_alert(*this)); } + }; + + struct TORRENT_EXPORT metadata_failed_alert: torrent_alert + { + metadata_failed_alert( + const torrent_handle& h + , const std::string& msg) + : torrent_alert(h, alert::info, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new metadata_failed_alert(*this)); } + }; + + struct TORRENT_EXPORT metadata_received_alert: torrent_alert + { + metadata_received_alert( + const torrent_handle& h + , const std::string& msg) + : torrent_alert(h, alert::info, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new metadata_received_alert(*this)); } + }; + + struct TORRENT_EXPORT udp_error_alert: alert + { + udp_error_alert( + udp::endpoint const& ep + , std::string const& msg) + : alert(alert::info, msg) + , endpoint(ep) + {} + + udp::endpoint endpoint; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new udp_error_alert(*this)); } + }; + + struct TORRENT_EXPORT external_ip_alert: alert + { + external_ip_alert( + address const& ip + , std::string const& msg) + : alert(alert::info, msg) + , external_address(ip) + {} + + address external_address; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new external_ip_alert(*this)); } + }; + + struct TORRENT_EXPORT listen_failed_alert: alert + { + listen_failed_alert( + tcp::endpoint const& ep + , std::string const& msg) + : alert(alert::fatal, msg) + , endpoint(ep) + {} + + tcp::endpoint endpoint; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new listen_failed_alert(*this)); } + }; + + struct TORRENT_EXPORT listen_succeeded_alert: alert + { + listen_succeeded_alert( + tcp::endpoint const& ep + , std::string const& msg) + : alert(alert::fatal, msg) + , endpoint(ep) + {} + + tcp::endpoint endpoint; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new listen_succeeded_alert(*this)); } + }; + + struct TORRENT_EXPORT portmap_error_alert: alert + { + portmap_error_alert(int i, int t, const std::string& msg) + : alert(alert::warning, msg), mapping(i), type(t) + {} + + int mapping; + int type; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new portmap_error_alert(*this)); } + }; + + struct TORRENT_EXPORT portmap_alert: alert + { + portmap_alert(int i, int port, int t, const std::string& msg) + : alert(alert::info, msg), mapping(i), external_port(port), type(t) + {} + + int mapping; + int external_port; + int type; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new portmap_alert(*this)); } + }; + + struct TORRENT_EXPORT fastresume_rejected_alert: torrent_alert + { + fastresume_rejected_alert(torrent_handle const& h + , std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(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 clone() const + { return std::auto_ptr(new peer_blocked_alert(*this)); } + }; + + struct TORRENT_EXPORT torrent_resumed_alert: torrent_alert + { + torrent_resumed_alert(torrent_handle const& h, std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new torrent_resumed_alert(*this)); } + }; +} + + +#endif diff --git a/libtorrent/include/libtorrent/assert.hpp b/libtorrent/include/libtorrent/assert.hpp new file mode 100644 index 000000000..6943fadc2 --- /dev/null +++ b/libtorrent/include/libtorrent/assert.hpp @@ -0,0 +1,53 @@ +/* + +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_ASSERT + +#include "libtorrent/config.hpp" +#include + +#ifdef __GNUC__ +std::string demangle(char const* name); +#endif + +#if (defined __linux__ || defined __MACH__) && defined __GNUC__ && !defined(NDEBUG) + +TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function); +#define TORRENT_ASSERT(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__) + +#else +#include +#define TORRENT_ASSERT(x) assert(x) +#endif + +#endif + diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp new file mode 100644 index 000000000..fa4f0d276 --- /dev/null +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -0,0 +1,677 @@ +/* + +Copyright (c) 2006, 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_SESSION_IMPL_HPP_INCLUDED +#define TORRENT_SESSION_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#ifndef TORRENT_DISABLE_GEO_IP +#include "libtorrent/GeoIP.h" +#endif + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/policy.hpp" +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/peer_info.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/fingerprint.hpp" +#include "libtorrent/debug.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/piece_block_progress.hpp" +#include "libtorrent/ip_filter.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/kademlia/dht_tracker.hpp" +#include "libtorrent/session_status.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/bandwidth_manager.hpp" +#include "libtorrent/natpmp.hpp" +#include "libtorrent/upnp.hpp" +#include "libtorrent/lsd.hpp" +#include "libtorrent/socket_type.hpp" +#include "libtorrent/connection_queue.hpp" +#include "libtorrent/disk_io_thread.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + namespace fs = boost::filesystem; + + namespace aux + { + struct session_impl; + +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + struct tracker_logger; +#endif + + // this is the link between the main thread and the + // thread started to run the main downloader loop + struct session_impl: boost::noncopyable + { + + // the size of each allocation that is chained in the send buffer + enum { send_buffer_size = 200 }; + +#ifndef NDEBUG + friend class ::libtorrent::peer_connection; +#endif + friend struct checker_impl; + friend class invariant_access; + typedef std::set > connection_map; + typedef std::map > torrent_map; + + session_impl( + std::pair listen_port_range + , fingerprint const& cl_fprint + , char const* listen_interface +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + , fs::path const& logpath +#endif + ); + ~session_impl(); + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::function( + torrent*, void*)> ext); +#endif +#ifndef NDEBUG + bool has_peer(peer_connection const* p) const + { + return std::find_if(m_connections.begin(), m_connections.end() + , boost::bind(&boost::intrusive_ptr::get, _1) == p) + != m_connections.end(); + } +#endif + void operator()(); + + void open_listen_port(); + + // if we are listening on an IPv6 interface + // this will return one of the IPv6 addresses on this + // machine, otherwise just an empty endpoint + tcp::endpoint get_ipv6_interface() const; + + void async_accept(boost::shared_ptr const& listener); + void on_incoming_connection(boost::shared_ptr const& s + , boost::weak_ptr listener, error_code const& e); + + // must be locked to access the data + // in this struct + typedef boost::recursive_mutex mutex_t; + mutable mutex_t m_mutex; + + boost::weak_ptr find_torrent(const sha1_hash& info_hash); + peer_id const& get_peer_id() const { return m_peer_id; } + + void close_connection(peer_connection const* p + , char const* message); + + void set_settings(session_settings const& s); + session_settings const& settings() const { return m_settings; } + +#ifndef TORRENT_DISABLE_DHT + void add_dht_node(std::pair const& node); + void add_dht_node(udp::endpoint n); + void add_dht_router(std::pair const& node); + void set_dht_settings(dht_settings const& s); + dht_settings const& get_dht_settings() const { return m_dht_settings; } + void start_dht(entry const& startup_state); + void stop_dht(); + entry dht_state() const; +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + void set_pe_settings(pe_settings const& settings); + pe_settings const& get_pe_settings() const { return m_pe_settings; } +#endif + + // called when a port mapping is successful, or a router returns + // a failure to map a port + void on_port_mapping(int mapping, int port, std::string const& errmsg + , int nat_transport); + + bool is_aborted() const { return m_abort; } + bool is_paused() const { return m_paused; } + + void pause(); + void resume(); + + void set_ip_filter(ip_filter const& f); + void set_port_filter(port_filter const& f); + + bool listen_on( + std::pair const& port_range + , const char* net_interface = 0); + bool is_listening() const; + + torrent_handle add_torrent(add_torrent_params const&); + + void remove_torrent(torrent_handle const& h, int options); + + std::vector get_torrents(); + + void check_torrent(boost::shared_ptr const& t); + void done_checking(boost::shared_ptr const& t); + + void set_severity_level(alert::severity_t s); + std::auto_ptr pop_alert(); + + alert const* wait_for_alert(time_duration max_wait); + + int upload_rate_limit() const; + int download_rate_limit() const; + + void set_download_rate_limit(int bytes_per_second); + void set_upload_rate_limit(int bytes_per_second); + void set_max_half_open_connections(int limit); + void set_max_connections(int limit); + void set_max_uploads(int limit); + + int max_connections() const { return m_max_connections; } + int max_uploads() const { return m_max_uploads; } + int max_half_open_connections() const { return m_half_open.limit(); } + + int num_uploads() const { return m_num_unchoked; } + int num_connections() const + { return m_connections.size(); } + + void unchoke_peer(peer_connection& c) + { + torrent* t = c.associated_torrent().lock().get(); + TORRENT_ASSERT(t); + if (t->unchoke_peer(c)) + ++m_num_unchoked; + } + + session_status status() const; + void set_peer_id(peer_id const& id); + void set_key(int key); + unsigned short listen_port() const; + + void abort(); + + torrent_handle find_torrent_handle(sha1_hash const& info_hash); + + void announce_lsd(sha1_hash const& ih); + + void set_peer_proxy(proxy_settings const& s) + { m_peer_proxy = s; } + void set_web_seed_proxy(proxy_settings const& s) + { m_web_seed_proxy = s; } + void set_tracker_proxy(proxy_settings const& s) + { m_tracker_proxy = s; } + + proxy_settings const& peer_proxy() const + { return m_peer_proxy; } + proxy_settings const& web_seed_proxy() const + { return m_web_seed_proxy; } + proxy_settings const& tracker_proxy() const + { return m_tracker_proxy; } + +#ifndef TORRENT_DISABLE_DHT + void set_dht_proxy(proxy_settings const& s) + { + m_dht_proxy = s; + m_dht_socket.set_proxy_settings(s); + } + proxy_settings const& dht_proxy() const + { return m_dht_proxy; } +#endif + +#ifndef TORRENT_DISABLE_GEO_IP + std::string as_name_for_ip(address const& a); + int as_for_ip(address const& a); + std::pair* lookup_as(int as); + bool load_asnum_db(char const* file); + bool has_asnum_db() const { return m_asnum_db; } + + bool load_country_db(char const* file); + bool has_country_db() const { return m_country_db; } + char const* country_for_ip(address const& a); +#endif + + void load_state(entry const& ses_state); + entry state() const; + +#ifdef TORRENT_STATS + void log_buffer_usage() + { + int send_buffer_capacity = 0; + int used_send_buffer = 0; + for (connection_map::const_iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) + { + send_buffer_capacity += (*i)->send_buffer_capacity(); + used_send_buffer += (*i)->send_buffer_size(); + } + TORRENT_ASSERT(send_buffer_capacity >= used_send_buffer); + m_buffer_usage_logger << log_time() << " send_buffer_size: " << send_buffer_capacity << std::endl; + m_buffer_usage_logger << log_time() << " used_send_buffer: " << used_send_buffer << std::endl; + m_buffer_usage_logger << log_time() << " send_buffer_utilization: " + << (used_send_buffer * 100.f / send_buffer_capacity) << std::endl; + } +#endif + void start_lsd(); + natpmp* start_natpmp(); + upnp* start_upnp(); + + void stop_lsd(); + void stop_natpmp(); + void stop_upnp(); + + int next_port(); + + // handles delayed alerts + alert_manager m_alerts; + + std::pair allocate_buffer(int size); + void free_buffer(char* buf, int size); + + char* allocate_disk_buffer(); + void free_disk_buffer(char* buf); + + void set_external_address(address const& ip); + address const& external_address() const { return m_external_address; } + +// private: + + void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); + +#ifndef TORRENT_DISABLE_POOL_ALLOCATOR + // this pool is used to allocate and recycle send + // buffers from. + boost::pool<> m_send_buffers; +#endif + boost::mutex m_send_buffer_mutex; + + // the file pool that all storages in this session's + // torrents uses. It sets a limit on the number of + // open files by this session. + // file pool must be destructed after the torrents + // since they will still have references to it + // when they are destructed. + file_pool m_files; + + // this is where all active sockets are stored. + // the selector can sleep while there's no activity on + // them + io_service m_io_service; + + // handles disk io requests asynchronously + // peers have pointers into the disk buffer + // pool, and must be destructed before this + // object. The disk thread relies on the file + // pool object, and must be destructed before + // m_files. The disk io thread posts completion + // events to the io service, and needs to be + // constructed after it. + disk_io_thread m_disk_thread; + + // this is a list of half-open tcp connections + // (only outgoing connections) + // this has to be one of the last + // members to be destructed + connection_queue m_half_open; + + // the bandwidth manager is responsible for + // handing out bandwidth to connections that + // asks for it, it can also throttle the + // rate. + bandwidth_manager m_download_channel; + bandwidth_manager m_upload_channel; + + bandwidth_manager* m_bandwidth_manager[2]; + + tracker_manager m_tracker_manager; + torrent_map m_torrents; + typedef std::list > check_queue_t; + check_queue_t m_queued_for_checking; + + // this maps sockets to their peer_connection + // object. It is the complete list of all connected + // peers. + connection_map m_connections; + + // filters incoming connections + ip_filter m_ip_filter; + + // filters outgoing connections + port_filter m_port_filter; + + // the peer id that is generated at the start of the session + peer_id m_peer_id; + + // the key is an id that is used to identify the + // client with the tracker only. It is randomized + // at startup + int m_key; + + // the number of retries we make when binding the + // listen socket. For each retry the port number + // is incremented by one + int m_listen_port_retries; + + // the ip-address of the interface + // we are supposed to listen on. + // if the ip is set to zero, it means + // that we should let the os decide which + // interface to listen on + tcp::endpoint m_listen_interface; + + // if we're listening on an IPv6 interface + // this is one of the non local IPv6 interfaces + // on this machine + tcp::endpoint m_ipv6_interface; + + struct listen_socket_t + { + listen_socket_t(): external_port(0) {} + // this is typically set to the same as the local + // listen port. In case a NAT port forward was + // successfully opened, this will be set to the + // port that is open on the external (NAT) interface + // on the NAT box itself. This is the port that has + // to be published to peers, since this is the port + // the client is reachable through. + int external_port; + + // the actual socket + boost::shared_ptr sock; + }; + // since we might be listening on multiple interfaces + // we might need more than one listen socket + std::list m_listen_sockets; + + listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false); + + // the settings for the client + session_settings m_settings; + // the proxy settings for different + // kinds of connections + proxy_settings m_peer_proxy; + proxy_settings m_web_seed_proxy; + proxy_settings m_tracker_proxy; +#ifndef TORRENT_DISABLE_DHT + proxy_settings m_dht_proxy; +#endif + + // set to true when the session object + // is being destructed and the thread + // should exit + volatile bool m_abort; + + // is true if the session is paused + bool m_paused; + + // the max number of unchoked peers as set by the user + int m_max_uploads; + + // the number of unchoked peers as set by the auto-unchoker + // this should always be >= m_max_uploads + int m_allowed_upload_slots; + + // the max number of connections, as set by the user + int m_max_connections; + + // the number of unchoked peers + int m_num_unchoked; + + // this is initialized to the unchoke_interval + // session_setting and decreased every second. + // when it reaches zero, it is reset to the + // unchoke_interval and the unchoke set is + // recomputed. + int m_unchoke_time_scaler; + + // this is used to decide when to recalculate which + // torrents to keep queued and which to activate + int m_auto_manage_time_scaler; + + // works like unchoke_time_scaler but it + // is only decresed when the unchoke set + // is recomputed, and when it reaches zero, + // the optimistic unchoke is moved to another peer. + int m_optimistic_unchoke_time_scaler; + + // works like unchoke_time_scaler. Each time + // it reaches 0, and all the connections are + // used, the worst connection will be disconnected + // from the torrent with the most peers + int m_disconnect_time_scaler; + + // when this scaler reaches zero, it will + // scrape one of the auto managed, paused, + // torrents. + int m_auto_scrape_time_scaler; + + // statistics gathered from all torrents. + stat m_stat; + + // is false by default and set to true when + // the first incoming connection is established + // this is used to know if the client is behind + // NAT or not. + bool m_incoming_connection; + + void second_tick(error_code const& e); + void recalculate_auto_managed_torrents(); + void recalculate_unchoke_slots(int congested_torrents + , int uncongested_torrents); + + ptime m_last_tick; + + // when outgoing_ports is configured, this is the + // port we'll bind the next outgoing socket to + int m_next_port; + +#ifndef TORRENT_DISABLE_DHT + boost::intrusive_ptr m_dht; + dht_settings m_dht_settings; + // if this is set to true, the dht listen port + // will be set to the same as the tcp listen port + // and will be synchronlized with it as it changes + // it defaults to true + bool m_dht_same_port; + + // see m_external_listen_port. This is the same + // but for the udp port used by the DHT. + int m_external_udp_port; + + udp_socket m_dht_socket; + + void on_receive_udp(error_code const& e + , udp::endpoint const& ep, char const* buf, int len); +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + pe_settings m_pe_settings; +#endif + + boost::intrusive_ptr m_natpmp; + boost::intrusive_ptr m_upnp; + boost::intrusive_ptr m_lsd; + + // 0 is natpmp 1 is upnp + int m_tcp_mapping[2]; + int m_udp_mapping[2]; + + // the timer used to fire the second_tick + deadline_timer m_timer; + + // the index of the torrent that will be offered to + // connect to a peer next time second_tick is called. + // This implements a round robin. + int m_next_connect_torrent; +#ifndef NDEBUG + void check_invariant() const; +#endif + +#ifdef TORRENT_STATS + // logger used to write bandwidth usage statistics + std::ofstream m_stats_logger; + int m_second_counter; + // used to log send buffer usage statistics + std::ofstream m_buffer_usage_logger; + // the number of send buffers that are allocated + int m_buffer_allocations; +#endif +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + boost::shared_ptr create_log(std::string const& name + , int instance, bool append = true); + + // this list of tracker loggers serves as tracker_callbacks when + // shutting down. This list is just here to keep them alive during + // whe shutting down process + std::list > m_tracker_loggers; + + fs::path m_logpath; + public: + boost::shared_ptr m_logger; + private: + +#endif + address m_external_address; + +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list(torrent*, void*)> > extension_list_t; + + extension_list_t m_extensions; +#endif + +#ifndef TORRENT_DISABLE_GEO_IP + GeoIP* m_asnum_db; + GeoIP* m_country_db; + + // maps AS number to the peak download rate + // we've seen from it. Entries are never removed + // from this map. Pointers to its elements + // are kept in the policy::peer structures. + std::map m_as_peak; +#endif + + // the main working thread + boost::scoped_ptr m_thread; + }; + +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + struct tracker_logger : request_callback + { + tracker_logger(session_impl& ses): m_ses(ses) {} + void tracker_warning(tracker_request const& req + , std::string const& str) + { + debug_log("*** tracker warning: " + str); + } + + void tracker_response(tracker_request const& + , std::vector& peers + , int interval + , int complete + , int incomplete + , address const& external_ip) + { + std::stringstream s; + s << "TRACKER RESPONSE:\n" + "interval: " << interval << "\n" + "peers:\n"; + for (std::vector::const_iterator i = peers.begin(); + i != peers.end(); ++i) + { + s << " " << std::setfill(' ') << std::setw(16) << i->ip + << " " << std::setw(5) << std::dec << i->port << " "; + if (!i->pid.is_all_zeros()) s << " " << i->pid; + s << "\n"; + } + s << "external ip: " << external_ip << "\n"; + debug_log(s.str()); + } + + void tracker_request_timed_out( + tracker_request const&) + { + debug_log("*** tracker timed out"); + } + + void tracker_request_error( + tracker_request const& + , int response_code + , const std::string& str) + { + debug_log(std::string("*** tracker error: ") + + boost::lexical_cast(response_code) + ": " + + str); + } + + void debug_log(const std::string& line) + { + (*m_ses.m_logger) << time_now_string() << " " << line << "\n"; + } + session_impl& m_ses; + }; +#endif + + } +} + + +#endif + diff --git a/libtorrent/include/libtorrent/bandwidth_limit.hpp b/libtorrent/include/libtorrent/bandwidth_limit.hpp new file mode 100644 index 000000000..e0675aa31 --- /dev/null +++ b/libtorrent/include/libtorrent/bandwidth_limit.hpp @@ -0,0 +1,120 @@ +/* + +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_BANDWIDTH_LIMIT_HPP_INCLUDED +#define TORRENT_BANDWIDTH_LIMIT_HPP_INCLUDED + +#include + +#include "libtorrent/assert.hpp" + +namespace libtorrent { + +// member of peer_connection +struct bandwidth_limit +{ + static const int inf = boost::integer_traits::const_max; + + bandwidth_limit() + : m_quota_left(0) + , m_local_limit(inf) + , m_current_rate(0) + {} + + void throttle(int limit) + { + TORRENT_ASSERT(limit > 0); + m_local_limit = limit; + } + + int throttle() const + { + return m_local_limit; + } + + void assign(int amount) + { + TORRENT_ASSERT(amount >= 0); + m_current_rate += amount; + m_quota_left += amount; + } + + void use_quota(int amount) + { + TORRENT_ASSERT(amount <= m_quota_left); + m_quota_left -= amount; + } + + int quota_left() const + { + return (std::max)(m_quota_left, 0); + } + + void expire(int amount) + { + TORRENT_ASSERT(amount >= 0); + m_current_rate -= amount; + } + + int max_assignable() const + { + if (m_local_limit == inf) return inf; + if (m_local_limit <= m_current_rate) return 0; + return m_local_limit - m_current_rate; + } + +private: + + // this is the amount of bandwidth we have + // been assigned without using yet. i.e. + // the bandwidth that we use up every time + // we receive or send a message. Once this + // hits zero, we need to request more + // bandwidth from the torrent which + // in turn will request bandwidth from + // the bandwidth manager + int m_quota_left; + + // the local limit is the number of bytes + // per window size we are allowed to use. + int m_local_limit; + + // the current rate is the number of + // bytes we have been assigned within + // the window size. + int m_current_rate; +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp new file mode 100644 index 000000000..ef58337c5 --- /dev/null +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -0,0 +1,492 @@ +/* + +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_BANDWIDTH_MANAGER_HPP_INCLUDED +#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT +#include +#endif + +#include "libtorrent/socket.hpp" +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/bandwidth_limit.hpp" +#include "libtorrent/bandwidth_queue_entry.hpp" + +using boost::weak_ptr; +using boost::shared_ptr; +using boost::intrusive_ptr; +using boost::bind; + + +namespace libtorrent { + +// the maximum block of bandwidth quota to +// hand out is 33kB. The block size may +// be smaller on lower limits +enum +{ + max_bandwidth_block_size = 33000, + min_bandwidth_block_size = 400 +}; + +const time_duration bw_window_size = seconds(1); + +template +struct history_entry +{ + history_entry(intrusive_ptr p, weak_ptr t + , int a, ptime exp) + : expires_at(exp), amount(a), peer(p), tor(t) {} + history_entry(int a, ptime exp) + : expires_at(exp), amount(a), peer(), tor() {} + ptime expires_at; + int amount; + intrusive_ptr peer; + weak_ptr tor; +}; + +template +T clamp(T val, T ceiling, T floor) +{ + TORRENT_ASSERT(ceiling >= floor); + if (val >= ceiling) return ceiling; + else if (val <= floor) return floor; + return val; +} + +template +struct assign_at_exit +{ + assign_at_exit(T& var, T val): var_(var), val_(val) {} + ~assign_at_exit() { var_ = val_; } + T& var_; + T val_; +}; + +template +struct bandwidth_manager +{ + bandwidth_manager(io_service& ios, int channel +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT + , bool log = false +#endif + ) + : m_ios(ios) + , m_history_timer(m_ios) + , m_limit(bandwidth_limit::inf) + , m_drain_quota(0) + , m_current_quota(0) + , m_channel(channel) + , m_in_hand_out_bandwidth(false) + , m_abort(false) + { +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT + if (log) + m_log.open("bandwidth_limiter.log", std::ios::trunc); + m_start = time_now(); +#endif + } + + void drain(int bytes) + { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(bytes >= 0); + m_drain_quota += bytes; + if (m_drain_quota > m_limit * 5) m_drain_quota = m_limit * 5; + } + + void throttle(int limit) + { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(limit >= 0); + m_limit = limit; + } + + int throttle() const + { + mutex_t::scoped_lock l(m_mutex); + return m_limit; + } + + void close() + { + m_abort = true; + m_queue.clear(); + m_history.clear(); + m_current_quota = 0; + m_history_timer.cancel(); + } + +#ifndef NDEBUG + bool is_queued(PeerConnection const* peer) const + { + mutex_t::scoped_lock l(m_mutex); + return is_queued(peer); + } + + bool is_queued(PeerConnection const* peer, boost::mutex::scoped_lock& l) const + { + for (typename queue_t::const_iterator i = m_queue.begin() + , end(m_queue.end()); i != end; ++i) + { + if (i->peer.get() == peer) return true; + } + return false; + } + + bool is_in_history(PeerConnection const* peer) const + { + mutex_t::scoped_lock l(m_mutex); + return is_in_history(peer, l); + } + + bool is_in_history(PeerConnection const* peer, boost::mutex::scoped_lock& l) const + { + for (typename history_t::const_iterator i + = m_history.begin(), end(m_history.end()); i != end; ++i) + { + if (i->peer.get() == peer) return true; + } + return false; + } +#endif + + int queue_size() const + { + mutex_t::scoped_lock l(m_mutex); + return m_queue.size(); + } + + // non prioritized means that, if there's a line for bandwidth, + // others will cut in front of the non-prioritized peers. + // this is used by web seeds + void request_bandwidth(intrusive_ptr const& peer + , int blk, int priority) + { + mutex_t::scoped_lock l(m_mutex); + INVARIANT_CHECK; + if (m_abort) return; + TORRENT_ASSERT(blk > 0); + TORRENT_ASSERT(!is_queued(peer.get(), l)); + + // make sure this peer isn't already in line + // waiting for bandwidth + TORRENT_ASSERT(peer->max_assignable_bandwidth(m_channel) > 0); + + typename queue_t::reverse_iterator i(m_queue.rbegin()); + while (i != m_queue.rend() && priority > i->priority) + { + ++i->priority; + ++i; + } + m_queue.insert(i.base(), bw_queue_entry(peer, blk, priority)); + if (!m_queue.empty()) hand_out_bandwidth(l); + } + +#ifndef NDEBUG + void check_invariant() const + { + int current_quota = 0; + for (typename history_t::const_iterator i + = m_history.begin(), end(m_history.end()); i != end; ++i) + { + current_quota += i->amount; + } + TORRENT_ASSERT(current_quota == m_current_quota); + + typename queue_t::const_iterator j = m_queue.begin(); + if (j != m_queue.end()) + { + ++j; + for (typename queue_t::const_iterator i = m_queue.begin() + , end(m_queue.end()); i != end && j != end; ++i, ++j) + TORRENT_ASSERT(i->priority >= j->priority); + } + } +#endif + +private: + + void add_history_entry(history_entry const& e) + { + INVARIANT_CHECK; + + m_history.push_front(e); + m_current_quota += e.amount; + // in case the size > 1 there is already a timer + // active that will be invoked, no need to set one up + +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT + m_log << std::setw(7) << total_milliseconds(time_now() - m_start) << " + " + " queue: " << std::setw(3) << m_queue.size() + << " used: " << std::setw(7) << m_current_quota + << " limit: " << std::setw(7) << m_limit + << " history: " << std::setw(3) << m_history.size() + << std::endl; +#endif + if (m_history.size() > 1) return; + + if (m_abort) return; + + error_code ec; + m_history_timer.expires_at(e.expires_at, ec); + m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); + } + + void on_history_expire(error_code const& e) + { + if (e) return; + + mutex_t::scoped_lock l(m_mutex); + INVARIANT_CHECK; + if (m_abort) return; + + TORRENT_ASSERT(!m_history.empty()); + + ptime now(time_now()); + while (!m_history.empty() && m_history.back().expires_at <= now) + { + history_entry e = m_history.back(); + m_history.pop_back(); + m_current_quota -= e.amount; + TORRENT_ASSERT(m_current_quota >= 0); + +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT + m_log << std::setw(7) << total_milliseconds(time_now() - m_start) << " - " + " queue: " << std::setw(3) << m_queue.size() + << " used: " << std::setw(7) << m_current_quota + << " limit: " << std::setw(7) << m_limit + << " history: " << std::setw(3) << m_history.size() + << std::endl; +#endif + intrusive_ptr c = e.peer; + if (!c) continue; + shared_ptr t = e.tor.lock(); + l.unlock(); + if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); + if (t) t->expire_bandwidth(m_channel, e.amount); + l.lock(); + } + + // now, wait for the next chunk to expire + if (!m_history.empty() && !m_abort) + { + error_code ec; + m_history_timer.expires_at(m_history.back().expires_at, ec); + m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); + } + + // since some bandwidth just expired, it + // means we can hand out more (in case there + // are still consumers in line) + if (!m_queue.empty()) hand_out_bandwidth(l); + } + + void hand_out_bandwidth(boost::mutex::scoped_lock& l) + { + // if we're already handing out bandwidth, just return back + // to the loop further down on the callstack + if (m_in_hand_out_bandwidth) return; + m_in_hand_out_bandwidth = true; + // set it to false when exiting function + assign_at_exit sg(m_in_hand_out_bandwidth, false); + + INVARIANT_CHECK; + + ptime now(time_now()); + + int limit = m_limit; + + // available bandwidth to hand out + int amount = limit - m_current_quota; + + if (amount <= 0) return; + + if (m_drain_quota > 0) + { + int drain_amount = (std::min)(m_drain_quota, amount); + m_drain_quota -= drain_amount; + amount -= drain_amount; + add_history_entry(history_entry( + drain_amount, now + bw_window_size)); + } + + queue_t tmp; + while (!m_queue.empty() && amount > 0) + { + bw_queue_entry qe = m_queue.front(); + TORRENT_ASSERT(qe.max_block_size > 0); + m_queue.pop_front(); + + shared_ptr t = qe.torrent.lock(); + if (!t) continue; + if (qe.peer->is_disconnecting()) + { + l.unlock(); + t->expire_bandwidth(m_channel, qe.max_block_size); + l.lock(); + continue; + } + + // at this point, max_assignable may actually be zero. Since + // the rate limit of the peer might have changed while it + // was in the queue. + int max_assignable = qe.peer->max_assignable_bandwidth(m_channel); + if (max_assignable == 0) + { + TORRENT_ASSERT(is_in_history(qe.peer.get(), l)); + tmp.push_back(qe); + continue; + } + + // this is the limit of the block size. It depends on the throttle + // so that it can be closer to optimal. Larger block sizes will give lower + // granularity to the rate but will be more efficient. At high rates + // the block sizes are bigger and at low rates, the granularity + // is more important and block sizes are smaller + + // the minimum rate that can be given is the block size, so, the + // block size must be smaller for lower rates. This is because + // the history window is one second, and the block will be forgotten + // after one second. + int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel) + , limit / 10); + + if (block_size < min_bandwidth_block_size) + { + block_size = (std::min)(int(min_bandwidth_block_size), limit); + } + else if (block_size > max_bandwidth_block_size) + { + if (limit == bandwidth_limit::inf) + { + block_size = max_bandwidth_block_size; + } + else + { + // try to make the block_size a divisor of + // m_limit to make the distributions as fair + // as possible + // TODO: move this calculcation to where the limit + // is changed + block_size = limit + / (limit / max_bandwidth_block_size); + } + } + if (block_size > qe.max_block_size) block_size = qe.max_block_size; + + if (amount < block_size / 4) + { + tmp.push_back(qe); +// m_queue.push_front(qe); + break; + } + + // so, hand out max_assignable, but no more than + // the available bandwidth (amount) and no more + // than the max_bandwidth_block_size + int hand_out_amount = (std::min)((std::min)(block_size, max_assignable) + , amount); + TORRENT_ASSERT(hand_out_amount > 0); + amount -= hand_out_amount; + TORRENT_ASSERT(hand_out_amount <= qe.max_block_size); + l.unlock(); + t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size); + qe.peer->assign_bandwidth(m_channel, hand_out_amount); + l.lock(); + add_history_entry(history_entry( + qe.peer, t, hand_out_amount, now + bw_window_size)); + } + if (!tmp.empty()) m_queue.insert(m_queue.begin(), tmp.begin(), tmp.end()); + } + + + typedef boost::mutex mutex_t; + mutable mutex_t m_mutex; + + // the io_service used for the timer + io_service& m_ios; + + // the timer that is waiting for the entries + // in the history queue to expire (slide out + // of the history window) + deadline_timer m_history_timer; + + // the rate limit (bytes per second) + int m_limit; + + // bytes to drain without handing out to a peer + // used to deduct the IP overhead + int m_drain_quota; + + // the sum of all recently handed out bandwidth blocks + int m_current_quota; + + // these are the consumers that want bandwidth + typedef std::deque > queue_t; + queue_t m_queue; + + // these are the consumers that have received bandwidth + // that will expire + typedef std::deque > history_t; + history_t m_history; + + // this is the channel within the consumers + // that bandwidth is assigned to (upload or download) + int m_channel; + + // this is true while we're in the hand_out_bandwidth loop + // to prevent recursive invocations to interfere + bool m_in_hand_out_bandwidth; + + bool m_abort; + +#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT + std::ofstream m_log; + ptime m_start; +#endif +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp b/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp new file mode 100644 index 000000000..54f669062 --- /dev/null +++ b/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp @@ -0,0 +1,56 @@ +/* + +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_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED +#define TORRENT_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED + +#include + +namespace libtorrent { + +template +struct bw_queue_entry +{ + bw_queue_entry(boost::intrusive_ptr const& pe + , int blk, int prio) + : peer(pe), torrent(peer->associated_torrent()) + , max_block_size(blk), priority(prio) {} + boost::intrusive_ptr peer; + boost::weak_ptr torrent; + int max_block_size; + int priority; // 0 is low prio +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/bencode.hpp b/libtorrent/include/libtorrent/bencode.hpp new file mode 100644 index 000000000..9443e7a65 --- /dev/null +++ b/libtorrent/include/libtorrent/bencode.hpp @@ -0,0 +1,415 @@ +/* + +Copyright (c) 2003, 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_BENCODE_HPP_INCLUDED +#define TORRENT_BENCODE_HPP_INCLUDED + + + +/* + * This file declares the following functions: + * + *---------------------------------- + * template + * void libtorrent::bencode(OutIt out, const libtorrent::entry& e); + * + * Encodes a message entry with bencoding into the output + * iterator given. The bencoding is described in the BitTorrent + * protocol description document OutIt must be an OutputIterator + * of type char. This may throw libtorrent::invalid_encoding if + * the entry contains invalid nodes (undefined_t for example). + * + *---------------------------------- + * template + * libtorrent::entry libtorrent::bdecode(InIt start, InIt end); + * + * Decodes the buffer given by the start and end iterators + * and returns the decoded entry. InIt must be an InputIterator + * of type char. May throw libtorrent::invalid_encoding if + * the string is not correctly bencoded. + * + */ + + + + +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/entry.hpp" +#include "libtorrent/config.hpp" + +#include "libtorrent/assert.hpp" + +#if defined(_MSC_VER) +namespace std +{ + using ::isdigit; + using ::atoi; +}; + +#define for if (false) {} else for +#endif + + +namespace libtorrent +{ + + struct TORRENT_EXPORT invalid_encoding: std::exception + { + virtual const char* what() const throw() { return "invalid bencoding"; } + }; + + namespace detail + { + template + int write_string(OutIt& out, const std::string& val) + { + int ret = val.length(); + std::string::const_iterator end = val.begin() + ret; + for (std::string::const_iterator i = val.begin() + , end(val.begin() + ret); i != end; ++i) + *out++ = *i; + return ret; + } + + TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val); + + template + int write_integer(OutIt& out, entry::integer_type val) + { + // the stack allocated buffer for keeping the + // decimal representation of the number can + // not hold number bigger than this: + BOOST_STATIC_ASSERT(sizeof(entry::integer_type) <= 8); + char buf[21]; + int ret = 0; + for (char const* str = integer_to_str(buf, 21, val); + *str != 0; ++str) + { + *out = *str; + ++out; + ++ret; + } + return ret; + } + + template + void write_char(OutIt& out, char c) + { + *out = c; + ++out; + } + + template + std::string read_until(InIt& in, InIt end, char end_token, bool& err) + { + std::string ret; + if (in == end) + { + err = true; + return ret; + } + while (*in != end_token) + { + ret += *in; + ++in; + if (in == end) + { + err = true; + return ret; + } + } + return ret; + } + + template + void read_string(InIt& in, InIt end, int len, std::string& str, bool& err) + { + TORRENT_ASSERT(len >= 0); + for (int i = 0; i < len; ++i) + { + if (in == end) + { + err = true; + return; + } + str += *in; + ++in; + } + } + + // returns the number of bytes written + template + int bencode_recursive(OutIt& out, const entry& e) + { + int ret = 0; + switch(e.type()) + { + case entry::int_t: + write_char(out, 'i'); + ret += write_integer(out, e.integer()); + write_char(out, 'e'); + ret += 2; + break; + case entry::string_t: + ret += write_integer(out, e.string().length()); + write_char(out, ':'); + ret += write_string(out, e.string()); + ret += 1; + break; + case entry::list_t: + write_char(out, 'l'); + for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i) + ret += bencode_recursive(out, *i); + write_char(out, 'e'); + ret += 2; + break; + case entry::dictionary_t: + write_char(out, 'd'); + for (entry::dictionary_type::const_iterator i = e.dict().begin(); + i != e.dict().end(); ++i) + { + // write key + ret += write_integer(out, i->first.length()); + write_char(out, ':'); + ret += write_string(out, i->first); + // write value + ret += bencode_recursive(out, i->second); + ret += 1; + } + write_char(out, 'e'); + ret += 2; + break; + default: + // do nothing + break; + } + return ret; + } + + template + void bdecode_recursive(InIt& in, InIt end, entry& ret, bool& err, int depth) + { + if (depth >= 100) + { + err = true; + return; + } + + if (in == end) + { + err = true; +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + switch (*in) + { + + // ---------------------------------------------- + // integer + case 'i': + { + ++in; // 'i' + std::string val = read_until(in, end, 'e', err); + if (err) return; + TORRENT_ASSERT(*in == 'e'); + ++in; // 'e' + ret = entry(entry::int_t); + ret.integer() = boost::lexical_cast(val); +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + } break; + + // ---------------------------------------------- + // list + case 'l': + { + ret = entry(entry::list_t); + ++in; // 'l' + while (*in != 'e') + { + ret.list().push_back(entry()); + entry& e = ret.list().back(); + bdecode_recursive(in, end, e, err, depth + 1); + if (err) + { +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + if (in == end) + { + err = true; +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + } +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + TORRENT_ASSERT(*in == 'e'); + ++in; // 'e' + } break; + + // ---------------------------------------------- + // dictionary + case 'd': + { + ret = entry(entry::dictionary_t); + ++in; // 'd' + while (*in != 'e') + { + entry key; + bdecode_recursive(in, end, key, err, depth + 1); + if (err || key.type() != entry::string_t) + { +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + entry& e = ret[key.string()]; + bdecode_recursive(in, end, e, err, depth + 1); + if (err) + { +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + if (in == end) + { + err = true; +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + } +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + TORRENT_ASSERT(*in == 'e'); + ++in; // 'e' + } break; + + // ---------------------------------------------- + // string + default: + if (isdigit((unsigned char)*in)) + { + std::string len_s = read_until(in, end, ':', err); + if (err) + { +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + TORRENT_ASSERT(*in == ':'); + ++in; // ':' + int len = std::atoi(len_s.c_str()); + ret = entry(entry::string_t); + read_string(in, end, len, ret.string(), err); + if (err) + { +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } + } + else + { + err = true; +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + return; + } +#ifndef NDEBUG + ret.m_type_queried = false; +#endif + } + } + } + + template + int bencode(OutIt out, const entry& e) + { + return detail::bencode_recursive(out, e); + } + + template + entry bdecode(InIt start, InIt end) + { + entry e; + bool err = false; + detail::bdecode_recursive(start, end, e, err, 0); + TORRENT_ASSERT(e.m_type_queried == false); + if (err) return entry(); + return e; + } + + template + entry bdecode(InIt start, InIt end, int& len) + { + entry e; + bool err = false; + InIt s = start; + detail::bdecode_recursive(start, end, e, err, 0); + len = std::distance(s, start); + TORRENT_ASSERT(len >= 0); + if (err) return entry(); + return e; + } +} + +#endif // TORRENT_BENCODE_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/bitfield.hpp b/libtorrent/include/libtorrent/bitfield.hpp new file mode 100644 index 000000000..fe14cfe1c --- /dev/null +++ b/libtorrent/include/libtorrent/bitfield.hpp @@ -0,0 +1,241 @@ +/* + +Copyright (c) 2008, 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_BITFIELD_HPP_INCLUDED +#define TORRENT_BITFIELD_HPP_INCLUDED + +#include "libtorrent/assert.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + struct TORRENT_EXPORT bitfield + { + bitfield(): m_bytes(0), m_size(0), m_own(false) {} + bitfield(int bits): m_bytes(0), m_size(0) + { resize(bits); } + bitfield(int bits, bool val): m_bytes(0), m_size(0) + { resize(bits, val); } + bitfield(char const* bytes, int bits): m_bytes(0), m_size(0) + { assign(bytes, bits); } + bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false) + { assign(rhs.bytes(), rhs.size()); } + + void borrow_bytes(char* bytes, int bits) + { + dealloc(); + m_bytes = (unsigned char*)bytes; + m_size = bits; + m_own = false; + } + ~bitfield() { dealloc(); } + + void assign(char const* bytes, int bits) + { resize(bits); memcpy(m_bytes, bytes, (bits + 7) / 8); } + + bool operator[](int index) const + { return get_bit(index); } + + bool get_bit(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + return m_bytes[index / 8] & (0x80 >> (index & 7)); + } + + void clear_bit(int index) + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + m_bytes[index / 8] &= ~(0x80 >> (index & 7)); + } + + void set_bit(int index) + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + m_bytes[index / 8] |= (0x80 >> (index & 7)); + } + + std::size_t size() const { return m_size; } + bool empty() const { return m_size == 0; } + + char const* bytes() const { return (char*)m_bytes; } + + bitfield& operator=(bitfield const& rhs) + { + assign(rhs.bytes(), rhs.size()); + return *this; + } + + int count() const + { + // 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, + // 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111 + const static char num_bits[] = + { + 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 + }; + + int ret = 0; + const int num_bytes = m_size / 8; + for (int i = 0; i < num_bytes; ++i) + { + ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4]; + } + + int rest = m_size - num_bytes * 8; + for (int i = 0; i < rest; ++i) + { + ret += (m_bytes[num_bytes] >> (7-i)) & 1; + } + TORRENT_ASSERT(ret <= m_size); + TORRENT_ASSERT(ret >= 0); + return ret; + } + + struct const_iterator + { + friend struct bitfield; + + typedef bool value_type; + typedef ptrdiff_t difference_type; + typedef bool const* pointer; + typedef bool& reference; + typedef std::forward_iterator_tag iterator_category; + + bool operator*() { return *byte & bit; } + const_iterator& operator++() { inc(); return *this; } + const_iterator operator++(int) + { const_iterator ret(*this); inc(); return ret; } + const_iterator& operator--() { dec(); return *this; } + const_iterator operator--(int) + { const_iterator ret(*this); dec(); return ret; } + + const_iterator(): byte(0), bit(0x80) {} + bool operator==(const_iterator const& rhs) const + { return byte == rhs.byte && bit == rhs.bit; } + + bool operator!=(const_iterator const& rhs) const + { return byte != rhs.byte || bit != rhs.bit; } + + private: + void inc() + { + TORRENT_ASSERT(byte); + if (bit == 0x01) + { + bit = 0x80; + ++byte; + } + else + { + bit >>= 1; + } + } + void dec() + { + TORRENT_ASSERT(byte); + if (bit == 0x80) + { + bit = 0x01; + --byte; + } + else + { + bit <<= 1; + } + } + const_iterator(unsigned char const* ptr, int offset) + : byte(ptr), bit(0x80 >> offset) {} + unsigned char const* byte; + int bit; + }; + + const_iterator begin() const { return const_iterator(m_bytes, 0); } + const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); } + + void resize(int bits, bool val) + { + resize(bits); + if (val) set_all(); else clear_all(); + } + + void set_all() + { + memset(m_bytes, 0xff, (m_size + 7) / 8); + } + + void clear_all() + { + memset(m_bytes, 0x00, (m_size + 7) / 8); + } + + void resize(int bits) + { + const int bytes = (bits + 7) / 8; + if (m_bytes) + { + if (m_own) + { + m_bytes = (unsigned char*)realloc(m_bytes, bytes); + m_own = true; + } + else if (bits > m_size) + { + unsigned char* tmp = (unsigned char*)malloc(bytes); + memcpy(tmp, m_bytes, (std::min)((m_size + 7)/ 8, bytes)); + m_bytes = tmp; + m_own = true; + } + } + else + { + m_bytes = (unsigned char*)malloc(bytes); + m_own = true; + } + m_size = bits; + } + + private: + + void dealloc() { if (m_own) free(m_bytes); m_bytes = 0; } + unsigned char* m_bytes; + int m_size; // in bits + bool m_own; + }; + +} + +#endif // TORRENT_BITFIELD_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp new file mode 100644 index 000000000..3a8d6a76e --- /dev/null +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -0,0 +1,107 @@ +/* + +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_BROADCAST_SOCKET_HPP_INCLUDED +#define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED + +#include "libtorrent/config.hpp" +#include "libtorrent/socket.hpp" +#include +#include +#include + +namespace libtorrent +{ + + TORRENT_EXPORT bool is_local(address const& a); + TORRENT_EXPORT bool is_loopback(address const& addr); + TORRENT_EXPORT bool is_multicast(address const& addr); + TORRENT_EXPORT bool is_any(address const& addr); + TORRENT_EXPORT int cidr_distance(address const& a1, address const& a2); + + int common_bits(unsigned char const* b1 + , unsigned char const* b2, int n); + + TORRENT_EXPORT address guess_local_address(io_service&); + + typedef boost::function receive_handler_t; + + class TORRENT_EXPORT broadcast_socket + { + public: + broadcast_socket(io_service& ios, udp::endpoint const& multicast_endpoint + , receive_handler_t const& handler, bool loopback = true); + ~broadcast_socket() { close(); } + + void send(char const* buffer, int size, error_code& ec); + void close(); + + private: + + struct socket_entry + { + socket_entry(boost::shared_ptr const& s): socket(s) {} + boost::shared_ptr socket; + char buffer[1024]; + udp::endpoint remote; + void close() + { + if (!socket) return; + error_code ec; + socket->close(ec); + } + }; + + void on_receive(socket_entry* s, error_code const& ec + , std::size_t bytes_transferred); + void open_unicast_socket(io_service& ios, address const& addr); + void open_multicast_socket(io_service& ios, address const& addr + , bool loopback); + + // these sockets are used to + // join the multicast group (on each interface) + // and receive multicast messages + std::list m_sockets; + // these sockets are not bound to any + // specific port and are used to + // send messages to the multicast group + // and receive unicast responses + std::list m_unicast_sockets; + udp::endpoint m_multicast_endpoint; + receive_handler_t m_on_receive; + + }; +} + +#endif + diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp new file mode 100644 index 000000000..c45f7cb31 --- /dev/null +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -0,0 +1,424 @@ +/* + +Copyright (c) 2003 - 2006, Arvid Norberg +Copyright (c) 2007, Arvid Norberg, Un Shyam +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_BT_PEER_CONNECTION_HPP_INCLUDED +#define TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#include "libtorrent/debug.hpp" + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/buffer.hpp" +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/piece_block_progress.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/pe_crypto.hpp" + +namespace libtorrent +{ + class torrent; + + namespace detail + { + struct session_impl; + } + + class TORRENT_EXPORT bt_peer_connection + : public peer_connection + { + friend class invariant_access; + public: + + // this is the constructor where the we are the active part. + // The peer_conenction should handshake and verify that the + // other end has the correct id + bt_peer_connection( + aux::session_impl& ses + , boost::weak_ptr t + , boost::shared_ptr 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 s + , tcp::endpoint const& remote + , policy::peer* peerinfo); + + void start(); + + ~bt_peer_connection(); + +#ifndef TORRENT_DISABLE_ENCRYPTION + bool supports_encryption() const + { return m_encrypted; } +#endif + + enum message_type + { + // standard messages + msg_choke = 0, + msg_unchoke, + msg_interested, + msg_not_interested, + msg_have, + msg_bitfield, + msg_request, + msg_piece, + msg_cancel, + // DHT extension + msg_dht_port, + // FAST extension + msg_suggest_piece = 0xd, + msg_have_all, + msg_have_none, + msg_reject_request, + msg_allowed_fast, + + // extension protocol message + msg_extended = 20, + + num_supported_messages + }; + + // called from the main loop when this connection has any + // work to do. + + void on_sent(error_code const& error + , std::size_t bytes_transferred); + void on_receive(error_code const& error + , std::size_t bytes_transferred); + + virtual void get_specific_peer_info(peer_info& p) const; + virtual bool in_handshake() const; + +#ifndef TORRENT_DISABLE_EXTENSIONS + bool support_extensions() const { return m_supports_extensions; } + + template + T* supports_extension() const + { + for (extension_list_t::const_iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + T* ret = dynamic_cast(i->get()); + if (ret) return ret; + } + return 0; + } +#endif + + // the message handlers are called + // each time a recv() returns some new + // data, the last time it will be called + // is when the entire packet has been + // received, then it will no longer + // be called. i.e. most handlers need + // to check how much of the packet they + // have received before any processing + void on_keepalive(); + void on_choke(int received); + void on_unchoke(int received); + void on_interested(int received); + void on_not_interested(int received); + void on_have(int received); + void on_bitfield(int received); + void on_request(int received); + void on_piece(int received); + void on_cancel(int received); + + // DHT extension + void on_dht_port(int received); + + // FAST extension + void on_suggest_piece(int received); + void on_have_all(int received); + void on_have_none(int received); + void on_reject_request(int received); + void on_allowed_fast(int received); + + void on_extended(int received); + + void on_extended_handshake(); + + typedef void (bt_peer_connection::*message_handler)(int received); + + // the following functions appends messages + // to the send buffer + void write_choke(); + void write_unchoke(); + void write_interested(); + void write_not_interested(); + void write_request(peer_request const& r); + void write_cancel(peer_request const& r); + void write_bitfield(); + void write_have(int index); + void write_piece(peer_request const& r, disk_buffer_holder& buffer); + void write_handshake(); +#ifndef TORRENT_DISABLE_EXTENSIONS + void write_extensions(); +#endif + void write_chat_message(const std::string& msg); + void write_metadata(std::pair req); + void write_metadata_request(std::pair req); + void write_keepalive(); + + // DHT extension + void write_dht_port(int listen_port); + + // FAST extension + void write_have_all(); + void write_have_none(); + void write_reject_request(peer_request const&); + void write_allow_fast(int piece); + + void on_connected(); + void on_metadata(); + +#ifndef NDEBUG + void check_invariant() const; + ptime m_last_choke; +#endif + + private: + + bool dispatch_message(int received); + // returns the block currently being + // downloaded. And the progress of that + // block. If the peer isn't downloading + // a piece for the moment, the boost::optional + // will be invalid. + boost::optional downloading_piece_progress() const; + +#ifndef TORRENT_DISABLE_ENCRYPTION + + // if (is_local()), we are 'a' otherwise 'b' + // + // 1. a -> b dhkey, pad + // 2. b -> a dhkey, pad + // 3. a -> b sync, payload + // 4. b -> a sync, payload + // 5. a -> b payload + + void write_pe1_2_dhkey(); + void write_pe3_sync(); + void write_pe4_sync(int crypto_select); + + void write_pe_vc_cryptofield(buffer::interval& write_buf, + int crypto_field, int pad_size); + + // stream key (info hash of attached torrent) + // secret is the DH shared secret + // initializes m_RC4_handler + void init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key); + +public: + + // these functions encrypt the send buffer if m_rc4_encrypted + // is true, otherwise it passes the call to the + // peer_connection functions of the same names + void send_buffer(char* buf, int size); + buffer::interval allocate_send_buffer(int size); + template + void append_send_buffer(char* buffer, int size, Destructor const& destructor) + { +#ifndef TORRENT_DISABLE_ENCRYPTION + if (m_rc4_encrypted) + m_RC4_handler->encrypt(buffer, size); +#endif + peer_connection::append_send_buffer(buffer, size, destructor); + } + void setup_send(); + +private: + + // Returns offset at which bytestream (src, src + src_size) + // matches bytestream(target, target + target_size). + // If no sync found, return -1 + int get_syncoffset(char const* src, int src_size, + char const* target, int target_size) const; +#endif + + enum state + { +#ifndef TORRENT_DISABLE_ENCRYPTION + read_pe_dhkey = 0, + read_pe_syncvc, + read_pe_synchash, + read_pe_skey_vc, + read_pe_cryptofield, + read_pe_pad, + read_pe_ia, + init_bt_handshake, + read_protocol_identifier, +#else + read_protocol_identifier = 0, +#endif + read_info_hash, + read_peer_id, + + // handshake complete + read_packet_size, + read_packet + }; + +#ifndef TORRENT_DISABLE_ENCRYPTION + enum + { + handshake_len = 68, + dh_key_len = 96 + }; +#endif + + std::string m_client_version; + + // state of on_receive + state m_state; + + // the timeout in seconds + int m_timeout; + + static const message_handler m_message_handler[num_supported_messages]; + + // this is a queue of ranges that describes + // where in the send buffer actual payload + // data is located. This is currently + // only used to be able to gather statistics + // seperately on payload and protocol data. + struct range + { + range(int s, int l) + : start(s) + , length(l) + { + TORRENT_ASSERT(s >= 0); + TORRENT_ASSERT(l > 0); + } + int start; + int length; + }; + static bool range_below_zero(const range& r) + { return r.start < 0; } + std::deque m_payloads; + +#ifndef TORRENT_DISABLE_EXTENSIONS + // this is set to true if the handshake from + // the peer indicated that it supports the + // extension protocol + bool m_supports_extensions; + char m_reserved_bits[20]; +#endif + bool m_supports_dht_port; + bool m_supports_fast; + +#ifndef TORRENT_DISABLE_ENCRYPTION + // this is set to true after the encryption method has been + // succesfully negotiated (either plaintext or rc4), to signal + // automatic encryption/decryption. + bool m_encrypted; + + // true if rc4, false if plaintext + bool m_rc4_encrypted; + + // used to disconnect peer if sync points are not found within + // the maximum number of bytes + int m_sync_bytes_read; + + // hold information about latest allocated send buffer + // need to check for non zero (begin, end) for operations with this + buffer::interval m_enc_send_buffer; + + // initialized during write_pe1_2_dhkey, and destroyed on + // creation of m_RC4_handler. Cannot reinitialize once + // initialized. + boost::scoped_ptr m_dh_key_exchange; + + // if RC4 is negotiated, this is used for + // encryption/decryption during the entire session. Destroyed + // if plaintext is selected + boost::scoped_ptr m_RC4_handler; + + // (outgoing only) synchronize verification constant with + // remote peer, this will hold RC4_decrypt(vc). Destroyed + // after the sync step. + boost::scoped_array m_sync_vc; + + // (incoming only) synchronize hash with remote peer, holds + // the sync hash (hash("req1",secret)). Destroyed after the + // sync step. + boost::scoped_ptr m_sync_hash; +#endif // #ifndef TORRENT_DISABLE_ENCRYPTION + +#ifndef NDEBUG + // this is set to true when the client's + // bitfield is sent to this peer + bool m_sent_bitfield; + + bool m_in_constructor; + + bool m_sent_handshake; +#endif + + }; +} + +#endif // TORRENT_BT_PEER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/buffer.hpp b/libtorrent/include/libtorrent/buffer.hpp new file mode 100644 index 000000000..425a6a634 --- /dev/null +++ b/libtorrent/include/libtorrent/buffer.hpp @@ -0,0 +1,205 @@ +/* +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 Rasterbar Software 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 LIBTORRENT_BUFFER_HPP +#define LIBTORRENT_BUFFER_HPP + +#include +#include +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent { + +class buffer +{ +public: + struct interval + { + interval() + : begin(0) + , end(0) + {} + + interval(char* begin, char* end) + : begin(begin) + , end(end) + {} + + char operator[](int index) const + { + TORRENT_ASSERT(begin + index < end); + return begin[index]; + } + + int left() const { TORRENT_ASSERT(end >= begin); return end - begin; } + + char* begin; + char* end; + }; + + struct const_interval + { + const_interval(char const* begin, char const* end) + : begin(begin) + , end(end) + {} + + char operator[](int index) const + { + TORRENT_ASSERT(begin + index < end); + return begin[index]; + } + + bool operator==(const const_interval& p_interval) + { + return (begin == p_interval.begin + && end == p_interval.end); + } + + int left() const { TORRENT_ASSERT(end >= begin); return end - begin; } + + char const* begin; + char const* end; + }; + + buffer(std::size_t n = 0) + : m_begin(0) + , m_end(0) + , m_last(0) + { + if (n) resize(n); + } + + buffer(buffer const& b) + : m_begin(0) + , m_end(0) + , m_last(0) + { + if (b.size() == 0) return; + resize(b.size()); + std::memcpy(m_begin, b.begin(), b.size()); + } + + buffer& operator=(buffer const& b) + { + resize(b.size()); + std::memcpy(m_begin, b.begin(), b.size()); + return *this; + } + + ~buffer() + { + ::operator delete (m_begin); + } + + buffer::interval data() { return interval(m_begin, m_end); } + buffer::const_interval data() const { return const_interval(m_begin, m_end); } + + void resize(std::size_t n) + { + reserve(n); + m_end = m_begin + n; + } + + void insert(char* point, char const* first, char const* last) + { + std::size_t p = point - m_begin; + if (point == m_end) + { + resize(size() + last - first); + std::memcpy(m_begin + p, first, last - first); + return; + } + + resize(size() + last - first); + std::memmove(m_begin + p + (last - first), m_begin + p, last - first); + std::memcpy(m_begin + p, first, last - first); + } + + void erase(char* begin, char* end) + { + TORRENT_ASSERT(end <= m_end); + TORRENT_ASSERT(begin >= m_begin); + TORRENT_ASSERT(begin <= end); + if (end == m_end) + { + resize(begin - m_begin); + return; + } + std::memmove(begin, end, m_end - end); + m_end = begin + (m_end - end); + } + + void clear() { m_end = m_begin; } + std::size_t size() const { return m_end - m_begin; } + std::size_t capacity() const { return m_last - m_begin; } + void reserve(std::size_t n) + { + if (n <= capacity()) return; + TORRENT_ASSERT(n > 0); + + char* buf = (char*)::operator new(n); + std::size_t s = size(); + std::memcpy(buf, m_begin, s); + ::operator delete (m_begin); + m_begin = buf; + m_end = buf + s; + m_last = m_begin + n; + } + + bool empty() const { return m_begin == m_end; } + char& operator[](std::size_t i) { TORRENT_ASSERT(i < size()); return m_begin[i]; } + char const& operator[](std::size_t i) const { TORRENT_ASSERT(i < size()); return m_begin[i]; } + + char* begin() { return m_begin; } + char const* begin() const { return m_begin; } + char* end() { return m_end; } + char const* end() const { return m_end; } + + void swap(buffer& b) + { + using std::swap; + swap(m_begin, b.m_begin); + swap(m_end, b.m_end); + swap(m_last, b.m_last); + } +private: + char* m_begin; // first + char* m_end; // one passed end of size + char* m_last; // one passed end of allocation +}; + + +} + +#endif // LIBTORRENT_BUFFER_HPP + diff --git a/libtorrent/include/libtorrent/chained_buffer.hpp b/libtorrent/include/libtorrent/chained_buffer.hpp new file mode 100644 index 000000000..caf2e89be --- /dev/null +++ b/libtorrent/include/libtorrent/chained_buffer.hpp @@ -0,0 +1,200 @@ +/* + +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_CHAINED_BUFFER_HPP_INCLUDED +#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED + +#include +#include +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif +#include +#include + +namespace libtorrent +{ +#if BOOST_VERSION >= 103500 + namespace asio = boost::asio; +#endif + struct chained_buffer + { + chained_buffer(): m_bytes(0), m_capacity(0) {} + + struct buffer_t + { + boost::function free; // destructs the buffer + char* buf; // the first byte of the buffer + int size; // the total size of the buffer + + char* start; // the first byte to send/receive in the buffer + int used_size; // this is the number of bytes to send/receive + }; + + bool empty() const { return m_bytes == 0; } + int size() const { return m_bytes; } + int capacity() const { return m_capacity; } + + void pop_front(int bytes_to_pop) + { + TORRENT_ASSERT(bytes_to_pop <= m_bytes); + while (bytes_to_pop > 0 && !m_vec.empty()) + { + buffer_t& b = m_vec.front(); + if (b.used_size > bytes_to_pop) + { + b.start += bytes_to_pop; + b.used_size -= bytes_to_pop; + m_bytes -= bytes_to_pop; + TORRENT_ASSERT(m_bytes <= m_capacity); + TORRENT_ASSERT(m_bytes >= 0); + TORRENT_ASSERT(m_capacity >= 0); + break; + } + + b.free(b.buf); + m_bytes -= b.used_size; + m_capacity -= b.size; + bytes_to_pop -= b.used_size; + TORRENT_ASSERT(m_bytes >= 0); + TORRENT_ASSERT(m_capacity >= 0); + TORRENT_ASSERT(m_bytes <= m_capacity); + m_vec.pop_front(); + } + } + + template + void append_buffer(char* buffer, int size, int used_size, D const& destructor) + { + TORRENT_ASSERT(size >= used_size); + buffer_t b; + b.buf = buffer; + b.size = size; + b.start = buffer; + b.used_size = used_size; + b.free = destructor; + m_vec.push_back(b); + + m_bytes += used_size; + m_capacity += size; + TORRENT_ASSERT(m_bytes <= m_capacity); + } + + // returns the number of bytes available at the + // end of the last chained buffer. + int space_in_last_buffer() + { + if (m_vec.empty()) return 0; + buffer_t& b = m_vec.back(); + return b.size - b.used_size - (b.start - b.buf); + } + + // tries to copy the given buffer to the end of the + // last chained buffer. If there's not enough room + // it returns false + bool append(char const* buf, int size) + { + char* insert = allocate_appendix(size); + if (insert == 0) return false; + std::memcpy(insert, buf, size); + return true; + } + + // tries to allocate memory from the end + // of the last buffer. If there isn't + // enough room, returns 0 + char* allocate_appendix(int size) + { + if (m_vec.empty()) return 0; + buffer_t& b = m_vec.back(); + char* insert = b.start + b.used_size; + if (insert + size > b.buf + b.size) return 0; + b.used_size += size; + m_bytes += size; + TORRENT_ASSERT(m_bytes <= m_capacity); + return insert; + } + + std::list const& build_iovec(int to_send) + { + m_tmp_vec.clear(); + + for (std::list::iterator i = m_vec.begin() + , end(m_vec.end()); to_send > 0 && i != end; ++i) + { + if (i->used_size > to_send) + { + TORRENT_ASSERT(to_send > 0); + m_tmp_vec.push_back(asio::const_buffer(i->start, to_send)); + break; + } + TORRENT_ASSERT(i->used_size > 0); + m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size)); + to_send -= i->used_size; + } + return m_tmp_vec; + } + + ~chained_buffer() + { + for (std::list::iterator i = m_vec.begin() + , end(m_vec.end()); i != end; ++i) + { + i->free(i->buf); + } + } + + private: + + // this is the list of all the buffers we want to + // send + std::list m_vec; + + // this is the number of bytes in the send buf. + // this will always be equal to the sum of the + // size of all buffers in vec + int m_bytes; + + // the total size of all buffers in the chain + // including unused space + int m_capacity; + + // this is the vector of buffers used when + // invoking the async write call + std::list m_tmp_vec; + }; +} + +#endif + diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp new file mode 100644 index 000000000..1ee97bd57 --- /dev/null +++ b/libtorrent/include/libtorrent/config.hpp @@ -0,0 +1,93 @@ +/* + +Copyright (c) 2005, 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_CONFIG_HPP_INCLUDED +#define TORRENT_CONFIG_HPP_INCLUDED + +#include +#include + +#if defined(__GNUC__) && __GNUC__ >= 4 + +#define TORRENT_DEPRECATED __attribute__ ((deprecated)) + +# if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED) +# define TORRENT_EXPORT __attribute__ ((visibility("default"))) +# else +# define TORRENT_EXPORT +# endif + +#elif defined(__GNUC__) + +# define TORRENT_EXPORT + +#elif defined(BOOST_MSVC) + +# if defined(TORRENT_BUILDING_SHARED) +# define TORRENT_EXPORT __declspec(dllexport) +# elif defined(TORRENT_LINKING_SHARED) +# define TORRENT_EXPORT __declspec(dllimport) +# else +# define TORRENT_EXPORT +# endif + +#else +# define TORRENT_EXPORT +#endif + +#ifndef TORRENT_DEPRECATED +#define TORRENT_DEPRECATED +#endif + +// set up defines for target environments +#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \ + || defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \ + || defined __FreeBSD_kernel__ +#define TORRENT_BSD +#elif defined __linux__ +#define TORRENT_LINUX +#elif defined WIN32 +#define TORRENT_WINDOWS +#else +#warning unkown OS, assuming BSD +#define TORRENT_BSD +#endif + +// should wpath or path be used? +#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY && BOOST_VERSION >= 103400 +#define TORRENT_USE_WPATH 1 +#else +#define TORRENT_USE_WPATH 0 +#endif + +#endif // TORRENT_CONFIG_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/connection_queue.hpp b/libtorrent/include/libtorrent/connection_queue.hpp new file mode 100644 index 000000000..527b862df --- /dev/null +++ b/libtorrent/include/libtorrent/connection_queue.hpp @@ -0,0 +1,113 @@ +/* + +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 +#include +#include +#include +#include "libtorrent/socket.hpp" +#include "libtorrent/time.hpp" + +#ifdef TORRENT_CONNECTION_LOGGING +#include +#endif + +namespace libtorrent +{ + +class connection_queue : public boost::noncopyable +{ +public: + connection_queue(io_service& ios); + + // if there are no free slots, returns the negative + // number of queued up connections + int free_slots() const; + + void enqueue(boost::function const& on_connect + , boost::function const& on_timeout + , time_duration timeout, int priority = 0); + void done(int ticket); + void limit(int limit); + int limit() const; + void close(); + +#ifndef NDEBUG + void check_invariant() const; +#endif + +private: + + void try_connect(); + void on_timeout(error_code const& e); + + struct entry + { + entry(): connecting(false), ticket(0), expires(max_time()), priority(0) {} + // called when the connection is initiated + boost::function on_connect; + // called if done hasn't been called within the timeout + boost::function on_timeout; + bool connecting; + int ticket; + ptime expires; + time_duration timeout; + int priority; + }; + + std::list 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; + + typedef boost::recursive_mutex mutex_t; + mutable mutex_t m_mutex; + +#ifndef NDEBUG + bool m_in_timeout_function; +#endif +#ifdef TORRENT_CONNECTION_LOGGING + std::ofstream m_log; +#endif +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/create_torrent.hpp b/libtorrent/include/libtorrent/create_torrent.hpp new file mode 100644 index 000000000..32c7a41f2 --- /dev/null +++ b/libtorrent/include/libtorrent/create_torrent.hpp @@ -0,0 +1,200 @@ +/* + +Copyright (c) 2008, 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_CREATE_TORRENT_HPP_INCLUDED +#define TORRENT_CREATE_TORRENT_HPP_INCLUDED + +#include "libtorrent/bencode.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/file_storage.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/hasher.hpp" + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + namespace fs = boost::filesystem; + namespace pt = boost::posix_time; + + struct TORRENT_EXPORT create_torrent + { + create_torrent(file_storage& fs, int piece_size); + create_torrent(file_storage& fs); + entry generate() const; + + file_storage const& files() const { return m_files; } + + void set_comment(char const* str); + void set_creator(char const* str); + void set_hash(int index, sha1_hash const& h); + void add_url_seed(std::string const& url); + void add_node(std::pair const& node); + void add_tracker(std::string const& url, int tier = 0); + + int num_pieces() const { return m_files.num_pieces(); } + int piece_length() const { return m_files.piece_length(); } + int piece_size(int i) const { return m_files.piece_size(i); } + + private: + + file_storage& m_files; + + // the urls to the trackers + typedef std::pair announce_entry; + std::vector m_urls; + + std::vector m_url_seeds; + + std::vector m_piece_hash; + + // dht nodes to add to the routing table/bootstrap from + typedef std::vector > nodes_t; + nodes_t m_nodes; + + // the hash that identifies this torrent + // is mutable because it's calculated + // lazily + mutable sha1_hash m_info_hash; + + // if a creation date is found in the torrent file + // this will be set to that, otherwise it'll be + // 1970, Jan 1 + pt::ptime m_creation_date; + + // if a comment is found in the torrent file + // this will be set to that comment + std::string m_comment; + + // an optional string naming the software used + // to create the torrent file + std::string m_created_by; + + // this is used when creating a torrent. If there's + // only one file there are cases where it's impossible + // to know if it should be written as a multifile torrent + // or not. e.g. test/test there's one file and one directory + // and they have the same name. + bool m_multifile; + + // this is true if the torrent is private. i.e., is should not + // be announced on the dht + bool m_private; + }; + + namespace detail + { + inline bool default_pred(boost::filesystem::path const&) { return true; } + + inline void nop(int i) {} + + template + void add_files_impl(file_storage& fs, boost::filesystem::path const& p + , boost::filesystem::path const& l, Pred pred) + { + using boost::filesystem::path; + using boost::filesystem::directory_iterator; + std::string const& leaf = l.leaf(); + if (leaf == ".." || leaf == ".") return; + if (!pred(l)) return; + path f(p / l); + if (is_directory(f)) + { + for (directory_iterator i(f), end; i != end; ++i) + add_files_impl(fs, p, l / i->leaf(), pred); + } + else + { + fs.add_file(l, file_size(f)); + } + } + } + + template + void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p) + { + detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p); + } + + inline void add_files(file_storage& fs, boost::filesystem::path const& file) + { + detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred); + } + + template + void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f) + { + file_pool fp; + boost::scoped_ptr st( + default_storage_constructor(const_cast(t.files()), p, fp)); + + // calculate the hash for all pieces + int num = t.num_pieces(); + std::vector buf(t.piece_length()); + for (int i = 0; i < num; ++i) + { + // read hits the disk and will block. Progress should + // be updated in between reads + st->read(&buf[0], i, 0, t.piece_size(i)); + hasher h(&buf[0], t.piece_size(i)); + t.set_hash(i, h.final()); + f(i); + } + } + + inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p) + { + set_piece_hashes(t, p, detail::nop); + } + +} + +#endif + diff --git a/libtorrent/include/libtorrent/debug.hpp b/libtorrent/include/libtorrent/debug.hpp new file mode 100644 index 000000000..0f2dad20b --- /dev/null +++ b/libtorrent/include/libtorrent/debug.hpp @@ -0,0 +1,94 @@ +/* + +Copyright (c) 2003, 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_DEBUG_HPP_INCLUDED +#define TORRENT_DEBUG_HPP_INCLUDED + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +namespace libtorrent +{ + // DEBUG API + + namespace fs = boost::filesystem; + + struct logger + { + logger(fs::path const& logpath, fs::path const& filename, int instance, bool append = true) + { +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + fs::path dir(fs::complete(logpath / ("libtorrent_logs" + boost::lexical_cast(instance)))); + if (!fs::exists(dir)) fs::create_directories(dir); + m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out)); + *this << "\n\n\n*** starting log ***\n"; +#ifndef BOOST_NO_EXCEPTIONS + } + catch (std::exception& e) + { + std::cerr << "failed to create log '" << filename.string() << "': " << e.what() << std::endl; + } +#endif + } + + template + logger& operator<<(T const& v) + { + m_file << v; + m_file.flush(); + return *this; + } + + std::ofstream m_file; + }; + +} + +#endif // TORRENT_DEBUG_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/disk_buffer_holder.hpp b/libtorrent/include/libtorrent/disk_buffer_holder.hpp new file mode 100644 index 000000000..31be6b3c7 --- /dev/null +++ b/libtorrent/include/libtorrent/disk_buffer_holder.hpp @@ -0,0 +1,65 @@ +/* + +Copyright (c) 2008, 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_DISK_BUFFER_HOLDER_HPP_INCLUDED +#define TORRENT_DISK_BUFFER_HOLDER_HPP_INCLUDED + +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + + namespace aux { class session_impl; } + class disk_io_thread; + + struct TORRENT_EXPORT disk_buffer_holder + { + disk_buffer_holder(aux::session_impl& ses, char* buf); + disk_buffer_holder(disk_io_thread& iothread, char* buf); + ~disk_buffer_holder(); + char* release(); + char* get() const { return m_buf; } + void reset(char* buf = 0); + + typedef char* (disk_buffer_holder::*unspecified_bool_type)(); + operator unspecified_bool_type() const + { return m_buf == 0? 0: &disk_buffer_holder::release; } + + private: + disk_io_thread& m_iothread; + char* m_buf; + }; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp new file mode 100644 index 000000000..3556c3cf6 --- /dev/null +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -0,0 +1,309 @@ +/* + +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_DISK_IO_THREAD +#define TORRENT_DISK_IO_THREAD + +#ifdef TORRENT_DISK_STATS +#include +#endif + +#include "libtorrent/storage.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "libtorrent/config.hpp" +#ifndef TORRENT_DISABLE_POOL_ALLOCATOR +#include +#endif + +namespace libtorrent +{ + + struct cached_piece_info + { + int piece; + std::vector blocks; + ptime last_use; + }; + + struct disk_io_job + { + disk_io_job() + : action(read) + , buffer(0) + , buffer_size(0) + , piece(0) + , offset(0) + , priority(0) + {} + + enum action_t + { + read + , write + , hash + , move_storage + , release_files + , delete_files + , check_fastresume + , check_files + , save_resume_data + , rename_file + , abort_thread + }; + + action_t action; + + char* buffer; + int buffer_size; + boost::intrusive_ptr storage; + // arguments used for read and write + int piece, offset; + // used for move_storage and rename_file. On errors, this is set + // to the error message + std::string str; + + // on error, this is set to the path of the + // file the disk operation failed on + std::string error_file; + + // priority decides whether or not this + // job will skip entries in the queue or + // not. It always skips in front of entries + // with lower priority + int priority; + + boost::shared_ptr resume_data; + + // this is called when operation completes + boost::function callback; + }; + + struct cache_status + { + cache_status() + : blocks_written(0) + , writes(0) + , blocks_read(0) + , blocks_read_hit(0) + , reads(0) + , cache_size(0) + , read_cache_size(0) + {} + + // the number of 16kB blocks written + size_type blocks_written; + // the number of write operations used + size_type writes; + // (blocks_written - writes) / blocks_written represents the + // "cache hit" ratio in the write cache + // the number of blocks read + + // the number of blocks passed back to the bittorrent engine + size_type blocks_read; + // the number of blocks that was just copied from the read cache + size_type blocks_read_hit; + // the number of read operations used + size_type reads; + + // the number of blocks in the cache (both read and write) + int cache_size; + + // the number of blocks in the cache used for read cache + int read_cache_size; + }; + + // this is a singleton consisting of the thread and a queue + // of disk io jobs + struct disk_io_thread : boost::noncopyable + { + disk_io_thread(io_service& ios, int block_size = 16 * 1024); + ~disk_io_thread(); + +#ifdef TORRENT_STATS + int disk_allocations() const + { return m_allocations; } +#endif + + void join(); + + // aborts read operations + void stop(boost::intrusive_ptr s); + void add_job(disk_io_job const& j + , boost::function const& f + = boost::function()); + + // keep track of the number of bytes in the job queue + // at any given time. i.e. the sum of all buffer_size. + // this is used to slow down the download global download + // speed when the queue buffer size is too big. + size_type queue_buffer_size() const + { return m_queue_buffer_size; } + + void get_cache_info(sha1_hash const& ih + , std::vector& ret) const; + + cache_status status() const; + void set_cache_size(int s); + void set_cache_expiry(int ex); + + void operator()(); + +#ifndef NDEBUG + bool is_disk_buffer(char* buffer) const; +#endif + + char* allocate_buffer(); + void free_buffer(char* buf); + +#ifndef NDEBUG + void check_invariant() const; +#endif + + private: + + struct cached_piece_entry + { + int piece; + // storage this piece belongs to + boost::intrusive_ptr storage; + // the last time a block was writting to this piece + ptime last_use; + // the number of blocks in the cache for this piece + int num_blocks; + // the pointers to the block data + boost::shared_array blocks; + }; + + typedef boost::recursive_mutex mutex_t; + typedef std::list cache_t; + + // cache operations + cache_t::iterator find_cached_piece( + cache_t& cache, disk_io_job const& j + , mutex_t::scoped_lock& l); + + // write cache operations + void flush_oldest_piece(mutex_t::scoped_lock& l); + void flush_expired_pieces(); + void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l); + void flush(cache_t::iterator i, mutex_t::scoped_lock& l); + void cache_block(disk_io_job& j, mutex_t::scoped_lock& l); + + // read cache operations + bool clear_oldest_read_piece(cache_t::iterator ignore + , mutex_t::scoped_lock& l); + int read_into_piece(cached_piece_entry& p, int start_block, mutex_t::scoped_lock& l); + int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l); + void free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l); + bool make_room(int num_blocks + , cache_t::iterator ignore + , mutex_t::scoped_lock& l); + int try_read_from_cache(disk_io_job const& j); + + // this mutex only protects m_jobs, m_queue_buffer_size + // and m_abort + mutable mutex_t m_queue_mutex; + boost::condition m_signal; + bool m_abort; + std::list m_jobs; + size_type m_queue_buffer_size; + + // this protects the piece cache and related members + mutable mutex_t m_piece_mutex; + // write cache + cache_t m_pieces; + + // read cache + cache_t m_read_pieces; + + // total number of blocks in use by both the read + // and the write cache. This is not supposed to + // exceed m_cache_size + cache_status m_cache_stats; + int m_num_cached_blocks; + + // in (16kB) blocks + int m_cache_size; + + // expiration time of cache entries in seconds + int m_cache_expiry; + + // if set to true, each piece flush will allocate + // one piece worth of temporary memory on the heap + // and copy the block data into it, and then perform + // a single write operation from that buffer. + // if memory is constrained, that temporary buffer + // might is avoided by setting this to false. + // in case the allocation fails, the piece flush + // falls back to writing each block separately. + bool m_coalesce_writes; + bool m_coalesce_reads; + bool m_use_read_cache; + + // this only protects the pool allocator + mutable mutex_t m_pool_mutex; +#ifndef TORRENT_DISABLE_POOL_ALLOCATOR + // memory pool for read and write operations + // and disk cache + boost::pool<> m_pool; +#endif + + // number of bytes per block. The BitTorrent + // protocol defines the block size to 16 KiB. + int m_block_size; + +#ifdef TORRENT_DISK_STATS + std::ofstream m_log; +#endif +#ifdef TORRENT_STATS + int m_allocations; +#endif + + size_type m_writes; + size_type m_blocks_written; + + io_service& m_ios; + + // thread for performing blocking disk io operations + boost::thread m_disk_io_thread; + }; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp new file mode 100644 index 000000000..473eb1ca8 --- /dev/null +++ b/libtorrent/include/libtorrent/entry.hpp @@ -0,0 +1,337 @@ +/* + +Copyright (c) 2003, 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_ENTRY_HPP_INCLUDED +#define TORRENT_ENTRY_HPP_INCLUDED + +/* + * + * This file declares the entry class. It is a + * variant-type that can be an integer, list, + * dictionary (map) or a string. This type is + * used to hold bdecoded data (which is the + * encoding BitTorrent messages uses). + * + * it has 4 accessors to access the actual + * type of the object. They are: + * integer() + * string() + * list() + * dict() + * The actual type has to match the type you + * are asking for, otherwise you will get an + * assertion failure. + * When you default construct an entry, it is + * uninitialized. You can initialize it through the + * assignment operator, copy-constructor or + * the constructor that takes a data_type enum. + * + * + */ + + +#include +#include +#include +#include +#include + +#include "libtorrent/size_type.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + struct TORRENT_EXPORT type_error: std::runtime_error + { + type_error(const char* error): std::runtime_error(error) {} + }; + + namespace detail + { + template + struct max2 { enum { value = v1>v2?v1:v2 }; }; + + template + struct max3 + { + enum + { + temp = max2::value, + value = temp>v3?temp:v3 + }; + }; + + template + struct max4 + { + enum + { + temp = max3::value, + value = temp>v4?temp:v4 + }; + }; + } + + class entry; + + class TORRENT_EXPORT entry + { + public: + + // the key is always a string. If a generic entry would be allowed + // as a key, sorting would become a problem (e.g. to compare a string + // to a list). The definition doesn't mention such a limit though. + typedef std::map dictionary_type; + typedef std::string string_type; + typedef std::list list_type; + typedef size_type integer_type; + + enum data_type + { + int_t, + string_t, + list_t, + dictionary_t, + undefined_t + }; + + data_type type() const; + + entry(dictionary_type const&); + entry(string_type const&); + entry(list_type const&); + entry(integer_type const&); + + entry(); + entry(data_type t); + entry(entry const& e); + ~entry(); + + bool operator==(entry const& e) const; + + void operator=(entry const&); + void operator=(dictionary_type const&); + void operator=(string_type const&); + void operator=(list_type const&); + void operator=(integer_type const&); + + integer_type& integer(); + const integer_type& integer() const; + string_type& string(); + const string_type& string() const; + list_type& list(); + const list_type& list() const; + dictionary_type& dict(); + const dictionary_type& dict() const; + + void swap(entry& e); + + // these functions requires that the entry + // is a dictionary, otherwise they will throw + entry& operator[](char const* key); + entry& operator[](std::string const& key); +#ifndef BOOST_NO_EXCEPTIONS + const entry& operator[](char const* key) const; + const entry& operator[](std::string const& key) const; +#endif + entry* find_key(char const* key); + entry const* find_key(char const* key) const; + entry* find_key(std::string const& key); + entry const* find_key(std::string const& key) const; + + void print(std::ostream& os, int indent = 0) const; + + protected: + + void construct(data_type t); + void copy(const entry& e); + void destruct(); + + private: + + data_type m_type; + +#if defined(_MSC_VER) && _MSC_VER < 1310 + // workaround for msvc-bug. + // assumes sizeof(map) == sizeof(map) + // and sizeof(list) == sizeof(list) + union + { + char data[ + detail::max4) + , sizeof(std::map) + , sizeof(string_type) + , sizeof(integer_type)>::value]; + integer_type dummy_aligner; + }; +#else + union + { + char data[detail::max4::value]; + integer_type dummy_aligner; + }; +#endif + +#ifndef NDEBUG + public: + // in debug mode this is set to false by bdecode + // to indicate that the program has not yet queried + // the type of this entry, and sould not assume + // that it has a certain type. This is asserted in + // the accessor functions. This does not apply if + // exceptions are used. + mutable bool m_type_queried; +#endif + }; + + inline std::ostream& operator<<(std::ostream& os, const entry& e) + { + e.print(os, 0); + return os; + } + + inline entry::data_type entry::type() const + { +#ifndef NDEBUG + m_type_queried = true; +#endif + return m_type; + } + + inline entry::~entry() { destruct(); } + + inline void entry::operator=(const entry& e) + { + destruct(); + copy(e); + } + + inline entry::integer_type& entry::integer() + { + if (m_type == undefined_t) construct(int_t); +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != int_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == int_t); + return *reinterpret_cast(data); + } + + inline entry::integer_type const& entry::integer() const + { +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != int_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == int_t); + return *reinterpret_cast(data); + } + + inline entry::string_type& entry::string() + { + if (m_type == undefined_t) construct(string_t); +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != string_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == string_t); + return *reinterpret_cast(data); + } + + inline entry::string_type const& entry::string() const + { +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != string_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == string_t); + return *reinterpret_cast(data); + } + + inline entry::list_type& entry::list() + { + if (m_type == undefined_t) construct(list_t); +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != list_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == list_t); + return *reinterpret_cast(data); + } + + inline entry::list_type const& entry::list() const + { +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != list_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == list_t); + return *reinterpret_cast(data); + } + + inline entry::dictionary_type& entry::dict() + { + if (m_type == undefined_t) construct(dictionary_t); +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != dictionary_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == dictionary_t); + return *reinterpret_cast(data); + } + + inline entry::dictionary_type const& entry::dict() const + { +#ifndef BOOST_NO_EXCEPTIONS + if (m_type != dictionary_t) throw type_error("invalid type requested from entry"); +#elif !defined NDEBUG + TORRENT_ASSERT(m_type_queried); +#endif + TORRENT_ASSERT(m_type == dictionary_t); + return *reinterpret_cast(data); + } + +} + +#endif // TORRENT_ENTRY_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/enum_net.hpp b/libtorrent/include/libtorrent/enum_net.hpp new file mode 100644 index 000000000..643c4c0c0 --- /dev/null +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -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. + +*/ + +#ifndef TORRENT_ENUM_NET_HPP_INCLUDED +#define TORRENT_ENUM_NET_HPP_INCLUDED + +#include "libtorrent/config.hpp" +#include "libtorrent/socket.hpp" + +namespace libtorrent +{ + + struct ip_interface + { + address interface_address; + address netmask; + char name[64]; + }; + + struct ip_route + { + address destination; + address netmask; + address gateway; + char name[64]; + }; + + // returns a list of the configured IP interfaces + // on the machine + TORRENT_EXPORT std::vector enum_net_interfaces(io_service& ios + , error_code& ec); + + TORRENT_EXPORT std::vector enum_routes(io_service& ios, error_code& ec); + + // returns true if the specified address is on the same + // local network as the specified interface + TORRENT_EXPORT bool in_subnet(address const& addr, ip_interface const& iface); + + // returns true if the specified address is on the same + // local network as us + TORRENT_EXPORT bool in_local_network(io_service& ios, address const& addr + , error_code& ec); + + TORRENT_EXPORT address get_default_gateway(io_service& ios + , error_code& ec); +} + +#endif + diff --git a/libtorrent/include/libtorrent/escape_string.hpp b/libtorrent/include/libtorrent/escape_string.hpp new file mode 100644 index 000000000..660dd4d08 --- /dev/null +++ b/libtorrent/include/libtorrent/escape_string.hpp @@ -0,0 +1,58 @@ +/* + +Copyright (c) 2003, 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_ESCAPE_STRING_HPP_INCLUDED +#define TORRENT_ESCAPE_STRING_HPP_INCLUDED + +#include +#include +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + std::string TORRENT_EXPORT unescape_string(std::string const& s); + std::string TORRENT_EXPORT escape_string(const char* str, int len); + std::string TORRENT_EXPORT escape_path(const char* str, int len); + + // encodes a string using the base64 scheme + TORRENT_EXPORT std::string base64encode(std::string const& s); + // encodes a string using the base32 scheme + TORRENT_EXPORT std::string base32encode(std::string const& s); + TORRENT_EXPORT std::string base32decode(std::string const& s); + + TORRENT_EXPORT boost::optional url_has_argument( + std::string const& url, std::string argument); + + TORRENT_EXPORT std::string to_hex(std::string const& s); +} + +#endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp new file mode 100644 index 000000000..b06a0fc74 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -0,0 +1,194 @@ +/* + +Copyright (c) 2006, 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_EXTENSIONS_HPP_INCLUDED +#define TORRENT_EXTENSIONS_HPP_INCLUDED + +#ifndef TORRENT_DISABLE_EXTENSIONS + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include "libtorrent/config.hpp" +#include "libtorrent/buffer.hpp" + +namespace libtorrent +{ + struct peer_plugin; + class bt_peer_connection; + struct peer_request; + class peer_connection; + class entry; + struct lazy_entry; + struct disk_buffer_holder; + struct bitfield; + + struct TORRENT_EXPORT torrent_plugin + { + virtual ~torrent_plugin() {} + // throwing an exception closes the connection + // returning a 0 pointer is valid and will not add + // the peer_plugin to the peer_connection + virtual boost::shared_ptr new_connection(peer_connection*) + { return boost::shared_ptr(); } + + virtual void on_piece_pass(int index) {} + virtual void on_piece_failed(int index) {} + + // called aproximately once every second + virtual void tick() {} + + // if true is returned, it means the handler handled the event, + // and no other plugins will have their handlers called, and the + // 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 + { + 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) + // closes the connection + + // 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(char const* reserved_bits) { 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(lazy_entry const& h) { return true; } + + // returning true from any of the message handlers + // indicates that the plugin has handeled the message. + // it will break the plugin chain traversing and not let + // anyone else handle the message, including the default + // handler. + + virtual bool on_choke() + { return false; } + + virtual bool on_unchoke() + { return false; } + + virtual bool on_interested() + { return false; } + + virtual bool on_not_interested() + { return false; } + + virtual bool on_have(int index) + { return false; } + + virtual bool on_bitfield(bitfield const& bitfield) + { return false; } + + virtual bool on_have_all() + { return false; } + + virtual bool on_have_none() + { return false; } + + virtual bool on_allowed_fast(int index) + { return false; } + + virtual bool on_request(peer_request const& req) + { return false; } + + virtual bool on_piece(peer_request const& piece, disk_buffer_holder& data) + { return false; } + + virtual bool on_cancel(peer_request const& req) + { return false; } + + virtual bool on_reject(peer_request const& req) + { return false; } + + virtual bool on_suggest(int index) + { return false; } + + // called when an extended message is received. If returning true, + // 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; } + + // called when a piece that this peer participated in either + // fails or passes the hash_check + virtual void on_piece_pass(int index) {} + virtual void on_piece_failed(int index) {} + + // called aproximately once every second + virtual void tick() {} + + // called each time a request message is to be sent. If true + // is returned, the original request message won't be sent and + // no other plugin will have this function called. + virtual bool write_request(peer_request const& r) { return false; } + }; + +} + +#endif + +#endif // TORRENT_EXTENSIONS_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/logger.hpp b/libtorrent/include/libtorrent/extensions/logger.hpp new file mode 100644 index 000000000..42e08fcf6 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/logger.hpp @@ -0,0 +1,54 @@ +/* + +Copyright (c) 2006, 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_LOGGER_HPP_INCLUDED +#define TORRENT_LOGGER_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + boost::shared_ptr create_logger_plugin(torrent*); +} + +#endif // TORRENT_LOGGER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp new file mode 100644 index 000000000..c42136d70 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp @@ -0,0 +1,55 @@ +/* + +Copyright (c) 2006, 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_METADATA_TRANSFER_HPP_INCLUDED +#define TORRENT_METADATA_TRANSFER_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include "libtorrent/config.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + TORRENT_EXPORT boost::shared_ptr create_metadata_plugin(torrent*, void*); +} + +#endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/smart_ban.hpp b/libtorrent/include/libtorrent/extensions/smart_ban.hpp new file mode 100644 index 000000000..5d7d30c82 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/smart_ban.hpp @@ -0,0 +1,55 @@ +/* + +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_SMART_BAN_HPP_INCLUDED +#define TORRENT_SMART_BAN_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include "libtorrent/config.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + TORRENT_EXPORT boost::shared_ptr create_smart_ban_plugin(torrent*, void*); +} + +#endif // TORRENT_SMART_BAN_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/ut_metadata.hpp b/libtorrent/include/libtorrent/extensions/ut_metadata.hpp new file mode 100644 index 000000000..91437b17c --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/ut_metadata.hpp @@ -0,0 +1,55 @@ +/* + +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_UT_METADATA_HPP_INCLUDED +#define TORRENT_UT_METADATA_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include "libtorrent/config.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + TORRENT_EXPORT boost::shared_ptr create_ut_metadata_plugin(torrent*, void*); +} + +#endif // TORRENT_UT_METADATA_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/ut_pex.hpp b/libtorrent/include/libtorrent/extensions/ut_pex.hpp new file mode 100644 index 000000000..ebf6aa834 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/ut_pex.hpp @@ -0,0 +1,54 @@ +/* + +Copyright (c) 2006, MassaRoddel +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_UT_PEX_EXTENSION_HPP_INCLUDED +#define TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include "libtorrent/config.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + TORRENT_EXPORT boost::shared_ptr create_ut_pex_plugin(torrent*, void*); +} + +#endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/file.hpp b/libtorrent/include/libtorrent/file.hpp new file mode 100644 index 000000000..a0d3ef1c0 --- /dev/null +++ b/libtorrent/include/libtorrent/file.hpp @@ -0,0 +1,130 @@ +/* + +Copyright (c) 2003, 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_FILE_HPP_INCLUDED +#define TORRENT_FILE_HPP_INCLUDED + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/size_type.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + namespace fs = boost::filesystem; + + class TORRENT_EXPORT file: public boost::noncopyable + { + public: + + class seek_mode + { + friend class file; + private: + seek_mode(int v): m_val(v) {} + int m_val; + }; + + static const seek_mode begin; + static const seek_mode end; + + class open_mode + { + friend class file; + public: + + open_mode(): m_mask(0) {} + + open_mode operator|(open_mode m) const + { return open_mode(m.m_mask | m_mask); } + + open_mode operator&(open_mode m) const + { return open_mode(m.m_mask & m_mask); } + + open_mode operator|=(open_mode m) + { + m_mask |= m.m_mask; + return *this; + } + + bool operator==(open_mode m) const { return m_mask == m.m_mask; } + bool operator!=(open_mode m) const { return m_mask != m.m_mask; } + + private: + + open_mode(int val): m_mask(val) {} + int m_mask; + }; + + static const open_mode in; + static const open_mode out; + + file(); + file(fs::path const& p, open_mode m); + ~file(); + + bool open(fs::path const& p, open_mode m); + void close(); + bool set_size(size_type size); + + size_type write(const char*, size_type num_bytes); + size_type read(char*, size_type num_bytes); + + size_type seek(size_type pos, seek_mode m = begin); + size_type tell(); + + std::string const& error() const; + + private: + + struct impl; + const std::auto_ptr m_impl; + + }; + +} + +#endif // TORRENT_FILE_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/file_pool.hpp b/libtorrent/include/libtorrent/file_pool.hpp new file mode 100644 index 000000000..69116d675 --- /dev/null +++ b/libtorrent/include/libtorrent/file_pool.hpp @@ -0,0 +1,103 @@ +/* + +Copyright (c) 2006, 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_FILE_POOL_HPP +#define TORRENT_FILE_POOL_HPP + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/file.hpp" +#include "libtorrent/time.hpp" + +namespace libtorrent +{ + + using boost::multi_index::multi_index_container; + using boost::multi_index::ordered_non_unique; + using boost::multi_index::ordered_unique; + using boost::multi_index::indexed_by; + using boost::multi_index::member; + namespace fs = boost::filesystem; + + struct TORRENT_EXPORT file_pool : boost::noncopyable + { + file_pool(int size = 40): m_size(size) {} + + boost::shared_ptr open_file(void* st, fs::path const& p + , file::open_mode m, std::string& error); + void release(void* st); + void release(fs::path const& p); + void resize(int size); + + private: + int m_size; + + struct lru_file_entry + { + lru_file_entry(): last_use(time_now()) {} + mutable boost::shared_ptr file_ptr; + fs::path file_path; + void* key; + ptime last_use; + file::open_mode mode; + }; + + typedef multi_index_container< + lru_file_entry, indexed_by< + ordered_unique > + , ordered_non_unique > + , ordered_non_unique > + > + > file_set; + + file_set m_files; + boost::mutex m_mutex; + }; +} + +#endif diff --git a/libtorrent/include/libtorrent/file_storage.hpp b/libtorrent/include/libtorrent/file_storage.hpp new file mode 100644 index 000000000..bbb606bf6 --- /dev/null +++ b/libtorrent/include/libtorrent/file_storage.hpp @@ -0,0 +1,146 @@ +/* + +Copyright (c) 2003-2008, 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_FILE_STORAGE_HPP_INCLUDED +#define TORRENT_FILE_STORAGE_HPP_INCLUDED + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/size_type.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/peer_request.hpp" + +namespace libtorrent +{ + namespace fs = boost::filesystem; + + struct TORRENT_EXPORT file_entry + { + file_entry(): offset(0), size(0), file_base(0) {} + + fs::path path; + size_type offset; // the offset of this file inside the torrent + size_type size; // the size of this file + // the offset in the file where the storage starts. + // This is always 0 unless parts of the torrent is + // compressed into a single file, such as a so-called part file. + size_type file_base; + }; + + struct TORRENT_EXPORT file_slice + { + int file_index; + size_type offset; + size_type size; + }; + + class TORRENT_EXPORT file_storage + { + friend class torrent_info; + public: + file_storage(); + ~file_storage() {} + + bool is_valid() const { return m_piece_length > 0; } + + void add_file(file_entry const& e); + void add_file(fs::path const& p, size_type size); + void rename_file(int index, std::string const& new_filename); + + std::vector map_block(int piece, size_type offset + , int size) const; + peer_request map_file(int file, size_type offset, int size) const; + + typedef std::vector::const_iterator iterator; + typedef std::vector::const_reverse_iterator reverse_iterator; + + iterator begin() const { return m_files.begin(); } + iterator end() const { return m_files.end(); } + reverse_iterator rbegin() const { return m_files.rbegin(); } + reverse_iterator rend() const { return m_files.rend(); } + int num_files() const + { return int(m_files.size()); } + + file_entry const& at(int index) const + { + TORRENT_ASSERT(index >= 0 && index < int(m_files.size())); + return m_files[index]; + } + + size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; } + void set_num_pieces(int n) { m_num_pieces = n; } + int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; } + void set_piece_length(int l) { m_piece_length = l; } + int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; } + int piece_size(int index) const; + + void set_name(std::string const& n) { m_name = n; } + const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; } + + void swap(file_storage& ti) + { + using std::swap; + swap(ti.m_piece_length, m_piece_length); + swap(ti.m_files, m_files); + swap(ti.m_total_size, m_total_size); + swap(ti.m_num_pieces, m_num_pieces); + swap(ti.m_name, m_name); + } + + private: + int m_piece_length; + + // the list of files that this torrent consists of + std::vector m_files; + + // the sum of all filesizes + size_type m_total_size; + + // the number of pieces in the torrent + int m_num_pieces; + std::string m_name; + }; +} + +#endif // TORRENT_FILE_STORAGE_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/fingerprint.hpp b/libtorrent/include/libtorrent/fingerprint.hpp new file mode 100644 index 000000000..237fef065 --- /dev/null +++ b/libtorrent/include/libtorrent/fingerprint.hpp @@ -0,0 +1,95 @@ +/* + +Copyright (c) 2003, 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_FINGERPRINT_HPP_INCLUDED +#define TORRENT_FINGERPRINT_HPP_INCLUDED + +#include +#include + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + struct fingerprint + { + fingerprint(const char* id_string, int major, int minor, int revision, int tag) + : major_version(major) + , minor_version(minor) + , revision_version(revision) + , tag_version(tag) + { + TORRENT_ASSERT(id_string); + TORRENT_ASSERT(major >= 0); + TORRENT_ASSERT(minor >= 0); + TORRENT_ASSERT(revision >= 0); + TORRENT_ASSERT(tag >= 0); + TORRENT_ASSERT(std::strlen(id_string) == 2); + name[0] = id_string[0]; + name[1] = id_string[1]; + } + + std::string to_string() const + { + std::stringstream s; + s << "-" << name[0] << name[1] + << version_to_char(major_version) + << version_to_char(minor_version) + << version_to_char(revision_version) + << version_to_char(tag_version) << "-"; + return s.str(); + } + + char name[2]; + int major_version; + int minor_version; + int revision_version; + int tag_version; + + private: + + char version_to_char(int v) const + { + if (v >= 0 && v < 10) return '0' + v; + else if (v >= 10) return 'A' + (v - 10); + TORRENT_ASSERT(false); + return '0'; + } + + }; + +} + +#endif // TORRENT_FINGERPRINT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/gzip.hpp b/libtorrent/include/libtorrent/gzip.hpp new file mode 100644 index 000000000..0528b58f2 --- /dev/null +++ b/libtorrent/include/libtorrent/gzip.hpp @@ -0,0 +1,43 @@ +/* + +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. + +*/ + +namespace libtorrent +{ + + TORRENT_EXPORT bool inflate_gzip( + char const* in, int size + , std::vector& buffer + , int maximum_size + , std::string& error); + +} + diff --git a/libtorrent/include/libtorrent/hasher.hpp b/libtorrent/include/libtorrent/hasher.hpp new file mode 100644 index 000000000..f1dba7d1a --- /dev/null +++ b/libtorrent/include/libtorrent/hasher.hpp @@ -0,0 +1,122 @@ +/* + +Copyright (c) 2003, 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_HASHER_HPP_INCLUDED +#define TORRENT_HASHER_HPP_INCLUDED + +#include + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" +#include "zlib.h" + +#ifdef TORRENT_USE_OPENSSL +extern "C" +{ +#include +} +#else +// from sha1.cpp +struct TORRENT_EXPORT SHA_CTX +{ + boost::uint32_t state[5]; + boost::uint32_t count[2]; + boost::uint8_t buffer[64]; +}; + +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); + +#endif + +namespace libtorrent +{ + + class adler32_crc + { + public: + adler32_crc(): m_adler(adler32(0, 0, 0)) {} + + void update(const char* data, int len) + { + TORRENT_ASSERT(data != 0); + TORRENT_ASSERT(len > 0); + m_adler = adler32(m_adler, (const Bytef*)data, len); + } + unsigned long final() const { return m_adler; } + void reset() { m_adler = adler32(0, 0, 0); } + + private: + + unsigned long m_adler; + + }; + + class hasher + { + public: + + hasher() { SHA1_Init(&m_context); } + hasher(const char* data, int len) + { + SHA1_Init(&m_context); + TORRENT_ASSERT(data != 0); + TORRENT_ASSERT(len > 0); + SHA1_Update(&m_context, reinterpret_cast(data), len); + } + void update(const char* data, int len) + { + TORRENT_ASSERT(data != 0); + TORRENT_ASSERT(len > 0); + SHA1_Update(&m_context, reinterpret_cast(data), len); + } + + sha1_hash final() + { + sha1_hash digest; + SHA1_Final(digest.begin(), &m_context); + return digest; + } + + void reset() { SHA1_Init(&m_context); } + + private: + + SHA_CTX m_context; + + }; +} + +#endif // TORRENT_HASHER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/http_connection.hpp b/libtorrent/include/libtorrent/http_connection.hpp new file mode 100644 index 000000000..b13b457fa --- /dev/null +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -0,0 +1,209 @@ +/* + +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 +#include +#include +#include +#include +#include +#include +#include + +#include "libtorrent/socket.hpp" +#include "libtorrent/http_parser.hpp" +#include "libtorrent/time.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/socket_type.hpp" +#include "libtorrent/session_settings.hpp" + +#ifdef TORRENT_USE_OPENSSL +#include "libtorrent/ssl_stream.hpp" +#include "libtorrent/variant_stream.hpp" +#endif + +namespace libtorrent +{ + +struct http_connection; +class connection_queue; + +typedef boost::function http_handler; + +typedef boost::function http_connect_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, boost::noncopyable +{ + http_connection(io_service& ios, connection_queue& cc + , http_handler const& handler, bool bottled = true + , http_connect_handler const& ch = http_connect_handler()) + : m_sock(ios) + , m_read_pos(0) + , m_resolver(ios) + , m_handler(handler) + , m_connect_handler(ch) + , 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_redirects(5) + , m_connection_ticket(-1) + , m_cc(cc) + , m_ssl(false) + , m_priority(0) + , m_abort(false) + { + TORRENT_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) + , int prio = 0, proxy_settings const* ps = 0, int handle_redirects = 5 + , std::string const& user_agent = "", address const& bind_addr = address_v4::any()); + + void start(std::string const& hostname, std::string const& port + , time_duration timeout, int prio = 0, proxy_settings const* ps = 0 + , bool ssl = false, int handle_redirect = 5 + , address const& bind_addr = address_v4::any()); + + void close(); + +#ifdef TORRENT_USE_OPENSSL + variant_stream > const& socket() const { return m_sock; } +#else + socket_type const& socket() const { return m_sock; } +#endif + +private: + + void on_resolve(error_code const& e + , tcp::resolver::iterator i); + void queue_connect(); + void connect(int ticket, tcp::endpoint target_address); + void on_connect_timeout(); + void on_connect(error_code const& e); + void on_write(error_code const& e); + void on_read(error_code const& e, std::size_t bytes_transferred); + static void on_timeout(boost::weak_ptr p + , error_code const& e); + void on_assign_bandwidth(error_code const& e); + + void callback(error_code const& e, char const* data = 0, int size = 0); + + std::vector m_recvbuffer; +#ifdef TORRENT_USE_OPENSSL + variant_stream > m_sock; +#else + socket_type m_sock; +#endif + int m_read_pos; + tcp::resolver m_resolver; + http_parser m_parser; + http_handler m_handler; + http_connect_handler m_connect_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; + std::string m_url; + + std::list m_endpoints; + + // 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; + + // the number of redirects to follow (in sequence) + int m_redirects; + + int m_connection_ticket; + connection_queue& m_cc; + + // specifies whether or not the connection is + // configured to use a proxy + proxy_settings m_proxy; + + // true if the connection is using ssl + bool m_ssl; + + // the address to bind to. address_v4::any() + // means do not bind + address m_bind_addr; + + // the priority we have in the connection queue. + // 0 is normal, 1 is high + int m_priority; + + bool m_abort; +}; + +} + +#endif diff --git a/libtorrent/include/libtorrent/http_parser.hpp b/libtorrent/include/libtorrent/http_parser.hpp new file mode 100644 index 000000000..7d308ca36 --- /dev/null +++ b/libtorrent/include/libtorrent/http_parser.hpp @@ -0,0 +1,111 @@ +/* + +Copyright (c) 2008, 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_PARSER_HPP_INCLUDED +#define TORRENT_HTTP_PARSER_HPP_INCLUDED + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/config.hpp" +#include "libtorrent/buffer.hpp" +#include "libtorrent/size_type.hpp" + +namespace libtorrent +{ + + class http_parser + { + public: + http_parser(); + std::string const& header(char const* key) const + { + static std::string empty; + std::map::const_iterator i + = m_header.find(key); + if (i == m_header.end()) return empty; + return i->second; + } + + std::string const& protocol() const { return m_protocol; } + int status_code() const { return m_status_code; } + std::string const& method() const { return m_method; } + std::string const& path() const { return m_path; } + std::string const& message() const { return m_server_message; } + buffer::const_interval get_body() const; + bool header_finished() const { return m_state == read_body; } + bool finished() const { return m_finished; } + boost::tuple incoming(buffer::const_interval recv_buffer + , bool& error); + int body_start() const { return m_body_start_pos; } + size_type content_length() const { return m_content_length; } + + void reset(); + + std::map const& headers() const { return m_header; } + + private: + int m_recv_pos; + int m_status_code; + std::string m_method; + std::string m_path; + std::string m_protocol; + std::string m_server_message; + + size_type m_content_length; + + enum { read_status, read_header, read_body, error_state } m_state; + + std::map m_header; + buffer::const_interval m_recv_buffer; + int m_body_start_pos; + + bool m_finished; + }; + +} + +#endif // TORRENT_HTTP_PARSER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/http_stream.hpp b/libtorrent/include/libtorrent/http_stream.hpp new file mode 100644 index 000000000..db1602120 --- /dev/null +++ b/libtorrent/include/libtorrent/http_stream.hpp @@ -0,0 +1,102 @@ +/* + +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_STREAM_HPP_INCLUDED +#define TORRENT_HTTP_STREAM_HPP_INCLUDED + +#include "libtorrent/proxy_base.hpp" + +namespace libtorrent { + +class http_stream : public proxy_base +{ +public: + + explicit http_stream(io_service& io_service) + : proxy_base(io_service) + , m_no_connect(false) + {} + + void set_no_connect(bool c) { m_no_connect = c; } + + void set_username(std::string const& user + , std::string const& password) + { + m_user = user; + m_password = password; + } + + typedef boost::function handler_type; + + template + 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 h(new handler_type(handler)); + + tcp::resolver::query q(m_hostname + , boost::lexical_cast(m_port)); + m_resolver.async_resolve(q, boost::bind( + &http_stream::name_lookup, this, _1, _2, h)); + } + +private: + + void name_lookup(error_code const& e, tcp::resolver::iterator i + , boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); + + // send and receive buffer + std::vector m_buffer; + // proxy authentication + std::string m_user; + std::string m_password; + + // this is true if the connection is HTTP based and + // want to talk directly to the proxy + bool m_no_connect; +}; + +} + +#endif diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp new file mode 100644 index 000000000..04701fc00 --- /dev/null +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -0,0 +1,100 @@ +/* + +Copyright (c) 2003, 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_TRACKER_CONNECTION_HPP_INCLUDED +#define TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED + +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + + struct http_connection; + class entry; + class http_parser; + class connection_queue; + struct session_settings; + + class TORRENT_EXPORT http_tracker_connection + : public tracker_connection + { + friend class tracker_manager; + public: + + http_tracker_connection( + io_service& ios + , connection_queue& cc + , tracker_manager& man + , tracker_request const& req + , address bind_infc + , boost::weak_ptr c + , session_settings const& stn + , proxy_settings const& ps + , std::string const& password = ""); + + void close(); + + private: + + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } + + void on_response(error_code const& ec, http_parser const& parser + , char const* data, int size); + + virtual void on_timeout() {} + + void parse(int status_code, const entry& e); + bool extract_peer_info(const entry& e, peer_entry& ret); + + tracker_manager& m_man; + boost::shared_ptr m_tracker_connection; + }; + +} + +#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/identify_client.hpp b/libtorrent/include/libtorrent/identify_client.hpp new file mode 100644 index 000000000..e8cb3b930 --- /dev/null +++ b/libtorrent/include/libtorrent/identify_client.hpp @@ -0,0 +1,58 @@ +/* + +Copyright (c) 2003, 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_IDENTIFY_CLIENT_HPP_INCLUDED +#define TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/fingerprint.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + + TORRENT_EXPORT std::string identify_client(const peer_id& p); + TORRENT_EXPORT boost::optional client_fingerprint(peer_id const& p); + +} + +#endif // TORRENT_IDENTIFY_CLIENT_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/instantiate_connection.hpp b/libtorrent/include/libtorrent/instantiate_connection.hpp new file mode 100644 index 000000000..26efcd6cf --- /dev/null +++ b/libtorrent/include/libtorrent/instantiate_connection.hpp @@ -0,0 +1,48 @@ +/* + +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 + +namespace libtorrent +{ + struct proxy_settings; + + bool instantiate_connection(io_service& ios + , proxy_settings const& ps, socket_type& s); +} + +#endif + diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp new file mode 100644 index 000000000..c2f4e5b60 --- /dev/null +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -0,0 +1,85 @@ +/* + +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_INTRUSIVE_PTR_BASE +#define TORRENT_INTRUSIVE_PTR_BASE + +#include +#include +#include +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + template + struct intrusive_ptr_base + { + intrusive_ptr_base(intrusive_ptr_base const&) + : m_refs(0) {} + + intrusive_ptr_base& operator=(intrusive_ptr_base const& rhs) + { return *this; } + + friend void intrusive_ptr_add_ref(intrusive_ptr_base const* s) + { + TORRENT_ASSERT(s->m_refs >= 0); + TORRENT_ASSERT(s != 0); + ++s->m_refs; + } + + friend void intrusive_ptr_release(intrusive_ptr_base const* s) + { + TORRENT_ASSERT(s->m_refs > 0); + TORRENT_ASSERT(s != 0); + if (--s->m_refs == 0) + boost::checked_delete(static_cast(s)); + } + + boost::intrusive_ptr self() + { return boost::intrusive_ptr((T*)this); } + + boost::intrusive_ptr self() const + { return boost::intrusive_ptr((T const*)this); } + + int refcount() const { return m_refs; } + + intrusive_ptr_base(): m_refs(0) {} + private: + // reference counter for intrusive_ptr + mutable boost::detail::atomic_count m_refs; + }; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/invariant_check.hpp b/libtorrent/include/libtorrent/invariant_check.hpp new file mode 100644 index 000000000..c687b6a63 --- /dev/null +++ b/libtorrent/include/libtorrent/invariant_check.hpp @@ -0,0 +1,78 @@ +// Copyright Daniel Wallin 2004. 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 TORRENT_INVARIANT_ACCESS_HPP_INCLUDED +#define TORRENT_INVARIANT_ACCESS_HPP_INCLUDED + +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + class invariant_access + { + public: + template + static void check_invariant(T const& self) + { + self.check_invariant(); + } + }; + + template + void check_invariant(T const& x) + { + invariant_access::check_invariant(x); + } + + struct invariant_checker {}; + + template + struct invariant_checker_impl : invariant_checker + { + invariant_checker_impl(T const& self_) + : self(self_) + { + try + { + check_invariant(self); + } + catch (...) + { + TORRENT_ASSERT(false); + } + } + + ~invariant_checker_impl() + { + try + { + check_invariant(self); + } + catch (...) + { + TORRENT_ASSERT(false); + } + } + + T const& self; + }; + + template + invariant_checker_impl make_invariant_checker(T const& x) + { + return invariant_checker_impl(x); + } +} + +#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS +#define INVARIANT_CHECK \ + invariant_checker const& _invariant_check = make_invariant_checker(*this); \ + (void)_invariant_check; \ + do {} while (false) +#else +#define INVARIANT_CHECK do {} while (false) +#endif + +#endif // TORRENT_INVARIANT_ACCESS_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/io.hpp b/libtorrent/include/libtorrent/io.hpp new file mode 100644 index 000000000..f73c3e290 --- /dev/null +++ b/libtorrent/include/libtorrent/io.hpp @@ -0,0 +1,153 @@ +/* + +Copyright (c) 2003, 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_IO_HPP_INCLUDED +#define TORRENT_IO_HPP_INCLUDED + +#include +#include + +namespace libtorrent +{ + namespace detail + { + template struct type {}; + + // reads an integer from a byte stream + // in big endian byte order and converts + // it to native endianess + template + inline T read_impl(InIt& start, type) + { + T ret = 0; + for (int i = 0; i < (int)sizeof(T); ++i) + { + ret <<= 8; + ret |= static_cast(*start); + ++start; + } + return ret; + } + + template + inline void write_impl(T val, OutIt& start) + { + for (int i = (int)sizeof(T)-1; i >= 0; --i) + { + *start = static_cast((val >> (i * 8)) & 0xff); + ++start; + } + } + + // -- adaptors + + template + boost::int64_t read_int64(InIt& start) + { return read_impl(start, type()); } + + template + boost::uint64_t read_uint64(InIt& start) + { return read_impl(start, type()); } + + template + boost::uint32_t read_uint32(InIt& start) + { return read_impl(start, type()); } + + template + boost::int32_t read_int32(InIt& start) + { return read_impl(start, type()); } + + template + boost::int16_t read_int16(InIt& start) + { return read_impl(start, type()); } + + template + boost::uint16_t read_uint16(InIt& start) + { return read_impl(start, type()); } + + template + boost::int8_t read_int8(InIt& start) + { return read_impl(start, type()); } + + template + boost::uint8_t read_uint8(InIt& start) + { return read_impl(start, type()); } + + + template + void write_uint64(boost::uint64_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_int64(boost::int64_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_uint32(boost::uint32_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_int32(boost::int32_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_uint16(boost::uint16_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_int16(boost::int16_t val, OutIt& start) + { write_impl(val, start); } + + template + void write_uint8(boost::uint8_t val, OutIt& start) + { write_impl(val, start); } + + template + 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 + void write_string(std::string const& str, OutIt& start) + { + std::copy(str.begin(), str.end(), start); + } + + } +} + +#endif // TORRENT_IO_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/ip_filter.hpp b/libtorrent/include/libtorrent/ip_filter.hpp new file mode 100644 index 000000000..1adb14551 --- /dev/null +++ b/libtorrent/include/libtorrent/ip_filter.hpp @@ -0,0 +1,317 @@ +/* + +Copyright (c) 2005, 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_IP_FILTER_HPP +#define TORRENT_IP_FILTER_HPP + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +#include "libtorrent/config.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + +inline bool operator<=(address const& lhs + , address const& rhs) +{ + return lhs < rhs || lhs == rhs; +} + +template +struct ip_range +{ + Addr first; + Addr last; + int flags; +}; + +namespace detail +{ + + template + Addr zero() + { + Addr zero; + std::fill(zero.begin(), zero.end(), 0); + return zero; + } + + template<> + inline boost::uint16_t zero() { return 0; } + + template + Addr plus_one(Addr const& a) + { + Addr tmp(a); + typedef typename Addr::reverse_iterator iter; + for (iter i = tmp.rbegin() + , end(tmp.rend()); i != end; ++i) + { + if (*i < (std::numeric_limits::max)()) + { + *i += 1; + break; + } + *i = 0; + } + return tmp; + } + + inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; } + + template + Addr minus_one(Addr const& a) + { + Addr tmp(a); + typedef typename Addr::reverse_iterator iter; + for (iter i = tmp.rbegin() + , end(tmp.rend()); i != end; ++i) + { + if (*i > 0) + { + *i -= 1; + break; + } + *i = (std::numeric_limits::max)(); + } + return tmp; + } + + inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; } + + template + Addr max_addr() + { + Addr tmp; + std::fill(tmp.begin(), tmp.end() + , (std::numeric_limits::max)()); + return Addr(tmp); + } + + template<> + inline boost::uint16_t max_addr() + { return (std::numeric_limits::max)(); } + + // this is the generic implementation of + // a filter for a specific address type. + // it works with IPv4 and IPv6 + template + class filter_impl + { + public: + + filter_impl() + { + // make the entire ip-range non-blocked + m_access_list.insert(range(zero(), 0)); + } + + void add_rule(Addr first, Addr last, int flags) + { + using boost::next; + using boost::prior; + + TORRENT_ASSERT(!m_access_list.empty()); + TORRENT_ASSERT(first < last || first == last); + + typename range_t::iterator i = m_access_list.upper_bound(first); + typename range_t::iterator j = m_access_list.upper_bound(last); + + if (i != m_access_list.begin()) --i; + + TORRENT_ASSERT(j != m_access_list.begin()); + TORRENT_ASSERT(j != i); + + int first_access = i->access; + int last_access = prior(j)->access; + + if (i->start != first && first_access != flags) + { + i = m_access_list.insert(i, range(first, flags)); + } + else if (i != m_access_list.begin() && prior(i)->access == flags) + { + --i; + first_access = i->access; + } + TORRENT_ASSERT(!m_access_list.empty()); + TORRENT_ASSERT(i != m_access_list.end()); + + if (i != j) m_access_list.erase(next(i), j); + if (i->start == first) + { + // we can do this const-cast because we know that the new + // start address will keep the set correctly ordered + const_cast(i->start) = first; + const_cast(i->access) = flags; + } + else if (first_access != flags) + { + m_access_list.insert(i, range(first, flags)); + } + + if ((j != m_access_list.end() + && minus_one(j->start) != last) + || (j == m_access_list.end() + && last != max_addr())) + { + TORRENT_ASSERT(j == m_access_list.end() || last < minus_one(j->start)); + if (last_access != flags) + j = m_access_list.insert(j, range(plus_one(last), last_access)); + } + + if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j); + TORRENT_ASSERT(!m_access_list.empty()); + } + + int access(Addr const& addr) const + { + TORRENT_ASSERT(!m_access_list.empty()); + typename range_t::const_iterator i = m_access_list.upper_bound(addr); + if (i != m_access_list.begin()) --i; + TORRENT_ASSERT(i != m_access_list.end()); + TORRENT_ASSERT(i->start <= addr && (boost::next(i) == m_access_list.end() + || addr < boost::next(i)->start)); + return i->access; + } + + template + std::vector > export_filter() const + { + std::vector > ret; + ret.reserve(m_access_list.size()); + + for (typename range_t::const_iterator i = m_access_list.begin() + , end(m_access_list.end()); i != end;) + { + ip_range r; + r.first = ExternalAddressType(i->start); + r.flags = i->access; + + ++i; + if (i == end) + r.last = ExternalAddressType(max_addr()); + else + r.last = ExternalAddressType(minus_one(i->start)); + + ret.push_back(r); + } + return ret; + } + + private: + + struct range + { + range(Addr addr, int access = 0): start(addr), access(access) {} + bool operator<(range const& r) const + { return start < r.start; } + bool operator<(Addr const& a) const + { return start < a; } + Addr start; + // the end of the range is implicit + // and given by the next entry in the set + int access; + }; + + typedef std::set range_t; + range_t m_access_list; + + }; + +} + +class TORRENT_EXPORT ip_filter +{ +public: + + enum access_flags + { + blocked = 1 + }; + + // both addresses MUST be of the same type (i.e. both must + // be either IPv4 or both must be IPv6) + void add_rule(address first, address last, int flags); + int access(address const& addr) const; + + typedef boost::tuple > + , std::vector > > filter_tuple_t; + + filter_tuple_t export_filter() const; + +// void print() const; + +private: + + detail::filter_impl m_filter4; + detail::filter_impl m_filter6; +}; + +class TORRENT_EXPORT port_filter +{ +public: + + enum access_flags + { + blocked = 1 + }; + + void add_rule(boost::uint16_t first, boost::uint16_t last, int flags); + int access(boost::uint16_t port) const; + +private: + + detail::filter_impl m_filter; + +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp b/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp new file mode 100644 index 000000000..bd4771ea4 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp @@ -0,0 +1,117 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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 CLOSEST_NODES_050323_HPP +#define CLOSEST_NODES_050323_HPP + +#include + +#include +#include +#include +#include +#include + +#include + +namespace libtorrent { namespace dht +{ + +class rpc_manager; + +// -------- closest nodes ----------- + +class closest_nodes : public traversal_algorithm +{ +public: + typedef boost::function< + void(std::vector const&) + > done_callback; + + static void initiate( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , done_callback const& callback + ); + +private: + void done(); + void invoke(node_id const& id, udp::endpoint addr); + + closest_nodes( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , done_callback const& callback + ); + + done_callback m_done_callback; +}; + +class closest_nodes_observer : public observer +{ +public: + closest_nodes_observer( + boost::intrusive_ptr const& algorithm + , node_id self + , node_id target) + : observer(algorithm->allocator()) + , m_algorithm(algorithm) + , m_target(target) + , m_self(self) + {} + ~closest_nodes_observer(); + + void send(msg& p) + { + p.info_hash = m_target; + } + + void timeout(); + void reply(msg const&); + void abort() { m_algorithm = 0; } + +private: + boost::intrusive_ptr m_algorithm; + node_id const m_target; + node_id const m_self; +}; + +} } // namespace libtorrent::dht + +#endif // CLOSEST_NODES_050323_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp new file mode 100644 index 000000000..ef07b1b91 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp @@ -0,0 +1,173 @@ +/* + +Copyright (c) 2006, 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_DISABLE_DHT + +#ifndef TORRENT_DHT_TRACKER +#define TORRENT_DHT_TRACKER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libtorrent/kademlia/node.hpp" +#include "libtorrent/kademlia/node_id.hpp" +#include "libtorrent/kademlia/traversal_algorithm.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/session_status.hpp" +#include "libtorrent/udp_socket.hpp" +#include "libtorrent/socket.hpp" + +namespace libtorrent { namespace dht +{ + +#ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_DECLARE_LOG(dht_tracker); +#endif + + struct dht_tracker; + + TORRENT_EXPORT void intrusive_ptr_add_ref(dht_tracker const*); + TORRENT_EXPORT void intrusive_ptr_release(dht_tracker const*); + + struct dht_tracker + { + friend void intrusive_ptr_add_ref(dht_tracker const*); + friend void intrusive_ptr_release(dht_tracker const*); + dht_tracker(udp_socket& sock, dht_settings const& settings + , entry const& bootstrap); + void stop(); + + void add_node(udp::endpoint node); + void add_node(std::pair const& node); + void add_router_node(std::pair const& node); + + entry state() const; + + void announce(sha1_hash const& ih, int listen_port + , boost::function const& + , sha1_hash const&)> f); + + void dht_status(session_status& s); + + // translate bittorrent kademlia message into the generic kademlia message + // used by the library + void on_receive(udp::endpoint const& ep, char const* pkt, int size); + void on_unreachable(udp::endpoint const& ep); + + private: + + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } + + void on_name_lookup(error_code const& e + , udp::resolver::iterator host); + void on_router_name_lookup(error_code const& e + , udp::resolver::iterator host); + void connection_timeout(error_code const& e); + void refresh_timeout(error_code const& e); + void tick(error_code const& e); + + void on_bootstrap(); + void send_packet(msg const& m); + + node_impl m_dht; + udp_socket& m_sock; + + std::vector m_send_buf; + + ptime m_last_new_key; + deadline_timer m_timer; + deadline_timer m_connection_timer; + deadline_timer m_refresh_timer; + dht_settings const& m_settings; + int m_refresh_bucket; + + // The mutex is used to abort the dht node + // it's only used to set m_abort to true + typedef boost::mutex mutex_t; + mutable mutex_t m_mutex; + bool m_abort; + + // used to resolve hostnames for nodes + udp::resolver m_host_resolver; + + // used to ignore abusive dht nodes + struct node_ban_entry + { + node_ban_entry(): count(0) {} + udp::endpoint src; + ptime limit; + int count; + }; + + enum { num_ban_nodes = 20 }; + + node_ban_entry m_ban_nodes[num_ban_nodes]; + + // reference counter for intrusive_ptr + mutable boost::detail::atomic_count m_refs; + +#ifdef TORRENT_DHT_VERBOSE_LOGGING + int m_replies_sent[5]; + int m_queries_received[5]; + int m_replies_bytes_sent[5]; + int m_queries_bytes_received[5]; + int m_counter; + int m_announces; + int m_failed_announces; + + int m_total_message_input; + int m_ut_message_input; + int m_lt_message_input; + int m_mp_message_input; + int m_gr_message_input; + int m_mo_message_input; + + int m_total_in_bytes; + int m_total_out_bytes; + + int m_queries_out_bytes; +#endif + }; +}} + +#endif +#endif diff --git a/libtorrent/include/libtorrent/kademlia/find_data.hpp b/libtorrent/include/libtorrent/kademlia/find_data.hpp new file mode 100644 index 000000000..7772ca7c3 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/find_data.hpp @@ -0,0 +1,125 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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 FIND_DATA_050323_HPP +#define FIND_DATA_050323_HPP + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace libtorrent { namespace dht +{ + +typedef std::vector packet_t; + +class rpc_manager; + +// -------- find data ----------- + +class find_data : public traversal_algorithm +{ +public: + typedef boost::function done_callback; + + static void initiate( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , done_callback const& callback + ); + + void got_data(msg const* m); + +private: + void done(); + void invoke(node_id const& id, udp::endpoint addr); + + find_data( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , done_callback const& callback + ); + + done_callback m_done_callback; + boost::shared_ptr m_packet; + bool m_done; +}; + +class find_data_observer : public observer +{ +public: + find_data_observer( + boost::intrusive_ptr const& algorithm + , node_id self + , node_id target) + : observer(algorithm->allocator()) + , m_algorithm(algorithm) + , m_target(target) + , m_self(self) + {} + ~find_data_observer(); + + void send(msg& m) + { + m.reply = false; + m.message_id = messages::get_peers; + m.info_hash = m_target; + } + + void timeout(); + void reply(msg const&); + void abort() { m_algorithm = 0; } + +private: + boost::intrusive_ptr m_algorithm; + node_id const m_target; + node_id const m_self; +}; + +} } // namespace libtorrent::dht + +#endif // FIND_DATA_050323_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/logging.hpp b/libtorrent/include/libtorrent/kademlia/logging.hpp new file mode 100644 index 000000000..c0cbb31a4 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/logging.hpp @@ -0,0 +1,146 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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_LOGGING_HPP +#define TORRENT_LOGGING_HPP + +#include +#include + +namespace libtorrent { namespace dht +{ + +class log +{ +public: + log(char const* id, std::ostream& stream) + : m_id(id) + , m_enabled(true) + , m_stream(stream) + { + } + + char const* id() const + { + return m_id; + } + + bool enabled() const + { + return m_enabled; + } + + void enable(bool e) + { + m_enabled = e; + } + + void flush() { m_stream.flush(); } + + template + log& operator<<(T const& x) + { + m_stream << x; + return *this; + } + +private: + char const* m_id; + bool m_enabled; + std::ostream& m_stream; +}; + +class log_event +{ +public: + log_event(log& log) + : log_(log) + { + if (log_.enabled()) + log_ << '[' << log.id() << "] "; + } + + ~log_event() + { + if (log_.enabled()) + { + log_ << "\n"; + log_.flush(); + } + } + + template + log_event& operator<<(T const& x) + { + log_ << x; + return *this; + } + + operator bool() const + { + return log_.enabled(); + } + +private: + log& log_; +}; + +class inverted_log_event : public log_event +{ +public: + inverted_log_event(log& log) : log_event(log) {} + + operator bool() const + { + return !log_event::operator bool(); + } +}; + +} } // namespace libtorrent::dht + +#define TORRENT_DECLARE_LOG(name) \ + libtorrent::dht::log& name ## _log() + +#define TORRENT_DEFINE_LOG(name) \ + libtorrent::dht::log& name ## _log() \ + { \ + static std::ofstream log_file("dht.log", std::ios::app); \ + static libtorrent::dht::log instance(#name, log_file); \ + return instance; \ + } + +#define TORRENT_LOG(name) \ + if (libtorrent::dht::inverted_log_event event_object__ = name ## _log()); \ + else static_cast(event_object__) + +#endif + diff --git a/libtorrent/include/libtorrent/kademlia/msg.hpp b/libtorrent/include/libtorrent/kademlia/msg.hpp new file mode 100644 index 000000000..00db7305c --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/msg.hpp @@ -0,0 +1,104 @@ +/* + +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 MSG_HPP +#define MSG_HPP + +#include +#include +#include "libtorrent/entry.hpp" +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif + +namespace libtorrent { +namespace dht { + +typedef std::vector packet_t; + +namespace messages +{ + enum { ping = 0, find_node = 1, get_peers = 2, announce_peer = 3, error = 4 }; + char const* const ids[] = { "ping", "find_node", "get_peers", "announce_peer", "error" }; +} // namespace messages + +struct msg +{ + msg() : reply(false), piggy_backed_ping(false) + , message_id(-1), port(0) {} + + // true if this message is a reply + bool reply; + // true if this is a reply with a piggy backed ping + bool piggy_backed_ping; + // the kind if message + int message_id; + // if this is a reply, a copy of the transaction id + // from the request. If it's a request, a transaction + // id that should be sent back in the reply + std::string transaction_id; + // if this packet has a piggy backed ping, this + // is the transaction id of that ping + std::string ping_transaction_id; + // the node id of the process sending the message + node_id id; + // the address of the process sending or receiving + // the message. + udp::endpoint addr; + // if this is a nodes response, these are the nodes + typedef std::vector nodes_t; + nodes_t nodes; + + typedef std::vector peers_t; + peers_t peers; + + // similar to transaction_id but for write operations. + entry write_token; + + // the info has for peer_requests, announce_peer + // and responses + node_id info_hash; + + // port for announce_peer messages + int port; + + // ERROR MESSAGES + int error_code; + std::string error_msg; +}; + + +} } + +#endif diff --git a/libtorrent/include/libtorrent/kademlia/node.hpp b/libtorrent/include/libtorrent/kademlia/node.hpp new file mode 100644 index 000000000..88a1677f1 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/node.hpp @@ -0,0 +1,261 @@ +/* + +Copyright (c) 2006, 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 NODE_HPP +#define NODE_HPP + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "libtorrent/socket.hpp" + +namespace libtorrent { namespace dht +{ + +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(node); +#endif + +// this is the entry for every peer +// the timestamp is there to make it possible +// to remove stale peers +struct peer_entry +{ + tcp::endpoint addr; + ptime added; +}; + +// this is a group. It contains a set of group members +struct torrent_entry +{ + std::set peers; +}; + +inline bool operator<(peer_entry const& lhs, peer_entry const& rhs) +{ + return lhs.addr.address() == rhs.addr.address() + ? lhs.addr.port() < rhs.addr.port() + : lhs.addr.address() < rhs.addr.address(); +} + +struct null_type {}; + +class announce_observer : public observer +{ +public: + announce_observer(boost::pool<>& allocator + , sha1_hash const& info_hash + , int listen_port + , entry const& write_token) + : observer(allocator) + , m_info_hash(info_hash) + , m_listen_port(listen_port) + , m_token(write_token) + {} + + void send(msg& m) + { + m.port = m_listen_port; + m.info_hash = m_info_hash; + m.write_token = m_token; + } + + void timeout() {} + void reply(msg const&) {} + void abort() {} + +private: + sha1_hash m_info_hash; + int m_listen_port; + entry m_token; +}; + +class get_peers_observer : public observer +{ +public: + get_peers_observer(sha1_hash const& info_hash + , int listen_port + , rpc_manager& rpc + , boost::function const&, sha1_hash const&)> f) + : observer(rpc.allocator()) + , m_info_hash(info_hash) + , m_listen_port(listen_port) + , m_rpc(rpc) + , m_fun(f) + {} + + void send(msg& m) + { + m.port = m_listen_port; + m.info_hash = m_info_hash; + } + + void timeout() {} + void reply(msg const& r) + { + observer_ptr o(new (m_rpc.allocator().malloc()) announce_observer( + m_rpc.allocator(), m_info_hash, m_listen_port, r.write_token)); +#ifndef NDEBUG + o->m_in_constructor = false; +#endif + m_rpc.invoke(messages::announce_peer, r.addr, o); + m_fun(r.peers, m_info_hash); + } + void abort() {} + +private: + sha1_hash m_info_hash; + int m_listen_port; + rpc_manager& m_rpc; + boost::function const&, sha1_hash const&)> m_fun; +}; + + + +class node_impl : boost::noncopyable +{ +typedef std::map table_t; +public: + node_impl(boost::function const& f + , dht_settings const& settings, boost::optional node_id); + + virtual ~node_impl() {} + + void refresh(node_id const& id, boost::function0 f); + void bootstrap(std::vector const& nodes + , boost::function0 f); + void find_node(node_id const& id, boost::function< + void(std::vector const&)> f); + void add_router_node(udp::endpoint router); + + void unreachable(udp::endpoint const& ep); + void incoming(msg const& m); + + void refresh(); + void refresh_bucket(int bucket); + int bucket_size(int bucket); + + typedef routing_table::iterator iterator; + + iterator begin() const { return m_table.begin(); } + iterator end() const { return m_table.end(); } + + typedef table_t::iterator data_iterator; + + node_id const& nid() const { return m_id; } + boost::tuple size() const{ return m_table.size(); } + size_type num_global_nodes() const + { return m_table.num_global_nodes(); } + + data_iterator begin_data() { return m_map.begin(); } + data_iterator end_data() { return m_map.end(); } + int data_size() const { return int(m_map.size()); } + +#ifdef TORRENT_DHT_VERBOSE_LOGGING + void print_state(std::ostream& os) const + { m_table.print_state(os); } +#endif + + void announce(sha1_hash const& info_hash, int listen_port + , boost::function const& + , sha1_hash const&)> f); + + bool verify_token(msg const& m); + entry generate_token(msg const& m); + + // the returned time is the delay until connection_timeout() + // should be called again the next time + time_duration connection_timeout(); + time_duration refresh_timeout(); + + // generates a new secret number used to generate write tokens + void new_write_key(); + + // pings the given node, and adds it to + // the routing table if it respons and if the + // bucket is not full. + void add_node(udp::endpoint node); + + void replacement_cache(bucket_t& nodes) const + { m_table.replacement_cache(nodes); } + +protected: + // is called when a find data request is received. Should + // return false if the data is not stored on this node. If + // the data is stored, it should be serialized into 'data'. + bool on_find(msg const& m, std::vector& peers) const; + + // this is called when a store request is received. The data + // is store-parameters and the data to be stored. + void on_announce(msg const& m, msg& reply); + + dht_settings const& m_settings; + + // the maximum number of peers to send in a get_peers + // reply. Ordinary trackers usually limit this to 50. + // 50 => 6 * 50 = 250 bytes + packet overhead + int m_max_peers_reply; + +private: + void incoming_request(msg const& h); + + node_id m_id; + routing_table m_table; + rpc_manager m_rpc; + table_t m_map; + + ptime m_last_tracker_tick; + + // secret random numbers used to create write tokens + int m_secret[2]; +}; + + +} } // namespace libtorrent::dht + +#endif // NODE_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/node_entry.hpp b/libtorrent/include/libtorrent/kademlia/node_entry.hpp new file mode 100644 index 000000000..e31a60e3f --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/node_entry.hpp @@ -0,0 +1,76 @@ +/* + +Copyright (c) 2006, 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 KADEMLIA_NODE_ENTRY_HPP +#define KADEMLIA_NODE_ENTRY_HPP + +#include "libtorrent/kademlia/node_id.hpp" +#include "libtorrent/socket.hpp" + +namespace libtorrent { namespace dht +{ + +struct node_entry +{ + node_entry(node_id const& id_, udp::endpoint addr_) + : id(id_) + , addr(addr_) + , fail_count(0) + { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + first_seen = time_now(); +#endif + } + node_entry(udp::endpoint addr_) + : id(0) + , addr(addr_) + , fail_count(0) + { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + first_seen = time_now(); +#endif + } + + node_id id; + udp::endpoint addr; + // the number of times this node has failed to + // respond in a row + int fail_count; +#ifdef TORRENT_DHT_VERBOSE_LOGGING + ptime first_seen; +#endif +}; + +} } // namespace libtorrent::dht + +#endif + diff --git a/libtorrent/include/libtorrent/kademlia/node_id.hpp b/libtorrent/include/libtorrent/kademlia/node_id.hpp new file mode 100644 index 000000000..4173808c9 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/node_id.hpp @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2006, 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 NODE_ID_HPP +#define NODE_ID_HPP + +#include + +#include +#include "libtorrent/peer_id.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent { namespace dht +{ + +typedef libtorrent::big_number node_id; + +// returns the distance between the two nodes +// using the kademlia XOR-metric +node_id distance(node_id const& n1, node_id const& n2); + +// returns true if: distance(n1, ref) < distance(n2, ref) +bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref); + +// returns n in: 2^n <= distance(n1, n2) < 2^(n+1) +// usefult for finding out which bucket a node belongs to +int distance_exp(node_id const& n1, node_id const& n2); + +node_id generate_id(); + +} } // namespace libtorrent::dht + +#endif // NODE_ID_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/observer.hpp b/libtorrent/include/libtorrent/kademlia/observer.hpp new file mode 100644 index 000000000..073f453bc --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/observer.hpp @@ -0,0 +1,102 @@ +/* + +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 OBSERVER_HPP +#define OBSERVER_HPP + +#include +#include +#include + +namespace libtorrent { +namespace dht { + +struct observer; +struct msg; + +// defined in rpc_manager.cpp +TORRENT_EXPORT void intrusive_ptr_add_ref(observer const*); +TORRENT_EXPORT void intrusive_ptr_release(observer const*); + +struct observer : boost::noncopyable +{ + friend TORRENT_EXPORT void intrusive_ptr_add_ref(observer const*); + friend TORRENT_EXPORT void intrusive_ptr_release(observer const*); + + observer(boost::pool<>& p) + : sent(time_now()) + , pool_allocator(p) + , m_refs(0) + { +#ifndef NDEBUG + m_in_constructor = true; +#endif + } + + virtual ~observer() + { + TORRENT_ASSERT(!m_in_constructor); + } + + // these two callbacks lets the observer add + // information to the message before it's sent + virtual void send(msg& m) = 0; + + // this is called when a reply is received + virtual void reply(msg const& m) = 0; + + // this is called when no reply has been received within + // some timeout + virtual void timeout() = 0; + + // if this is called the destructor should + // not invoke any new messages, and should + // only clean up. It means the rpc-manager + // is being destructed + virtual void abort() = 0; + + udp::endpoint target_addr; + ptime sent; +#ifndef NDEBUG + bool m_in_constructor; +#endif +private: + boost::pool<>& pool_allocator; + // reference counter for intrusive_ptr + mutable boost::detail::atomic_count m_refs; +}; + +typedef boost::intrusive_ptr observer_ptr; + +} } + +#endif diff --git a/libtorrent/include/libtorrent/kademlia/refresh.hpp b/libtorrent/include/libtorrent/kademlia/refresh.hpp new file mode 100644 index 000000000..953c4d871 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/refresh.hpp @@ -0,0 +1,214 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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 REFRESH_050324_HPP +#define REFRESH_050324_HPP + +#include + +#include +#include +#include +#include + +#include + +namespace libtorrent { namespace dht +{ + +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(refresh); +#endif + +class routing_table; +class rpc_manager; + +class refresh : public traversal_algorithm +{ +public: + typedef boost::function done_callback; + + template + static void initiate( + node_id target + , int branch_factor + , int max_active_pings + , int max_results + , routing_table& table + , InIt first + , InIt last + , rpc_manager& rpc + , done_callback const& callback + ); + + void ping_reply(node_id id); + void ping_timeout(node_id id, bool prevent_request = false); + +private: + template + refresh( + node_id target + , int branch_factor + , int max_active_pings + , int max_results + , routing_table& table + , InIt first + , InIt last + , rpc_manager& rpc + , done_callback const& callback + ); + + void done(); + void invoke(node_id const& id, udp::endpoint addr); + + void invoke_pings_or_finish(bool prevent_request = false); + + int m_max_active_pings; + int m_active_pings; + + done_callback m_done_callback; + + std::vector::iterator m_leftover_nodes_iterator; +}; + +class refresh_observer : public observer +{ +public: + refresh_observer( + boost::intrusive_ptr const& algorithm + , node_id self + , node_id target) + : observer(algorithm->allocator()) + , m_target(target) + , m_self(self) + , m_algorithm(algorithm) + {} + ~refresh_observer(); + + void send(msg& m) + { + m.info_hash = m_target; + } + + void timeout(); + void reply(msg const& m); + void abort() { m_algorithm = 0; } + + +private: + node_id const m_target; + node_id const m_self; + boost::intrusive_ptr m_algorithm; +}; + +class ping_observer : public observer +{ +public: + ping_observer( + boost::intrusive_ptr const& algorithm + , node_id self) + : observer(algorithm->allocator()) + , m_self(self) + , m_algorithm(algorithm) + {} + ~ping_observer(); + + void send(msg& p) {} + void timeout(); + void reply(msg const& m); + void abort() { m_algorithm = 0; } + + +private: + node_id const m_self; + boost::intrusive_ptr m_algorithm; +}; + +template +inline refresh::refresh( + node_id target + , int branch_factor + , int max_active_pings + , int max_results + , routing_table& table + , InIt first + , InIt last + , rpc_manager& rpc + , done_callback const& callback +) + : traversal_algorithm( + target + , branch_factor + , max_results + , table + , rpc + , first + , last + ) + , m_max_active_pings(max_active_pings) + , m_active_pings(0) + , m_done_callback(callback) +{ + boost::intrusive_ptr self(this); + add_requests(); +} + +template +inline void refresh::initiate( + node_id target + , int branch_factor + , int max_active_pings + , int max_results + , routing_table& table + , InIt first + , InIt last + , rpc_manager& rpc + , done_callback const& callback +) +{ + new refresh( + target + , branch_factor + , max_active_pings + , max_results + , table + , first + , last + , rpc + , callback + ); +} + +} } // namespace libtorrent::dht + +#endif // REFRESH_050324_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/routing_table.hpp b/libtorrent/include/libtorrent/kademlia/routing_table.hpp new file mode 100644 index 000000000..e3f2e7ded --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/routing_table.hpp @@ -0,0 +1,250 @@ +/* + +Copyright (c) 2006, 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 ROUTING_TABLE_HPP +#define ROUTING_TABLE_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace libtorrent { namespace dht +{ + +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(table); +#endif + + +typedef std::vector bucket_t; + +// differences in the implementation from the description in +// the paper: +// +// * The routing table tree is not allocated dynamically, there +// are always 160 buckets. +// * Nodes are not marked as being stale, they keep a counter +// that tells how many times in a row they have failed. When +// a new node is to be inserted, the node that has failed +// the most times is replaced. If none of the nodes in the +// bucket has failed, then it is put in the replacement +// cache (just like in the paper). + +class routing_table; + +namespace aux +{ + + // Iterates over a flattened routing_table structure. + class routing_table_iterator + : public boost::iterator_facade< + routing_table_iterator + , node_entry const + , boost::forward_traversal_tag + > + { + public: + routing_table_iterator() + { + } + + private: + friend class libtorrent::dht::routing_table; + friend class boost::iterator_core_access; + + typedef boost::array, 160>::const_iterator + bucket_iterator_t; + + routing_table_iterator( + bucket_iterator_t begin + , bucket_iterator_t end) + : m_bucket_iterator(begin) + , m_bucket_end(end) + , m_iterator(begin != end ? begin->first.begin() : bucket_t::const_iterator()) + { + if (m_bucket_iterator == m_bucket_end) return; + while (m_iterator == m_bucket_iterator->first.end()) + { + if (++m_bucket_iterator == m_bucket_end) + break; + m_iterator = m_bucket_iterator->first.begin(); + } + } + + bool equal(routing_table_iterator const& other) const + { + return m_bucket_iterator == other.m_bucket_iterator + && (m_bucket_iterator == m_bucket_end + || m_iterator == other.m_iterator); + } + + void increment() + { + TORRENT_ASSERT(m_bucket_iterator != m_bucket_end); + ++m_iterator; + while (m_iterator == m_bucket_iterator->first.end()) + { + if (++m_bucket_iterator == m_bucket_end) + break; + m_iterator = m_bucket_iterator->first.begin(); + } + } + + node_entry const& dereference() const + { + TORRENT_ASSERT(m_bucket_iterator != m_bucket_end); + return *m_iterator; + } + + bucket_iterator_t m_bucket_iterator; + bucket_iterator_t m_bucket_end; + bucket_t::const_iterator m_iterator; + }; + +} // namespace aux + +class routing_table +{ +public: + typedef aux::routing_table_iterator iterator; + typedef iterator const_iterator; + + routing_table(node_id const& id, int bucket_size + , dht_settings const& settings); + + void node_failed(node_id const& id); + + // adds an endpoint that will never be added to + // the routing table + void add_router_node(udp::endpoint router); + + // iterates over the router nodes added + typedef std::set::const_iterator router_iterator; + router_iterator router_begin() const { return m_router_nodes.begin(); } + router_iterator router_end() const { return m_router_nodes.end(); } + + // this function is called every time the node sees + // a sign of a node being alive. This node will either + // be inserted in the k-buckets or be moved to the top + // of its bucket. + bool node_seen(node_id const& id, udp::endpoint addr); + + // returns time when the given bucket needs another refresh. + // if the given bucket is empty but there are nodes + // in a bucket closer to us, or if the bucket is non-empty and + // the time from the last activity is more than 15 minutes + ptime next_refresh(int bucket); + + // fills the vector with the count nodes from our buckets that + // are nearest to the given id. + void find_node(node_id const& id, std::vector& l + , bool include_self, int count = 0); + + // returns true if the given node would be placed in a bucket + // that is not full. If the node already exists in the table + // this function returns false + bool need_node(node_id const& id); + + // this will set the given bucket's latest activity + // to the current time + void touch_bucket(int bucket); + + int bucket_size(int bucket) + { + TORRENT_ASSERT(bucket >= 0 && bucket < 160); + return (int)m_buckets[bucket].first.size(); + } + int bucket_size() const { return m_bucket_size; } + + iterator begin() const; + iterator end() const; + + boost::tuple size() const; + size_type num_global_nodes() const; + + // returns true if there are no working nodes + // in the routing table + bool need_bootstrap() const; + int num_active_buckets() const + { return 160 - m_lowest_active_bucket + 1; } + + void replacement_cache(bucket_t& nodes) const; +#ifdef TORRENT_DHT_VERBOSE_LOGGING + // used for debug and monitoring purposes. This will print out + // the state of the routing table to the given stream + void print_state(std::ostream& os) const; +#endif + +private: + + // constant called k in paper + int m_bucket_size; + + dht_settings const& m_settings; + + // 160 (k-bucket, replacement cache) pairs + typedef boost::array, 160> table_t; + table_t m_buckets; + // timestamps of the last activity in each bucket + typedef boost::array table_activity_t; + table_activity_t m_bucket_activity; + node_id m_id; // our own node id + + // this is a set of all the endpoints that have + // been identified as router nodes. They will + // be used in searches, but they will never + // be added to the routing table. + std::set m_router_nodes; + + // this is the lowest bucket index with nodes in it + int m_lowest_active_bucket; +}; + +} } // namespace libtorrent::dht + +#endif // ROUTING_TABLE_HPP + diff --git a/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp new file mode 100644 index 000000000..837c091dd --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp @@ -0,0 +1,141 @@ +/* + +Copyright (c) 2006, 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 RPC_MANAGER_HPP +#define RPC_MANAGER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "libtorrent/time.hpp" + +namespace libtorrent { namespace dht +{ + +struct observer; + +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(rpc); +#endif + +struct null_observer : public observer +{ + null_observer(boost::pool<>& allocator): observer(allocator) {} + virtual void reply(msg const&) {} + virtual void timeout() {} + virtual void send(msg&) {} + void abort() {} +}; + +class routing_table; + +class rpc_manager +{ +public: + typedef boost::function1 fun; + typedef boost::function1 send_fun; + + rpc_manager(fun const& incoming_fun, node_id const& our_id + , routing_table& table, send_fun const& sf); + ~rpc_manager(); + + void unreachable(udp::endpoint const& ep); + + // returns true if the node needs a refresh + bool incoming(msg const&); + time_duration tick(); + + void invoke(int message_id, udp::endpoint target + , observer_ptr o); + + void reply(msg& m); + void reply_with_ping(msg& m); + +#ifndef NDEBUG + size_t allocation_size() const; + void check_invariant() const; +#endif + + boost::pool<>& allocator() const + { return m_pool_allocator; } + +private: + + enum { max_transactions = 2048 }; + + unsigned int new_transaction_id(observer_ptr o); + void update_oldest_transaction_id(); + + boost::uint32_t calc_connection_id(udp::endpoint addr); + + mutable boost::pool<> m_pool_allocator; + + typedef boost::array + transactions_t; + transactions_t m_transactions; + std::vector m_aborted_transactions; + + // this is the next transaction id to be used + int m_next_transaction_id; + // this is the oldest transaction id still + // (possibly) in use. This is the transaction + // that will time out first, the one we are + // waiting for to time out + int m_oldest_transaction_id; + + fun m_incoming; + send_fun m_send; + node_id m_our_id; + routing_table& m_table; + ptime m_timer; + node_id m_random_number; + bool m_destructing; +}; + +} } // namespace libtorrent::dht + +#endif + + diff --git a/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp b/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp new file mode 100644 index 000000000..74d79edc9 --- /dev/null +++ b/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp @@ -0,0 +1,161 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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 TRAVERSAL_ALGORITHM_050324_HPP +#define TRAVERSAL_ALGORITHM_050324_HPP + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace libtorrent { namespace dht +{ +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(traversal); +#endif + +class rpc_manager; + +// this class may not be instantiated as a stack object +class traversal_algorithm : boost::noncopyable +{ +public: + void traverse(node_id const& id, udp::endpoint addr); + void finished(node_id const& id); + void failed(node_id const& id, bool prevent_request = false); + virtual ~traversal_algorithm() {} + boost::pool<>& allocator() const; + +protected: + template + traversal_algorithm( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , InIt start + , InIt end + ); + + void add_requests(); + void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags); + + virtual void done() = 0; + virtual void invoke(node_id const& id, udp::endpoint addr) = 0; + + struct result + { + result(node_id const& id, udp::endpoint addr, unsigned char f = 0) + : id(id), addr(addr), flags(f) {} + + node_id id; + udp::endpoint addr; + enum { queried = 1, initial = 2, no_id = 4 }; + unsigned char flags; + }; + + std::vector::iterator last_iterator(); + + friend void intrusive_ptr_add_ref(traversal_algorithm* p) + { + p->m_ref_count++; + } + + friend void intrusive_ptr_release(traversal_algorithm* p) + { + if (--p->m_ref_count == 0) + delete p; + } + + int m_ref_count; + + node_id m_target; + int m_branch_factor; + int m_max_results; + std::vector m_results; + std::set m_failed; + routing_table& m_table; + rpc_manager& m_rpc; + int m_invoke_count; +}; + +template +traversal_algorithm::traversal_algorithm( + node_id target + , int branch_factor + , int max_results + , routing_table& table + , rpc_manager& rpc + , InIt start // <- nodes to initiate traversal with + , InIt end +) + : m_ref_count(0) + , m_target(target) + , m_branch_factor(branch_factor) + , m_max_results(max_results) + , m_table(table) + , m_rpc(rpc) + , m_invoke_count(0) +{ + using boost::bind; + + for (InIt i = start; i != end; ++i) + { + add_entry(i->id, i->addr, result::initial); + } + + // in case the routing table is empty, use the + // router nodes in the table + if (start == end) + { + for (routing_table::router_iterator i = table.router_begin() + , end(table.router_end()); i != end; ++i) + { + add_entry(node_id(0), *i, result::initial); + } + } + +} + +} } // namespace libtorrent::dht + +#endif // TRAVERSAL_ALGORITHM_050324_HPP + diff --git a/libtorrent/include/libtorrent/lazy_entry.hpp b/libtorrent/include/libtorrent/lazy_entry.hpp new file mode 100644 index 000000000..ffd4337e4 --- /dev/null +++ b/libtorrent/include/libtorrent/lazy_entry.hpp @@ -0,0 +1,232 @@ +/* + +Copyright (c) 2003, 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_LAZY_ENTRY_HPP_INCLUDED +#define TORRENT_LAZY_ENTRY_HPP_INCLUDED + +#include +#include +#include "libtorrent/assert.hpp" +#include "libtorrent/size_type.hpp" +#include + +namespace libtorrent +{ + struct lazy_entry; + + char const* parse_int(char const* start, char const* end, char delimiter, boost::int64_t& val); + // return 0 = success + int lazy_bdecode(char const* start, char const* end, lazy_entry& ret, int depth_limit = 1000); + + struct lazy_entry + { + enum entry_type_t + { + none_t, dict_t, list_t, string_t, int_t + }; + + lazy_entry() : m_type(none_t), m_begin(0), m_end(0) + { m_data.start = 0; } + + entry_type_t type() const { return m_type; } + + // start points to the first decimal digit + // length is the number of digits + void construct_int(char const* start, int length) + { + TORRENT_ASSERT(m_type == none_t); + m_type = int_t; + m_data.start = start; + m_size = length; + m_begin = start - 1; // include 'i' + m_end = start + length + 1; // include 'e' + } + + size_type int_value() const; + + // string functions + // ================ + + void construct_string(char const* start, int length); + + // the string is not null-terminated! + char const* string_ptr() const + { + TORRENT_ASSERT(m_type == string_t); + return m_data.start; + } + + // this will return a null terminated string + // it will write to the source buffer! + char const* string_cstr() const + { + TORRENT_ASSERT(m_type == string_t); + const_cast(m_data.start)[m_size] = 0; + return m_data.start; + } + + std::string string_value() const + { + TORRENT_ASSERT(m_type == string_t); + return std::string(m_data.start, m_size); + } + + int string_length() const + { return m_size; } + + // dictionary functions + // ==================== + + void construct_dict(char const* begin) + { + TORRENT_ASSERT(m_type == none_t); + m_type = dict_t; + m_size = 0; + m_capacity = 0; + m_begin = begin; + } + + lazy_entry* dict_append(char const* name); + lazy_entry* dict_find(char const* name); + lazy_entry const* dict_find(char const* name) const + { return const_cast(this)->dict_find(name); } + + std::string dict_find_string_value(char const* name) const; + size_type dict_find_int_value(char const* name, size_type default_val = 0) const; + lazy_entry const* dict_find_dict(char const* name) const; + lazy_entry const* dict_find_list(char const* name) const; + + std::pair dict_at(int i) const + { + TORRENT_ASSERT(m_type == dict_t); + TORRENT_ASSERT(i < m_size); + std::pair const& e = m_data.dict[i]; + return std::make_pair(std::string(e.first, e.second.m_begin - e.first), &e.second); + } + + int dict_size() const + { + TORRENT_ASSERT(m_type == dict_t); + return m_size; + } + + // list functions + // ============== + + void construct_list(char const* begin) + { + TORRENT_ASSERT(m_type == none_t); + m_type = list_t; + m_size = 0; + m_capacity = 0; + m_begin = begin; + } + + lazy_entry* list_append(); + lazy_entry* list_at(int i) + { + TORRENT_ASSERT(m_type == list_t); + TORRENT_ASSERT(i < m_size); + return &m_data.list[i]; + } + lazy_entry const* list_at(int i) const + { return const_cast(this)->list_at(i); } + + std::string list_string_value_at(int i) const; + size_type list_int_value_at(int i, size_type default_val = 0) const; + + int list_size() const + { + TORRENT_ASSERT(m_type == list_t); + return m_size; + } + + // end points one byte passed last byte + void set_end(char const* end) + { + TORRENT_ASSERT(end > m_begin); + m_end = end; + } + + void clear(); + + // releases ownership of any memory allocated + void release() + { + m_data.start = 0; + m_size = 0; + m_capacity = 0; + m_type = none_t; + } + + ~lazy_entry() + { clear(); } + + // returns pointers into the source buffer where + // this entry has its bencoded data + std::pair data_section() const; + + void swap(lazy_entry& e) + { + using std::swap; + swap(m_type, e.m_type); + swap(m_data.start, e.m_data.start); + swap(m_size, e.m_size); + swap(m_capacity, e.m_capacity); + swap(m_begin, e.m_begin); + swap(m_end, e.m_end); + } + + private: + + entry_type_t m_type; + union data_t + { + std::pair* dict; + lazy_entry* list; + char const* start; + } m_data; + int m_size; // if list or dictionary, the number of items + int m_capacity; // if list or dictionary, allocated number of items + // used for dictionaries and lists to record the range + // in the original buffer they are based on + char const* m_begin; + char const* m_end; + }; + + std::ostream& operator<<(std::ostream& os, lazy_entry const& e); + +}; + + +#endif + diff --git a/libtorrent/include/libtorrent/lsd.hpp b/libtorrent/include/libtorrent/lsd.hpp new file mode 100644 index 000000000..6e3ddea7d --- /dev/null +++ b/libtorrent/include/libtorrent/lsd.hpp @@ -0,0 +1,98 @@ +/* + +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 "libtorrent/broadcast_socket.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" + +#include +#include +#include +#include +#include + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) +#include +#endif + +namespace libtorrent +{ + +typedef boost::function peer_callback_t; + +class lsd : public intrusive_ptr_base +{ +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: + + void resend_announce(error_code const& e, std::string msg); + void on_announce(udp::endpoint const& from, char* buffer + , std::size_t bytes_transferred); +// void setup_receive(); + + peer_callback_t m_callback; + + // current retry count + int m_retry_count; + + // the udp socket used to send and receive + // multicast messages on + broadcast_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 + diff --git a/libtorrent/include/libtorrent/magnet_uri.hpp b/libtorrent/include/libtorrent/magnet_uri.hpp new file mode 100644 index 000000000..2e947efa0 --- /dev/null +++ b/libtorrent/include/libtorrent/magnet_uri.hpp @@ -0,0 +1,59 @@ +/* + +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_MAGNET_URI_HPP_INCLUDED +#define TORRENT_MAGNET_URI_HPP_INCLUDED + +#include +#include "libtorrent/config.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/session.hpp" +#include + +namespace libtorrent +{ + namespace fs = boost::filesystem; + + struct torrent_handle; + + std::string TORRENT_EXPORT make_magnet_uri(torrent_handle const& handle); + + torrent_handle TORRENT_EXPORT add_magnet_uri(session& ses, std::string const& uri + , fs::path const& save_path + , storage_mode_t storage_mode = storage_mode_sparse + , bool paused = false + , storage_constructor_type sc = default_storage_constructor + , void* userdata = 0); +} + +#endif + diff --git a/libtorrent/include/libtorrent/natpmp.hpp b/libtorrent/include/libtorrent/natpmp.hpp new file mode 100644 index 000000000..8ce54132b --- /dev/null +++ b/libtorrent/include/libtorrent/natpmp.hpp @@ -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. + +*/ + +#ifndef TORRENT_NATPMP_HPP +#define TORRENT_NATPMP_HPP + +#include "libtorrent/socket.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" + +#include +#include + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) +#include +#endif + +namespace libtorrent +{ + +// int: port mapping index +// int: external port +// std::string: error message +typedef boost::function portmap_callback_t; + +class natpmp : public intrusive_ptr_base +{ +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 + enum protocol_type { none = 0, udp = 1, tcp = 2 }; + int add_mapping(protocol_type p, int external_port, int local_port); + void delete_mapping(int mapping_index); + + void close(); + +private: + + void update_mapping(int i); + void send_map_request(int i); + void resend_request(int i, error_code const& e); + void on_reply(error_code const& e + , std::size_t bytes_transferred); + void try_next_mapping(int i); + void update_expiration_timer(); + void mapping_expired(error_code const& e, int i); + + void disable(char const* message); + + struct mapping_t + { + enum action_t { action_none, action_add, action_delete }; + mapping_t() + : action(action_none) + , local_port(0) + , external_port(0) + , protocol(none) + {} + + // indicates that the mapping has changed + // and needs an update + int action; + + // 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; + + int protocol; + }; + + portmap_callback_t m_callback; + + std::vector m_mappings; + + // 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; + + // the mapping index that will expire next + int m_next_refresh; + + bool m_disabled; + + bool m_abort; + + typedef boost::mutex mutex_t; + mutex_t m_mutex; + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + std::ofstream m_log; +#endif +}; + +} + + +#endif + diff --git a/libtorrent/include/libtorrent/parse_url.hpp b/libtorrent/include/libtorrent/parse_url.hpp new file mode 100644 index 000000000..18a6ddf90 --- /dev/null +++ b/libtorrent/include/libtorrent/parse_url.hpp @@ -0,0 +1,59 @@ +/* + +Copyright (c) 2008, 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_PARSE_URL_HPP_INCLUDED +#define TORRENT_PARSE_URL_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + + TORRENT_EXPORT boost::tuple + parse_url_components(std::string url); + +} + +#endif + diff --git a/libtorrent/include/libtorrent/pch.hpp b/libtorrent/include/libtorrent/pch.hpp new file mode 100644 index 000000000..de937c596 --- /dev/null +++ b/libtorrent/include/libtorrent/pch.hpp @@ -0,0 +1,127 @@ +/* + +Copyright (c) 2008, 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. + +*/ + +#ifdef BOOST_BUILD_PCH_ENABLED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +#define Protocol Protocol_ +#endif + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +#undef Protocol +#endif + +#endif + diff --git a/libtorrent/include/libtorrent/pe_crypto.hpp b/libtorrent/include/libtorrent/pe_crypto.hpp new file mode 100644 index 000000000..dd1260497 --- /dev/null +++ b/libtorrent/include/libtorrent/pe_crypto.hpp @@ -0,0 +1,124 @@ +/* + +Copyright (c) 2007, Un Shyam +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_DISABLE_ENCRYPTION + +#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED +#define TORRENT_PE_CRYPTO_HPP_INCLUDED + +#include +#include +#include + +#include "libtorrent/peer_id.hpp" // For sha1_hash +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + class dh_key_exchange + { + public: + dh_key_exchange(); + ~dh_key_exchange(); + bool good() const { return m_dh; } + + // Get local public key, always 96 bytes + char const* get_local_key() const; + + // read remote_pubkey, generate and store shared secret in + // m_dh_secret. + int compute_secret(const char* remote_pubkey); + + const char* get_secret() const; + + private: + int get_local_key_size() const + { + TORRENT_ASSERT(m_dh); + return BN_num_bytes(m_dh->pub_key); + } + + DH* m_dh; + + char m_dh_local_key[96]; + char m_dh_secret[96]; + }; + + class RC4_handler // Non copyable + { + public: + // Input longkeys must be 20 bytes + RC4_handler(const sha1_hash& rc4_local_longkey, + const sha1_hash& rc4_remote_longkey) + + { + RC4_set_key(&m_local_key, 20, + reinterpret_cast(rc4_local_longkey.begin())); + RC4_set_key(&m_remote_key, 20, + reinterpret_cast(rc4_remote_longkey.begin())); + + // Discard first 1024 bytes + char buf[1024]; + encrypt(buf, 1024); + decrypt(buf, 1024); + }; + + ~RC4_handler() {}; + + void encrypt(char* pos, int len) + { + TORRENT_ASSERT(len >= 0); + TORRENT_ASSERT(pos); + + RC4 (&m_local_key, len, reinterpret_cast(pos), + reinterpret_cast(pos)); + } + + void decrypt(char* pos, int len) + { + TORRENT_ASSERT(len >= 0); + TORRENT_ASSERT(pos); + + RC4 (&m_remote_key, len, reinterpret_cast(pos), + reinterpret_cast(pos)); + } + + private: + RC4_KEY m_local_key; // Key to encrypt outgoing data + RC4_KEY m_remote_key; // Key to decrypt incoming data + }; + +} // namespace libtorrent + +#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED +#endif // TORRENT_DISABLE_ENCRYPTION + diff --git a/libtorrent/include/libtorrent/peer.hpp b/libtorrent/include/libtorrent/peer.hpp new file mode 100644 index 000000000..c404a611d --- /dev/null +++ b/libtorrent/include/libtorrent/peer.hpp @@ -0,0 +1,63 @@ +/* + +Copyright (c) 2003, 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_PEER_HPP_INCLUDED +#define TORRENT_PEER_HPP_INCLUDED + +#include + +#include "libtorrent/peer_id.hpp" + +namespace libtorrent +{ + + struct TORRENT_EXPORT peer_entry + { + std::string ip; + int port; + peer_id pid; + + bool operator==(const peer_entry& p) const + { + return pid == p.pid; + } + + bool operator<(const peer_entry& p) const + { + return pid < p.pid; + } + }; + +} + +#endif // TORRENT_PEER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp new file mode 100644 index 000000000..f43857d5e --- /dev/null +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -0,0 +1,845 @@ +/* + +Copyright (c) 2003, 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_PEER_CONNECTION_HPP_INCLUDED +#define TORRENT_PEER_CONNECTION_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#include "libtorrent/debug.hpp" + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/buffer.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/piece_block_progress.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/bandwidth_limit.hpp" +#include "libtorrent/policy.hpp" +#include "libtorrent/socket_type.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/chained_buffer.hpp" +#include "libtorrent/disk_buffer_holder.hpp" +#include "libtorrent/bitfield.hpp" + +namespace libtorrent +{ + class torrent; + struct peer_plugin; + + namespace detail + { + struct session_impl; + } + + struct TORRENT_EXPORT protocol_error: std::runtime_error + { + protocol_error(const std::string& msg): std::runtime_error(msg) {}; + }; + + class TORRENT_EXPORT peer_connection + : public intrusive_ptr_base + , public boost::noncopyable + { + friend class invariant_access; + public: + + enum channels + { + upload_channel, + download_channel, + num_channels + }; + + // this is the constructor where the we are the active part. + // The peer_conenction should handshake and verify that the + // other end has the correct id + peer_connection( + aux::session_impl& ses + , boost::weak_ptr t + , boost::shared_ptr 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 + peer_connection( + aux::session_impl& ses + , boost::shared_ptr s + , tcp::endpoint const& remote + , policy::peer* peerinfo); + + // this function is called after it has been constructed and properly + // reference counted. It is safe to call self() in this function + // and schedule events with references to itself (that is not safe to + // do in the constructor). + virtual void start(); + + 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(); + + void send_allowed_set(); + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::shared_ptr); +#endif + + // this function is called once the torrent associated + // with this peer connection has retrieved the meta- + // data. If the torrent was spawned with metadata + // this is called from the constructor. + void init(); + + // this is called when the metadata is retrieved + // and the files has been checked + virtual void on_metadata() {} + + 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; } + + int prefer_whole_pieces() const + { + if (on_parole()) return 1; + return m_prefer_whole_pieces; + } + + bool on_parole() const + { return peer_info_struct() && peer_info_struct()->on_parole; } + + void prefer_whole_pieces(int num) + { m_prefer_whole_pieces = num; } + + bool request_large_blocks() const + { return m_request_large_blocks; } + + void request_large_blocks(bool b) + { m_request_large_blocks = b; } + + void set_priority(int p) + { m_priority = p; } + + void fast_reconnect(bool r); + bool fast_reconnect() const { return m_fast_reconnect; } + + // 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); + + // tells if this connection has data it want to send + // and has enough upload bandwidth quota left to send it. + bool can_write() const; + bool can_read() const; + + bool is_seed() const; + + void set_upload_only(bool u) { m_upload_only = u; } + bool upload_only() const { return m_upload_only; } + + // will send a keep-alive message to the peer + void keep_alive(); + + peer_id const& pid() const { return m_peer_id; } + void set_pid(const peer_id& pid) { m_peer_id = pid; } + bool has_piece(int i) const; + + std::deque const& download_queue() const; + std::deque const& request_queue() const; + std::deque const& upload_queue() const; + + bool is_interesting() const { return m_interesting; } + bool is_choked() const { return m_choked; } + + bool is_peer_interested() const { return m_peer_interested; } + bool has_peer_choked() const { return m_peer_choked; } + + void update_interest(); + + virtual void get_peer_info(peer_info& p) const; + + // 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 + // which torrent it should be associated with + boost::weak_ptr associated_torrent() const + { return m_torrent; } + + const stat& statistics() const { return m_statistics; } + void add_stat(size_type downloaded, size_type uploaded); + + void calc_ip_overhead(); + + // is called once every second by the main loop + void second_tick(float tick_interval); + + boost::shared_ptr get_socket() const { return m_socket; } + tcp::endpoint const& remote() const { return m_remote; } + + bitfield const& get_bitfield() const; + std::vector const& allowed_fast(); + std::vector const& suggested_pieces() const { return m_suggested_pieces; } + + ptime connected_time() const { return m_connect; } + ptime last_received() const { return m_last_receive; } + + void timed_out(); + // this will cause this peer_connection to be disconnected. + void disconnect(char const* message, int error = 0); + bool is_disconnecting() const { return m_disconnecting; } + + // this is called when the connection attempt has succeeded + // and the peer_connection is supposed to set m_connecting + // to false, and stop monitor writability + void on_connection_complete(error_code const& e); + + // returns true if this connection is still waiting to + // finish the connection attempt + bool is_connecting() const { return m_connecting; } + + // returns true if the socket of this peer hasn't been + // attempted to connect yet (i.e. it's queued for + // connection attempt). + bool is_queued() const { return m_queued; } + + // called when it's time for this peer_conncetion to actually + // initiate the tcp connection. This may be postponed until + // the library isn't using up the limitation of half-open + // tcp connections. + void connect(int ticket); + + // This is called for every peer right after the upload + // bandwidth has been distributed among them + // It will reset the used bandwidth to 0. + void reset_upload_quota(); + + // free upload. + size_type total_free_upload() const; + void add_free_upload(size_type free_upload); + + // trust management. + void received_valid_data(int index); + void received_invalid_data(int index); + + size_type share_diff() const; + + // a connection is local if it was initiated by us. + // 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; } + + bool failed() const { return m_failed; } + + int desired_queue_size() const { return m_desired_queue_size; } + + // compares this connection against the given connection + // for which one is more eligible for an unchoke. + // returns true if this is more eligible + bool unchoke_compare(boost::intrusive_ptr const& p) const; + + // resets the byte counters that are used to measure + // the number of bytes transferred within unchoke cycles + void reset_choke_counters(); + +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING + boost::shared_ptr m_logger; +#endif + + // the message handlers are called + // each time a recv() returns some new + // data, the last time it will be called + // is when the entire packet has been + // received, then it will no longer + // be called. i.e. most handlers need + // to check how much of the packet they + // have received before any processing + void incoming_keepalive(); + void incoming_choke(); + void incoming_unchoke(); + void incoming_interested(); + void incoming_not_interested(); + void incoming_have(int piece_index); + void incoming_bitfield(bitfield const& bits); + void incoming_request(peer_request const& r); + void incoming_piece(peer_request const& p, disk_buffer_holder& data); + void incoming_piece(peer_request const& p, char const* data); + void incoming_piece_fragment(); + void incoming_cancel(peer_request const& r); + + void incoming_dht_port(int listen_port); + + void incoming_reject_request(peer_request const& r); + void incoming_have_all(); + void incoming_have_none(); + void incoming_allowed_fast(int index); + void incoming_suggest(int index); + + // the following functions appends messages + // to the send buffer + void send_choke(); + void send_unchoke(); + void send_interested(); + void send_not_interested(); + + // adds a block to the request queue + void add_request(piece_block const& b); + // removes a block from the request queue or download queue + // sends a cancel message if appropriate + // refills the request queue, and possibly ignoring pieces requested + // by peers in the ignore list (to avoid recursion) + void cancel_request(piece_block const& b); + void send_block_requests(); + + int max_assignable_bandwidth(int channel) const + { return m_bandwidth_limit[channel].max_assignable(); } + + int bandwidth_throttle(int channel) const + { return m_bandwidth_limit[channel].throttle(); } + + void assign_bandwidth(int channel, int amount); + void expire_bandwidth(int channel, int amount); + +#ifndef NDEBUG + void check_invariant() const; + ptime m_last_choke; +#endif + + + // is true until we can be sure that the other end + // speaks our protocol (be it bittorrent or http). + virtual bool in_handshake() const = 0; + + // returns the block currently being + // downloaded. And the progress of that + // block. If the peer isn't downloading + // a piece for the moment, the boost::optional + // will be invalid. + virtual boost::optional + downloading_piece_progress() const + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "downloading_piece_progress() dispatched to the base class!\n"; +#endif + return boost::optional(); + } + + // these functions are virtual to let bt_peer_connection hook into them + // and encrypt the content + virtual void send_buffer(char const* begin, int size); + virtual buffer::interval allocate_send_buffer(int size); + virtual void setup_send(); + + template + void append_send_buffer(char* buffer, int size, Destructor const& destructor) + { + m_send_buffer.append_buffer(buffer, size, size, destructor); +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " append_send_buffer: " << size << std::endl; + m_ses.log_buffer_usage(); +#endif + } + +#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES + void set_country(char const* c) + { + TORRENT_ASSERT(strlen(c) == 2); + m_country[0] = c[0]; + m_country[1] = c[1]; + } + bool has_country() const { return m_country[0] != 0; } +#endif + + int send_buffer_size() const + { return m_send_buffer.size(); } + + int send_buffer_capacity() const + { return m_send_buffer.capacity(); } + + int packet_size() const { return m_packet_size; } + + bool packet_finished() const + { return m_packet_size <= m_recv_pos; } + +#ifndef NDEBUG + bool piece_failed; +#endif + + // upload and download channel state + // enum from peer_info::bw_state + char m_channel_state[2]; + + protected: + + virtual void get_specific_peer_info(peer_info& p) const = 0; + + virtual void write_choke() = 0; + virtual void write_unchoke() = 0; + virtual void write_interested() = 0; + virtual void write_not_interested() = 0; + virtual void write_request(peer_request const& r) = 0; + virtual void write_cancel(peer_request const& r) = 0; + virtual void write_have(int index) = 0; + virtual void write_keepalive() = 0; + virtual void write_piece(peer_request const& r, disk_buffer_holder& buffer) = 0; + + virtual void write_reject_request(peer_request const& r) = 0; + virtual void write_allow_fast(int piece) = 0; + + virtual void on_connected() = 0; + virtual void on_tick() {} + + virtual void on_receive(error_code const& error + , std::size_t bytes_transferred) = 0; + virtual void on_sent(error_code const& error + , std::size_t bytes_transferred) = 0; + +#ifndef TORRENT_DISABLE_ENCRYPTION + buffer::interval wr_recv_buffer() + { + TORRENT_ASSERT(!m_disk_recv_buffer); + TORRENT_ASSERT(m_disk_recv_buffer_size == 0); + if (m_recv_buffer.empty()) return buffer::interval(0,0); + return buffer::interval(&m_recv_buffer[0] + , &m_recv_buffer[0] + m_recv_pos); + } + + std::pair wr_recv_buffers(int bytes); +#endif + + buffer::const_interval receive_buffer() const + { + if (m_recv_buffer.empty()) return buffer::const_interval(0,0); + return buffer::const_interval(&m_recv_buffer[0] + , &m_recv_buffer[0] + m_recv_pos); + } + + bool allocate_disk_receive_buffer(int disk_buffer_size); + char* release_disk_receive_buffer(); + bool has_disk_receive_buffer() const { return m_disk_recv_buffer; } + void cut_receive_buffer(int size, int packet_size); + void reset_recv_buffer(int packet_size); + + void setup_receive(); + + void attach_to_torrent(sha1_hash const& ih); + + bool verify_piece(peer_request const& p) const; + + // the bandwidth channels, upload and download + // keeps track of the current quotas + bandwidth_limit m_bandwidth_limit[num_channels]; + + // statistics about upload and download speeds + // and total amount of uploads and downloads for + // this peer + stat m_statistics; + + // a back reference to the session + // the peer belongs to. + aux::session_impl& m_ses; + + // called from the main loop when this connection has any + // work to do. + void on_send_data(error_code const& error + , std::size_t bytes_transferred); + void on_receive_data(error_code const& error + , std::size_t bytes_transferred); + + // this is the limit on the number of outstanding requests + // we have to this peer. This is initialized to the settings + // in the session_settings structure. But it may be lowered + // if the peer is known to require a smaller limit (like BitComet). + // or if the extended handshake sets a limit. + // web seeds also has a limit on the queue size. + int m_max_out_request_queue; + + void set_timeout(int s) { m_timeout = s; } + +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list > extension_list_t; + 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 + +#ifndef NDEBUG + boost::intrusive_ptr self() + { + TORRENT_ASSERT(!m_in_constructor); + return intrusive_ptr_base::self(); + } +#endif + + private: + + void fill_send_buffer(); + void on_disk_read_complete(int ret, disk_io_job const& j, peer_request r); + void on_disk_write_complete(int ret, disk_io_job const& j + , peer_request r, boost::shared_ptr t); + + // the time when we last got a part of a + // piece packet from this peer + ptime m_last_piece; + // the time we sent a request to + // this peer the last time + ptime m_last_request; + // the time we received the last + // piece request from the peer + ptime m_last_incoming_request; + // the time when we unchoked this peer + ptime m_last_unchoke; + + // timeouts + ptime m_last_receive; + ptime m_last_sent; + + // the time when the first entry in the + // request queue was requested, increased + // for each entry that is popped from the + // download queue. Used for request timeout + ptime m_requested; + + // a timestamp when the remote download rate + // was last updated + ptime m_remote_dl_update; + + // the time when async_connect was called + ptime m_connect; + + // the time when this peer sent us a not_interested message + // the last time. + ptime m_became_uninterested; + + // the time when we sent a not_interested message to + // this peer the last time. + ptime m_became_uninteresting; + + // the amount of data this peer has been given + // as free upload. This is distributed from + // peers from which we get free download + // this will be negative on a peer from which + // we get free download, and positive on peers + // that we give the free upload, to keep the balance. + size_type m_free_upload; + + // the total payload download bytes + // at the last unchoke cycle. This is used to + // measure the number of bytes transferred during + // an unchoke cycle, to unchoke peers the more bytes + // they sent us + size_type m_downloaded_at_last_unchoke; + +#ifndef TORRENT_DISABLE_GEO_IP + std::string m_inet_as_name; +#endif + + buffer m_recv_buffer; + + // if this peer is receiving a piece, this + // points to a disk buffer that the data is + // read into. This eliminates a memcopy from + // the receive buffer into the disk buffer + disk_buffer_holder m_disk_recv_buffer; + + chained_buffer m_send_buffer; + + boost::shared_ptr 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; + + // this is the torrent this connection is + // associated with. If the connection is an + // incoming conncetion, this is set to zero + // until the info_hash is received. Then it's + // set to the torrent it belongs to. + boost::weak_ptr m_torrent; + + // remote peer's id + peer_id m_peer_id; + + // the pieces the other end have + bitfield m_have_piece; + + // the queue of requests we have got + // from this peer + std::deque m_requests; + + // the blocks we have reserved in the piece + // picker and will request from this peer. + std::deque m_request_queue; + + // the queue of blocks we have requested + // from this peer + std::deque m_download_queue; + + // the pieces we will send to the peer + // if requested (regardless of choke state) + std::set m_accept_fast; + + // the pieces the peer will send us if + // requested (regardless of choke state) + std::vector m_allowed_fast; + + // pieces that has been suggested to be + // downloaded from this peer + std::vector m_suggested_pieces; + + // the number of pieces this peer + // has. Must be the same as + // std::count(m_have_piece.begin(), + // m_have_piece.end(), true) + int m_num_pieces; + + // the timeout in seconds + int m_timeout; + + // the size (in bytes) of the bittorrent message + // we're currently receiving + int m_packet_size; + + // the number of bytes of the bittorrent payload + // we've received so far + int m_recv_pos; + + int m_disk_recv_buffer_size; + + // the number of bytes we are currently reading + // from disk, that will be added to the send + // buffer as soon as they complete + int m_reading_bytes; + + // the number of invalid piece-requests + // we have got from this peer. If the request + // queue gets empty, and there have been + // invalid requests, we can assume the + // peer is waiting for those pieces. + // we can then clear its download queue + // by sending choke, unchoke. + int m_num_invalid_requests; + + // this is the priority with which this peer gets + // download bandwidth quota assigned to it. + int m_priority; + + 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; + + // bytes downloaded since last second + // timer timeout; used for determining + // approx download rate + int m_remote_bytes_dled; + + // approximate peer download rate + int m_remote_dl_rate; + + // the number of bytes send to the disk-io + // thread that hasn't yet been completely written. + int m_outstanding_writing_bytes; + + // max transfer rates seen on this peer + int m_download_rate_peak; + int m_upload_rate_peak; + + // estimated round trip time to this peer + // based on the time from when async_connect + // was called to when on_connection_complete + // was called. The rtt is specified in milliseconds + boost::uint16_t m_rtt; + + // if set to non-zero, this peer will always prefer + // to request entire n pieces, rather than blocks. + // where n is the value of this variable. + // if it is 0, the download rate limit setting + // will be used to determine if whole pieces + // are preferred. + boost::uint8_t m_prefer_whole_pieces; + + // the number of request we should queue up + // at the remote end. + boost::uint8_t m_desired_queue_size; + + // if this is true, the disconnection + // timestamp is not updated when the connection + // is closed. This means the time until we can + // reconnect to this peer is shorter, and likely + // immediate. + bool m_fast_reconnect:1; + + // is true if it was we that connected to the peer + // and false if we got an incoming connection + // could be considered: true = local, false = remote + bool m_active:1; + + // other side says that it's interested in downloading + // from us. + bool m_peer_interested:1; + + // the other side has told us that it won't send anymore + // data to us for a while + bool m_peer_choked:1; + + // the peer has pieces we are interested in + bool m_interesting:1; + + // we have choked the upload to the peer + bool m_choked:1; + + // this is set to true if the connection timed + // out or closed the connection. In that + // case we will not try to reconnect to + // this peer + bool m_failed:1; + + // 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:1; + + // this is set to true when a have_all + // message is received. This information + // is used to fill the bitmask in init() + bool m_have_all:1; + + // if this is true, this peer is assumed to handle all piece + // requests in fifo order. All skipped blocks are re-requested + // immediately instead of having a looser requirement + // where blocks can be sent out of order. The default is to + // allow non-fifo order. + bool m_assume_fifo:1; + + // this is true if this connection has been added + // to the list of connections that will be closed. + bool m_disconnecting:1; + + // this is true until this socket has become + // writable for the first time (i.e. the + // connection completed). While connecting + // the timeout will not be triggered. This is + // because windows XP SP2 may delay connection + // attempts, which means that the connection + // may not even have been attempted when the + // time out is reached. + bool m_connecting:1; + + // This is true until connect is called on the + // peer_connection's socket. It is false on incoming + // connections. + bool m_queued:1; + + // 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 + // merged into larger blocks. This is used by + // the http-downloader, to request whole pieces + // at a time. + bool m_request_large_blocks:1; + + // set to true when this peer is only uploading + bool m_upload_only:1; + + // set to true when a piece request times out. The + // result is that the desired pending queue size + // is set to 1 + bool m_snubbed:1; + +#ifndef NDEBUG + public: + bool m_in_constructor:1; +#endif + }; +} + +#endif // TORRENT_PEER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp new file mode 100644 index 000000000..0ec096de3 --- /dev/null +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -0,0 +1,197 @@ +/* + +Copyright (c) 2003, 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_PEER_ID_HPP_INCLUDED +#define TORRENT_PEER_ID_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + class TORRENT_EXPORT big_number + { + // the number of bytes of the number + enum { number_size = 20 }; + public: + enum { size = number_size }; + + big_number() {} + + explicit big_number(char const* s) + { + if (s == 0) clear(); + else std::memcpy(m_number, s, size); + } + + explicit big_number(std::string const& s) + { + TORRENT_ASSERT(s.size() >= 20); + int sl = int(s.size()) < size ? int(s.size()) : size; + std::memcpy(m_number, &s[0], sl); + } + + void clear() + { + std::fill(m_number,m_number+number_size,0); + } + + bool is_all_zeros() const + { + return std::count(m_number,m_number+number_size,0) == number_size; + } + + bool operator==(big_number const& n) const + { + return std::equal(n.m_number, n.m_number+number_size, m_number); + } + + bool operator!=(big_number const& n) const + { + return !std::equal(n.m_number, n.m_number+number_size, m_number); + } + + bool operator<(big_number const& n) const + { + for (int i = 0; i < number_size; ++i) + { + if (m_number[i] < n.m_number[i]) return true; + if (m_number[i] > n.m_number[i]) return false; + } + return false; + } + + big_number operator~() + { + big_number ret; + for (int i = 0; i< number_size; ++i) + ret.m_number[i] = ~m_number[i]; + return ret; + } + + big_number& operator &= (big_number const& n) + { + for (int i = 0; i< number_size; ++i) + m_number[i] &= n.m_number[i]; + return *this; + } + + big_number& operator |= (big_number const& n) + { + for (int i = 0; i< number_size; ++i) + m_number[i] |= n.m_number[i]; + return *this; + } + + big_number& operator ^= (big_number const& n) + { + for (int i = 0; i< number_size; ++i) + m_number[i] ^= n.m_number[i]; + return *this; + } + + unsigned char& operator[](int i) + { TORRENT_ASSERT(i >= 0 && i < number_size); return m_number[i]; } + + unsigned char const& operator[](int i) const + { TORRENT_ASSERT(i >= 0 && i < number_size); return m_number[i]; } + + typedef const unsigned char* const_iterator; + typedef unsigned char* iterator; + + const_iterator begin() const { return m_number; } + const_iterator end() const { return m_number+number_size; } + + iterator begin() { return m_number; } + iterator end() { return m_number+number_size; } + + std::string to_string() const + { return std::string((char const*)&m_number[0], number_size); } + + private: + + unsigned char m_number[number_size]; + + }; + + typedef big_number peer_id; + typedef big_number sha1_hash; + + inline std::ostream& operator<<(std::ostream& os, big_number const& peer) + { + for (big_number::const_iterator i = peer.begin(); + i != peer.end(); ++i) + { + os << std::hex << std::setw(2) << std::setfill('0') + << static_cast(*i); + } + os << std::dec << std::setfill(' '); + return os; + } + + inline std::istream& operator>>(std::istream& is, big_number& peer) + { + using namespace std; + + for (big_number::iterator i = peer.begin(); + i != peer.end(); ++i) + { + char c[2]; + is >> c[0] >> c[1]; + c[0] = tolower(c[0]); + c[1] = tolower(c[1]); + if ( + ((c[0] < '0' || c[0] > '9') && (c[0] < 'a' || c[0] > 'f')) + || ((c[1] < '0' || c[1] > '9') && (c[1] < 'a' || c[1] > 'f')) + || is.fail()) + { + is.setstate(ios_base::failbit); + return is; + } + *i = ((isdigit(c[0])?c[0]-'0':c[0]-'a'+10) << 4) + + (isdigit(c[1])?c[1]-'0':c[1]-'a'+10); + } + return is; + } + +} + +#endif // TORRENT_PEER_ID_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp new file mode 100644 index 000000000..d447b51f8 --- /dev/null +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -0,0 +1,210 @@ +/* + +Copyright (c) 2003, 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_PEER_INFO_HPP_INCLUDED +#define TORRENT_PEER_INFO_HPP_INCLUDED + +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/size_type.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/bitfield.hpp" + +namespace libtorrent +{ + struct TORRENT_EXPORT peer_info + { + enum + { + interesting = 0x1, + choked = 0x2, + remote_interested = 0x4, + remote_choked = 0x8, + supports_extensions = 0x10, + local_connection = 0x20, + handshake = 0x40, + connecting = 0x80, + queued = 0x100, + on_parole = 0x200, + seed = 0x400, + optimistic_unchoke = 0x800, + snubbed = 0x1000 +#ifndef TORRENT_DISABLE_ENCRYPTION + , rc4_encrypted = 0x100000, + plaintext_encrypted = 0x200000 +#endif + }; + + unsigned int flags; + + enum peer_source_flags + { + tracker = 0x1, + dht = 0x2, + pex = 0x4, + lsd = 0x8, + resume_data = 0x10, + incoming = 0x20 + }; + + int source; + + // bw_idle: the channel is not used + // bw_torrent: the channel is waiting for torrent quota + // bw_global: the channel is waiting for global quota + // bw_network: the channel is waiting for an async write + // for read operation to complete + enum bw_state { bw_idle, bw_torrent, bw_global, bw_network }; + + char read_state; + char write_state; + + tcp::endpoint ip; + float up_speed; + float down_speed; + float payload_up_speed; + float payload_down_speed; + size_type total_download; + size_type total_upload; + peer_id pid; + bitfield pieces; + int upload_limit; + int download_limit; + + // time since last request + time_duration last_request; + + // time since last download or upload + time_duration last_active; + + // the number of seconds until the current + // pending request times out + int request_timeout; + + // the size of the send buffer for this peer, in bytes + int send_buffer_size; + // the number bytes that's actually used of the send buffer + int used_send_buffer; + + int receive_buffer_size; + int used_receive_buffer; + + // the number of failed hashes for this peer + int num_hashfails; + +#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 + +#ifndef TORRENT_DISABLE_GEO_IP + // atonomous system this peer belongs to + std::string inet_as_name; + int inet_as; +#endif + + size_type load_balancing; + + // this is the number of requests + // we have sent to this peer + // that we haven't got a response + // for yet + int download_queue_length; + + // the number of requests that is + // tried to be maintained (this is + // typically a function of download speed) + int target_dl_queue_length; + + // this is the number of requests + // the peer has sent to us + // 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 + int downloading_piece_index; + int downloading_block_index; + int downloading_progress; + int downloading_total; + + std::string client; + + enum + { + standard_bittorrent = 0, + web_seed = 1 + }; + int connection_type; + + // approximate peer download rate + int remote_dl_rate; + + // number of bytes this peer has in + // the disk write queue + int pending_disk_bytes; + + // numbers used for bandwidth limiting + int send_quota; + int receive_quota; + + // estimated rtt to peer, in milliseconds + int rtt; + + // the highest transfer rates seen for this peer + int download_rate_peak; + int upload_rate_peak; + }; + + struct TORRENT_EXPORT peer_list_entry + { + enum flags_t + { + banned = 1, + }; + + tcp::endpoint ip; + int flags; + boost::uint8_t failcount; + boost::uint8_t source; + }; +} + +#endif // TORRENT_PEER_INFO_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/peer_request.hpp b/libtorrent/include/libtorrent/peer_request.hpp new file mode 100644 index 000000000..445ff4d7e --- /dev/null +++ b/libtorrent/include/libtorrent/peer_request.hpp @@ -0,0 +1,49 @@ +/* + +Copyright (c) 2006, 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_PEER_REQUEST_HPP_INCLUDED +#define TORRENT_PEER_REQUEST_HPP_INCLUDED + +namespace libtorrent +{ + struct TORRENT_EXPORT peer_request + { + int piece; + int start; + int length; + bool operator==(peer_request const& r) const + { return piece == r.piece && start == r.start && length == r.length; } + }; +} + +#endif // TORRENT_PEER_REQUEST_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/piece_block_progress.hpp b/libtorrent/include/libtorrent/piece_block_progress.hpp new file mode 100644 index 000000000..481ffc971 --- /dev/null +++ b/libtorrent/include/libtorrent/piece_block_progress.hpp @@ -0,0 +1,57 @@ +/* + +Copyright (c) 2003, 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_PIECE_BLOCK_PROGRESS_HPP_INCLUDED +#define TORRENT_PIECE_BLOCK_PROGRESS_HPP_INCLUDED + +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + struct TORRENT_EXPORT piece_block_progress + { + // the piece and block index + // determines exactly which + // part of the torrent that + // is currently being downloaded + int piece_index; + int block_index; + // the number of bytes we have received + // of this block + int bytes_downloaded; + // the number of bytes in the block + int full_block_bytes; + }; +} + +#endif // TORRENT_PIECE_BLOCK_PROGRESS_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp new file mode 100644 index 000000000..bd0f862b6 --- /dev/null +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -0,0 +1,497 @@ +/* + +Copyright (c) 2003, 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_PIECE_PICKER_HPP_INCLUDED +#define TORRENT_PIECE_PICKER_HPP_INCLUDED + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + + class torrent; + class peer_connection; + class bitfield; + + struct TORRENT_EXPORT piece_block + { + piece_block(int p_index, int b_index) + : piece_index(p_index) + , block_index(b_index) + {} + int piece_index; + int block_index; + + bool operator<(piece_block const& b) const + { + if (piece_index < b.piece_index) return true; + if (piece_index == b.piece_index) return block_index < b.block_index; + return false; + } + + bool operator==(piece_block const& b) const + { return piece_index == b.piece_index && block_index == b.block_index; } + + bool operator!=(piece_block const& b) const + { return piece_index != b.piece_index || block_index != b.block_index; } + + }; + + class TORRENT_EXPORT piece_picker + { + public: + + struct block_info + { + block_info(): peer(0), num_peers(0), state(state_none) {} + // the peer this block was requested or + // downloaded from. This is a pointer to + // a policy::peer object + void* peer; + // the number of peers that has this block in their + // download or request queues + unsigned num_peers:14; + // the state of this block + enum { state_none, state_requested, state_writing, state_finished }; + unsigned state:2; + }; + + // 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), writing(0), requested(0) {} + piece_state_t state; + + // the index of the piece + int index; + // info about each block + // this is a pointer into the m_block_info + // vector owned by the piece_picker + block_info* info; + // the number of blocks in the finished state + boost::int16_t finished; + // the number of blocks in the writing state + boost::int16_t writing; + // the number of blocks in the requested state + boost::int16_t requested; + }; + + piece_picker(); + + void get_availability(std::vector& avail) const; + + void sequential_download(bool sd); + bool sequential_download() const { return m_sequential_download >= 0; } + + // increases the peer count for the given piece + // (is used when a HAVE message is received) + void inc_refcount(int index); + void dec_refcount(int index); + + // increases the peer count for the given piece + // (is used when a BITFIELD message is received) + void inc_refcount(bitfield const& bitmask); + // decreases the peer count for the given piece + // (used when a peer disconnects) + void dec_refcount(bitfield const& bitmask); + + // 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 + // we are not interested in this piece anymore + // (i.e. we don't have to maintain a refcount) + void we_have(int index); + void we_dont_have(int index); + + void init(int blocks_per_piece, int total_num_blocks); + int num_pieces() const { return int(m_piece_map.size()); } + + bool have_piece(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < int(m_piece_map.size())); + return m_piece_map[index].index == piece_pos::we_have_index; + } + + // sets the priority of a piece. + // returns true if the priority was changed from 0 to non-0 + // or vice versa + bool set_piece_priority(int index, int prio); + + // returns the priority for the piece at 'index' + int piece_priority(int index) const; + + // returns the current piece priorities for all pieces + void piece_priorities(std::vector& pieces) const; + + // ========== start deprecation ============== + + // fills the bitmask with 1's for pieces that are filtered + void filtered_pieces(std::vector& 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 + // priority order. It doesn't care about the download flag. + // The user of this function must lookup if any piece is + // marked as being downloaded. If the user of this function + // decides to download a piece, it must mark it as being downloaded + // itself, by using the mark_as_downloading() member function. + // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! + // The last argument is the policy::peer pointer for the peer that + // we'll download from. + void pick_pieces(bitfield const& pieces + , std::vector& interesting_blocks + , int num_pieces, int prefer_whole_pieces + , void* peer, piece_state_t speed + , bool rarest_first, bool on_parole + , std::vector const& suggested_pieces) const; + + // picks blocks from each of the pieces in the piece_list + // vector that is also in the piece bitmask. The blocks + // are added to interesting_blocks, and busy blocks are + // added to backup_blocks. num blocks is the number of + // blocks to be picked. Blocks are not picked from pieces + // that are being downloaded + int add_blocks(std::vector const& piece_list + , bitfield const& pieces + , std::vector& interesting_blocks + , int num_blocks, int prefer_whole_pieces + , void* peer, std::vector const& ignore) const; + + // picks blocks only from downloading pieces + int add_blocks_downloading( + bitfield const& pieces + , std::vector& interesting_blocks + , std::vector& backup_blocks + , int num_blocks, int prefer_whole_pieces + , void* peer, piece_state_t speed + , bool on_parole) const; + + // clears the peer pointer in all downloading pieces with this + // peer pointer + void clear_peer(void* peer); + + // returns true if any client is currently downloading this + // piece-block, or if it's queued for downloading by some client + // or if it already has been successfully downloaded + bool is_requested(piece_block block) const; + // returns true if the block has been downloaded + bool is_downloaded(piece_block block) const; + // returns true if the block has been downloaded and written to disk + bool is_finished(piece_block block) const; + + // marks this piece-block as queued for downloading + bool mark_as_downloading(piece_block block, void* peer + , piece_state_t s); + void mark_as_writing(piece_block block, void* peer); + void mark_as_finished(piece_block block, void* peer); + void write_failed(piece_block block); + int num_peers(piece_block block) const; + + // returns information about the given piece + void piece_info(int index, piece_picker::downloading_piece& st) const; + + // if a piece had a hash-failure, it must be restored and + // made available for redownloading + void restore_piece(int index); + + // clears the given piece's download flag + // this means that this piece-block can be picked again + void abort_download(piece_block block); + + bool is_piece_finished(int index) const; + + // returns the number of blocks there is in the given piece + int blocks_in_piece(int index) const; + + // the number of downloaded blocks that hasn't passed + // the hash-check yet + int unverified_blocks() const; + + void get_downloaders(std::vector& d, int index) const; + + std::vector const& get_download_queue() const + { return m_downloads; } + + void* get_downloader(piece_block block) const; + + // the number of filtered pieces we don't have + int num_filtered() const { return m_num_filtered; } + + // the number of filtered pieces we already have + int num_have_filtered() const { return m_num_have_filtered; } + + int num_have() const { return m_num_have; } + +#ifndef NDEBUG + // used in debug mode + void verify_priority(int start, int end, int prio) const; + void check_invariant(const torrent* t = 0) const; + void verify_pick(std::vector const& picked + , bitfield const& bits) const; + void print_pieces() const; +#endif + + // functor that compares indices on downloading_pieces + struct has_index + { + has_index(int i): index(i) { TORRENT_ASSERT(i >= 0); } + bool operator()(const downloading_piece& p) const + { return p.index == index; } + int index; + }; + + int blocks_in_last_piece() const + { return m_blocks_in_last_piece; } + + float distributed_copies() const; + + private: + + friend struct piece_pos; + + bool can_pick(int piece, bitfield const& bitmask) const; + std::pair expand_piece(int piece, int whole_pieces + , bitfield const& have) const; + + struct piece_pos + { + piece_pos() {} + piece_pos(int peer_count_, int index_) + : peer_count(peer_count_) + , downloading(0) + , piece_priority(1) + , index(index_) + { + TORRENT_ASSERT(peer_count_ >= 0); + TORRENT_ASSERT(index_ >= 0); + } + + // the number of peers that has this piece + // (availability) + unsigned peer_count : 10; + // is 1 if the piece is marked as being downloaded + unsigned downloading : 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 : 18; + + 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; TORRENT_ASSERT(have()); } + void set_not_have() { index = 0; TORRENT_ASSERT(!have()); } + + bool filtered() const { return piece_priority == filter_priority; } + void filtered(bool f) { piece_priority = f ? filter_priority : 0; } + + int priority(piece_picker const* picker) const + { + if (downloading || filtered() + || have() || peer_count + picker->m_seeds == 0) + return -1; + + // priority 5, 6 and 7 disregards availability of the piece + if (piece_priority > 4) return 7 - piece_priority; + + // pieces we are currently downloading have high priority + int prio = peer_count * 4; +// if (prio >= picker->m_prio_limit * 6) prio = picker->m_prio_limit * 6; + + return prio + (4 - piece_priority); + } + + bool operator!=(piece_pos p) const + { return index != p.index || peer_count != p.peer_count; } + + bool operator==(piece_pos p) const + { return index == p.index && peer_count == p.peer_count; } + + }; + + BOOST_STATIC_ASSERT(sizeof(piece_pos) == sizeof(char) * 4); + + void update_pieces() const; + + // fills in the range [start, end) of pieces in + // m_pieces that have priority 'prio' + void priority_range(int prio, int* start, int* end); + + // adds the piece 'index' to m_pieces + void add(int index); + // removes the piece with the given priority and the + // elem_index in the m_pieces vector + void remove(int priority, int elem_index); + // updates the position of the piece with the given + // priority and the elem_index in the m_pieces vector + void update(int priority, int elem_index); + // shuffles the given piece inside it's priority range + void shuffle(int priority, int elem_index); + + void sort_piece(std::vector::iterator dp); + + downloading_piece& add_download_piece(); + void erase_download_piece(std::vector::iterator i); + + // the number of seeds. These are not added to + // the availability counters of the pieces + int m_seeds; + + // the following vectors are mutable because they sometimes may + // be updated lazily, triggered by const functions + + // this vector contains all piece indices that are pickable + // sorted by priority. Pieces are in random random order + // among pieces with the same priority + mutable std::vector m_pieces; + + // these are indices to the priority boundries inside + // the m_pieces vector. priority 0 always start at + // 0, priority 1 starts at m_priority_boundries[0] etc. + mutable std::vector m_priority_boundries; + + // 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 + // doesn't exist in the piece_info buckets + // pieces with the filtered flag set doesn't have entries in + // the m_piece_info buckets either + mutable std::vector m_piece_map; + + // each piece that's currently being downloaded + // has an entry in this list with block allocations. + // i.e. it says wich parts of the piece that + // is being downloaded + std::vector 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 m_block_info; + + int m_blocks_per_piece; + int m_blocks_in_last_piece; + + // the number of filtered pieces that we don't already + // have. total_number_of_pieces - number_of_pieces_we_have + // - num_filtered is supposed to the number of pieces + // we still want to download + int m_num_filtered; + + // 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; + + // -1 means sequential download is not active. + // >= 0 means that pieces are requested in sequential order + // and this variable is the next piece to request. + // in that case m_pieces is cleared and not used. + int m_sequential_download; + + // if this is set to true, it means update_pieces() + // has to be called before accessing m_pieces. + mutable bool m_dirty; + public: + + enum { max_pieces = piece_pos::we_have_index - 1 }; + + }; + + inline int piece_picker::blocks_in_piece(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < (int)m_piece_map.size()); + if (index+1 == (int)m_piece_map.size()) + return m_blocks_in_last_piece; + else + return m_blocks_per_piece; + } + +} + +#endif // TORRENT_PIECE_PICKER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp new file mode 100644 index 000000000..0c9380b8a --- /dev/null +++ b/libtorrent/include/libtorrent/policy.hpp @@ -0,0 +1,295 @@ +/* + +Copyright (c) 2003, 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_POLICY_HPP_INCLUDED +#define TORRENT_POLICY_HPP_INCLUDED + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer.hpp" +#include "libtorrent/piece_picker.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/size_type.hpp" +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/time.hpp" + +namespace libtorrent +{ + + class torrent; + class peer_connection; + + enum + { + // the limits of the download queue size + min_request_queue = 2, + + // the amount of free upload allowed before + // the peer is choked + free_upload_amount = 4 * 16 * 1024 + }; + + void request_a_block(torrent& t, peer_connection& c); + + class TORRENT_EXPORT policy + { + public: + + policy(torrent* t); + + // this is called every 10 seconds to allow + // for peer choking management + void pulse(); + + struct peer; + // this is called once for every peer we get from + // the tracker, pex, lsd or dht. + policy::peer* peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid + , int source, char flags); + + // false means duplicate connection + bool update_peer_port(int port, policy::peer* p, int src); + + // called when an incoming connection is accepted + // false means the connection was refused or failed + bool new_connection(peer_connection& c); + + // the given connection was just closed + void connection_closed(const peer_connection& c); + + // the peer has got at least one interesting piece + void peer_is_interesting(peer_connection& c); + + int count_choked() const; + + // the peer unchoked us + void unchoked(peer_connection& c); + + // the peer is interested in our pieces + void interested(peer_connection& c); + + // the peer is not interested in our pieces + void not_interested(peer_connection& c); + + void ip_filter_updated(); + +#ifndef NDEBUG + bool has_connection(const peer_connection* p); + + void check_invariant() const; +#endif + + struct peer + { + enum connection_type { not_connectable, connectable }; + peer(tcp::endpoint const& ip, connection_type t, int src); + + size_type total_download() const; + size_type total_upload() const; + + // the ip/port pair this peer is or was connected on + tcp::endpoint ip; + +#ifndef TORRENT_DISABLE_GEO_IP +#ifndef NDEBUG + // only used in debug mode to assert that + // the first entry in the AS pair keeps the same + boost::uint16_t inet_as_num; +#endif + // The AS this peer belongs to + std::pair* inet_as; +#endif + + // the number of failed connection attempts + // this peer has + boost::uint8_t failcount; + + // for every valid piece we receive where this + // peer was one of the participants, we increase + // this value. For every invalid piece we receive + // where this peer was a participant, we decrease + // this value. If it sinks below a threshold, its + // considered a bad peer and will be banned. + boost::int8_t trust_points; + + // a bitmap combining the peer_source flags + // from peer_info. + boost::uint8_t source; + + // the number of times this peer has been + // part of a piece that failed the hash check + boost::uint8_t hashfails; + + // type specifies if the connection was incoming + // or outgoing. If we ever saw this peer as connectable + // it will remain as connectable + unsigned type:4; + + // the number of times we have allowed a fast + // reconnect for this peer. + unsigned fast_reconnects:4; + +#ifndef TORRENT_DISABLE_ENCRYPTION + // Hints encryption support of peer. Only effective + // for and when the outgoing encryption policy + // allows both encrypted and non encrypted + // connections (pe_settings::out_enc_policy + // == enabled). The initial state of this flag + // determines the initial connection attempt + // type (true = encrypted, false = standard). + // This will be toggled everytime either an + // encrypted or non-encrypted handshake fails. + bool pe_support:1; +#endif + // true if this peer currently is unchoked + // because of an optimistic unchoke. + // when the optimistic unchoke is moved to + // another peer, this peer will be choked + // if this is true + bool optimistically_unchoked:1; + + // this is true if the peer is a seed + bool seed:1; + + // 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 on_parole:1; + + // is set to true if this peer has been banned + bool banned:1; + +#ifndef TORRENT_DISABLE_DHT + // this is set to true when this peer as been + // pinged by the DHT + bool added_to_dht:1; +#endif + + // if the peer is connected now, this + // will refer to a valid peer_connection + peer_connection* connection; + + // this is the accumulated amount of + // uploaded and downloaded data to this + // peer. It only accounts for what was + // shared during the last connection to + // this peer. i.e. These are only updated + // when the connection is closed. For the + // total amount of upload and download + // we'll have to add thes figures with the + // statistics from the peer_connection. + size_type prev_amount_upload; + size_type prev_amount_download; + + // the time when this peer was optimistically unchoked + // the last time. + libtorrent::ptime last_optimistically_unchoked; + + // the time when the peer connected to us + // or disconnected if it isn't connected right now + libtorrent::ptime connected; + }; + + int num_peers() const { return m_peers.size(); } + + typedef std::multimap::iterator iterator; + typedef std::multimap::const_iterator const_iterator; + iterator begin_peer() { return m_peers.begin(); } + iterator end_peer() { return m_peers.end(); } + const_iterator begin_peer() const { return m_peers.begin(); } + const_iterator end_peer() const { return m_peers.end(); } + + bool connect_one_peer(); + + bool has_peer(policy::peer const* p) const; + + int num_seeds() const { return m_num_seeds; } + int num_connect_candidates() const { return m_num_connect_candidates; } + void recalculate_connect_candidates() + { + if (m_num_connect_candidates == 0) + m_num_connect_candidates = 1; + } + + void erase_peer(iterator i); + + private: + + bool compare_peer(policy::peer const& lhs, policy::peer const& rhs + , address const& external_ip) const; + + iterator find_connect_candidate(); + + bool is_connect_candidate(peer const& p, bool finished); + + std::multimap m_peers; + + // since the peer list can grow too large + // to scan all of it, start at this iterator + iterator m_round_robin; + + torrent* m_torrent; + + // free download we have got that hasn't + // been distributed yet. + size_type m_available_free_upload; + + // The number of peers in our peer list + // that are connect candidates. i.e. they're + // not already connected and they have not + // yet reached their max try count and they + // have the connectable state (we have a listen + // port for them). + int m_num_connect_candidates; + + // the number of seeds in the peer list + int m_num_seeds; + }; + +} + +#endif // TORRENT_POLICY_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/proxy_base.hpp b/libtorrent/include/libtorrent/proxy_base.hpp new file mode 100644 index 000000000..873e84190 --- /dev/null +++ b/libtorrent/include/libtorrent/proxy_base.hpp @@ -0,0 +1,211 @@ +/* + +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_PROXY_BASE_HPP_INCLUDED +#define TORRENT_PROXY_BASE_HPP_INCLUDED + +#include "libtorrent/io.hpp" +#include "libtorrent/socket.hpp" +#include +#include +#include +#if BOOST_VERSION < 103500 +#include +#include +#else +#include +#include +#endif + +namespace libtorrent { + +class proxy_base : 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 proxy_base(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; + } + + template + void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) + { + m_sock.async_read_some(buffers, handler); + } + + template + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) + { + return m_sock.read_some(buffers, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + template + std::size_t read_some(Mutable_Buffers const& buffers) + { + return m_sock.read_some(buffers); + } + + template + void io_control(IO_Control_Command& ioc) + { + m_sock.io_control(ioc); + } +#endif + + template + void io_control(IO_Control_Command& ioc, error_code& ec) + { + m_sock.io_control(ioc, ec); + } + + template + void async_write_some(Const_Buffers const& buffers, Handler const& handler) + { + m_sock.async_write_some(buffers, handler); + } + +#ifndef BOOST_NO_EXCEPTIONS + template + void set_option(SettableSocketOption const& opt) + { + m_sock.set_option(opt); + } +#endif + + template + error_code set_option(SettableSocketOption const& opt, error_code& ec) + { + return m_sock.set_option(opt, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + void bind(endpoint_type const& endpoint) + { + m_sock.bind(endpoint); + } +#endif + + void bind(endpoint_type const& endpoint, error_code& ec) + { + m_sock.bind(endpoint, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + void open(protocol_type const& p) + { + m_sock.open(p); + } +#endif + + void open(protocol_type const& p, error_code& ec) + { + m_sock.open(p, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + void close() + { + m_remote_endpoint = endpoint_type(); + m_sock.close(); + m_resolver.cancel(); + } +#endif + + void close(error_code& ec) + { + m_sock.close(ec); + m_resolver.cancel(); + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type remote_endpoint() const + { + return m_remote_endpoint; + } +#endif + + endpoint_type remote_endpoint(error_code& ec) const + { + return m_remote_endpoint; + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type local_endpoint() const + { + return m_sock.local_endpoint(); + } +#endif + + endpoint_type local_endpoint(error_code& ec) const + { + return m_sock.local_endpoint(ec); + } + + io_service& get_io_service() + { + return m_sock.get_io_service(); + } + + lowest_layer_type& lowest_layer() + { + return m_sock.lowest_layer(); + } + + bool is_open() const { return m_sock.is_open(); } + +protected: + + stream_socket m_sock; + std::string m_hostname; + int m_port; + + endpoint_type m_remote_endpoint; + + tcp::resolver m_resolver; +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/random_sample.hpp b/libtorrent/include/libtorrent/random_sample.hpp new file mode 100644 index 000000000..1eaaec1e3 --- /dev/null +++ b/libtorrent/include/libtorrent/random_sample.hpp @@ -0,0 +1,74 @@ +/* + +Copyright (c) 2006, Arvid Norberg & Daniel Wallin +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_RANDOM_SAMPLE_HPP +#define TORRENT_RANDOM_SAMPLE_HPP + +#include +#include + +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + + template + inline void random_sample_n(InIter start, InIter end + , OutIter out, Distance n) + { + Distance t = 0; + Distance m = 0; + Distance N = std::distance(start, end); + + TORRENT_ASSERT(N >= n); + + while (m < n) + { + if ((std::rand() / (RAND_MAX + 1.f)) * (N - t) >= n - m) + { + ++start; + ++t; + } + else + { + *out = *start; + ++out; + ++start; + ++t; + ++m; + } + } + } + +} + +#endif diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp new file mode 100644 index 000000000..d95782d79 --- /dev/null +++ b/libtorrent/include/libtorrent/session.hpp @@ -0,0 +1,350 @@ +/* + +Copyright (c) 2006, 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_SESSION_HPP_INCLUDED +#define TORRENT_SESSION_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/config.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/session_status.hpp" +#include "libtorrent/version.hpp" +#include "libtorrent/fingerprint.hpp" +#include "libtorrent/time.hpp" +#include "libtorrent/disk_io_thread.hpp" +#include "libtorrent/peer_id.hpp" + +#include "libtorrent/storage.hpp" + +#ifdef _MSC_VER +# include +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + class ip_filter; + class port_filter; + class connection_queue; + class natpmp; + class upnp; + + namespace fs = boost::filesystem; + + namespace aux + { + // workaround for microsofts + // hardware exceptions that makes + // it hard to debug stuff +#ifdef _MSC_VER + struct eh_initializer + { + eh_initializer() + { + ::_set_se_translator(straight_to_debugger); + } + + static void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*) + { throw; } + }; +#else + struct eh_initializer {}; +#endif + struct session_impl; + + struct filesystem_init + { + filesystem_init(); + }; + + } + + class TORRENT_EXPORT session_proxy + { + friend class session; + public: + session_proxy() {} + private: + session_proxy(boost::shared_ptr impl) + : m_impl(impl) {} + boost::shared_ptr m_impl; + }; + + struct add_torrent_params + { + add_torrent_params(storage_constructor_type sc = default_storage_constructor) + : tracker_url(0) + , name(0) + , resume_data(0) + , storage_mode(storage_mode_sparse) + , paused(true) + , auto_managed(true) + , duplicate_is_error(false) + , storage(sc) + , userdata(0) + {} + + boost::intrusive_ptr ti; + char const* tracker_url; + sha1_hash info_hash; + char const* name; + fs::path save_path; + std::vector* resume_data; + storage_mode_t storage_mode; + bool paused; + bool auto_managed; + bool duplicate_is_error; + storage_constructor_type storage; + void* userdata; + }; + + class TORRENT_EXPORT session: public boost::noncopyable, aux::eh_initializer + { + public: + + session(fingerprint const& print = fingerprint("LT" + , LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + , fs::path logpath = "." +#endif + ); + session( + fingerprint const& print + , std::pair listen_port_range + , char const* listen_interface = "0.0.0.0" +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + , fs::path logpath = "." +#endif + ); + + ~session(); + + // returns a list of all torrents in this session + std::vector get_torrents() const; + + // returns an invalid handle in case the torrent doesn't exist + torrent_handle find_torrent(sha1_hash const& info_hash) const; + + // all torrent_handles must be destructed before the session is destructed! + torrent_handle add_torrent(add_torrent_params const& params); + + // deprecated in 0.14 + torrent_handle add_torrent( + torrent_info const& ti + , fs::path const& save_path + , entry const& resume_data = entry() + , storage_mode_t storage_mode = storage_mode_sparse + , bool paused = false + , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED; + + // deprecated in 0.14 + torrent_handle add_torrent( + boost::intrusive_ptr ti + , fs::path const& save_path + , entry const& resume_data = entry() + , storage_mode_t storage_mode = storage_mode_sparse + , bool paused = false + , storage_constructor_type sc = default_storage_constructor + , void* userdata = 0) TORRENT_DEPRECATED; + + // deprecated in 0.14 + torrent_handle add_torrent( + char const* tracker_url + , sha1_hash const& info_hash + , char const* name + , fs::path const& save_path + , entry const& resume_data = entry() + , storage_mode_t storage_mode = storage_mode_sparse + , bool paused = false + , storage_constructor_type sc = default_storage_constructor + , void* userdata = 0) TORRENT_DEPRECATED; + + session_proxy abort() { return session_proxy(m_impl); } + + void pause(); + void resume(); + bool is_paused() const; + + session_status status() const; + cache_status get_cache_status() const; + + void get_cache_info(sha1_hash const& ih + , std::vector& ret) const; + +#ifndef TORRENT_DISABLE_DHT + void start_dht(entry const& startup_state = entry()); + void stop_dht(); + void set_dht_settings(dht_settings const& settings); + entry dht_state() const; + void add_dht_node(std::pair const& node); + void add_dht_router(std::pair const& node); +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + void set_pe_settings(pe_settings const& settings); + pe_settings const& get_pe_settings() const; +#endif + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::function(torrent*, void*)> ext); +#endif + +#ifndef TORRENT_DISABLE_GEO_IP + int as_for_ip(address const& addr); + bool load_asnum_db(char const* file); + bool load_country_db(char const* file); +#endif + + void load_state(entry const& ses_state); + entry state() const; + + void set_ip_filter(ip_filter const& f); + void set_port_filter(port_filter const& f); + void set_peer_id(peer_id const& pid); + void set_key(int key); + peer_id id() const; + + bool is_listening() const; + + // if the listen port failed in some way + // you can retry to listen on another port- + // range with this function. If the listener + // succeeded and is currently listening, + // a call to this function will shut down the + // listen port and reopen it using these new + // properties (the given interface and port range). + // As usual, if the interface is left as 0 + // this function will return false on failure. + // If it fails, it will also generate alerts describing + // the error. It will return true on success. + bool listen_on( + std::pair const& port_range + , const char* net_interface = 0); + + // returns the port we ended up listening on + unsigned short listen_port() const; + + // Get the number of uploads. + int num_uploads() const; + + // Get the number of connections. This number also contains the + // number of half open connections. + int num_connections() const; + + enum options_t + { + none = 0, + delete_files = 1 + }; + + void remove_torrent(const torrent_handle& h, int options = none); + + 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; + int max_half_open_connections() const; + + void set_upload_rate_limit(int bytes_per_second); + void set_download_rate_limit(int bytes_per_second); + void set_max_uploads(int limit); + void set_max_connections(int limit); + void set_max_half_open_connections(int limit); + + std::auto_ptr pop_alert(); + void set_severity_level(alert::severity_t s); + + alert const* wait_for_alert(time_duration max_wait); + + connection_queue& get_connection_queue(); + + // starts/stops UPnP, NATPMP or LSD port mappers + // they are stopped by default + void start_lsd(); + natpmp* start_natpmp(); + upnp* start_upnp(); + + void stop_lsd(); + void stop_natpmp(); + void stop_upnp(); + + private: + + // just a way to initialize boost.filesystem + // before the session_impl is created + aux::filesystem_init m_dummy; + + // data shared between the main thread + // and the working thread + boost::shared_ptr m_impl; + }; + +} + +#endif // TORRENT_SESSION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp new file mode 100644 index 000000000..c7aee4a0f --- /dev/null +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -0,0 +1,493 @@ +/* + +Copyright (c) 2003, 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_SESSION_SETTINGS_HPP_INCLUDED +#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, + // socks4 server, requires username. + socks4, + // 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) + : user_agent(user_agent_) + , tracker_completion_timeout(60) + , tracker_receive_timeout(40) + , stop_tracker_timeout(5) + , tracker_maximum_response_length(1024*1024) + , piece_timeout(10) + , request_timeout(40) + , request_queue_time(3.f) + , max_allowed_in_request_queue(250) + , max_out_request_queue(200) + , whole_pieces_threshold(20) + , peer_timeout(120) + , urlseed_timeout(20) + , urlseed_pipeline_size(5) + , urlseed_wait_retry(30) + , file_pool_size(40) + , allow_multiple_connections_per_ip(false) + , max_failcount(3) + , min_reconnect_time(60) + , peer_connect_timeout(7) + , ignore_limits_on_local_network(true) + , connection_speed(20) + , send_redundant_have(false) + , lazy_bitfields(true) + , inactivity_timeout(600) + , unchoke_interval(15) + , optimistic_unchoke_multiplier(4) + , num_want(200) + , initial_picker_threshold(4) + , allowed_fast_set_size(10) + , max_outstanding_disk_bytes_per_connection(64 * 1024) + , handshake_timeout(10) +#ifndef TORRENT_DISABLE_DHT + , use_dht_as_fallback(true) +#endif + , free_torrent_hashes(true) + , upnp_ignore_nonrouters(true) + , send_buffer_watermark(80 * 1024) + , auto_upload_slots(true) + , cache_size(512) + , cache_expiry(60) + , outgoing_ports(0,0) + , peer_tos(0) + , active_downloads(8) + , active_seeds(5) + , active_limit(15) + , dont_count_slow_torrents(true) + , auto_manage_interval(30) + , share_ratio_limit(2.f) + , seed_time_ratio_limit(7.f) + , seed_time_limit(24 * 60 * 60) // 24 hours + , peer_turnover(1 / 50.f) + , peer_turnover_cutoff(1.f) + , close_redundant_connections(true) + , auto_scrape_interval(1800) + , auto_scrape_min_interval(300) + , max_peerlist_size(8000) + {} + + // 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 + std::string user_agent; + + // the number of seconds to wait until giving up on a + // tracker request if it hasn't finished + int tracker_completion_timeout; + + // the number of seconds where no data is received + // from the tracker until it should be considered + // as timed out + int tracker_receive_timeout; + + // the time to wait when sending a stopped message + // before considering a tracker to have timed out. + // this is usually shorter, to make the client quit + // faster + int stop_tracker_timeout; + + // if the content-length is greater than this value + // the tracker connection will be aborted + int tracker_maximum_response_length; + + // the number of seconds from a request is sent until + // it times out if no piece response is returned. + int piece_timeout; + + // the number of seconds one block (16kB) is expected + // to be received within. If it's not, the block is + // requested from a different peer + int request_timeout; + + // the length of the request queue given in the number + // of seconds it should take for the other end to send + // all the pieces. i.e. the actual number of requests + // depends on the download rate and this number. + float request_queue_time; + + // the number of outstanding block requests a peer is + // allowed to queue up in the client. If a peer sends + // more requests than this (before the first one has + // been sent) the last request will be dropped. + // the higher this is, the faster upload speeds the + // client can get to a single peer. + int max_allowed_in_request_queue; + + // the maximum number of outstanding requests to + // send to a peer. This limit takes precedence over + // request_queue_time. + int max_out_request_queue; + + // if a whole piece can be downloaded in this number + // of seconds, or less, the peer_connection will prefer + // to request whole pieces at a time from this peer. + // The benefit of this is to better utilize disk caches by + // doing localized accesses and also to make it easier + // to identify bad peers if a piece fails the hash check. + int whole_pieces_threshold; + + // the number of seconds to wait for any activity on + // the peer wire before closing the connectiong due + // to time out. + int peer_timeout; + + // same as peer_timeout, but only applies to url-seeds. + // this is usually set lower, because web servers are + // expected to be more reliable. + int urlseed_timeout; + + // controls the pipelining size of url-seeds + int urlseed_pipeline_size; + + // time to wait until a new retry takes place + int urlseed_wait_retry; + + // sets the upper limit on the total number of files this + // session will keep open. The reason why files are + // left open at all is that some anti virus software + // hooks on every file close, and scans the file for + // viruses. deferring the closing of the files will + // be the difference between a usable system and + // a completely hogged down system. Most operating + // systems also has a limit on the total number of + // file descriptors a process may have open. It is + // usually a good idea to find this limit and set the + // number of connections and the number of files + // limits so their sum is slightly below it. + int file_pool_size; + + // false to not allow multiple connections from the same + // 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; + + // the number of connection attempts that + // are made per second. + int connection_speed; + + // if this is set to true, have messages will be sent + // to peers that already have the piece. This is + // typically not necessary, but it might be necessary + // for collecting statistics in some cases. Default is false. + bool send_redundant_have; + + // if this is true, outgoing bitfields will never be fuil. If the + // client is seed, a few bits will be set to 0, and later filled + // in with have messages. This is to prevent certain ISPs + // from stopping people from seeding. + bool lazy_bitfields; + + // if a peer is uninteresting and uninterested for longer + // than this number of seconds, it will be disconnected. + // default is 10 minutes + int inactivity_timeout; + + // the number of seconds between chokes/unchokes + int unchoke_interval; + + // the number of unchoke intervals between + // optimistic unchokes + int optimistic_unchoke_multiplier; + + // if this is set, this IP will be reported do the + // tracker in the ip= parameter. + address announce_ip; + + // the num want sent to trackers + int num_want; + + // while we have fewer pieces than this, pick + // random pieces instead of rarest first. + int initial_picker_threshold; + + // the number of allowed pieces to send to peers + // that supports the fast extensions + int allowed_fast_set_size; + + // the maximum number of bytes a connection may have + // pending in the disk write queue before its download + // rate is being throttled. This prevents fast downloads + // to slow medias to allocate more and more memory + // indefinitely. This should be set to at least 32 kB + // to not completely disrupt normal downloads. + int max_outstanding_disk_bytes_per_connection; + + // the number of seconds to wait for a handshake + // response from a peer. If no response is received + // within this time, the peer is disconnected. + int handshake_timeout; + +#ifndef TORRENT_DISABLE_DHT + // while this is true, the dht will note be used unless the + // tracker is online + bool use_dht_as_fallback; +#endif + + // if this is true, the piece hashes will be freed, in order + // to save memory, once the torrent is seeding. This will + // make the get_torrent_info() function to return an incomplete + // torrent object that cannot be passed back to add_torrent() + bool free_torrent_hashes; + + // when this is true, the upnp port mapper will ignore + // any upnp devices that don't have an address that matches + // our currently configured router. + bool upnp_ignore_nonrouters; + + // if the send buffer has fewer bytes than this, we'll + // read another 16kB block onto it. If set too small, + // upload rate capacity will suffer. If set too high, + // memory will be wasted. + // The actual watermark may be lower than this in case + // the upload rate is low, this is the upper limit. + int send_buffer_watermark; + + // if auto_upload_slots is true, and a global upload + // limit is set and the upload rate is less than 90% + // of the upload limit, on new slot is opened up. If + // the upload rate is >= upload limit for an extended + // period of time, one upload slot is closed. The + // upload slots are never automatically decreased below + // the manual settings, through max_uploads. + bool auto_upload_slots; + + // the disk write cache, specified in 16 KiB blocks. + // default is 512 (= 8 MB) + int cache_size; + + // the number of seconds a write cache entry sits + // idle in the cache before it's forcefully flushed + // to disk. Default is 60 seconds. + int cache_expiry; + + // if != (0, 0), this is the range of ports that + // outgoing connections will be bound to. This + // is useful for users that have routers that + // allow QoS settings based on local port. + std::pair outgoing_ports; + + // the TOS byte of all peer traffic (including + // web seeds) is set to this value. The default + // is the QBSS scavenger service + // http://qbone.internet2.edu/qbss/ + // For unmarked packets, set to 0 + char peer_tos; + + // for auto managed torrents, these are the limits + // they are subject to. If there are too many torrents + // some of the auto managed ones will be paused until + // some slots free up. + int active_downloads; + int active_seeds; + int active_limit; + + // if this is true, torrents that don't have any significant + // transfers are not counted as active when determining which + // auto managed torrents to pause and resume + bool dont_count_slow_torrents; + + // the number of seconds in between recalculating which + // torrents to activate and which ones to queue + int auto_manage_interval; + + // when a seeding torrent reaches eaither the share ratio + // (bytes up / bytes down) or the seed time ratio + // (seconds as seed / seconds as downloader) or the seed + // time limit (seconds as seed) it is considered + // done, and it will leave room for other torrents + // the default value for share ratio is 2 + // the default seed time ratio is 7, because that's a common + // asymmetry ratio on connections + float share_ratio_limit; + float seed_time_ratio_limit; + int seed_time_limit; + + // the percentage of peers to disconnect every + // 90 seconds (if we're at the peer limit) + // defaults to 1/50:th + float peer_turnover; + + // when we are connected to more than + // limit * peer_turnover_enable peers + // disconnect peer_turnover fraction + // of the peers + float peer_turnover_cutoff; + + // if this is true (default) connections where both + // ends have no utility in keeping the connection open + // are closed. for instance if both ends have completed + // their downloads + bool close_redundant_connections; + + // the number of seconds between scrapes of + // queued torrents (auto managed and paused) + int auto_scrape_interval; + + // the minimum number of seconds between any + // automatic scrape (regardless of torrent) + int auto_scrape_min_interval; + + // the max number of peers in the peer list + // per torrent. This is the peers we know + // about, not necessarily connected to. + int max_peerlist_size; + }; + +#ifndef TORRENT_DISABLE_DHT + struct dht_settings + { + dht_settings() + : max_peers_reply(50) + , search_branching(5) + , service_port(0) + , max_fail_count(20) + {} + + // the maximum number of peers to send in a + // reply to get_peers + int max_peers_reply; + + // the number of simultanous "connections" when + // searching the DHT. + 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 + // in a row before it is removed from the table. + int max_fail_count; + }; +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + + struct pe_settings + { + pe_settings() + : out_enc_policy(enabled) + , in_enc_policy(enabled) + , allowed_enc_level(both) + , prefer_rc4(false) + {} + + enum enc_policy + { + forced, // disallow non encrypted connections + enabled, // allow encrypted and non encrypted connections + disabled // disallow encrypted connections + }; + + enum enc_level + { + plaintext, // use only plaintext encryption + rc4, // use only rc4 encryption + both // allow both + }; + + enc_policy out_enc_policy; + enc_policy in_enc_policy; + + enc_level allowed_enc_level; + // if the allowed encryption level is both, setting this to + // true will prefer rc4 if both methods are offered, plaintext + // otherwise + bool prefer_rc4; + }; +#endif + +} + +#endif diff --git a/libtorrent/include/libtorrent/session_status.hpp b/libtorrent/include/libtorrent/session_status.hpp new file mode 100644 index 000000000..4e42dba5f --- /dev/null +++ b/libtorrent/include/libtorrent/session_status.hpp @@ -0,0 +1,74 @@ +/* + +Copyright (c) 2006, 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_SESSION_STATUS_HPP_INCLUDED +#define TORRENT_SESSION_STATUS_HPP_INCLUDED + + +namespace libtorrent +{ + + struct TORRENT_EXPORT session_status + { + bool has_incoming_connections; + + float upload_rate; + float download_rate; + + float payload_upload_rate; + float payload_download_rate; + + size_type total_download; + size_type total_upload; + + size_type total_payload_download; + size_type total_payload_upload; + + int num_peers; + int num_unchoked; + int allowed_upload_slots; + + int up_bandwidth_queue; + int down_bandwidth_queue; + +#ifndef TORRENT_DISABLE_DHT + int dht_nodes; + int dht_node_cache; + int dht_torrents; + size_type dht_global_nodes; +#endif + }; + +} + +#endif // TORRENT_SESSION_STATUS_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/size_type.hpp b/libtorrent/include/libtorrent/size_type.hpp new file mode 100644 index 000000000..6020a5ac3 --- /dev/null +++ b/libtorrent/include/libtorrent/size_type.hpp @@ -0,0 +1,52 @@ +/* + +Copyright (c) 2003, 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_SIZE_TYPE_HPP_INCLUDED +#define TORRENT_SIZE_TYPE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + typedef boost::int64_t size_type; +} + + +#endif diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp new file mode 100644 index 000000000..d041024bb --- /dev/null +++ b/libtorrent/include/libtorrent/socket.hpp @@ -0,0 +1,233 @@ +/* + +Copyright (c) 2003, 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_SOCKET_HPP_INCLUDED +#define TORRENT_SOCKET_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +// if building as Objective C++, asio's template +// parameters Protocol has to be renamed to avoid +// colliding with keywords + +#ifdef __OBJC__ +#define Protocol Protocol_ +#endif + +#include + +#if BOOST_VERSION < 103500 +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef __OBJC__ +#undef Protocol +#endif + +#include "libtorrent/io.hpp" +#include "libtorrent/time.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + +#if BOOST_VERSION < 103500 + using asio::ip::tcp; + using asio::ip::udp; + using asio::async_write; + using asio::async_read; + + typedef asio::ip::tcp::socket stream_socket; + typedef asio::ip::address address; + typedef asio::ip::address_v4 address_v4; + typedef asio::ip::address_v6 address_v6; + typedef asio::ip::udp::socket datagram_socket; + typedef asio::ip::tcp::acceptor socket_acceptor; + typedef asio::io_service io_service; + typedef asio::error_code error_code; + + namespace asio = ::asio; + typedef asio::basic_deadline_timer deadline_timer; +#else + using boost::system::error_code; + using boost::asio::ip::tcp; + using boost::asio::ip::udp; + using boost::asio::async_write; + using boost::asio::async_read; + + typedef boost::asio::ip::tcp::socket stream_socket; + typedef boost::asio::ip::address address; + typedef boost::asio::ip::address_v4 address_v4; + typedef boost::asio::ip::address_v6 address_v6; + typedef boost::asio::ip::udp::socket datagram_socket; + typedef boost::asio::ip::tcp::acceptor socket_acceptor; + typedef boost::asio::io_service io_service; + + namespace asio = boost::asio; + typedef boost::asio::basic_deadline_timer deadline_timer; +#endif + + inline std::ostream& print_address(std::ostream& os, address const& addr) + { + error_code ec; + std::string a = addr.to_string(ec); + if (ec) return os; + os << a; + return os; + } + + inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep) + { + address const& addr = ep.address(); + error_code ec; + std::string a = addr.to_string(ec); + if (ec) return os; + + if (addr.is_v6()) + os << "[" << a << "]:"; + else + os << a << ":"; + os << ep.port(); + return os; + } + + namespace detail + { + template + void write_address(address const& a, OutIt& out) + { + if (a.is_v4()) + { + write_uint32(a.to_v4().to_ulong(), out); + } + else if (a.is_v6()) + { + address_v6::bytes_type bytes + = a.to_v6().to_bytes(); + std::copy(bytes.begin(), bytes.end(), out); + } + } + + template + address read_v4_address(InIt& in) + { + unsigned long ip = read_uint32(in); + return address_v4(ip); + } + + template + address read_v6_address(InIt& in) + { + typedef address_v6::bytes_type bytes_t; + bytes_t bytes; + for (bytes_t::iterator i = bytes.begin() + , end(bytes.end()); i != end; ++i) + *i = read_uint8(in); + return address_v6(bytes); + } + + template + void write_endpoint(Endpoint const& e, OutIt& out) + { + write_address(e.address(), out); + write_uint16(e.port(), out); + } + + template + Endpoint read_v4_endpoint(InIt& in) + { + address addr = read_v4_address(in); + int port = read_uint16(in); + return Endpoint(addr, port); + } + + template + Endpoint read_v6_endpoint(InIt& in) + { + address addr = read_v6_address(in); + int port = read_uint16(in); + return Endpoint(addr, port); + } + } + + struct v6only + { + v6only(bool enable): m_value(enable) {} + template + int level(Protocol const&) const { return IPPROTO_IPV6; } + template + int name(Protocol const&) const { return IPV6_V6ONLY; } + template + int const* data(Protocol const&) const { return &m_value; } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + int m_value; + }; + + struct type_of_service + { + type_of_service(char val): m_value(val) {} + template + int level(Protocol const&) const { return IPPROTO_IP; } + template + int name(Protocol const&) const { return IP_TOS; } + template + char const* data(Protocol const&) const { return &m_value; } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + char m_value; + }; +} + +#endif // TORRENT_SOCKET_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/socket_type.hpp b/libtorrent/include/libtorrent/socket_type.hpp new file mode 100644 index 000000000..9ed8f9a4b --- /dev/null +++ b/libtorrent/include/libtorrent/socket_type.hpp @@ -0,0 +1,51 @@ +/* + +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_SOCKET_TYPE +#define TORRENT_SOCKET_TYPE + +#include "libtorrent/socks5_stream.hpp" +#include "libtorrent/socks4_stream.hpp" +#include "libtorrent/http_stream.hpp" +#include "libtorrent/variant_stream.hpp" + +namespace libtorrent +{ + typedef variant_stream< + stream_socket + , socks5_stream + , socks4_stream + , http_stream> socket_type; +} + +#endif + diff --git a/libtorrent/include/libtorrent/socks4_stream.hpp b/libtorrent/include/libtorrent/socks4_stream.hpp new file mode 100644 index 000000000..e7054595e --- /dev/null +++ b/libtorrent/include/libtorrent/socks4_stream.hpp @@ -0,0 +1,92 @@ +/* + +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_SOCKS4_STREAM_HPP_INCLUDED +#define TORRENT_SOCKS4_STREAM_HPP_INCLUDED + +#include "libtorrent/proxy_base.hpp" + +namespace libtorrent { + +class socks4_stream : public proxy_base +{ +public: + + explicit socks4_stream(io_service& io_service_) + : proxy_base(io_service_) + {} + + void set_username(std::string const& user) + { + m_user = user; + } + + typedef boost::function handler_type; + + template + 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 SOCKS4 CONNECT message + + // to avoid unnecessary copying of the handler, + // store it in a shaed_ptr + boost::shared_ptr h(new handler_type(handler)); + + tcp::resolver::query q(m_hostname + , boost::lexical_cast(m_port)); + m_resolver.async_resolve(q, boost::bind( + &socks4_stream::name_lookup, this, _1, _2, h)); + } + +private: + + void name_lookup(error_code const& e, tcp::resolver::iterator i + , boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); + + // send and receive buffer + std::vector m_buffer; + // proxy authentication + std::string m_user; +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/socks5_stream.hpp b/libtorrent/include/libtorrent/socks5_stream.hpp new file mode 100644 index 000000000..24b27da85 --- /dev/null +++ b/libtorrent/include/libtorrent/socks5_stream.hpp @@ -0,0 +1,104 @@ +/* + +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_SOCKS5_STREAM_HPP_INCLUDED +#define TORRENT_SOCKS5_STREAM_HPP_INCLUDED + +#include "libtorrent/proxy_base.hpp" + +namespace libtorrent { + +class socks5_stream : public proxy_base +{ +public: + + explicit socks5_stream(io_service& io_service) + : proxy_base(io_service) + {} + + void set_username(std::string const& user + , std::string const& password) + { + m_user = user; + m_password = password; + } + + typedef boost::function handler_type; + + template + 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 h(new handler_type(handler)); + + tcp::resolver::query q(m_hostname + , boost::lexical_cast(m_port)); + m_resolver.async_resolve(q, boost::bind( + &socks5_stream::name_lookup, this, _1, _2, h)); + } + +private: + + void name_lookup(error_code const& e, tcp::resolver::iterator i + , boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); + void handshake3(error_code const& e, boost::shared_ptr h); + void handshake4(error_code const& e, boost::shared_ptr h); + void socks_connect(boost::shared_ptr h); + void connect1(error_code const& e, boost::shared_ptr h); + void connect2(error_code const& e, boost::shared_ptr h); + void connect3(error_code const& e, boost::shared_ptr h); + + // send and receive buffer + std::vector m_buffer; + // proxy authentication + std::string m_user; + std::string m_password; +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/ssl_stream.hpp b/libtorrent/include/libtorrent/ssl_stream.hpp new file mode 100644 index 000000000..363c819f6 --- /dev/null +++ b/libtorrent/include/libtorrent/ssl_stream.hpp @@ -0,0 +1,227 @@ +/* + +Copyright (c) 2008, 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_SSL_STREAM_HPP_INCLUDED +#define TORRENT_SSL_STREAM_HPP_INCLUDED + +#include "libtorrent/socket.hpp" +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif +// openssl seems to believe it owns +// this name in every single scope +#undef set_key + +namespace libtorrent { + +template +class ssl_stream +{ +public: + + explicit ssl_stream(io_service& io_service) + : m_context(io_service, asio::ssl::context::sslv23_client) + , m_sock(io_service, m_context) + { + m_context.set_verify_mode(asio::ssl::context::verify_none); + } + + typedef Stream next_layer_type; + typedef typename Stream::lowest_layer_type lowest_layer_type; + typedef typename Stream::endpoint_type endpoint_type; + typedef typename Stream::protocol_type protocol_type; + typedef typename asio::ssl::stream sock_type; + + typedef boost::function handler_type; + + template + void async_connect(endpoint_type const& endpoint, Handler const& handler) + { + // the connect is split up in the following steps: + // 1. connect to peer + // 2. perform SSL client handshake + + // to avoid unnecessary copying of the handler, + // store it in a shared_ptr + boost::shared_ptr h(new handler_type(handler)); + + m_sock.next_layer().async_connect(endpoint + , boost::bind(&ssl_stream::connected, this, _1, h)); + } + + template + void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) + { + m_sock.async_read_some(buffers, handler); + } + + template + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) + { + return m_sock.read_some(buffers, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + template + std::size_t read_some(Mutable_Buffers const& buffers) + { + return m_sock.read_some(buffers); + } + + template + void io_control(IO_Control_Command& ioc) + { + m_sock.next_layer().io_control(ioc); + } +#endif + + template + void io_control(IO_Control_Command& ioc, error_code& ec) + { + m_sock.next_layer().io_control(ioc, ec); + } + + template + void async_write_some(Const_Buffers const& buffers, Handler const& handler) + { + m_sock.async_write_some(buffers, handler); + } + +#ifndef BOOST_NO_EXCEPTIONS + void bind(endpoint_type const& endpoint) + { + m_sock.next_layer().bind(endpoint); + } +#endif + + void bind(endpoint_type const& endpoint, error_code& ec) + { + m_sock.next_layer().bind(endpoint, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + void open(protocol_type const& p) + { + m_sock.next_layer().open(p); + } +#endif + + void open(protocol_type const& p, error_code& ec) + { + m_sock.next_layer().open(p, ec); + } + + bool is_open() const + { + return const_cast(m_sock).next_layer().is_open(); + } + +#ifndef BOOST_NO_EXCEPTIONS + void close() + { + m_sock.next_layer().close(); + } +#endif + + void close(error_code& ec) + { + m_sock.next_layer().close(ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type remote_endpoint() const + { + return const_cast(m_sock).next_layer().remote_endpoint(); + } +#endif + + endpoint_type remote_endpoint(error_code& ec) const + { + return const_cast(m_sock).next_layer().remote_endpoint(ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type local_endpoint() const + { + return const_cast(m_sock).next_layer().local_endpoint(); + } +#endif + + endpoint_type local_endpoint(error_code& ec) const + { + return const_cast(m_sock).next_layer().local_endpoint(ec); + } + + io_service& get_io_service() + { + return m_sock.get_io_service(); + } + + lowest_layer_type& lowest_layer() + { + return m_sock.lowest_layer(); + } + + next_layer_type& next_layer() + { + return m_sock.next_layer(); + } + +private: + + void connected(error_code const& e, boost::shared_ptr h) + { + if (e) + { + (*h)(e); + return; + } + + m_sock.async_handshake(asio::ssl::stream_base::client + , boost::bind(&ssl_stream::handshake, this, _1, h)); + } + + void handshake(error_code const& e, boost::shared_ptr h) + { + (*h)(e); + } + + asio::ssl::context m_context; + asio::ssl::stream m_sock; +}; + +} + +#endif + diff --git a/libtorrent/include/libtorrent/stat.hpp b/libtorrent/include/libtorrent/stat.hpp new file mode 100644 index 000000000..ae29671e3 --- /dev/null +++ b/libtorrent/include/libtorrent/stat.hpp @@ -0,0 +1,241 @@ +/* + +Copyright (c) 2003, 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_STAT_HPP_INCLUDED +#define TORRENT_STAT_HPP_INCLUDED + +#include +#include +#include +#include + +#include "libtorrent/size_type.hpp" +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" + +namespace libtorrent +{ + class TORRENT_EXPORT stat_channel + { + friend class invariant_access; + public: + enum { history = 10 }; + + stat_channel() + : m_counter(0) + , m_total_counter(0) + , m_rate_sum(0) + { + std::memset(m_rate_history, 0, sizeof(m_rate_history)); + } + + void operator+=(stat_channel const& s) + { + m_counter += s.m_counter; + m_total_counter += s.m_counter; + } + + void add(int count) + { + TORRENT_ASSERT(count >= 0); + + m_counter += count; + m_total_counter += count; + } + + // should be called once every second + void second_tick(float tick_interval); + float rate() const { return m_rate_sum / float(history); } + size_type rate_sum() const { return m_rate_sum; } + size_type total() const { return m_total_counter; } + + void offset(size_type counter) + { + TORRENT_ASSERT(counter >= 0); + m_total_counter += counter; + } + + size_type counter() const { return m_counter; } + + private: + +#ifndef NDEBUG + void check_invariant() const + { + int sum = 0; + for (int i = 0; i < history; ++i) sum += m_rate_history[i]; + TORRENT_ASSERT(m_rate_sum == sum); + TORRENT_ASSERT(m_total_counter >= 0); + } +#endif + + // history of rates a few seconds back + int m_rate_history[history]; + + // the accumulator for this second. + int m_counter; + + // total counters + size_type m_total_counter; + + // sum of all elements in m_rate_history + size_type m_rate_sum; + }; + + class TORRENT_EXPORT stat + { + friend class invariant_access; + public: + void operator+=(const stat& s) + { + for (int i = 0; i < num_channels; ++i) + m_stat[i] += s.m_stat[i]; + } + + void received_bytes(int bytes_payload, int bytes_protocol) + { + TORRENT_ASSERT(bytes_payload >= 0); + TORRENT_ASSERT(bytes_protocol >= 0); + + m_stat[download_payload].add(bytes_payload); + m_stat[download_protocol].add(bytes_protocol); + } + + void sent_bytes(int bytes_payload, int bytes_protocol) + { + TORRENT_ASSERT(bytes_payload >= 0); + TORRENT_ASSERT(bytes_protocol >= 0); + + m_stat[upload_payload].add(bytes_payload); + m_stat[upload_protocol].add(bytes_protocol); + } + + // calculate ip protocol overhead + void calc_ip_overhead() + { + int uploaded = m_stat[upload_protocol].counter() + + m_stat[upload_payload].counter(); + int downloaded = m_stat[download_protocol].counter() + + m_stat[download_payload].counter(); + + // IP + TCP headers are 40 bytes per MTU (1460) + // bytes of payload, but at least 40 bytes + m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, uploaded>0?40:0)); + m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, downloaded>0?40:0)); + + // also account for ACK traffic. That adds to the transfers + // in the opposite direction. Even on connections with symmetric + // transfer rates, it seems to add a penalty. + m_stat[upload_ip_protocol].add((std::max)(downloaded * 40 / 1460, downloaded>0?40:0)); + m_stat[download_ip_protocol].add((std::max)(uploaded * 40 / 1460, uploaded>0?40:0)); + } + + int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); } + int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); } + + // should be called once every second + void second_tick(float tick_interval) + { + for (int i = 0; i < num_channels; ++i) + m_stat[i].second_tick(tick_interval); + } + + float upload_rate() const + { + return (m_stat[upload_payload].rate_sum() + + m_stat[upload_protocol].rate_sum() + + m_stat[upload_ip_protocol].rate_sum()) + / float(stat_channel::history); + } + + float download_rate() const + { + return (m_stat[download_payload].rate_sum() + + m_stat[download_protocol].rate_sum() + + m_stat[download_ip_protocol].rate_sum()) + / float(stat_channel::history); + } + + float upload_payload_rate() const + { return m_stat[upload_payload].rate(); } + + float download_payload_rate() const + { return m_stat[download_payload].rate(); } + + size_type total_payload_upload() const + { return m_stat[upload_payload].total(); } + size_type total_payload_download() const + { return m_stat[download_payload].total(); } + + size_type total_protocol_upload() const + { return m_stat[upload_protocol].total(); } + size_type total_protocol_download() const + { return m_stat[download_protocol].total(); } + + // this is used to offset the statistics when a + // peer_connection is opened and have some previous + // transfers from earlier connections. + void add_stat(size_type downloaded, size_type uploaded) + { + TORRENT_ASSERT(downloaded >= 0); + TORRENT_ASSERT(uploaded >= 0); + m_stat[download_payload].offset(downloaded); + m_stat[upload_payload].offset(uploaded); + } + + size_type last_payload_downloaded() const + { return m_stat[download_payload].counter(); } + size_type last_payload_uploaded() const + { return m_stat[upload_payload].counter(); } + + private: + + // these are the channels we keep stats for + enum + { + upload_payload, + upload_protocol, + upload_ip_protocol, + download_payload, + download_protocol, + download_ip_protocol, + num_channels + }; + + stat_channel m_stat[num_channels]; + }; + +} + +#endif // TORRENT_STAT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp new file mode 100644 index 000000000..1733abe8a --- /dev/null +++ b/libtorrent/include/libtorrent/storage.hpp @@ -0,0 +1,422 @@ +/* + +Copyright (c) 2003, 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_STORAGE_HPP_INCLUDE +#define TORRENT_STORAGE_HPP_INCLUDE + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/piece_picker.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/buffer.hpp" + +namespace libtorrent +{ + namespace aux + { + struct piece_checker_data; + } + + namespace fs = boost::filesystem; + + class session; + struct file_pool; + struct disk_io_job; + struct disk_buffer_holder; + + enum storage_mode_t + { + storage_mode_allocate = 0, + storage_mode_sparse, + storage_mode_compact + }; + +#if defined(_WIN32) && defined(UNICODE) + + TORRENT_EXPORT std::wstring safe_convert(std::string const& s); + +#endif + + TORRENT_EXPORT std::vector > get_filesizes( + file_storage const& t + , fs::path p); + + TORRENT_EXPORT bool match_filesizes( + file_storage const& t + , fs::path p + , std::vector > const& sizes + , bool compact_mode + , std::string* error = 0); + + struct TORRENT_EXPORT file_allocation_failed: std::exception + { + file_allocation_failed(const char* error_msg): m_msg(error_msg) {} + virtual const char* what() const throw() { return m_msg.c_str(); } + virtual ~file_allocation_failed() throw() {} + std::string m_msg; + }; + + struct TORRENT_EXPORT partial_hash + { + partial_hash(): offset(0) {} + // the number of bytes in the piece that has been hashed + int offset; + // the sha-1 context + hasher h; + }; + + struct TORRENT_EXPORT storage_interface + { + // 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 + // false return value indicates an error + virtual bool initialize(bool allocate_files) = 0; + + // negative return value indicates an error + virtual int read(char* buf, int slot, int offset, int size) = 0; + + // negative return value indicates an error + virtual int write(const char* buf, int slot, int offset, int size) = 0; + + // non-zero return value indicates an error + virtual bool move_storage(fs::path save_path) = 0; + + // verify storage dependent fast resume entries + virtual bool verify_resume_data(lazy_entry const& rd, std::string& error) = 0; + + // write storage dependent fast resume entries + virtual bool write_resume_data(entry& rd) const = 0; + + // moves (or copies) the content in src_slot to dst_slot + virtual bool move_slot(int src_slot, int dst_slot) = 0; + + // swaps the data in slot1 and slot2 + virtual bool 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 bool swap_slots3(int slot1, int slot2, int slot3) = 0; + + // returns the sha1-hash for the data at the given slot + virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0; + + // this will close all open files that are opened for + // writing. This is called when a torrent has finished + // downloading. + // non-zero return value indicates an error + virtual bool release_files() = 0; + + // this will rename the file specified by index. + virtual bool rename_file(int index, std::string const& new_filename) = 0; + + // this will close all open files and delete them + // non-zero return value indicates an error + virtual bool delete_files() = 0; + + void set_error(std::string const& file, std::string const& msg) const + { + m_error_file = file; + m_error = msg; + } + + std::string const& error() const { return m_error; } + std::string const& error_file() const { return m_error_file; } + void clear_error() { m_error.clear(); m_error_file.clear(); } + + mutable std::string m_error; + mutable std::string m_error_file; + + virtual ~storage_interface() {} + }; + + typedef storage_interface* (&storage_constructor_type)( + file_storage const&, fs::path const&, file_pool&); + + TORRENT_EXPORT storage_interface* default_storage_constructor( + file_storage const&, fs::path const&, file_pool&); + TORRENT_EXPORT storage_interface* mapped_storage_constructor( + file_storage const&, fs::path const&, file_pool&); + + struct disk_io_thread; + + class TORRENT_EXPORT piece_manager + : public intrusive_ptr_base + , boost::noncopyable + { + friend class invariant_access; + friend struct disk_io_thread; + public: + + piece_manager( + boost::shared_ptr const& torrent + , boost::intrusive_ptr info + , fs::path const& path + , file_pool& fp + , disk_io_thread& io + , storage_constructor_type sc + , storage_mode_t sm); + + ~piece_manager(); + + boost::intrusive_ptr info() const { return m_info; } + void write_resume_data(entry& rd) const; + + void async_check_fastresume(lazy_entry const* resume_data + , boost::function const& handler); + + void async_check_files(boost::function const& handler); + + void async_rename_file(int index, std::string const& name + , boost::function const& handler); + + void async_read( + peer_request const& r + , boost::function const& handler + , int priority = 0); + + void async_write( + peer_request const& r + , disk_buffer_holder& buffer + , boost::function const& f); + + void async_hash(int piece, boost::function const& f); + + void async_release_files( + boost::function const& handler + = boost::function()); + + void async_delete_files( + boost::function const& handler + = boost::function()); + + void async_move_storage(fs::path const& p + , boost::function const& handler); + + void async_save_resume_data( + boost::function const& handler); + + enum return_t + { + // return values from check_fastresume and check_files + no_error = 0, + need_full_check = -1, + fatal_disk_error = -2, + disk_check_aborted = -3 + }; + + private: + + fs::path save_path() const; + + bool verify_resume_data(lazy_entry const& rd, std::string& error) + { return m_storage->verify_resume_data(rd, error); } + + bool is_allocating() const + { return m_state == state_expand_pieces; } + + void mark_failed(int index); + + std::string const& error() const { return m_storage->error(); } + std::string const& error_file() const { return m_storage->error_file(); } + void clear_error() { m_storage->clear_error(); } + + int slot_for(int piece) const; + int piece_for(int slot) const; + + // helper functions for check_dastresume + int check_no_fastresume(std::string& error); + int check_init_storage(std::string& error); + + // if error is set and return value is 'no_error' or 'need_full_check' + // the error message indicates that the fast resume data was rejected + // if 'fatal_disk_error' is returned, the error message indicates what + // when wrong in the disk access + int check_fastresume(lazy_entry const& rd, std::string& error); + + // this function returns true if the checking is complete + int check_files(int& current_slot, int& have_piece, std::string& error); + + bool compact_allocation() const + { return m_storage_mode == storage_mode_compact; } + +#ifndef NDEBUG + std::string name() const { return m_info->name(); } +#endif + + bool allocate_slots(int num_slots, bool abort_on_disk = false); + + int read_impl( + char* buf + , int piece_index + , int offset + , int size); + + int write_impl( + const char* buf + , int piece_index + , int offset + , int size); + + bool check_one_piece(int& have_piece); + int identify_data( + const std::vector& piece_data + , int current_slot); + + void switch_to_full_mode(); + sha1_hash hash_for_piece_impl(int piece); + + int release_files_impl() { return m_storage->release_files(); } + int delete_files_impl() { return m_storage->delete_files(); } + int rename_file_impl(int index, std::string const& new_filename) + { return m_storage->rename_file(index, new_filename); } + + int move_storage_impl(fs::path const& save_path); + + int allocate_slot_for_piece(int piece_index); +#ifndef NDEBUG + void check_invariant() const; +#ifdef TORRENT_STORAGE_DEBUG + void debug_log() const; +#endif +#endif + boost::intrusive_ptr m_info; + file_storage const& m_files; + + boost::scoped_ptr m_storage; + + storage_mode_t m_storage_mode; + + // slots that haven't had any file storage allocated + std::vector m_unallocated_slots; + // slots that have file storage, but isn't assigned to a piece + std::vector m_free_slots; + + enum + { + has_no_slot = -3 // the piece has no storage + }; + + // maps piece indices to slots. If a piece doesn't + // have any storage, it is set to 'has_no_slot' + std::vector m_piece_to_slot; + + enum + { + unallocated = -1, // the slot is unallocated + unassigned = -2 // the slot is allocated but not assigned to a piece + }; + + // maps slots to piece indices, if a slot doesn't have a piece + // it can either be 'unassigned' or 'unallocated' + std::vector m_slot_to_piece; + + fs::path m_save_path; + + mutable boost::recursive_mutex m_mutex; + + enum { + // the default initial state + state_none, + // the file checking is complete + state_finished, + // checking the files + state_full_check, + // move pieces to their final position + state_expand_pieces + } m_state; + int m_current_slot; + // used during check. If any piece is found + // that is not in its final position, this + // is set to true + bool m_out_of_place; + // used to move pieces while expanding + // the storage from compact allocation + // to full allocation + buffer m_scratch_buffer; + buffer m_scratch_buffer2; + // the piece that is in the scratch buffer + int m_scratch_piece; + + // this is saved in case we need to instantiate a new + // storage (osed when remapping files) + storage_constructor_type m_storage_constructor; + + // temporary buffer used while checking + std::vector m_piece_data; + + // this maps a piece hash to piece index. It will be + // build the first time it is used (to save time if it + // isn't needed) + std::multimap m_hash_to_piece; + + // this map contains partial hashes for downloading + // pieces. This is only accessed from within the + // disk-io thread. + std::map m_piece_hasher; + + disk_io_thread& m_io_thread; + + // the reason for this to be a void pointer + // is to avoid creating a dependency on the + // torrent. This shared_ptr is here only + // to keep the torrent object alive until + // the piece_manager destructs. This is because + // the torrent_info object is owned by the torrent. + boost::shared_ptr m_torrent; + }; + +} + +#endif // TORRENT_STORAGE_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp new file mode 100644 index 000000000..e74247ebb --- /dev/null +++ b/libtorrent/include/libtorrent/time.hpp @@ -0,0 +1,410 @@ +/* + +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 +#include + +#ifndef _WIN32 +#include +#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; + } + + std::string log_time(); +} + +#if (!defined (__MACH__) && !defined (_WIN32) && (!defined(_POSIX_MONOTONIC_CLOCK) \ + || _POSIX_MONOTONIC_CLOCK < 0)) || defined (TORRENT_USE_BOOST_DATE_TIME) + +#include +#include "libtorrent/assert.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 + +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif +#include +#include "libtorrent/assert.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) {} + time_duration& operator-=(time_duration const& c) { diff -= c.diff; return *this; } + time_duration& operator+=(time_duration const& c) { diff += c.diff; return *this; } + time_duration operator+(time_duration const& c) { return time_duration(diff + c.diff); } + 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; } + 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::max)()); } + int total_seconds(time_duration td); + int total_milliseconds(time_duration td); + boost::int64_t total_microseconds(time_duration td); +} + +// asio time_traits +#if BOOST_VERSION >= 103500 +namespace boost { +#endif +namespace asio +{ + template<> + struct time_traits + { + 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 BOOST_VERSION >= 103500 +} +#endif + +#if defined(__MACH__) + +#include +#include +#include "libtorrent/assert.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 + TORRENT_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); + TORRENT_ASSERT(timebase_info.numer > 0); + TORRENT_ASSERT(timebase_info.denom > 0); + } + // make sure we don't overflow + TORRENT_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 +#include "libtorrent/assert.hpp" + +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; + TORRENT_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; + TORRENT_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 int(aux::performance_counter_to_microseconds(td.diff) + / 1000000); + } + inline int total_milliseconds(time_duration td) + { + return int(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 +#include "libtorrent/assert.hpp" + +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 + diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp new file mode 100644 index 000000000..cf834e833 --- /dev/null +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -0,0 +1,966 @@ +/* + +Copyright (c) 2003, 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_TORRENT_HPP_INCLUDE +#define TORRENT_TORRENT_HPP_INCLUDE + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/policy.hpp" +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/piece_picker.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/escape_string.hpp" +#include "libtorrent/bandwidth_limit.hpp" +#include "libtorrent/bandwidth_queue_entry.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/bitfield.hpp" + +namespace libtorrent +{ +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + struct logger; +#endif + + class piece_manager; + struct torrent_plugin; + struct bitfield; + + namespace aux + { + struct session_impl; + struct piece_checker_data; + } + + namespace fs = boost::filesystem; + + // a torrent is a class that holds information + // for a specific download. It updates itself against + // the tracker + class TORRENT_EXPORT torrent: public request_callback + , public boost::enable_shared_from_this + { + public: + + torrent( + aux::session_impl& ses + , boost::intrusive_ptr tf + , fs::path const& save_path + , tcp::endpoint const& net_interface + , storage_mode_t m_storage_mode + , int block_size + , storage_constructor_type sc + , bool paused + , std::vector* resume_data + , int seq + , bool auto_managed); + + // used with metadata-less torrents + // (the metadata is downloaded from the peers) + torrent( + aux::session_impl& ses + , char const* tracker_url + , sha1_hash const& info_hash + , char const* name + , fs::path const& save_path + , tcp::endpoint const& net_interface + , storage_mode_t m_storage_mode + , int block_size + , storage_constructor_type sc + , bool paused + , std::vector* resume_data + , int seq + , bool auto_managed); + + ~torrent(); + + void parse_resume_data(std::vector* resume_data); + + // starts the announce timer + void start(); + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::shared_ptr); + void add_extension(boost::function(torrent*, void*)> const& ext + , void* userdata); +#endif + +#ifndef NDEBUG + bool has_peer(peer_connection* p) const + { return m_connections.find(p) != m_connections.end(); } +#endif + + // this is called when the torrent has metadata. + // it will initialize the storage and the piece-picker + void init(); + + void on_resume_data_checked(int ret, disk_io_job const& j); + void on_force_recheck(int ret, disk_io_job const& j); + void on_piece_checked(int ret, disk_io_job const& j); + void files_checked(); + void start_checking(); + + int seed_rank(session_settings const& s) const; + + storage_mode_t storage_mode() const { return m_storage_mode; } + // this will flag the torrent as aborted. The main + // loop in session_impl will check for this state + // on all torrents once every second, and take + // the necessary actions then. + void abort(); + bool is_aborted() const { return m_abort; } + + torrent_status::state_t state() const { return m_state; } + + session_settings const& settings() const; + + aux::session_impl& session() { return m_ses; } + + void set_sequential_download(bool sd); + bool is_sequential_download() const + { return m_sequential_download; } + + void set_queue_position(int p); + int queue_position() const { return m_sequence_number; } + + void second_tick(stat& accumulator, float tick_interval); + + // debug purpose only + void print(std::ostream& os) const; + + std::string name() const; + + stat statistics() const { return m_stat; } + void add_stats(stat const& s) { m_stat += s; } + size_type bytes_left() const; + boost::tuples::tuple bytes_done() const; + size_type quantized_bytes_done() const; + + void ip_filter_updated() { m_policy.ip_filter_updated(); } + + bool has_error() const { return !m_error.empty(); } + void pause(); + void resume(); + + void do_pause(); + void do_resume(); + + bool is_paused() const; + bool is_torrent_paused() const { return m_paused; } + void force_recheck(); + void save_resume_data(); + + bool is_auto_managed() const { return m_auto_managed; } + void auto_managed(bool a); + + void delete_files(); + + // ============ start deprecation ============= + void filter_piece(int index, bool filter); + void filter_pieces(std::vector const& bitmask); + bool is_piece_filtered(int index) const; + void filtered_pieces(std::vector& bitmask) const; + void filter_files(std::vector const& files); + // ============ end deprecation ============= + + void piece_availability(std::vector& avail) const; + + void set_piece_priority(int index, int priority); + int piece_priority(int index) const; + + void prioritize_pieces(std::vector const& pieces); + void piece_priorities(std::vector&) const; + + void prioritize_files(std::vector const& files); + + torrent_status status() const; + void file_progress(std::vector& fp) const; + + void use_interface(const char* net_interface); + tcp::endpoint const& get_interface() const { return m_net_interface; } + + void connect_to_url_seed(std::string const& url); + bool connect_to_peer(policy::peer* peerinfo); + + void set_ratio(float ratio) + { TORRENT_ASSERT(ratio >= 0.0f); m_ratio = ratio; } + + 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 + + bandwidth_limit m_bandwidth_limit[2]; + + void request_bandwidth(int channel + , boost::intrusive_ptr const& p + , int max_block_size, int priority); + + void perform_bandwidth_request(int channel + , boost::intrusive_ptr const& p + , int block_size, int priority); + + void expire_bandwidth(int channel, int amount); + void assign_bandwidth(int channel, int amount, int blk); + + int bandwidth_throttle(int channel) const; + + int max_assignable_bandwidth(int channel) const + { return m_bandwidth_limit[channel].max_assignable(); } + + int bandwidth_queue_size(int channel) const; + +// -------------------------------------------- + // PEER MANAGEMENT + + // add or remove a url that will be attempted for + // finding the file(s) in this torrent. + void add_url_seed(std::string const& url) + { m_web_seeds.insert(url); } + + void remove_url_seed(std::string const& url) + { m_web_seeds.erase(url); } + + void retry_url_seed(std::string const& url); + + std::set url_seeds() const + { return m_web_seeds; } + + bool free_upload_slots() const + { return m_num_uploads < m_max_uploads; } + + void choke_peer(peer_connection& c); + bool unchoke_peer(peer_connection& c); + + // used by peer_connection to attach itself to a torrent + // since incoming connections don't know what torrent + // they're a part of until they have received an info_hash. + // false means attach failed + bool attach_peer(peer_connection* p); + + // this will remove the peer and make sure all + // the pieces it had have their reference counter + // decreased in the piece_picker + void remove_peer(peer_connection* p); + + void cancel_block(piece_block block); + + bool want_more_peers() const; + bool try_connect_peer(); + void give_connect_points(int points); + + // the number of peers that belong to this torrent + int num_peers() const { return (int)m_connections.size(); } + int num_seeds() const; + + typedef std::set::iterator peer_iterator; + typedef std::set::const_iterator const_peer_iterator; + + const_peer_iterator begin() const { return m_connections.begin(); } + const_peer_iterator end() const { return m_connections.end(); } + + peer_iterator begin() { return m_connections.begin(); } + peer_iterator end() { return m_connections.end(); } + + void resolve_peer_country(boost::intrusive_ptr const& p) const; + + void get_full_peer_list(std::vector& v) const; + void get_peer_info(std::vector& v); + void get_download_queue(std::vector& queue); + +// -------------------------------------------- + // TRACKER MANAGEMENT + + // these are callbacks called by the tracker_connection instance + // (either http_tracker_connection or udp_tracker_connection) + // when this torrent got a response from its tracker request + // or when a failure occured + virtual void tracker_response( + tracker_request const& r + , std::vector& e, int interval + , int complete, int incomplete, address const& external_ip); + virtual void tracker_request_timed_out( + tracker_request const& r); + virtual void tracker_request_error(tracker_request const& r + , int response_code, const std::string& str); + virtual void tracker_warning(tracker_request const& req + , std::string const& msg); + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloaded); + + // generates a request string for sending + // to the tracker + tracker_request generate_tracker_request(); + + // if no password and username is set + // this will return an empty string, otherwise + // it will concatenate the login and password + // ready to be sent over http (but without + // base64 encoding). + std::string tracker_login() const; + + // returns the absolute time when the next tracker + // announce will take place. + ptime next_announce() const; + + // returns true if it is time for this torrent to make another + // tracker request + bool should_request(); + + // forcefully sets next_announce to the current time + void force_tracker_request(); + void force_tracker_request(ptime); + void scrape_tracker(); + ptime const& last_scrape() const { return m_last_scrape; } + + // sets the username and password that will be sent to + // the tracker + void set_tracker_login(std::string const& name, std::string const& pw); + + // the tcp::endpoint of the tracker that we managed to + // announce ourself at the last time we tried to announce + const tcp::endpoint& current_tracker() const; + +// -------------------------------------------- + // PIECE MANAGEMENT + + // returns true if we have downloaded the given piece + bool have_piece(int index) const + { + return has_picker()?m_picker->have_piece(index):true; + } + + int num_have() const + { + return has_picker() + ?m_picker->num_have() + :m_torrent_file->num_pieces(); + } + + // when we get a have message, this is called for that piece + void peer_has(int index) + { + if (m_picker.get()) + { + TORRENT_ASSERT(!is_seed()); + m_picker->inc_refcount(index); + } +#ifndef NDEBUG + else + { + TORRENT_ASSERT(is_seed()); + } +#endif + } + + // when we get a bitfield message, this is called for that piece + void peer_has(bitfield const& bits) + { + if (m_picker.get()) + { + TORRENT_ASSERT(!is_seed()); + m_picker->inc_refcount(bits); + } +#ifndef NDEBUG + else + { + TORRENT_ASSERT(is_seed()); + } +#endif + } + + void peer_has_all() + { + if (m_picker.get()) + { + TORRENT_ASSERT(!is_seed()); + m_picker->inc_refcount_all(); + } +#ifndef NDEBUG + else + { + TORRENT_ASSERT(is_seed()); + } +#endif + } + + void peer_lost(int index) + { + if (m_picker.get()) + { + TORRENT_ASSERT(!is_seed()); + m_picker->dec_refcount(index); + } +#ifndef NDEBUG + else + { + TORRENT_ASSERT(is_seed()); + } +#endif + } + + int block_size() const { TORRENT_ASSERT(m_block_size > 0); return m_block_size; } + peer_request to_req(piece_block const& p); + + void disconnect_all(); + int disconnect_peers(int num); + + // this is called wheh the torrent has completed + // the download. It will post an event, disconnect + // all seeds and let the tracker know we're finished. + void completed(); + + // this is the asio callback that is called when a name + // lookup for a PEER is completed. + void on_peer_name_lookup(error_code const& e, tcp::resolver::iterator i + , peer_id pid); + + // this is the asio callback that is called when a name + // lookup for a WEB SEED is completed. + void on_name_lookup(error_code const& e, tcp::resolver::iterator i + , std::string url, tcp::endpoint proxy); + + // this is the asio callback that is called when a name + // lookup for a proxy for a web seed is completed. + void on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator i + , std::string url); + + // this is called when the torrent has finished. i.e. + // all the pieces we have not filtered have been downloaded. + // If no pieces are filtered, this is called first and then + // completed() is called immediately after it. + void finished(); + + // This is the opposite of finished. It is called if we used + // to be finished but enabled some files for download so that + // we wasn't finished anymore. + void resume_download(); + + void async_verify_piece(int piece_index, boost::function const&); + + // this is called from the peer_connection + // each time a piece has failed the hash + // test + void piece_finished(int index, int passed_hash_check); + + // piece_passed is called when a piece passes the hash check + // this will tell all peers that we just got his piece + // and also let the piece picker know that we have this piece + // so it wont pick it for download + void piece_passed(int index); + + // piece_failed is called when a piece fails the hash check + void piece_failed(int index); + + // this will restore the piece picker state for a piece + // by re marking all the requests to blocks in this piece + // that are still outstanding in peers' download queues. + // this is done when a piece fails + void restore_piece_state(int index); + + void received_redundant_data(int num_bytes) + { TORRENT_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_picker + || m_state == torrent_status::seeding + || m_picker->num_have() == m_picker->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_picker->num_have() - m_picker->num_filtered() == 0; + } + + fs::path save_path() const; + alert_manager& alerts() const; + piece_picker& picker() + { + TORRENT_ASSERT(m_picker.get()); + return *m_picker; + } + bool has_picker() const + { + return m_picker.get() != 0; + } + policy& get_policy() { return m_policy; } + piece_manager& filesystem(); + torrent_info const& torrent_file() const + { return *m_torrent_file; } + + std::vector const& trackers() const + { return m_trackers; } + + void replace_trackers(std::vector const& urls); + + torrent_handle get_handle(); + + void write_resume_data(entry& rd) const; + void read_resume_data(lazy_entry const& rd); + + // LOGGING +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + virtual void debug_log(const std::string& line); +#endif + + // DEBUG +#ifndef NDEBUG + void check_invariant() const; +#endif + +// -------------------------------------------- + // RESOURCE MANAGEMENT + + void set_peer_upload_limit(tcp::endpoint ip, int limit); + 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); + int max_uploads() const { return m_max_uploads; } + void set_max_connections(int limit); + int max_connections() const { return m_max_connections; } + + void move_storage(fs::path const& save_path); + + // renames the file with the given index to the new name + // the name may include a directory path + // returns false on failure + bool rename_file(int index, std::string const& name); + + // unless this returns true, new connections must wait + // with their initialization. + bool ready_for_connections() const + { return m_connections_initialized; } + bool valid_metadata() const + { return m_torrent_file->is_valid(); } + + // parses the info section from the given + // bencoded tree and moves the torrent + // to the checker thread for initial checking + // of the storage. + // a return value of false indicates an error + bool set_metadata(lazy_entry const& metadata, std::string& error); + + int sequence_number() const { return m_sequence_number; } + + private: + + void on_files_deleted(int ret, disk_io_job const& j); + void on_files_released(int ret, disk_io_job const& j); + void on_torrent_paused(int ret, disk_io_job const& j); + void on_storage_moved(int ret, disk_io_job const& j); + void on_save_resume_data(int ret, disk_io_job const& j); + void on_file_renamed(int ret, disk_io_job const& j); + + void on_piece_verified(int ret, disk_io_job const& j + , boost::function f); + + void try_next_tracker(); + int prioritize_tracker(int tracker_index); + void on_country_lookup(error_code const& error, tcp::resolver::iterator i + , boost::intrusive_ptr p) const; + bool request_bandwidth_from_session(int channel) const; + + void update_peer_interest(bool was_finished); + + policy m_policy; + + // total time we've been available on this torrent + // does not count when the torrent is stopped or paused + time_duration m_active_time; + + // total time we've been available as a seed on this torrent + // does not count when the torrent is stopped or paused + time_duration m_seeding_time; + + // all time totals of uploaded and downloaded payload + // stored in resume data + size_type m_total_uploaded; + size_type m_total_downloaded; + + // if this torrent is running, this was the time + // when it was started. This is used to have a + // bias towards keeping seeding torrents that + // recently was started, to avoid oscillation + ptime m_started; + + // the last time we initiated a scrape request to + // one of the trackers in this torrent + ptime m_last_scrape; + + boost::intrusive_ptr m_torrent_file; + + tracker_request::event_t m_event; + + void parse_response(const entry& e, std::vector& peer_list); + + // if this pointer is 0, the torrent is in + // a state where the metadata hasn't been + // received yet. + // the piece_manager keeps the torrent object + // alive by holding a shared_ptr to it and + // the torrent keeps the piece manager alive + // with this intrusive_ptr. This cycle is + // broken when torrent::abort() is called + // Then the torrent releases the piece_manager + // and when the piece_manager is complete with all + // outstanding disk io jobs (that keeps + // the piece_manager alive) it will destruct + // and release the torrent file. The reason for + // this is that the torrent_info is used by + // the piece_manager, and stored in the + // torrent, so the torrent cannot destruct + // before the piece_manager. + boost::intrusive_ptr m_owning_storage; + + // this is a weak (non owninig) pointer to + // the piece_manager. This is used after the torrent + // has been aborted, and it can no longer own + // the object. + piece_manager* m_storage; + + // the time of next tracker request + ptime m_next_request; + +#ifndef NDEBUG + public: +#endif + std::set m_connections; +#ifndef NDEBUG + private: +#endif + + // The list of web seeds in this torrent. Seeds + // with fatal errors are removed from the set + std::set m_web_seeds; + + // a list of web seeds that have failed and are + // waiting to be retried + std::map m_web_seeds_next_retry; + + // urls of the web seeds that we are currently + // resolving the address for + std::set m_resolving_web_seeds; + +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list > extension_list_t; + extension_list_t m_extensions; +#endif + + // used to resolve the names of web seeds + mutable tcp::resolver m_host_resolver; + + // 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 p + , 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 t + , std::vector const& peers); + void on_dht_announce_response(std::vector 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; + + // ----------------------------- + + // a back reference to the session + // this torrent belongs to. + aux::session_impl& m_ses; + + boost::scoped_ptr m_picker; + + // the queue of peer_connections that want more bandwidth + typedef std::deque > queue_t; + queue_t m_bandwidth_queue[2]; + + std::vector m_trackers; + // this is an index into m_trackers + + // the number of bytes that has been + // downloaded that failed the hash-test + size_type m_total_failed_bytes; + size_type m_total_redundant_bytes; + + std::string m_username; + std::string m_password; + + // the network interface all outgoing connections + // are opened through + tcp::endpoint m_net_interface; + + fs::path m_save_path; + + // determines the storage state for this torrent. + storage_mode_t m_storage_mode; + + // the state of this torrent (queued, checking, downloading) + torrent_status::state_t m_state; + + // if there's an error on this torrent, this is the + // error message + std::string m_error; + + // used if there is any resume data + std::vector m_resume_data; + lazy_entry m_resume_entry; + + // if the torrent is started without metadata, it may + // still be given a name until the metadata is received + // once the metadata is received this field will no + // longer be used and will be reset + boost::scoped_ptr m_name; + + session_settings const& m_settings; + + storage_constructor_type m_storage_constructor; + + float m_progress; + + // the upload/download ratio that each peer + // tries to maintain. + // 0 is infinite + float m_ratio; + + // the maximum number of uploads for this torrent + int m_max_uploads; + + // the number of unchoked peers in this torrent + int m_num_uploads; + + // the maximum number of connections for this torrent + int m_max_connections; + + // the size of a request block + // each piece is divided into these + // blocks when requested + int m_block_size; + + // ----------------------------- + // DATA FROM TRACKER RESPONSE + + // the scrape data from the tracker response, this + // is optional and may be -1. + int m_complete; + int m_incomplete; + +#ifndef NDEBUG + // this is the amount downloaded when this torrent + // is started. i.e. + // total_done - m_initial_done <= total_payload_download + size_type m_initial_done; +#endif + // this is the deficit counter in the Deficit Round Robin + // used to determine which torrent gets the next + // connection attempt. See: + // http://www.ecs.umass.edu/ece/wolf/courses/ECE697J/papers/DRR.pdf + // The quanta assigned to each torrent depends on the torrents + // priority, whether it's seed and the number of connected + // peers it has. This has the effect that some torrents + // will have more connection attempts than other. Each + // connection attempt costs 100 points from the deficit + // counter. points are deducted in try_connect_peer and + // increased in give_connect_points. Outside of the + // torrent object, these points are called connect_points. + int m_deficit_counter; + + // the number number of seconds between requests + // from the tracker + boost::int16_t m_duration; + + // the sequence number for this torrent, this is a + // monotonically increasing number for each added torrent + boost::int16_t m_sequence_number; + + // the index to the last tracker that worked + boost::int8_t m_last_working_tracker; + + // the tracker that is currently (or was last) + // tried + boost::int8_t m_currently_trying_tracker; + + // the number of connection attempts that has + // failed in a row, this is currently used to + // determine the timeout until next try. + boost::int8_t m_failed_trackers; + + // this is a counter that is decreased every + // second, and when it reaches 0, the policy::pulse() + // is called and the time scaler is reset to 10. + boost::int8_t m_time_scaler; + + // is set to true when the torrent has + // been aborted. + bool m_abort:1; + + // is true if this torrent has been paused + bool m_paused:1; + // this is true from the time when the torrent was + // paused to the time should_request() is called + bool m_just_paused:1; + + // if this is true, libtorrent may pause and resume + // this torrent depending on queuing rules. Torrents + // started with auto_managed flag set may be added in + // a paused state in case there are no available + // slots. + bool m_auto_managed:1; + +#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 resolved + // at a time. + mutable bool m_resolving_country:1; + + // this is true if the user has enabled + // country resolution in this torrent + bool m_resolve_countries:1; +#endif + + // 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 + bool m_sequential_download:1; + + // is false by default and set to + // true when the first tracker reponse + // is received + bool m_got_tracker_response:1; + + // this is set to false as long as the connections + // of this torrent hasn't been initialized. If we + // have metadata from the start, connections are + // initialized immediately, if we didn't have metadata, + // they are initialized right after files_checked(). + // valid_resume_data() will return false as long as + // the connections aren't initialized, to avoid + // them from altering the piece-picker before it + // has been initialized with files_checked(). + bool m_connections_initialized:1; + + // is set to true every time there is an incoming + // connection to this torrent + bool m_has_incoming:1; + + // this is set to true when the files are checked + // before the files are checked, we don't try to + // connect to peers + bool m_files_checked:1; + }; + + inline ptime torrent::next_announce() const + { + return m_next_request; + } + + inline void torrent::force_tracker_request() + { + m_next_request = time_now(); + } + + inline void torrent::force_tracker_request(ptime t) + { + m_next_request = t; + } + + inline void torrent::set_tracker_login( + std::string const& name + , std::string const& pw) + { + m_username = name; + m_password = pw; + } + +} + +#endif // TORRENT_TORRENT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp new file mode 100644 index 000000000..25e9bbf21 --- /dev/null +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -0,0 +1,488 @@ +/* + +Copyright (c) 2003, 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_TORRENT_HANDLE_HPP_INCLUDED +#define TORRENT_TORRENT_HANDLE_HPP_INCLUDED + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer_id.hpp" +#include "libtorrent/peer_info.hpp" +#include "libtorrent/piece_picker.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/time.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/storage.hpp" + +namespace libtorrent +{ + namespace fs = boost::filesystem; + + namespace aux + { + struct session_impl; + struct checker_impl; + } + + struct torrent_plugin; + + struct TORRENT_EXPORT duplicate_torrent: std::exception + { + virtual const char* what() const throw() + { return "torrent already exists in session"; } + }; + + struct TORRENT_EXPORT invalid_handle: std::exception + { + virtual const char* what() const throw() + { return "invalid torrent handle used"; } + }; + + struct TORRENT_EXPORT torrent_status + { + torrent_status() + : state(queued_for_checking) + , paused(false) + , progress(0.f) + , total_download(0) + , total_upload(0) + , total_payload_download(0) + , total_payload_upload(0) + , total_failed_bytes(0) + , total_redundant_bytes(0) + , download_rate(0) + , upload_rate(0) + , download_payload_rate(0) + , upload_payload_rate(0) + , num_seeds(0) + , num_peers(0) + , num_complete(-1) + , num_incomplete(-1) + , list_seeds(0) + , list_peers(0) + , num_pieces(0) + , total_done(0) + , total_wanted_done(0) + , total_wanted(0) + , distributed_copies(0.f) + , block_size(0) + , num_uploads(0) + , num_connections(0) + , uploads_limit(0) + , connections_limit(0) + , storage_mode(storage_mode_sparse) + , up_bandwidth_queue(0) + , down_bandwidth_queue(0) + , all_time_upload(0) + , all_time_download(0) + , active_time(0) + , seeding_time(0) + , seed_rank(0) + , last_scrape(0) + , has_incoming(false) + {} + + enum state_t + { + queued_for_checking, + checking_files, + connecting_to_tracker, + downloading_metadata, + downloading, + finished, + seeding, + allocating + }; + + state_t state; + bool paused; + float progress; + std::string error; + + boost::posix_time::time_duration next_announce; + boost::posix_time::time_duration announce_interval; + + std::string current_tracker; + + // transferred this session! + // total, payload plus protocol + size_type total_download; + size_type total_upload; + + // payload only + size_type total_payload_download; + size_type total_payload_upload; + + // the amount of payload bytes that + // has failed their hash test + size_type total_failed_bytes; + + // the number of payload bytes that + // has been received redundantly. + size_type total_redundant_bytes; + + // current transfer rate + // payload plus protocol + float download_rate; + float upload_rate; + + // the rate of payload that is + // sent and received + float download_payload_rate; + float upload_payload_rate; + + // the number of peers this torrent is connected to + // that are seeding. + int num_seeds; + + // the number of peers this torrent + // is connected to (including seeds). + int num_peers; + + // if the tracker sends scrape info in its + // announce reply, these fields will be + // set to the total number of peers that + // have the whole file and the total number + // of peers that are still downloading + int num_complete; + int num_incomplete; + + // this is the number of seeds whose IP we know + // but are not necessarily connected to + int list_seeds; + + // this is the number of peers whose IP we know + // (including seeds), but are not necessarily + // connected to + int list_peers; + + // the number of peers in our peerlist that + // we potentially could connect to + int connect_candidates; + + bitfield pieces; + + // this is the number of pieces the client has + // downloaded. it is equal to: + // std::accumulate(pieces->begin(), pieces->end()); + int num_pieces; + + // the number of bytes of the file we have + // including pieces that may have been filtered + // after we downloaded them + size_type total_done; + + // the number of bytes we have of those that we + // want. i.e. not counting bytes from pieces that + // are filtered as not wanted. + size_type total_wanted_done; + + // the total number of bytes we want to download + // this may be smaller than the total torrent size + // in case any pieces are filtered as not wanted + size_type total_wanted; + + // the number of distributed copies of the file. + // note that one copy may be spread out among many peers. + // + // the integer part tells how many copies + // there are of the rarest piece(s) + // + // the fractional part tells the fraction of pieces that + // have more copies than the rarest piece(s). + float distributed_copies; + + // the block size that is used in this torrent. i.e. + // the number of bytes each piece request asks for + // and each bit in the download queue bitfield represents + int block_size; + + int num_uploads; + int num_connections; + int uploads_limit; + int connections_limit; + + // true if the torrent is saved in compact mode + // false if it is saved in full allocation mode + storage_mode_t storage_mode; + + int up_bandwidth_queue; + int down_bandwidth_queue; + + // number of bytes downloaded since torrent was started + // saved and restored from resume data + size_type all_time_upload; + size_type all_time_download; + + // the number of seconds of being active + // and as being a seed, saved and restored + // from resume data + int active_time; + int seeding_time; + + // higher value means more important to seed + int seed_rank; + + // number of seconds since last scrape, or -1 if + // there hasn't been a scrape + int last_scrape; + + // true if there are incoming connections to this + // torrent + bool has_incoming; + }; + + struct TORRENT_EXPORT block_info + { + enum block_state_t + { none, requested, writing, finished }; + + tcp::endpoint peer; + // number of bytes downloaded in this block + unsigned bytes_progress:16; + // the total number of bytes in this block + unsigned block_size:16; + // the state this block is in (see block_state_t) + unsigned state:2; + // the number of peers that has requested this block + // typically 0 or 1. If > 1, this block is in + // end game mode + unsigned num_peers:14; + }; + + struct TORRENT_EXPORT partial_piece_info + { + enum { max_blocks_per_piece = 256 }; + int piece_index; + int blocks_in_piece; + // the number of blocks in the finished state + int finished; + // the number of blocks in the writing state + int writing; + // the number of blocks in the requested state + int requested; + block_info blocks[max_blocks_per_piece]; + enum state_t { none, slow, medium, fast }; + state_t piece_state; + }; + + struct TORRENT_EXPORT torrent_handle + { + friend class invariant_access; + friend struct aux::session_impl; + friend class torrent; + + torrent_handle() {} + + void get_full_peer_list(std::vector& v) const; + void get_peer_info(std::vector& v) const; + torrent_status status() const; + void get_download_queue(std::vector& queue) const; + + // fills the specified vector with the download progress [0, 1] + // of each file in the torrent. The files are ordered as in + // the torrent_info. + void file_progress(std::vector& progress); + + std::vector const& trackers() const; + void replace_trackers(std::vector const&) const; + + void add_url_seed(std::string const& url) const; + void remove_url_seed(std::string const& url) const; + std::set url_seeds() const; + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::function(torrent*, void*)> const& ext + , void* userdata = 0); +#endif + + bool has_metadata() const; + const torrent_info& get_torrent_info() const; + bool is_valid() const; + + bool is_seed() const; + bool is_finished() const; + bool is_paused() const; + void pause() const; + void resume() const; + void force_recheck() const; + void save_resume_data() const; + + bool is_auto_managed() const; + void auto_managed(bool m) const; + + int queue_position() const; + void queue_position_up() const; + void queue_position_down() const; + void queue_position_top() const; + void queue_position_bottom() 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 ============ + + // deprecated in 0.13 + // marks the piece with the given index as filtered + // it will not be downloaded + void filter_piece(int index, bool filter) const TORRENT_DEPRECATED; + void filter_pieces(std::vector const& pieces) const TORRENT_DEPRECATED; + bool is_piece_filtered(int index) const TORRENT_DEPRECATED; + std::vector filtered_pieces() const TORRENT_DEPRECATED; + // marks the file with the given index as filtered + // it will not be downloaded + void filter_files(std::vector const& files) const TORRENT_DEPRECATED; + + // ================ end deprecation ============ + + void piece_availability(std::vector& avail) const; + + // 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 const& pieces) const; + std::vector piece_priorities() const; + + void prioritize_files(std::vector const& files) const; + + + // set the interface to bind outgoing connections + // to. + void use_interface(const char* net_interface) const; + + // deprecated in 0.14 + // use save_resume_data() instead. It is async. and + // will return the resume data in an alert + entry write_resume_data() const TORRENT_DEPRECATED; + + // forces this torrent to reannounce + // (make a rerequest from the tracker) + void force_reannounce() const; + + // forces a reannounce in the specified amount of time. + // This overrides the default announce interval, and no + // announce will take place until the given time has + // timed out. + void force_reannounce(boost::posix_time::time_duration) const; + + // performs a scrape request + void scrape_tracker() const; + + // returns the name of this torrent, in case it doesn't + // have metadata it returns the name assigned to it + // when it was added. + std::string name() const; + + // TODO: add a feature where the user can tell the torrent + // to finish all pieces currently in the pipeline, and then + // 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_sequential_download(bool sd) const; + bool is_sequential_download() 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, 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 + void set_ratio(float up_down_ratio) const; + + fs::path save_path() const; + + // -1 means unlimited unchokes + void set_max_uploads(int max_uploads) const; + + // -1 means unlimited connections + void set_max_connections(int max_connections) const; + + void set_tracker_login(std::string const& name + , std::string const& password) const; + + // post condition: save_path() == save_path if true is returned + void move_storage(fs::path const& save_path) const; + void rename_file(int index, fs::path const& new_name) const; + + sha1_hash info_hash() const; + + bool operator==(const torrent_handle& h) const + { return m_torrent.lock() == h.m_torrent.lock(); } + + bool operator!=(const torrent_handle& h) const + { return m_torrent.lock() != h.m_torrent.lock(); } + + bool operator<(const torrent_handle& h) const + { return m_torrent.lock() < h.m_torrent.lock(); } + + private: + + torrent_handle(boost::weak_ptr const& t) + : m_torrent(t) + {} + +#ifndef NDEBUG + void check_invariant() const; +#endif + + boost::weak_ptr m_torrent; + + }; + + +} + +#endif // TORRENT_TORRENT_HANDLE_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp new file mode 100644 index 000000000..0cc9b93b2 --- /dev/null +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -0,0 +1,242 @@ +/* + +Copyright (c) 2003-2008, 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_TORRENT_INFO_HPP_INCLUDED +#define TORRENT_TORRENT_INFO_HPP_INCLUDED + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/entry.hpp" +#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/size_type.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/time.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/file_storage.hpp" + +namespace libtorrent +{ + namespace pt = boost::posix_time; + namespace gr = boost::gregorian; + namespace fs = boost::filesystem; + + struct TORRENT_EXPORT announce_entry + { + announce_entry(std::string const& u): url(u), tier(0) {} + std::string url; + int tier; + }; + +#ifndef BOOST_NO_EXCEPTIONS + struct TORRENT_EXPORT invalid_torrent_file: std::exception + { + virtual const char* what() const throw() { return "invalid torrent file"; } + }; +#endif + + int TORRENT_EXPORT load_file(fs::path const& filename, std::vector& v); + + class TORRENT_EXPORT torrent_info : public intrusive_ptr_base + { + public: + + torrent_info(sha1_hash const& info_hash); + torrent_info(lazy_entry const& torrent_file); + torrent_info(char const* buffer, int size); + torrent_info(fs::path const& filename); + ~torrent_info(); + + file_storage const& files() const { return m_files; } + + void add_tracker(std::string const& url, int tier = 0); + std::vector const& trackers() const { return m_urls; } + + std::vector const& url_seeds() const + { return m_url_seeds; } + void add_url_seed(std::string const& url) + { m_url_seeds.push_back(url); } + + size_type total_size() const { return m_files.total_size(); } + int piece_length() const { return m_files.piece_length(); } + int num_pieces() const { return m_files.num_pieces(); } + const sha1_hash& info_hash() const { return m_info_hash; } + const std::string& name() const { return m_files.name(); } + + typedef file_storage::iterator file_iterator; + typedef file_storage::reverse_iterator reverse_file_iterator; + + file_iterator begin_files() const { return m_files.begin(); } + file_iterator end_files() const { return m_files.end(); } + reverse_file_iterator rbegin_files() const { return m_files.rbegin(); } + reverse_file_iterator rend_files() const { return m_files.rend(); } + int num_files() const { return m_files.num_files(); } + file_entry const& file_at(int index) const { return m_files.at(index); } + + std::vector map_block(int piece, size_type offset, int size) const + { return m_files.map_block(piece, offset, size); } + peer_request map_file(int file, size_type offset, int size) const + { return m_files.map_file(file, offset, size); } + +// ------- start deprecation ------- +// these functions will be removed in a future version + torrent_info(entry const& torrent_file) TORRENT_DEPRECATED; + void print(std::ostream& os) const TORRENT_DEPRECATED; +// ------- end deprecation ------- + + bool is_valid() const { return m_files.is_valid(); } + + bool priv() const { return m_private; } + + int piece_size(int index) const { return m_files.piece_size(index); } + + sha1_hash hash_for_piece(int index) const + { return sha1_hash(hash_for_piece_ptr(index)); } + + char const* hash_for_piece_ptr(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_files.num_pieces()); + TORRENT_ASSERT(m_piece_hashes); + TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); + return &m_piece_hashes[index*20]; + } + + boost::optional creation_date() const; + + const std::string& creator() const + { return m_created_by; } + + const std::string& comment() const + { return m_comment; } + + // dht nodes to add to the routing table/bootstrap from + typedef std::vector > nodes_t; + + nodes_t const& nodes() const + { return m_nodes; } + void add_node(std::pair const& node) + { m_nodes.push_back(node); } + + bool parse_info_section(lazy_entry const& e, std::string& error); + + lazy_entry const* info(char const* key) const + { + if (m_info_dict.type() == lazy_entry::none_t) + lazy_bdecode(m_info_section.get(), m_info_section.get() + + m_info_section_size, m_info_dict); + return m_info_dict.dict_find(key); + } + + void swap(torrent_info& ti); + + boost::shared_array metadata() const + { return m_info_section; } + + int metadata_size() const { return m_info_section_size; } + + private: + + bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error); + + file_storage m_files; + + // the urls to the trackers + std::vector m_urls; + std::vector m_url_seeds; + nodes_t m_nodes; + + // the hash that identifies this torrent + // is mutable because it's calculated + // lazily + sha1_hash m_info_hash; + + // if a creation date is found in the torrent file + // this will be set to that, otherwise it'll be + // 1970, Jan 1 + pt::ptime m_creation_date; + + // if a comment is found in the torrent file + // this will be set to that comment + std::string m_comment; + + // an optional string naming the software used + // to create the torrent file + std::string m_created_by; + + // this is used when creating a torrent. If there's + // only one file there are cases where it's impossible + // to know if it should be written as a multifile torrent + // or not. e.g. test/test there's one file and one directory + // and they have the same name. + bool m_multifile; + + // this is true if the torrent is private. i.e., is should not + // be announced on the dht + bool m_private; + + // this is a copy of the info section from the torrent. + // it use maintained in this flat format in order to + // make it available through the metadata extension + boost::shared_array m_info_section; + int m_info_section_size; + + // this is a pointer into the m_info_section buffer + // pointing to the first byte of the first sha-1 hash + char const* m_piece_hashes; + + // the info section parsed. points into m_info_section + // parsed lazily + mutable lazy_entry m_info_dict; + }; + +} + +#endif // TORRENT_TORRENT_INFO_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp new file mode 100644 index 000000000..c9d1f52c6 --- /dev/null +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -0,0 +1,246 @@ +/* + +Copyright (c) 2003, 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_TRACKER_MANAGER_HPP_INCLUDED +#define TORRENT_TRACKER_MANAGER_HPP_INCLUDED + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/socket.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/peer.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/time.hpp" +#include "libtorrent/connection_queue.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" + +namespace libtorrent +{ + struct request_callback; + class tracker_manager; + struct timeout_handler; + struct tracker_connection; + + // returns -1 if gzip header is invalid or the header size in bytes + TORRENT_EXPORT int gzip_header(const char* buf, int size); + + struct TORRENT_EXPORT tracker_request + { + tracker_request() + : kind(announce_request) + , event(none) + , key(0) + , num_want(0) + {} + + enum + { + announce_request, + scrape_request + } kind; + + enum event_t + { + none, + completed, + started, + stopped + }; + + sha1_hash info_hash; + peer_id pid; + size_type downloaded; + size_type uploaded; + size_type left; + unsigned short listen_port; + event_t event; + std::string url; + int key; + int num_want; + std::string ipv6; + }; + + struct TORRENT_EXPORT request_callback + { + friend class tracker_manager; + request_callback(): m_manager(0) {} + virtual ~request_callback() {} + virtual void tracker_warning(tracker_request const& req + , std::string const& msg) = 0; + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloads) {} + virtual void tracker_response( + tracker_request const& req + , std::vector& peers + , int interval + , int complete + , int incomplete + , address const& external_ip) = 0; + virtual void tracker_request_timed_out( + tracker_request const& req) = 0; + virtual void tracker_request_error( + tracker_request const& req + , int response_code + , const std::string& description) = 0; + + tcp::endpoint m_tracker_address; + +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + virtual void debug_log(const std::string& line) = 0; +#endif + private: + tracker_manager* m_manager; + }; + + struct TORRENT_EXPORT timeout_handler + : intrusive_ptr_base + , boost::noncopyable + { + timeout_handler(io_service& str); + + void set_timeout(int completion_timeout, int read_timeout); + void restart_read_timeout(); + void cancel(); + + virtual void on_timeout() = 0; + virtual ~timeout_handler() {} + + private: + + void timeout_callback(error_code const&); + + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } + + // used for timeouts + // this is set when the request has been sent + ptime m_start_time; + // this is set every time something is received + ptime m_read_time; + // the asio async operation + deadline_timer m_timeout; + + int m_completion_timeout; + int m_read_timeout; + + typedef boost::mutex mutex_t; + mutable mutex_t m_mutex; + bool m_abort; + }; + + struct TORRENT_EXPORT tracker_connection + : timeout_handler + { + tracker_connection(tracker_manager& man + , tracker_request const& req + , io_service& ios + , address bind_interface + , boost::weak_ptr r); + + boost::shared_ptr requester(); + virtual ~tracker_connection() {} + + tracker_request const& tracker_req() const { return m_req; } + + void fail(int code, char const* msg); + void fail_timeout(); + virtual void close(); + address const& bind_interface() const { return m_bind_interface; } + + protected: + boost::weak_ptr m_requester; + private: + address m_bind_interface; + tracker_manager& m_man; + const tracker_request m_req; + }; + + class TORRENT_EXPORT tracker_manager: boost::noncopyable + { + public: + + tracker_manager(session_settings const& s, proxy_settings const& ps) + : m_settings(s) + , m_proxy(ps) + , m_abort(false) {} + + void queue_request( + io_service& ios + , connection_queue& cc + , tracker_request r + , std::string const& auth + , address bind_infc + , boost::weak_ptr c + = boost::weak_ptr()); + void abort_all_requests(); + + void remove_request(tracker_connection const*); + bool empty() const; + int num_requests() const; + + private: + + typedef boost::recursive_mutex mutex_t; + mutable mutex_t m_mutex; + + typedef std::list > + tracker_connections_t; + tracker_connections_t m_connections; + session_settings const& m_settings; + proxy_settings const& m_proxy; + bool m_abort; + }; +} + +#endif // TORRENT_TRACKER_MANAGER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/udp_socket.hpp b/libtorrent/include/libtorrent/udp_socket.hpp new file mode 100644 index 000000000..77eae5050 --- /dev/null +++ b/libtorrent/include/libtorrent/udp_socket.hpp @@ -0,0 +1,106 @@ +/* + +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_UDP_SOCKET_HPP_INCLUDED +#define TORRENT_UDP_SOCKET_HPP_INCLUDED + +#include "libtorrent/socket.hpp" +#include "libtorrent/session_settings.hpp" + +#include +#include + +namespace libtorrent +{ + class connection_queue; + + class udp_socket + { + public: + typedef boost::function callback_t; + + udp_socket(io_service& ios, callback_t const& c, connection_queue& cc); + + bool is_open() const { return m_ipv4_sock.is_open() || m_ipv6_sock.is_open(); } + io_service& get_io_service() { return m_ipv4_sock.get_io_service(); } + + void send(udp::endpoint const& ep, char const* p, int len, error_code& ec); + void bind(udp::endpoint const& ep, error_code& ec); + void bind(int port); + void close(); + int local_port() const { return m_bind_port; } + + void set_proxy_settings(proxy_settings const& ps); + proxy_settings const& get_proxy_settings() { return m_proxy_settings; } + + private: + + callback_t m_callback; + + void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred); + void on_name_lookup(error_code const& e, tcp::resolver::iterator i); + void on_timeout(); + void on_connect(int ticket); + void on_connected(error_code const& ec); + void handshake1(error_code const& e); + void handshake2(error_code const& e); + void handshake3(error_code const& e); + void handshake4(error_code const& e); + void socks_forward_udp(); + void connect1(error_code const& e); + void connect2(error_code const& e); + + void wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec); + void unwrap(error_code const& e, char const* buf, int size); + + udp::socket m_ipv4_sock; + udp::socket m_ipv6_sock; + udp::endpoint m_v4_ep; + udp::endpoint m_v6_ep; + char m_v4_buf[1600]; + char m_v6_buf[1600]; + int m_bind_port; + + tcp::socket m_socks5_sock; + int m_connection_ticket; + proxy_settings m_proxy_settings; + connection_queue& m_cc; + tcp::resolver m_resolver; + char m_tmp_buf[100]; + bool m_tunnel_packets; + udp::endpoint m_proxy_addr; + }; +} + +#endif + diff --git a/libtorrent/include/libtorrent/udp_tracker_connection.hpp b/libtorrent/include/libtorrent/udp_tracker_connection.hpp new file mode 100644 index 000000000..dd0dea9fe --- /dev/null +++ b/libtorrent/include/libtorrent/udp_tracker_connection.hpp @@ -0,0 +1,124 @@ +/* + +Copyright (c) 2003, 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_UDP_TRACKER_CONNECTION_HPP_INCLUDED +#define TORRENT_UDP_TRACKER_CONNECTION_HPP_INCLUDED + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/udp_socket.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/peer.hpp" +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + class TORRENT_EXPORT udp_tracker_connection: public tracker_connection + { + friend class tracker_manager; + public: + + udp_tracker_connection( + io_service& ios + , connection_queue& cc + , tracker_manager& man + , tracker_request const& req + , address bind_infc + , boost::weak_ptr c + , session_settings const& stn + , proxy_settings const& ps); + + void close(); + + private: + + enum action_t + { + action_connect, + action_announce, + action_scrape, + action_error + }; + + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } + + void name_lookup(error_code const& error, udp::resolver::iterator i); + void timeout(error_code const& error); + + void on_receive(error_code const& e, udp::endpoint const& ep + , char const* buf, int size); + void on_connect_response(char const* buf, int size); + void on_announce_response(char const* buf, int size); + void on_scrape_response(char const* buf, int size); + + void send_udp_connect(); + void send_udp_announce(); + void send_udp_scrape(); + + virtual void on_timeout(); + + tracker_manager& m_man; + + udp::resolver m_name_lookup; + udp_socket m_socket; + udp::endpoint m_target; + + int m_transaction_id; + boost::int64_t m_connection_id; + session_settings const& m_settings; + int m_attempts; + + action_t m_state; + }; + +} + +#endif // TORRENT_UDP_TRACKER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp new file mode 100644 index 000000000..54e832c8a --- /dev/null +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -0,0 +1,282 @@ +/* + +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/broadcast_socket.hpp" +#include "libtorrent/http_connection.hpp" +#include "libtorrent/connection_queue.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" + +#include +#include +#include +#include +#include +#include + + +#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) && !defined (TORRENT_UPNP_LOGGING) +#define TORRENT_UPNP_LOGGING +#endif + +#if defined(TORRENT_UPNP_LOGGING) +#include +#endif + +namespace libtorrent +{ + +// int: port-mapping index +// int: external port +// std::string: error message +// an empty string as error means success +typedef boost::function portmap_callback_t; + +class upnp : public intrusive_ptr_base +{ +public: + upnp(io_service& ios, connection_queue& cc + , address const& listen_interface, std::string const& user_agent + , portmap_callback_t const& cb, bool ignore_nonrouters, void* state = 0); + ~upnp(); + + void* drain_state(); + + enum protocol_type { none = 0, udp = 1, tcp = 2 }; + int add_mapping(protocol_type p, int external_port, int local_port); + void delete_mapping(int mapping_index); + + void discover_device(); + void close(); + + std::string router_model() + { + mutex_t::scoped_lock l(m_mutex); + return m_model; + } + +private: + + void discover_device_impl(); + static address_v4 upnp_multicast_address; + static udp::endpoint upnp_multicast_endpoint; + + enum { default_lease_time = 3600 }; + + void resend_request(error_code const& e); + void on_reply(udp::endpoint const& from, char* buffer + , std::size_t bytes_transferred); + + struct rootdevice; + void next(rootdevice& d, int i); + void update_map(rootdevice& d, int i); + + + void on_upnp_xml(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d + , http_connection& c); + void on_upnp_map_response(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d + , int mapping, http_connection& c); + void on_upnp_unmap_response(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d + , int mapping, http_connection& c); + void on_expire(error_code const& e); + + void disable(char const* msg); + void return_error(int mapping, int code); + + void delete_port_mapping(rootdevice& d, int i); + void create_port_mapping(http_connection& c, rootdevice& d, int i); + void post(upnp::rootdevice const& d, std::string const& soap + , std::string const& soap_action); + + int num_mappings() const { return int(m_mappings.size()); } + + struct global_mapping_t + { + global_mapping_t() + : protocol(none) + , external_port(0) + , local_port(0) + {} + int protocol; + int external_port; + int local_port; + }; + + struct mapping_t + { + enum action_t { action_none, action_add, action_delete }; + mapping_t() + : action(action_none) + , local_port(0) + , external_port(0) + , protocol(none) + , failcount(0) + {} + + // the time the port mapping will expire + ptime expires; + + int action; + + // 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; + + // 2 = udp, 1 = tcp + int protocol; + + // the number of times this mapping has failed + int failcount; + }; + + struct rootdevice + { + rootdevice(): service_namespace(0) + , lease_duration(default_lease_time) + , supports_specific_external(true) + , disabled(false) + { +#ifndef NDEBUG + magic = 1337; +#endif + } + +#ifndef NDEBUG + ~rootdevice() + { + TORRENT_ASSERT(magic == 1337); + magic = 0; + } +#endif + + // 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; + + std::vector mapping; + + 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 upnp_connection; + +#ifndef NDEBUG + int magic; +#endif + void close() const + { + TORRENT_ASSERT(magic == 1337); + if (!upnp_connection) return; + upnp_connection->close(); + upnp_connection.reset(); + } + + bool operator<(rootdevice const& rhs) const + { return url < rhs.url; } + }; + + struct upnp_state_t + { + std::vector mappings; + std::set devices; + }; + + std::vector m_mappings; + + std::string const& m_user_agent; + + // the set of devices we've found + std::set m_devices; + + portmap_callback_t m_callback; + + // current retry count + int m_retry_count; + + io_service& m_io_service; + + // the udp socket used to send and receive + // multicast messages on the network + broadcast_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; + + bool m_disabled; + bool m_closing; + bool m_ignore_non_routers; + + connection_queue& m_cc; + + typedef boost::mutex mutex_t; + mutex_t m_mutex; + + std::string m_model; + +#ifdef TORRENT_UPNP_LOGGING + std::ofstream m_log; +#endif +}; + +} + + +#endif + diff --git a/libtorrent/include/libtorrent/utf8.hpp b/libtorrent/include/libtorrent/utf8.hpp new file mode 100644 index 000000000..157a7fdba --- /dev/null +++ b/libtorrent/include/libtorrent/utf8.hpp @@ -0,0 +1,161 @@ +/* + Copyright (C) 2004-2005 Cory Nelson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +// namespaces added by Arvid Norberg + +#ifndef __UTF8_H__ +#define __UTF8_H__ + +#include +#include +#include +#include + +namespace libtorrent { +namespace detail { + +template +wchar_t decode_utf8_mb(InputIterator &iter, InputIterator last) +{ + if (iter == last) throw std::runtime_error("incomplete UTF-8 sequence"); + if (((*iter) & 0xc0) != 0x80) throw std::runtime_error("invalid UTF-8 sequence"); + + return (wchar_t)((*iter++) & 0x3f); +} + +template +wchar_t decode_utf8(InputIterator &iter, InputIterator last) +{ + wchar_t ret; + + if (((*iter) & 0x80) == 0) // one byte + { + ret = *iter++; + } + else if (((*iter) & 0xe0) == 0xc0) // two bytes + { + wchar_t byte1 = (*iter++) & 0x1f; + wchar_t byte2 = decode_utf8_mb(iter, last); + ret = (byte1 << 6) | byte2; + } + else if (((*iter) & 0xf0) == 0xe0) // three bytes + { + wchar_t byte1 = (*iter++) & 0x0f; + wchar_t byte2 = decode_utf8_mb(iter, last); + wchar_t byte3 = decode_utf8_mb(iter, last); + ret = (byte1 << 12) | (byte2 << 6) | byte3; + } + // TODO: support surrogate pairs + else throw std::runtime_error("UTF-8 not convertable to UTF-16"); + + return ret; +} + +template +OutputIterator utf8_wchar(InputIterator first, InputIterator last, OutputIterator dest) +{ + for(; first!=last; ++dest) + *dest = decode_utf8(first, last); + return dest; +} + +template +void encode_wchar(InputIterator iter, OutputIterator &dest) +{ + if(*iter <= 0x007F) + { + *dest=(char)*iter; + ++dest; + } + else if(*iter <= 0x07FF) + { + *dest = (char)( + 0xC0 | + ((*iter & 0x07C0) >> 6) + ); + ++dest; + + *dest = (char)( + 0x80 | + (*iter & 0x003F) + ); + ++dest; + } + else if(*iter <= 0xFFFF) + { + *dest = (char)( + 0xE0 | + ((*iter & 0xF000) >> 12) + ); + ++dest; + + *dest = (char)( + 0x80 | + ((*iter & 0x0FC0) >> 6) + ); + ++dest; + + *dest = (char)( + 0x80 | + (*iter & 0x003F) + ); + ++dest; + } +} + +template +OutputIterator wchar_utf8(InputIterator first, InputIterator last, OutputIterator dest) +{ + for(; first!=last; ++first) + encode_wchar(first, dest); + return dest; +} + +} + +inline void utf8_wchar(const std::string &utf8, std::wstring &wide) +{ + wide.clear(); + detail::utf8_wchar(utf8.begin(), utf8.end(), std::back_inserter(wide)); +} + +inline std::wstring utf8_wchar(const std::string &str) +{ + std::wstring ret; + utf8_wchar(str, ret); + return ret; +} + +inline void wchar_utf8(const std::wstring &wide, std::string &utf8) +{ + utf8.clear(); + detail::wchar_utf8(wide.begin(), wide.end(), std::back_inserter(utf8)); +} + +inline std::string wchar_utf8(const std::wstring &str) +{ + std::string ret; + wchar_utf8(str, ret); + return ret; +} + +} + +#endif diff --git a/libtorrent/include/libtorrent/variant_stream.hpp b/libtorrent/include/libtorrent/variant_stream.hpp new file mode 100644 index 000000000..3551f5c9e --- /dev/null +++ b/libtorrent/include/libtorrent/variant_stream.hpp @@ -0,0 +1,754 @@ +// 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 + +# include +# include +# include +# include +# include + +# include +# include +# include + +# include +# include + +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif + +# define NETWORK_VARIANT_STREAM_LIMIT 5 + +namespace libtorrent { + +namespace aux +{ + + struct delete_visitor + : boost::static_visitor<> + { + template + void operator()(T* p) const + { + delete p; + } + + void operator()(boost::blank) const + {} + }; + +// -------------- io_control ----------- + + template + struct io_control_visitor_ec: boost::static_visitor<> + { + io_control_visitor_ec(IO_Control_Command& ioc, error_code& ec_) + : ioc(ioc), ec(ec_) {} + + template + void operator()(T* p) const + { + p->io_control(ioc, ec); + } + + void operator()(boost::blank) const + {} + + IO_Control_Command& ioc; + error_code& ec; + }; + + template + struct io_control_visitor + : boost::static_visitor<> + { + io_control_visitor(IO_Control_Command& ioc) + : ioc(ioc) {} + + template + void operator()(T* p) const + { + p->io_control(ioc); + } + + void operator()(boost::blank) const + {} + + IO_Control_Command& ioc; + }; +// -------------- async_connect ----------- + + template + struct async_connect_visitor + : boost::static_visitor<> + { + async_connect_visitor(EndpointType const& endpoint, Handler const& handler) + : endpoint(endpoint) + , handler(handler) + {} + + template + void operator()(T* p) const + { + p->async_connect(endpoint, handler); + } + + void operator()(boost::blank) const + {} + + EndpointType const& endpoint; + Handler const& handler; + }; + +// -------------- bind ----------- + + template + struct bind_visitor_ec + : boost::static_visitor<> + { + bind_visitor_ec(EndpointType const& ep, error_code& ec_) + : endpoint(ep) + , ec(ec_) + {} + + template + void operator()(T* p) const + { p->bind(endpoint, ec); } + + void operator()(boost::blank) const {} + + EndpointType const& endpoint; + error_code& ec; + }; + + template + struct bind_visitor + : boost::static_visitor<> + { + bind_visitor(EndpointType const& ep) + : endpoint(ep) + {} + + template + void operator()(T* p) const + { p->bind(endpoint); } + + void operator()(boost::blank) const {} + + EndpointType const& endpoint; + }; + +// -------------- open ----------- + + template + struct open_visitor_ec + : boost::static_visitor<> + { + open_visitor_ec(Protocol const& p, error_code& ec_) + : proto(p) + , ec(ec_) + {} + + template + void operator()(T* p) const + { p->open(proto, ec); } + + void operator()(boost::blank) const {} + + Protocol const& proto; + error_code& ec; + }; + + template + struct open_visitor + : boost::static_visitor<> + { + open_visitor(Protocol const& p) + : proto(p) + {} + + template + void operator()(T* p) const + { p->open(proto); } + + void operator()(boost::blank) const {} + + Protocol const& proto; + }; + +// -------------- is_open ----------- + + struct is_open_visitor + : boost::static_visitor + { + is_open_visitor() {} + + template + bool operator()(T const* p) const + { return p->is_open(); } + + bool operator()(boost::blank) const { return false; } + }; + +// -------------- close ----------- + + struct close_visitor_ec + : boost::static_visitor<> + { + close_visitor_ec(error_code& ec_) + : ec(ec_) + {} + + template + void operator()(T* p) const + { p->close(ec); } + + void operator()(boost::blank) const {} + + error_code& ec; + }; + + struct close_visitor + : boost::static_visitor<> + { + template + void operator()(T* p) const + { p->close(); } + + void operator()(boost::blank) const {} + }; + +// -------------- remote_endpoint ----------- + + template + struct remote_endpoint_visitor_ec + : boost::static_visitor + { + remote_endpoint_visitor_ec(error_code& ec_) + : ec(ec_) + {} + + template + EndpointType operator()(T const* p) const + { return p->remote_endpoint(ec); } + + EndpointType operator()(boost::blank) const + { return EndpointType(); } + + error_code& ec; + }; + + template + struct remote_endpoint_visitor + : boost::static_visitor + { + template + EndpointType operator()(T const* p) const + { return p->remote_endpoint(); } + + EndpointType operator()(boost::blank) const + { return EndpointType(); } + }; + +// -------------- set_option ----------- + + template + struct set_option_visitor + : boost::static_visitor<> + { + set_option_visitor(SettableSocketOption const& opt) + : opt_(opt) + {} + + template + void operator()(T* p) const + { p->set_option(opt_); } + + void operator()(boost::blank) const {} + + SettableSocketOption const& opt_; + }; + + template + struct set_option_visitor_ec + : boost::static_visitor + { + set_option_visitor_ec(SettableSocketOption const& opt, error_code& ec) + : opt_(opt) + , ec_(ec) + {} + + template + error_code operator()(T* p) const + { return p->set_option(opt_, ec_); } + + error_code operator()(boost::blank) const + { return ec_; } + + SettableSocketOption const& opt_; + error_code& ec_; + }; + +// -------------- local_endpoint ----------- + + template + struct local_endpoint_visitor_ec + : boost::static_visitor + { + local_endpoint_visitor_ec(error_code& ec_) + : ec(ec_) + {} + + template + EndpointType operator()(T const* p) const + { + return p->local_endpoint(ec); + } + + EndpointType operator()(boost::blank) const + { + return EndpointType(); + } + + error_code& ec; + }; + + template + struct local_endpoint_visitor + : boost::static_visitor + { + template + EndpointType operator()(T const* p) const + { + return p->local_endpoint(); + } + + EndpointType operator()(boost::blank) const + { + return EndpointType(); + } + }; + +// -------------- async_read_some ----------- + + template + struct async_read_some_visitor + : boost::static_visitor<> + { + async_read_some_visitor(Mutable_Buffers const& buffers, Handler const& handler) + : buffers(buffers) + , handler(handler) + {} + + template + 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 + struct read_some_visitor + : boost::static_visitor + { + read_some_visitor(Mutable_Buffers const& buffers) + : buffers(buffers) + {} + + template + 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 + struct read_some_visitor_ec + : boost::static_visitor + { + read_some_visitor_ec(Mutable_Buffers const& buffers, error_code& ec_) + : buffers(buffers) + , ec(ec_) + {} + + template + 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; + error_code& ec; + }; + +// -------------- async_write_some ----------- + + template + struct async_write_some_visitor + : boost::static_visitor<> + { + async_write_some_visitor(Const_Buffers const& buffers, Handler const& handler) + : buffers(buffers) + , handler(handler) + {} + + template + 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 ----------- + + struct in_avail_visitor_ec + : boost::static_visitor + { + in_avail_visitor_ec(error_code& ec_) + : ec(ec_) + {} + + template + std::size_t operator()(T const* p) const + { + return p->in_avail(ec); + } + + std::size_t operator()(boost::blank) const + { + return 0; + } + + error_code& ec; + }; + + struct in_avail_visitor + : boost::static_visitor + { + template + std::size_t operator()(T const* p) const + { + return p->in_avail(); + } + + void operator()(boost::blank) const + {} + }; + +// -------------- io_service ----------- + + template + struct io_service_visitor + : boost::static_visitor + { + template + IOService& operator()(T* p) const + { + return p->get_io_service(); + } + + IOService& operator()(boost::blank) const + { + return *(IOService*)0; + } + }; + +// -------------- lowest_layer ----------- + + template + struct lowest_layer_visitor + : boost::static_visitor + { + template + 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::type types; + + typedef typename boost::make_variant_over< + typename boost::mpl::push_back< + typename boost::mpl::transform< + types + , boost::add_pointer + >::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(io_service& ios) + : m_io_service(ios), m_variant(boost::blank()) {} + + template + void instantiate(io_service& ios) + { + TORRENT_ASSERT(&ios == &m_io_service); + std::auto_ptr owned(new S(ios)); + boost::apply_visitor(aux::delete_visitor(), m_variant); + m_variant = owned.get(); + owned.release(); + } + + template + S& get() + { + return *boost::get(m_variant); + } + + bool instantiated() const + { + return m_variant.which() != boost::mpl::size::value; + } + + ~variant_stream() + { + boost::apply_visitor(aux::delete_visitor(), m_variant); + } + + template + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::read_some_visitor_ec(buffers, ec) + , m_variant + ); + } + + template + std::size_t read_some(Mutable_Buffers const& buffers) + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::read_some_visitor(buffers) + , m_variant + ); + } + + template + void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::async_read_some_visitor(buffers, handler) + , m_variant + ); + } + + template + void async_write_some(Const_Buffers const& buffers, Handler const& handler) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::async_write_some_visitor(buffers, handler) + , m_variant + ); + } + + template + void async_connect(endpoint_type const& endpoint, Handler const& handler) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::async_connect_visitor(endpoint, handler), m_variant + ); + } + + template + void io_control(IO_Control_Command& ioc) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::io_control_visitor(ioc), m_variant + ); + } + + template + void io_control(IO_Control_Command& ioc, error_code& ec) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::io_control_visitor_ec(ioc, ec) + , m_variant + ); + } + + void bind(endpoint_type const& endpoint) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor(aux::bind_visitor(endpoint), m_variant); + } + + void bind(endpoint_type const& endpoint, error_code& ec) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::bind_visitor_ec(endpoint, ec), m_variant + ); + } + + void open(protocol_type const& p) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor(aux::open_visitor(p), m_variant); + } + + void open(protocol_type const& p, error_code& ec) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor( + aux::open_visitor_ec(p, ec), m_variant + ); + } + + bool is_open() const + { + return boost::apply_visitor(aux::is_open_visitor(), m_variant); + } + + void close() + { + if (!instantiated()) return; + boost::apply_visitor(aux::close_visitor(), m_variant); + } + + void close(error_code& ec) + { + if (!instantiated()) return; + boost::apply_visitor( + aux::close_visitor_ec(ec), m_variant + ); + } + + std::size_t in_avail() const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor(aux::in_avail_visitor(), m_variant); + } + + std::size_t in_avail(error_code& ec) const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::in_avail_visitor_ec(ec), m_variant + ); + } + + endpoint_type remote_endpoint() const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor(aux::remote_endpoint_visitor(), m_variant); + } + + endpoint_type remote_endpoint(error_code& ec) const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::remote_endpoint_visitor_ec(ec), m_variant + ); + } + + template + void set_option(SettableSocketOption const& opt) + { + TORRENT_ASSERT(instantiated()); + boost::apply_visitor(aux::set_option_visitor(opt) + , m_variant); + } + + template + error_code set_option(SettableSocketOption const& opt, error_code& ec) + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor(aux::set_option_visitor_ec(opt, ec) + , m_variant); + } + + endpoint_type local_endpoint() const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor(aux::local_endpoint_visitor(), m_variant); + } + + endpoint_type local_endpoint(error_code& ec) const + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::local_endpoint_visitor_ec(ec), m_variant + ); + } + + io_service& get_io_service() + { + return m_io_service; + } + + lowest_layer_type& lowest_layer() + { + TORRENT_ASSERT(instantiated()); + return boost::apply_visitor( + aux::lowest_layer_visitor(), m_variant + ); + } + +private: + io_service& m_io_service; + variant_type m_variant; +}; + +} // namespace libtorrent + +#endif // VARIANT_STREAM_070211_HPP + diff --git a/libtorrent/include/libtorrent/version.hpp b/libtorrent/include/libtorrent/version.hpp new file mode 100644 index 000000000..06b1bbe13 --- /dev/null +++ b/libtorrent/include/libtorrent/version.hpp @@ -0,0 +1,41 @@ +/* + +Copyright (c) 2003, 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_VERSION_HPP_INCLUDED +#define TORRENT_VERSION_HPP_INCLUDED + +#define LIBTORRENT_VERSION_MAJOR 0 +#define LIBTORRENT_VERSION_MINOR 14 + +#define LIBTORRENT_VERSION "0.14.0.0" + +#endif diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp new file mode 100644 index 000000000..f8e7af99f --- /dev/null +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -0,0 +1,183 @@ +/* + +Copyright (c) 2003, 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_WEB_PEER_CONNECTION_HPP_INCLUDED +#define TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#include "libtorrent/debug.hpp" + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/buffer.hpp" +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/piece_block_progress.hpp" +#include "libtorrent/config.hpp" +// parse_url +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/http_parser.hpp" + +namespace libtorrent +{ + class torrent; + + namespace detail + { + struct session_impl; + } + + class TORRENT_EXPORT web_peer_connection + : public peer_connection + { + friend class invariant_access; + public: + + // this is the constructor where the we are the active part. + // The peer_conenction should handshake and verify that the + // other end has the correct id + web_peer_connection( + aux::session_impl& ses + , boost::weak_ptr t + , boost::shared_ptr s + , tcp::endpoint const& remote + , std::string const& url + , policy::peer* peerinfo); + + ~web_peer_connection(); + + // called from the main loop when this connection has any + // work to do. + void on_sent(error_code const& error + , std::size_t bytes_transferred); + void on_receive(error_code const& error + , std::size_t bytes_transferred); + + std::string const& url() const { return m_url; } + + virtual void get_specific_peer_info(peer_info& p) const; + virtual bool in_handshake() const; + + // the following functions appends messages + // to the send buffer + void write_choke() {} + void write_unchoke() {} + void write_interested() {} + void write_not_interested() {} + void write_request(peer_request const& r); + void write_cancel(peer_request const& r) + { incoming_reject_request(r); } + void write_have(int index) {} + void write_piece(peer_request const& r, disk_buffer_holder& buffer) { TORRENT_ASSERT(false); } + void write_keepalive() {} + void on_connected(); + void write_reject_request(peer_request const&) {} + void write_allow_fast(int) {} + +#ifndef NDEBUG + void check_invariant() const; +#endif + + private: + + // returns the block currently being + // downloaded. And the progress of that + // block. If the peer isn't downloading + // a piece for the moment, the boost::optional + // will be invalid. + boost::optional downloading_piece_progress() const; + + // this has one entry per bittorrent request + std::deque m_requests; + // this has one entry per http-request + // (might be more than the bt requests) + std::deque m_file_requests; + + std::string m_server_string; + http_parser m_parser; + std::string m_auth; + std::string m_host; + int m_port; + std::string m_path; + std::string m_url; + + // the first request will contain a little bit more data + // than subsequent ones, things that aren't critical are left + // out to save bandwidth. + bool m_first_request; + + // this is used for intermediate storage of pieces + // that is received in more than on HTTP responses + std::vector 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; + + // position in the current range response + int m_range_pos; + }; +} + +#endif // TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/xml_parse.hpp b/libtorrent/include/libtorrent/xml_parse.hpp new file mode 100644 index 000000000..aaf71a816 --- /dev/null +++ b/libtorrent/include/libtorrent/xml_parse.hpp @@ -0,0 +1,211 @@ +/* + +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 + +#include + +namespace libtorrent +{ + enum + { + xml_start_tag, + xml_end_tag, + xml_empty_tag, + xml_declaration_tag, + xml_string, + xml_attribute, + xml_comment, + xml_parse_error + }; + + // callback(int type, char const* name, char const* val) + // str2 is only used for attributes. name is element or attribute + // name and val is attribute value + + template + void xml_parse(char* p, char* end, CallbackType callback) + { + for(;p != end; ++p) + { + char const* start = p; + char const* val_start = 0; + int token; + // look for tag start + for(; *p != '<' && p != end; ++p); + + if (p != start) + { + if (p != end) + { + TORRENT_ASSERT(*p == '<'); + *p = 0; + } + token = xml_string; + callback(token, start, val_start); + if (p != end) *p = '<'; + } + + if (p == end) break; + + // skip '<' + ++p; + + // parse the name of the tag. + for (start = p; p != end && *p != '>' && !std::isspace(*p); ++p); + + char* tag_name_end = p; + + // skip the attributes for now + for (; p != end && *p != '>'; ++p); + + // parse error + if (p == end) + { + token = xml_parse_error; + start = "unexpected end of file"; + callback(token, start, val_start); + break; + } + + TORRENT_ASSERT(*p == '>'); + // save the character that terminated the tag name + // it could be both '>' and ' '. + char save = *tag_name_end; + *tag_name_end = 0; + + char* tag_end = p; + if (*start == '/') + { + ++start; + token = xml_end_tag; + callback(token, start, val_start); + } + else if (*(p-1) == '/') + { + *(p-1) = 0; + token = xml_empty_tag; + callback(token, start, val_start); + *(p-1) = '/'; + tag_end = p - 1; + } + else if (*start == '?' && *(p-1) == '?') + { + *(p-1) = 0; + ++start; + token = xml_declaration_tag; + callback(token, start, val_start); + *(p-1) = '?'; + tag_end = p - 1; + } + else if (start + 5 < p && memcmp(start, "!--", 3) == 0 && memcmp(p-2, "--", 2) == 0) + { + start += 3; + *(p-2) = 0; + token = xml_comment; + callback(token, start, val_start); + *(p-2) = '-'; + tag_end = p - 2; + } + else + { + token = xml_start_tag; + callback(token, start, val_start); + } + + *tag_name_end = save; + + // parse attributes + for (char* i = tag_name_end; i < tag_end; ++i) + { + // find start of attribute name + for (; i != tag_end && std::isspace(*i); ++i); + if (i == tag_end) break; + start = i; + // find end of attribute name + for (; i != tag_end && *i != '=' && !std::isspace(*i); ++i); + char* name_end = i; + + // look for equality sign + for (; i != tag_end && *i != '='; ++i); + + if (i == tag_end) + { + token = xml_parse_error; + val_start = 0; + start = "garbage inside element brackets"; + callback(token, start, val_start); + break; + } + + ++i; + for (; i != tag_end && std::isspace(*i); ++i); + // check for parse error (values must be quoted) + if (i == tag_end || (*i != '\'' && *i != '\"')) + { + token = xml_parse_error; + val_start = 0; + start = "unquoted attribute value"; + callback(token, start, val_start); + break; + } + char quote = *i; + ++i; + val_start = i; + for (; i != tag_end && *i != quote; ++i); + // parse error (missing end quote) + if (i == tag_end) + { + token = xml_parse_error; + val_start = 0; + start = "missing end quote on attribute"; + callback(token, start, val_start); + break; + } + save = *i; + *i = 0; + *name_end = 0; + token = xml_attribute; + callback(token, start, val_start); + *name_end = '='; + *i = save; + } + } + + } + +} + + +#endif + diff --git a/libtorrent/src/allocate_resources.cpp b/libtorrent/src/allocate_resources.cpp deleted file mode 100644 index deef06dc4..000000000 --- a/libtorrent/src/allocate_resources.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - -Copyright (c) 2006, Magnus Jonsson, 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. - -*/ - -//The Standard Library defines the two template functions std::min() -//and std::max() in the header. In general, you should -//use these template functions for calculating the min and max values -//of a pair. Unfortunately, Visual C++ does not define these function -// templates. This is because the names min and max clash with -//the traditional min and max macros defined in . -//As a workaround, Visual C++ defines two alternative templates with -//identical functionality called _cpp_min() and _cpp_max(). You can -//use them instead of std::min() and std::max().To disable the -//generation of the min and max macros in Visual C++, #define -//NOMINMAX before #including . - -#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 - #define NOMINMAX -#endif - -#include "libtorrent/allocate_resources.hpp" -#include "libtorrent/size_type.hpp" -#include "libtorrent/peer_connection.hpp" -#include "libtorrent/torrent.hpp" -#include "libtorrent/aux_/allocate_resources_impl.hpp" - -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1310 -#define for if (false) {} else for -#else -#include -#endif - -namespace libtorrent -{ - int saturated_add(int a, int b) - { - assert(a >= 0); - assert(b >= 0); - assert(a <= resource_request::inf); - assert(b <= resource_request::inf); - assert(resource_request::inf + resource_request::inf < 0); - - unsigned int sum = unsigned(a) + unsigned(b); - if (sum > unsigned(resource_request::inf)) - sum = resource_request::inf; - - assert(sum >= unsigned(a) && sum >= unsigned(b)); - return int(sum); - } - -#if defined(_MSC_VER) && _MSC_VER < 1310 - - namespace detail - { - struct iterator_wrapper - { - typedef std::map >::iterator orig_iter; - - orig_iter iter; - - iterator_wrapper(orig_iter i): iter(i) {} - void operator++() { ++iter; } - torrent& operator*() { return *(iter->second); } - bool operator==(const iterator_wrapper& i) const - { return iter == i.iter; } - bool operator!=(const iterator_wrapper& i) const - { return iter != i.iter; } - }; - - struct iterator_wrapper2 - { - typedef std::map::iterator orig_iter; - - orig_iter iter; - - iterator_wrapper2(orig_iter i): iter(i) {} - void operator++() { ++iter; } - peer_connection& operator*() { return *(iter->second); } - bool operator==(const iterator_wrapper2& i) const - { return iter == i.iter; } - bool operator!=(const iterator_wrapper2& i) const - { return iter != i.iter; } - }; - - } - - void allocate_resources( - int resources - , std::map >& c - , resource_request torrent::* res) - { - aux::allocate_resources_impl( - resources - , detail::iterator_wrapper(c.begin()) - , detail::iterator_wrapper(c.end()) - , res); - } - - void allocate_resources( - int resources - , std::map& c - , resource_request peer_connection::* res) - { - aux::allocate_resources_impl( - resources - , detail::iterator_wrapper2(c.begin()) - , detail::iterator_wrapper2(c.end()) - , res); - } - -#else - - namespace aux - { - peer_connection& pick_peer( - std::pair - , boost::intrusive_ptr > const& p) - { - return *p.second; - } - - peer_connection& pick_peer2( - std::pair const& p) - { - return *p.second; - } - - torrent& deref(std::pair > const& p) - { - return *p.second; - } - - session& deref(session* p) - { - return *p; - } - } - - void allocate_resources( - int resources - , std::map >& c - , resource_request torrent::* res) - { - typedef std::map >::iterator orig_iter; - typedef std::pair > in_param; - typedef boost::transform_iterator new_iter; - - aux::allocate_resources_impl( - resources - , new_iter(c.begin(), &aux::deref) - , new_iter(c.end(), &aux::deref) - , res); - } - - void allocate_resources( - int resources - , std::map& c - , resource_request peer_connection::* res) - { - typedef std::map::iterator orig_iter; - typedef std::pair in_param; - typedef boost::transform_iterator new_iter; - - aux::allocate_resources_impl( - resources - , new_iter(c.begin(), &aux::pick_peer2) - , new_iter(c.end(), &aux::pick_peer2) - , res); - } - - void allocate_resources( - int resources - , std::vector& _sessions - , resource_request session::* res) - { - typedef std::vector::iterator orig_iter; - typedef session* in_param; - typedef boost::transform_iterator new_iter; - - aux::allocate_resources_impl( - resources - , new_iter(_sessions.begin(), &aux::deref) - , new_iter(_sessions.end(), &aux::deref) - , res); - } - -#endif - -} // namespace libtorrent diff --git a/libtorrent/src/mapped_storage.cpp b/libtorrent/src/mapped_storage.cpp index 90fadd5b1..e5cf4647a 100644 --- a/libtorrent/src/mapped_storage.cpp +++ b/libtorrent/src/mapped_storage.cpp @@ -755,8 +755,8 @@ namespace libtorrent m_pool.release(this); #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - fs::wpath old_path = safe_convert(old_name); - fs::wpath new_path = safe_convert(m_save_path / new_filename); + fs::wpath old_path = safe_convert(old_name.string()); + fs::wpath new_path = safe_convert((m_save_path / new_filename).string()); #else fs::path const& old_path = old_name; fs::path new_path = m_save_path / new_filename;