Пример #1
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();
    }
  }