00001
00002
00003
00004
00005
00006
00007
00008 #ifdef _MSC_VER
00009 #pragma warning(push, 1)
00010 #endif
00011
00012 #include <boost/shared_ptr.hpp>
00013
00014 #ifdef _MSC_VER
00015 #pragma warning(pop)
00016 #endif
00017
00018 #include "libtorrent/peer_connection.hpp"
00019 #include "libtorrent/bt_peer_connection.hpp"
00020 #include "libtorrent/bencode.hpp"
00021 #include "libtorrent/torrent.hpp"
00022 #include "libtorrent/extensions.hpp"
00023
00024 #include "libtorrent/extensions/ut_pex.hpp"
00025
00026 namespace libtorrent { namespace
00027 {
00028 const char extension_name[] = "ut_pex";
00029
00030 enum
00031 {
00032 extension_index = 1,
00033 max_peer_entries = 100
00034 };
00035
00036 struct ut_pex_plugin: torrent_plugin
00037 {
00038 ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(0) {}
00039
00040 virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);
00041
00042 std::vector<char>& get_ut_pex_msg()
00043 {
00044 return m_ut_pex_msg;
00045 }
00046
00047
00048
00049
00050
00051
00052 virtual void tick()
00053 {
00054 if (++m_1_minute < 60) return;
00055
00056 m_1_minute = 0;
00057 std::list<tcp::endpoint> cs;
00058 for (torrent::peer_iterator i = m_torrent.begin()
00059 , end(m_torrent.end()); i != end; ++i)
00060 {
00061
00062
00063 if (!i->second->is_local()) continue;
00064
00065 if (i->second->is_connecting()) continue;
00066 cs.push_back(i->first);
00067 }
00068 std::list<tcp::endpoint> added_peers, dropped_peers;
00069
00070 std::set_difference(cs.begin(), cs.end(), m_old_peers.begin()
00071 , m_old_peers.end(), std::back_inserter(added_peers));
00072 std::set_difference(m_old_peers.begin(), m_old_peers.end()
00073 , cs.begin(), cs.end(), std::back_inserter(dropped_peers));
00074 m_old_peers = cs;
00075
00076 unsigned int num_peers = max_peer_entries;
00077
00078 std::string pla, pld, plf;
00079 std::back_insert_iterator<std::string> pla_out(pla);
00080 std::back_insert_iterator<std::string> pld_out(pld);
00081 std::back_insert_iterator<std::string> plf_out(plf);
00082
00083
00084 for (std::list<tcp::endpoint>::const_iterator i = added_peers.begin()
00085 , end(added_peers.end());i != end; ++i)
00086 {
00087 if (!i->address().is_v4()) continue;
00088 detail::write_endpoint(*i, pla_out);
00089
00090
00091 detail::write_uint8(0, plf_out);
00092
00093 if (--num_peers == 0) break;
00094 }
00095
00096 num_peers = max_peer_entries;
00097
00098 for (std::list<tcp::endpoint>::const_iterator i = dropped_peers.begin()
00099 , end(dropped_peers.end());i != end; ++i)
00100 {
00101 if (!i->address().is_v4()) continue;
00102 detail::write_endpoint(*i, pld_out);
00103
00104 if (--num_peers == 0) break;
00105 }
00106
00107 entry pex(entry::dictionary_t);
00108 pex["added"] = pla;
00109 pex["dropped"] = pld;
00110 pex["added.f"] = plf;
00111
00112 m_ut_pex_msg.clear();
00113 bencode(std::back_inserter(m_ut_pex_msg), pex);
00114 }
00115
00116 private:
00117 torrent& m_torrent;
00118
00119 std::list<tcp::endpoint> m_old_peers;
00120 int m_1_minute;
00121 std::vector<char> m_ut_pex_msg;
00122 };
00123
00124 struct ut_pex_peer_plugin : peer_plugin
00125 {
00126 ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
00127 : m_torrent(t)
00128 , m_pc(pc)
00129 , m_tp(tp)
00130 , m_1_minute(0)
00131 , m_message_index(0)
00132 {}
00133
00134 virtual void add_handshake(entry& h)
00135 {
00136 entry& messages = h["m"];
00137 messages[extension_name] = extension_index;
00138 }
00139
00140 virtual bool on_extension_handshake(entry const& h)
00141 {
00142 entry const& messages = h["m"];
00143
00144 if (entry const* index = messages.find_key(extension_name))
00145 {
00146 m_message_index = index->integer();
00147 return true;
00148 }
00149 else
00150 {
00151 m_message_index = 0;
00152 return false;
00153 }
00154 }
00155
00156 virtual bool on_extended(int length, int msg, buffer::const_interval body)
00157 {
00158 if (msg != extension_index) return false;
00159 if (m_message_index == 0) return false;
00160
00161 if (length > 500 * 1024)
00162 throw protocol_error("ut peer exchange message larger than 500 kB");
00163
00164 if (body.left() < length) return true;
00165
00166
00167
00168
00169 if (m_torrent.is_seed()) return true;
00170
00171 entry Pex = bdecode(body.begin, body.end);
00172 entry* PeerList = Pex.find_key("added");
00173
00174 if (!PeerList) return true;
00175 std::string const& peers = PeerList->string();
00176 int num_peers = peers.length() / 6;
00177 char const* in = peers.c_str();
00178
00179 peer_id pid;
00180 pid.clear();
00181 policy& p = m_torrent.get_policy();
00182 for (int i = 0; i < num_peers; ++i)
00183 {
00184 tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
00185 if (!m_torrent.connection_for(adr)) p.peer_from_tracker(adr, pid);
00186 }
00187 return true;
00188 }
00189
00190
00191
00192 virtual void tick()
00193 {
00194 if (!m_message_index) return;
00195 if (++m_1_minute <= 60) return;
00196
00197 send_ut_peer_list();
00198 m_1_minute = 0;
00199 }
00200
00201 private:
00202
00203 void send_ut_peer_list()
00204 {
00205 std::vector<char>& pex_msg = m_tp.get_ut_pex_msg();
00206
00207 buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());
00208
00209 detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
00210 detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
00211 detail::write_uint8(m_message_index, i.begin);
00212 std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
00213 i.begin += pex_msg.size();
00214
00215 assert(i.begin == i.end);
00216 m_pc.setup_send();
00217 }
00218
00219 torrent& m_torrent;
00220 peer_connection& m_pc;
00221 ut_pex_plugin& m_tp;
00222 int m_1_minute;
00223 int m_message_index;
00224 };
00225
00226 boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
00227 {
00228 return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
00229 , *pc, *this));
00230 }
00231 }}
00232
00233 namespace libtorrent
00234 {
00235
00236 boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t)
00237 {
00238 if (t->torrent_file().priv())
00239 {
00240 return boost::shared_ptr<torrent_plugin>();
00241 }
00242 return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
00243 }
00244
00245 }
00246