Beispiel #1
0
 /**
  * Can't find a published standard for this anywhere. See the libtorrent code. Here we use the
  * "added" key as a single string of concatenated 32-byte peer hashes. added.f and dropped
  * unsupported
  *
  * @since 0.8.4
  */
 private static void handlePEX(Peer peer, PeerListener listener, byte[] bs, Log log) {
   if (log.shouldLog(Log.DEBUG)) log.debug("Got PEX msg from " + peer);
   try {
     InputStream is = new ByteArrayInputStream(bs);
     BDecoder dec = new BDecoder(is);
     BEValue bev = dec.bdecodeMap();
     Map<String, BEValue> map = bev.getMap();
     bev = map.get("added");
     if (bev == null) return;
     byte[] ids = bev.getBytes();
     if (ids.length < HASH_LENGTH) return;
     int len = Math.min(ids.length, (I2PSnarkUtil.MAX_CONNECTIONS - 1) * HASH_LENGTH);
     List<PeerID> peers = new ArrayList<PeerID>(len / HASH_LENGTH);
     for (int off = 0; off < len; off += HASH_LENGTH) {
       byte[] hash = new byte[HASH_LENGTH];
       System.arraycopy(ids, off, hash, 0, HASH_LENGTH);
       if (DataHelper.eq(hash, peer.getPeerID().getDestHash())) continue;
       PeerID pID = new PeerID(hash, listener.getUtil());
       peers.add(pID);
     }
     // could include ourselves, listener must remove
     listener.gotPeers(peer, peers);
   } catch (Exception e) {
     if (log.shouldLog(Log.INFO)) log.info("PEX msg exception from " + peer, e);
     // peer.disconnect(false);
   }
 }
Beispiel #2
0
 /**
  * Creates a new MetaInfo from the given BDecoder. The BDecoder must have a complete dictionary
  * describing the torrent.
  */
 private MetaInfo(BDecoder be) throws IOException {
   // Note that evaluation order matters here...
   this(be.bdecodeMap().getMap());
   byte[] origInfohash = be.get_special_map_digest();
   // shouldn't ever happen
   if (!DataHelper.eq(origInfohash, info_hash))
     throw new InvalidBEncodingException("Infohash mismatch, please report");
 }
Beispiel #3
0
 /**
  * Efficiently returns the name and the 20 byte SHA1 hash of the info dictionary in a torrent file
  * Caller must close stream.
  *
  * @param infoHashOut 20-byte out parameter
  * @since 0.8.5
  */
 public static String getNameAndInfoHash(InputStream in, byte[] infoHashOut) throws IOException {
   BDecoder bd = new BDecoder(in);
   Map<String, BEValue> m = bd.bdecodeMap().getMap();
   BEValue ibev = m.get("info");
   if (ibev == null) throw new InvalidBEncodingException("Missing info map");
   Map<String, BEValue> i = ibev.getMap();
   BEValue rvbev = i.get("name");
   if (rvbev == null) throw new InvalidBEncodingException("Missing name");
   byte[] h = bd.get_special_map_digest();
   System.arraycopy(h, 0, infoHashOut, 0, 20);
   return rvbev.getString();
 }
Beispiel #4
0
 /**
  * Receive the DHT port numbers
  *
  * @since DHT
  */
 private static void handleDHT(Peer peer, PeerListener listener, byte[] bs, Log log) {
   if (log.shouldLog(Log.DEBUG)) log.debug("Got DHT msg from " + peer);
   try {
     InputStream is = new ByteArrayInputStream(bs);
     BDecoder dec = new BDecoder(is);
     BEValue bev = dec.bdecodeMap();
     Map<String, BEValue> map = bev.getMap();
     int qport = map.get("port").getInt();
     int rport = map.get("rport").getInt();
     listener.gotPort(peer, qport, rport);
   } catch (Exception e) {
     if (log.shouldLog(Log.INFO)) log.info("DHT msg exception from " + peer, e);
     // peer.disconnect(false);
   }
 }
Beispiel #5
0
  private static void handleHandshake(Peer peer, PeerListener listener, byte[] bs, Log log) {
    if (log.shouldLog(Log.DEBUG)) log.debug("Got handshake msg from " + peer);
    try {
      // this throws NPE on missing keys
      InputStream is = new ByteArrayInputStream(bs);
      BDecoder dec = new BDecoder(is);
      BEValue bev = dec.bdecodeMap();
      Map<String, BEValue> map = bev.getMap();
      peer.setHandshakeMap(map);
      Map<String, BEValue> msgmap = map.get("m").getMap();

      if (log.shouldLog(Log.DEBUG))
        log.debug("Peer " + peer + " supports extensions: " + msgmap.keySet());

      // if (msgmap.get(TYPE_PEX) != null) {
      //    if (log.shouldLog(Log.DEBUG))
      //        log.debug("Peer supports PEX extension: " + peer);
      //    // peer state calls peer listener calls sendPEX()
      // }

      // if (msgmap.get(TYPE_DHT) != null) {
      //    if (log.shouldLog(Log.DEBUG))
      //        log.debug("Peer supports DHT extension: " + peer);
      //    // peer state calls peer listener calls sendDHT()
      // }

      MagnetState state = peer.getMagnetState();

      if (msgmap.get(TYPE_METADATA) == null) {
        if (log.shouldLog(Log.DEBUG))
          log.debug("Peer does not support metadata extension: " + peer);
        // drop if we need metainfo and we haven't found anybody yet
        synchronized (state) {
          if (!state.isInitialized()) {
            if (log.shouldLog(Log.DEBUG)) log.debug("Dropping peer, we need metadata! " + peer);
            peer.disconnect();
          }
        }
        return;
      }

      BEValue msize = map.get("metadata_size");
      if (msize == null) {
        if (log.shouldLog(Log.DEBUG))
          log.debug("Peer does not have the metainfo size yet: " + peer);
        // drop if we need metainfo and we haven't found anybody yet
        synchronized (state) {
          if (!state.isInitialized()) {
            if (log.shouldLog(Log.DEBUG)) log.debug("Dropping peer, we need metadata! " + peer);
            peer.disconnect();
          }
        }
        return;
      }
      int metaSize = msize.getInt();
      if (log.shouldLog(Log.DEBUG)) log.debug("Got the metainfo size: " + metaSize);

      int remaining;
      synchronized (state) {
        if (state.isComplete()) return;

        if (state.isInitialized()) {
          if (state.getSize() != metaSize) {
            if (log.shouldLog(Log.DEBUG))
              log.debug("Wrong metainfo size " + metaSize + " from: " + peer);
            peer.disconnect();
            return;
          }
        } else {
          // initialize it
          if (metaSize > MAX_METADATA_SIZE) {
            if (log.shouldLog(Log.DEBUG))
              log.debug("Huge metainfo size " + metaSize + " from: " + peer);
            peer.disconnect(false);
            return;
          }
          if (log.shouldLog(Log.INFO))
            log.info("Initialized state, metadata size = " + metaSize + " from " + peer);
          state.initialize(metaSize);
        }
        remaining = state.chunksRemaining();
      }

      // send requests for chunks
      int count = Math.min(remaining, PARALLEL_REQUESTS);
      for (int i = 0; i < count; i++) {
        int chk;
        synchronized (state) {
          chk = state.getNextRequest();
        }
        if (log.shouldLog(Log.INFO)) log.info("Request chunk " + chk + " from " + peer);
        sendRequest(peer, chk);
      }
    } catch (Exception e) {
      if (log.shouldLog(Log.WARN)) log.warn("Handshake exception from " + peer, e);
    }
  }
Beispiel #6
0
  /**
   * REF: BEP 9
   *
   * @since 0.8.4
   */
  private static void handleMetadata(Peer peer, PeerListener listener, byte[] bs, Log log) {
    if (log.shouldLog(Log.DEBUG)) log.debug("Got metadata msg from " + peer);
    try {
      InputStream is = new ByteArrayInputStream(bs);
      BDecoder dec = new BDecoder(is);
      BEValue bev = dec.bdecodeMap();
      Map<String, BEValue> map = bev.getMap();
      int type = map.get("msg_type").getInt();
      int piece = map.get("piece").getInt();

      MagnetState state = peer.getMagnetState();
      if (type == TYPE_REQUEST) {
        if (log.shouldLog(Log.DEBUG)) log.debug("Got request for " + piece + " from: " + peer);
        byte[] pc;
        synchronized (state) {
          pc = state.getChunk(piece);
        }
        sendPiece(peer, piece, pc);
        // Do this here because PeerConnectionOut only reports for PIECE messages
        peer.uploaded(pc.length);
        listener.uploaded(peer, pc.length);
      } else if (type == TYPE_DATA) {
        int size = map.get("total_size").getInt();
        if (log.shouldLog(Log.DEBUG))
          log.debug("Got data for " + piece + " length " + size + " from: " + peer);
        boolean done;
        int chk = -1;
        synchronized (state) {
          if (state.isComplete()) return;
          int len = is.available();
          if (len != size) {
            // probably fatal
            if (log.shouldLog(Log.WARN)) log.warn("total_size " + size + " but avail data " + len);
          }
          peer.downloaded(len);
          listener.downloaded(peer, len);
          done = state.saveChunk(piece, bs, bs.length - len, len);
          if (log.shouldLog(Log.INFO)) log.info("Got chunk " + piece + " from " + peer);
          if (!done) chk = state.getNextRequest();
        }
        // out of the lock
        if (done) {
          // Done!
          // PeerState will call the listener (peer coord), who will
          // check to see if the MagnetState has it
          if (log.shouldLog(Log.WARN)) log.warn("Got last chunk from " + peer);
        } else {
          // get the next chunk
          if (log.shouldLog(Log.INFO)) log.info("Request chunk " + chk + " from " + peer);
          sendRequest(peer, chk);
        }
      } else if (type == TYPE_REJECT) {
        if (log.shouldLog(Log.WARN)) log.warn("Got reject msg from " + peer);
        peer.disconnect(false);
      } else {
        if (log.shouldLog(Log.WARN)) log.warn("Got unknown metadata msg from " + peer);
        peer.disconnect(false);
      }
    } catch (Exception e) {
      if (log.shouldLog(Log.INFO)) log.info("Metadata ext. msg. exception from " + peer, e);
      // fatal ?
      peer.disconnect(false);
    }
  }