PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/azureus-4.7.0.2/com/aelitis/azureus/core/peermanager/messaging/bittorrent/ltep/UTPeerExchange.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 315 lines | 161 code | 43 blank | 111 comment | 59 complexity | 88f3d9cfc48c7d427b5754f324c97309 MD5 | raw file
  1. /*
  2. * Created on 18 Sep 2007
  3. * Created by Allan Crooks
  4. * Copyright (C) 2007 Aelitis, All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * AELITIS, SAS au capital de 46,603.30 euros
  19. * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
  20. */
  21. package com.aelitis.azureus.core.peermanager.messaging.bittorrent.ltep;
  22. import java.util.*;
  23. import org.gudy.azureus2.core3.logging.LogEvent;
  24. import org.gudy.azureus2.core3.logging.LogIDs;
  25. import org.gudy.azureus2.core3.logging.Logger;
  26. import org.gudy.azureus2.core3.util.DirectByteBuffer;
  27. import com.aelitis.azureus.core.networkmanager.NetworkManager;
  28. import com.aelitis.azureus.core.peermanager.messaging.Message;
  29. import com.aelitis.azureus.core.peermanager.messaging.MessageException;
  30. import com.aelitis.azureus.core.peermanager.messaging.MessagingUtil;
  31. import com.aelitis.azureus.core.peermanager.messaging.azureus.AZStylePeerExchange;
  32. import com.aelitis.azureus.core.peermanager.peerdb.PeerItem;
  33. import com.aelitis.azureus.core.peermanager.peerdb.PeerItemFactory;
  34. /**
  35. * @author Allan Crooks
  36. *
  37. * Largely copied from AZPeerExchange.
  38. */
  39. public class UTPeerExchange implements AZStylePeerExchange, LTMessage {
  40. // Debug flag for testing purposes - currently disabled by default.
  41. public static final boolean ENABLED = true;
  42. private static final LogIDs LOGID = LogIDs.NET;
  43. private static final int IPv4_SIZE_WITH_PORT = 6;
  44. private static final int IPv6_SIZE_WITH_PORT = 18;
  45. private DirectByteBuffer buffer = null;
  46. private String description = null;
  47. private final byte version;
  48. private final PeerItem[] peers_added;
  49. private final PeerItem[] peersAddedNoSeeds;
  50. private final PeerItem[] peers_dropped;
  51. public UTPeerExchange(PeerItem[] _peers_added, PeerItem[] _peers_dropped, PeerItem[] peersAddedNoSeeds, byte version ) {
  52. this.peers_added = _peers_added;
  53. this.peers_dropped = _peers_dropped;
  54. this.version = version;
  55. this.peersAddedNoSeeds = peersAddedNoSeeds != null ? peersAddedNoSeeds : _peers_added;
  56. }
  57. private void insertPeers(String key_name, Map root_map, boolean include_flags, PeerItem[] peers) {
  58. if (peers == null) {return;}
  59. if (peers.length == 0) {return;}
  60. List v4_peers = null;
  61. List v6_peers = null;
  62. for (int i=0; i<peers.length; i++) {
  63. if (!peers[i].isIPv4()) {
  64. if (v6_peers == null) {
  65. v6_peers = new ArrayList();
  66. v4_peers = new ArrayList(Arrays.asList(peers).subList(0, i));
  67. }
  68. v6_peers.add(peers[i]);
  69. }
  70. else {
  71. if (v4_peers != null) {
  72. v4_peers.add(peers[i]);
  73. }
  74. }
  75. }
  76. if (v4_peers == null) {v4_peers = Arrays.asList(peers);}
  77. insertPeers(key_name, root_map, include_flags, v4_peers, IPv4_SIZE_WITH_PORT);
  78. insertPeers(key_name + "6", root_map, include_flags, v6_peers, IPv6_SIZE_WITH_PORT);
  79. }
  80. private void insertPeers(String key_name, Map root_map, boolean include_flags, List peers, int peer_byte_size) {
  81. if (peers == null) {return;}
  82. if (peers.isEmpty()) {return;}
  83. byte[] raw_peers = new byte[peers.size() * peer_byte_size];
  84. byte[] peer_flags = (include_flags) ? new byte[peers.size()] : null;
  85. PeerItem peer;
  86. for (int i=0; i<peers.size(); i++ ) {
  87. peer = (PeerItem)peers.get(i);
  88. byte[] serialised_peer = peer.getSerialization();
  89. if (serialised_peer.length != peer_byte_size) {System.out.println("> " + serialised_peer.length + ":" + peer_byte_size);}
  90. System.arraycopy(serialised_peer, 0, raw_peers, i * peer_byte_size, peer_byte_size);
  91. if (peer_flags != null && NetworkManager.getCryptoRequired(peer.getCryptoLevel())) {
  92. peer_flags[i] |= 0x01; // Encrypted connection.
  93. }
  94. // 0x02 indicates if the peer is a seed, but that's difficult to determine
  95. // so we'll leave it.
  96. } // end for
  97. root_map.put(key_name, raw_peers);
  98. if (peer_flags != null) {
  99. root_map.put(key_name + ".f", peer_flags);
  100. }
  101. }
  102. private List extractPeers(String key_name, Map root_map, int peer_byte_size, boolean noSeeds) {
  103. ArrayList peers = new ArrayList();
  104. byte[] raw_peer_data = (byte[])root_map.get(key_name);
  105. if( raw_peer_data != null ) {
  106. if (raw_peer_data.length % peer_byte_size != 0) {
  107. if (Logger.isEnabled())
  108. Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "PEX (UT): peer data size not multiple of " + peer_byte_size + ": " + raw_peer_data.length));
  109. }
  110. int peer_num = raw_peer_data.length / peer_byte_size;
  111. byte[] flags = null;
  112. if (root_map != null) {
  113. Object flags_obj = root_map.get(key_name + ".f");
  114. // For some reason, some peers send flags as longs. I haven't seen
  115. // it myself, so I don't know how to extract data from it. So we'll
  116. // just stick to byte arrays.
  117. if (flags_obj instanceof byte[]) {flags = (byte[])flags_obj;}
  118. }
  119. if (flags != null && flags.length != peer_num) {
  120. if (flags.length > 0) {
  121. if (Logger.isEnabled()) {
  122. Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "PEX (UT): invalid peer flags: peers=" + peer_num + ", flags=" + flags.length ));
  123. }
  124. }
  125. flags = null;
  126. }
  127. for (int i=0; i<peer_num; i++) {
  128. byte[] full_address = new byte[peer_byte_size];
  129. System.arraycopy(raw_peer_data, i * peer_byte_size, full_address, 0, peer_byte_size);
  130. byte type = PeerItemFactory.HANDSHAKE_TYPE_PLAIN;
  131. if (flags != null && (flags[i] & 0x01) != 0)
  132. type = PeerItemFactory.HANDSHAKE_TYPE_CRYPTO;
  133. if (flags != null && (flags[i] & 0x02) != 0 && noSeeds)
  134. continue;
  135. try {
  136. PeerItem peer = PeerItemFactory.createPeerItem(full_address, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, type, 0);
  137. peers.add(peer);
  138. }
  139. catch (Exception e) {
  140. if (Logger.isEnabled())
  141. Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "PEX (UT): invalid peer received"));
  142. }
  143. }
  144. }
  145. return peers;
  146. }
  147. public PeerItem[] getAddedPeers(boolean seeds) {return seeds ? peers_added : peersAddedNoSeeds; }
  148. public PeerItem[] getAddedPeers() { return peers_added; }
  149. public PeerItem[] getDroppedPeers() { return peers_dropped; }
  150. public String getID() { return LTMessage.ID_UT_PEX; }
  151. public byte[] getIDBytes() { return LTMessage.ID_UT_PEX_BYTES; }
  152. public String getFeatureID() { return LTMessage.LT_FEATURE_ID; }
  153. public int getFeatureSubID() { return LTMessage.SUBID_UT_PEX; }
  154. public int getType() { return Message.TYPE_PROTOCOL_PAYLOAD; }
  155. public byte getVersion() { return version; };
  156. public String getDescription() {
  157. if( description == null ) {
  158. int add_count = peers_added == null ? 0 : peers_added.length;
  159. int drop_count = peers_dropped == null ? 0 : peers_dropped.length;
  160. description = getID().toUpperCase() + " with " +add_count+ " added and " +drop_count+ " dropped peers";
  161. }
  162. return description;
  163. }
  164. public DirectByteBuffer[] getData() {
  165. if( buffer == null ) {
  166. Map payload_map = new HashMap();
  167. // bencoded_buffer = payload_map;
  168. insertPeers("added", payload_map, true, peers_added );
  169. insertPeers("dropped", payload_map, false, peers_dropped );
  170. buffer = MessagingUtil.convertPayloadToBencodedByteStream(payload_map, DirectByteBuffer.AL_MSG_UT_PEX);
  171. }
  172. return new DirectByteBuffer[] {buffer};
  173. }
  174. public Message deserialize( DirectByteBuffer data, byte version ) throws MessageException {
  175. Map root = MessagingUtil.convertBencodedByteStreamToPayload(data, 2, getID());
  176. List added = extractPeers("added", root, IPv4_SIZE_WITH_PORT,false);
  177. List addedNoSeeds = extractPeers("added", root, IPv4_SIZE_WITH_PORT,true);
  178. List dropped = extractPeers("dropped", root, IPv4_SIZE_WITH_PORT,false);
  179. added.addAll(extractPeers("added6", root, IPv6_SIZE_WITH_PORT,false));
  180. addedNoSeeds.addAll(extractPeers("added6", root, IPv6_SIZE_WITH_PORT,true));
  181. dropped.addAll(extractPeers("dropped6", root, IPv6_SIZE_WITH_PORT,false));
  182. PeerItem[] addedArr = (PeerItem[])added.toArray(new PeerItem[added.size()]);
  183. PeerItem[] addedNoSeedsArr = (PeerItem[])addedNoSeeds.toArray(new PeerItem[addedNoSeeds.size()]);
  184. PeerItem[] droppedArr = (PeerItem[])dropped.toArray(new PeerItem[dropped.size()]);
  185. return new UTPeerExchange(addedArr, droppedArr,addedNoSeedsArr, version);
  186. }
  187. public void destroy() {
  188. if( buffer != null ) buffer.returnToPool();
  189. }
  190. /**
  191. * Arbitrary value - most clients are configured to about 100 or so...
  192. * We'll allow ourselves to be informed about 200 connected peers from
  193. * the initial handshake, and then cap either list to about 100.
  194. *
  195. * These values are plucked from the air really - although I've seen PEX
  196. * sizes where the added list is about 300 (sometimes), most contain a
  197. * sensible number (not normally over 100).
  198. *
  199. * Subsequent PEX messages are relatively small too, so we'll stick to
  200. * smaller limits - 50 would be probably fine, but watching some big
  201. * swarms over a short period, the biggest "added" list I saw was one
  202. * containing 38 peers, so it's quite possible list sizes above 50 get
  203. * sent out. So 100 is a safe-ish figure.
  204. *
  205. * Update: uTorrent doesn't have any set limits on this, apparently it simply
  206. * depends on the number of connections a peer has, which can be large for
  207. * fast peers (I've seen 350 peers for example). Increased limits somewhat
  208. * and added code to ignore excessive peers rather than dropping the
  209. * connection
  210. */
  211. public int getMaxAllowedPeersPerVolley(boolean initial, boolean added) {
  212. return (initial && added) ? 500 : 250;
  213. }
  214. /**** DEBUG STUFF ****/
  215. /*
  216. public String toString() {
  217. List adds = (this.peers_added != null) ? Arrays.asList(this.peers_added) : null;
  218. List drops = (this.peers_dropped != null) ? Arrays.asList(this.peers_dropped) : null;
  219. return "UTPEX: " + adds + ", " + drops;
  220. }
  221. private Map bencoded_buffer = null;
  222. public static void main(String[] args) throws Exception {
  223. PeerItem[] p1 = new PeerItem[] {
  224. PeerItemFactory.createPeerItem("2001:0db8:85a3:08d3:1319:8a2e:0370:7334", 4096, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 10),
  225. PeerItemFactory.createPeerItem("2001:0db8:0:0:0:8a2e:0370:7334", 128, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_CRYPTO, 0, PeerItemFactory.CRYPTO_LEVEL_CURRENT, 10),
  226. PeerItemFactory.createPeerItem("1280:0:0:0:0:0:0:7334", 255, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 25),
  227. };
  228. PeerItem[] p2 = new PeerItem[] {
  229. PeerItemFactory.createPeerItem("192.168.0.1", 6473, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 16, PeerItemFactory.CRYPTO_LEVEL_1, 10),
  230. PeerItemFactory.createPeerItem("127.0.0.1", 128, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_CRYPTO, 0, PeerItemFactory.CRYPTO_LEVEL_1, 10),
  231. PeerItemFactory.createPeerItem("172.16.0.1", 255, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 25),
  232. };
  233. PeerItem[] p3 = new PeerItem[] {
  234. PeerItemFactory.createPeerItem("2001:0db8:85a3:08d3:1319:8a2e:0370:7334", 55, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 10),
  235. PeerItemFactory.createPeerItem("127.0.0.1", 128, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_CRYPTO, 0, PeerItemFactory.CRYPTO_LEVEL_1, 10),
  236. PeerItemFactory.createPeerItem("1280:0:0:0:0:0:0:7334", 255, PeerItemFactory.PEER_SOURCE_PEER_EXCHANGE, PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 25),
  237. };
  238. UTPeerExchange u1 = new UTPeerExchange(p1, p2, (byte)0);
  239. UTPeerExchange u2 = new UTPeerExchange(p2, p3, (byte)0);
  240. UTPeerExchange u3 = new UTPeerExchange(p3, p1, (byte)0);
  241. UTPeerExchange u4 = new UTPeerExchange(new PeerItem[0], p1, (byte)0);
  242. UTPeerExchange u5 = new UTPeerExchange(p1, new PeerItem[0], (byte)0);
  243. u1.getData();
  244. u2.getData();
  245. u3.getData();
  246. u4.getData();
  247. u5.getData();
  248. UTPeerExchange[] uts = new UTPeerExchange[] {null, u1, u2, u3, u4, u5};
  249. for (int i=1; i<6; i++) {
  250. java.util.Iterator itr = uts[i].bencoded_buffer.keySet().iterator();
  251. while (itr.hasNext()) {
  252. String k = (String)itr.next();
  253. byte[] b = (byte[])uts[i].bencoded_buffer.get(k);
  254. System.out.println(k + ": " + org.gudy.azureus2.core3.util.ByteFormatter.encodeString(b));
  255. }
  256. System.out.println('-');
  257. }
  258. System.out.println(u1.deserialize(u1.getData()[0], (byte)0));
  259. System.out.println(u1.deserialize(u2.getData()[0], (byte)0));
  260. System.out.println(u1.deserialize(u3.getData()[0], (byte)0));
  261. System.out.println(u1.deserialize(u4.getData()[0], (byte)0));
  262. System.out.println(u1.deserialize(u5.getData()[0], (byte)0));
  263. }
  264. */
  265. }