Beispiel #1
0
  void bitfieldMessage(byte[] bitmap) {
    synchronized (this) {
      if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " rcv bitfield");
      if (bitfield != null) {
        // XXX - Be liberal in what you accept?
        if (_log.shouldLog(Log.WARN)) _log.warn("Got unexpected bitfield message from " + peer);
        return;
      }

      // XXX - Check for weird bitfield and disconnect?
      // FIXME will have to regenerate the bitfield after we know exactly
      // how many pieces there are, as we don't know how many spare bits there are.
      if (metainfo == null) bitfield = new BitField(bitmap, bitmap.length * 8);
      else bitfield = new BitField(bitmap, metainfo.getPieces());
    }
    if (metainfo == null) return;
    boolean interest = listener.gotBitField(peer, bitfield);
    setInteresting(interest);
    if (bitfield.complete() && !interest) {
      // They are seeding and we are seeding,
      // why did they contact us? (robert)
      // Dump them quick before we send our whole bitmap
      if (_log.shouldLog(Log.WARN)) _log.warn("Disconnecting seed that connects to seeds: " + peer);
      peer.disconnect(true);
    }
  }
Beispiel #2
0
 /**
  * Disconnects this peer if it was connected. If deregister is true, PeerListener.disconnected()
  * will be called when the connection is completely terminated. Otherwise the connection is
  * silently terminated.
  */
 public void disconnect(boolean deregister) {
   // Both in and out connection will call this.
   this.deregister = deregister;
   disconnect();
 }
Beispiel #3
0
  /**
   * Runs the connection to the other peer. This method does not return until the connection is
   * terminated.
   *
   * <p>When the connection is correctly started the connected() method of the given PeerListener is
   * called. If the connection ends or the connection could not be setup correctly the
   * disconnected() method is called.
   *
   * <p>If the given BitField is non-null it is send to the peer as first message.
   */
  public void runConnection(
      I2PSnarkUtil util, PeerListener listener, BitField bitfield, MagnetState mState) {
    if (state != null) throw new IllegalStateException("Peer already started");

    if (_log.shouldLog(Log.DEBUG))
      _log.debug("Running connection to " + peerID.toString(), new Exception("connecting"));
    try {
      // Do we need to handshake?
      if (din == null) {
        // Outgoing connection
        sock = util.connect(peerID);
        if (_log.shouldLog(Log.DEBUG)) _log.debug("Connected to " + peerID + ": " + sock);
        if ((sock == null) || (sock.isClosed())) {
          throw new IOException("Unable to reach " + peerID);
        }
        InputStream in = sock.getInputStream();
        OutputStream out = sock.getOutputStream();
        byte[] id = handshake(in, out);
        byte[] expected_id = peerID.getID();
        if (expected_id == null) {
          peerID.setID(id);
        } else if (Arrays.equals(expected_id, id)) {
          if (_log.shouldLog(Log.DEBUG))
            _log.debug("Handshake got matching IDs with " + toString());
        } else {
          throw new IOException(
              "Unexpected peerID '"
                  + PeerID.idencode(id)
                  + "' expected '"
                  + PeerID.idencode(expected_id)
                  + "'");
        }
      } else {
        // Incoming connection
        if (_log.shouldLog(Log.DEBUG))
          _log.debug("Already have din [" + sock + "] with " + toString());
      }

      // bad idea?
      if (metainfo == null && (options & OPTION_EXTENSION) == 0) {
        if (_log.shouldLog(Log.INFO))
          _log.info("Peer does not support extensions and we need metainfo, dropping");
        throw new IOException("Peer does not support extensions and we need metainfo, dropping");
      }

      PeerConnectionIn in = new PeerConnectionIn(this, din);
      PeerConnectionOut out = new PeerConnectionOut(this, dout);
      PeerState s = new PeerState(this, listener, metainfo, in, out);

      if ((options & OPTION_EXTENSION) != 0) {
        if (_log.shouldLog(Log.DEBUG))
          _log.debug("Peer supports extensions, sending reply message");
        int metasize = metainfo != null ? metainfo.getInfoBytes().length : -1;
        out.sendExtension(0, ExtensionHandler.getHandshake(metasize));
      }

      if ((options & OPTION_I2P_DHT) != 0 && util.getDHT() != null) {
        if (_log.shouldLog(Log.DEBUG)) _log.debug("Peer supports DHT, sending PORT message");
        int port = util.getDHT().getPort();
        out.sendPort(port);
      }

      // Send our bitmap
      if (bitfield != null) s.out.sendBitfield(bitfield);

      // We are up and running!
      state = s;
      magnetState = mState;
      listener.connected(this);

      if (_log.shouldLog(Log.DEBUG)) _log.debug("Start running the reader with " + toString());
      // Use this thread for running the incomming connection.
      // The outgoing connection creates its own Thread.
      out.startup();
      Thread.currentThread().setName("Snark reader from " + peerID);
      s.in.run();
    } catch (IOException eofe) {
      // Ignore, probably just the other side closing the connection.
      // Or refusing the connection, timing out, etc.
      if (_log.shouldLog(Log.DEBUG)) _log.debug(this.toString(), eofe);
    } catch (Throwable t) {
      _log.error(this + ": " + t.getMessage(), t);
      if (t instanceof OutOfMemoryError) throw (OutOfMemoryError) t;
    } finally {
      if (deregister) listener.disconnected(this);
      disconnect();
    }
  }
Beispiel #4
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 #5
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);
    }
  }