예제 #1
0
 public void removeTorrent(TorrentHash torrentHash) {
   this.announce.removeTorrent(torrentHash);
   SharedTorrent torrent = this.torrents.remove(torrentHash.getHexInfoHash());
   if (torrent != null) {
     torrent.setClientState(ClientState.DONE);
     torrent.close();
   }
 }
예제 #2
0
  /** Main client entry point for stand-alone operation. */
  public static void main(String[] args) {
    BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-25t] %-5p: %m%n")));

    CmdLineParser parser = new CmdLineParser();
    CmdLineParser.Option help = parser.addBooleanOption('h', "help");
    CmdLineParser.Option output = parser.addStringOption('o', "output");
    CmdLineParser.Option iface = parser.addStringOption('i', "iface");

    try {
      parser.parse(args);
    } catch (CmdLineParser.OptionException oe) {
      System.err.println(oe.getMessage());
      usage(System.err);
      System.exit(1);
    }

    // Display help and exit if requested
    if (Boolean.TRUE.equals(parser.getOptionValue(help))) {
      usage(System.out);
      System.exit(0);
    }

    String outputValue = (String) parser.getOptionValue(output, DEFAULT_OUTPUT_DIRECTORY);
    String ifaceValue = (String) parser.getOptionValue(iface);

    String[] otherArgs = parser.getRemainingArgs();
    if (otherArgs.length != 1) {
      usage(System.err);
      System.exit(1);
    }

    try {
      Client c = new Client(getIPv4Address(ifaceValue));
      SharedTorrent torrent =
          SharedTorrent.fromFile(new File(otherArgs[0]), new File(outputValue), false);
      c.addTorrent(torrent);

      // Set a shutdown hook that will stop the sharing/seeding and send
      // a STOPPED announce request.
      Runtime.getRuntime().addShutdownHook(new Thread(new ClientShutdown(c, null)));

      c.share();
      if (ClientState.ERROR.equals(torrent.getClientState())) {
        System.exit(1);
      }
    } catch (Exception e) {
      logger.error("Fatal error: {}", e.getMessage(), e);
      System.exit(2);
    }
  }
예제 #3
0
  /** Close torrent and set final client state before signing off. */
  private void finish() {

    this.announce.stop();

    for (SharedTorrent torrent : this.torrents.values()) {
      torrent.close();
      if (torrent.isFinished()) {
        torrent.setClientState(ClientState.DONE);
      } else {
        torrent.setClientState(ClientState.ERROR);
      }
    }

    logger.info("BitTorrent client signing off.");
  }
예제 #4
0
  /**
   * Display information about the BitTorrent client state.
   *
   * <p>This emits an information line in the log about this client's state. It includes the number
   * of choked peers, number of connected peers, number of known peers, information about the
   * torrent availability and completion and current transmission rates.
   */
  public synchronized void info() {
    float dl = 0;
    float ul = 0;
    int numConnected = 0;
    for (SharingPeer peer : getConnectedPeers()) {
      dl += peer.getDLRate().get();
      ul += peer.getULRate().get();
      numConnected++;
    }

    for (SharedTorrent torrent : this.torrents.values()) {
      logger.debug(
          "{} {}/{} pieces ({}%) [{}/{}] with {}/{} peers at {}/{} kB/s.",
          new Object[] {
            torrent.getClientState().name(),
            torrent.getCompletedPieces().cardinality(),
            torrent.getPieceCount(),
            String.format("%.2f", torrent.getCompletion()),
            torrent.getAvailablePieces().cardinality(),
            torrent.getRequestedPieces().cardinality(),
            numConnected,
            this.peers.size(),
            String.format("%.2f", dl / 1024.0),
            String.format("%.2f", ul / 1024.0),
          });
    }
  }
예제 #5
0
  /**
   * Piece download completion handler.
   *
   * <p>When a piece is completed, and valid, we announce to all connected peers that we now have
   * this piece.
   *
   * <p>We use this handler to identify when all of the pieces have been downloaded. When that's the
   * case, we can start the seeding period, if any.
   *
   * @param peer The peer we got the piece from.
   * @param piece The piece in question.
   */
  @Override
  public void handlePieceCompleted(SharingPeer peer, Piece piece) throws IOException {
    final SharedTorrent torrent = peer.getTorrent();
    synchronized (torrent) {
      if (piece.isValid()) {
        // Make sure the piece is marked as completed in the torrent
        // Note: this is required because the order the
        // PeerActivityListeners are called is not defined, and we
        // might be called before the torrent's piece completion
        // handler is.
        torrent.markCompleted(piece);
        logger.debug(
            "Completed download of {}, now has {}/{} pieces.",
            new Object[] {
              piece, torrent.getCompletedPieces().cardinality(), torrent.getPieceCount()
            });

        // Send a HAVE message to all connected peers
        PeerMessage have = PeerMessage.HaveMessage.craft(piece.getIndex());
        for (SharingPeer remote : getConnectedPeers()) {
          remote.send(have);
        }
      }

      if (torrent.isComplete()) {
        logger.info("Last piece validated and completed, " + "download is complete.");
        torrent.finish();

        try {
          this.announce
              .getCurrentTrackerClient(torrent)
              .announce(
                  TrackerMessage.AnnounceRequestMessage.RequestEvent.COMPLETED, true, torrent);
        } catch (AnnounceException ae) {
          logger.warn("Error announcing completion event to " + "tracker: {}", ae.getMessage());
        }

        torrent.setClientState(ClientState.SEEDING);
        if (seed == 0) {
          peer.unbind(false);
          this.announce.removeTorrent(torrent);
        }
      }
    }
  }
예제 #6
0
  public void addTorrent(SharedTorrent torrent) throws IOException, InterruptedException {
    torrent.init();
    if (!torrent.isInitialized()) {
      torrent.close();
      return;
    }

    this.torrents.put(torrent.getHexInfoHash(), torrent);

    // Initial completion test
    if (torrent.isComplete()) {
      torrent.setClientState(ClientState.SEEDING);
    } else {
      torrent.setClientState(ClientState.SHARING);
    }

    this.announce.addTorrent(torrent, this);
  }
예제 #7
0
 /** Tells whether we are a seed for the torrent we're sharing. */
 public boolean isSeed(String hexInfoHash) {
   SharedTorrent t = this.torrents.get(hexInfoHash);
   return t != null && t.isComplete();
 }