Exemple #1
0
  private void x_startTorrent() {
    boolean ok = _util.connect();
    if (!ok) fatal("Unable to connect to I2P");
    if (coordinator == null) {
      I2PServerSocket serversocket = _util.getServerSocket();
      if (serversocket == null) fatal("Unable to listen for I2P connections");
      else {
        Destination d = serversocket.getManager().getSession().getMyDestination();
        if (_log.shouldLog(Log.INFO))
          _log.info(
              "Listening on I2P destination "
                  + d.toBase64()
                  + " / "
                  + d.calculateHash().toBase64());
      }
      if (_log.shouldLog(Log.INFO))
        _log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
      activity = "Collecting pieces";
      coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
      coordinator.setUploaded(savedUploaded);
      if (_peerCoordinatorSet != null) {
        // multitorrent
        _peerCoordinatorSet.add(coordinator);
      } else {
        // single torrent
        acceptor = new ConnectionAcceptor(_util, new PeerAcceptor(coordinator));
      }
      // TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator?
      trackerclient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
    }
    // ensure acceptor is running when in multitorrent
    if (_peerCoordinatorSet != null && acceptor != null) {
      acceptor.startAccepting();
    }

    stopped = false;
    if (coordinator.halted()) {
      coordinator.restart();
      if (_peerCoordinatorSet != null) _peerCoordinatorSet.add(coordinator);
    }
    if (!trackerclient.started()) {
      trackerclient.start();
    } else if (trackerclient.halted()) {
      if (storage != null) {
        try {
          storage.reopen();
        } catch (IOException ioe) {
          try {
            storage.close();
          } catch (IOException ioee) {
            ioee.printStackTrace();
          }
          fatal("Could not reopen storage", ioe);
        }
      }
      trackerclient.start();
    } else {
      if (_log.shouldLog(Log.INFO)) _log.info("NOT starting TrackerClient???");
    }
  }
Exemple #2
0
 /**
  * Called when the PeerCoordinator got the MetaInfo via magnet. CoordinatorListener. Create the
  * storage, tell SnarkManager, and give the storage back to the coordinator.
  *
  * @throws RuntimeException via fatal()
  * @since 0.8.4
  */
 public void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo) {
   try {
     String base = Storage.filterName(metainfo.getName());
     File baseFile;
     if (_util.getFilesPublic()) baseFile = new File(rootDataDir, base);
     else baseFile = new SecureFile(rootDataDir, base);
     // The following two may throw IOE...
     storage = new Storage(_util, baseFile, metainfo, this, false);
     storage.check();
     // ... so don't set meta until here
     meta = metainfo;
     if (completeListener != null) {
       String newName = completeListener.gotMetaInfo(this);
       if (newName != null) torrent = newName;
       // else some horrible problem
     }
     coordinator.setStorage(storage);
   } catch (IOException ioe) {
     if (storage != null) {
       try {
         storage.close();
       } catch (IOException ioee) {
       }
     }
     fatal("Could not check or create storage", ioe);
   }
 }
Exemple #3
0
  /**
   * multitorrent, magnet
   *
   * @param torrent a fake name for now (not a file name)
   * @param ih 20-byte info hash
   * @param trackerURL may be null
   * @throws RuntimeException via fatal()
   * @since 0.8.4
   */
  public Snark(
      I2PSnarkUtil util,
      String torrent,
      byte[] ih,
      String trackerURL,
      CompleteListener complistener,
      PeerCoordinatorSet peerCoordinatorSet,
      ConnectionAcceptor connectionAcceptor,
      boolean start,
      String rootDir) {
    completeListener = complistener;
    _util = util;
    _log = util.getContext().logManager().getLog(Snark.class);
    _peerCoordinatorSet = peerCoordinatorSet;
    acceptor = connectionAcceptor;
    this.torrent = torrent;
    this.infoHash = ih;
    this.additionalTrackerURL = trackerURL;
    this.rootDataDir =
        rootDir != null ? new File(rootDir) : null; // null only for FetchAndAdd extension
    savedUploaded = 0;
    stopped = true;
    id = generateID();

    // All we have is an infoHash
    // meta remains null
    // storage remains null

    if (start) startTorrent();
  }
Exemple #4
0
 public boolean overUpBWLimit() {
   if (_peerCoordinatorSet == null) return false;
   long total = 0;
   for (PeerCoordinator c : _peerCoordinatorSet) {
     if (!c.halted()) total += c.getCurrentUploadRate();
   }
   long limit = 1024l * _util.getMaxUpBW();
   if (_log.shouldLog(Log.INFO)) _log.info("Total up bw: " + total + " Limit: " + limit);
   return total > limit;
 }
Exemple #5
0
 public boolean overUploadLimit(int uploaders) {
   if (_peerCoordinatorSet == null || uploaders <= 0) return false;
   int totalUploaders = 0;
   for (PeerCoordinator c : _peerCoordinatorSet) {
     if (!c.halted()) totalUploaders += c.uploaders;
   }
   int limit = _util.getMaxUploaders();
   if (_log.shouldLog(Log.DEBUG))
     _log.debug("Total uploaders: " + totalUploaders + " Limit: " + limit);
   return totalUploaders > limit;
 }
Exemple #6
0
 @Override
 public String toString() {
   return "MetaInfo[info_hash='"
       + I2PSnarkUtil.toHex(info_hash)
       + "', announce='"
       + announce
       + "', name='"
       + name
       + "', files="
       + files
       + ", #pieces='"
       + piece_hashes.length / 20
       + "', piece_length='"
       + piece_length
       + "', length='"
       + length
       + "']";
 }
Exemple #7
0
 private byte[] calculateInfoHash() {
   Map<String, BEValue> info = createInfoMap();
   if (_log.shouldLog(Log.DEBUG)) {
     StringBuilder buf = new StringBuilder(128);
     buf.append("info: ");
     for (Map.Entry<String, BEValue> entry : info.entrySet()) {
       String key = entry.getKey();
       Object val = entry.getValue();
       buf.append(key).append('=');
       buf.append(val.toString());
     }
     _log.debug(buf.toString());
   }
   byte[] infoBytes = BEncoder.bencode(info);
   // _log.debug("info bencoded: [" + Base64.encode(infoBytes, true) + "]");
   MessageDigest digest = SHA1.getInstance();
   byte hash[] = digest.digest(infoBytes);
   if (_log.shouldLog(Log.DEBUG)) _log.debug("info hash: " + I2PSnarkUtil.toHex(hash));
   return hash;
 }
Exemple #8
0
 /** @since 0.8.5 */
 public static void main(String[] args) {
   if (args.length <= 0) {
     System.err.println("Usage: MetaInfo files...");
     return;
   }
   for (int i = 0; i < args.length; i++) {
     InputStream in = null;
     try {
       in = new FileInputStream(args[i]);
       MetaInfo meta = new MetaInfo(in);
       System.out.println(args[i] + " InfoHash: " + I2PSnarkUtil.toHex(meta.getInfoHash()));
     } catch (IOException ioe) {
       System.err.println("Error in file " + args[i] + ": " + ioe);
     } finally {
       try {
         if (in != null) in.close();
       } catch (IOException ioe) {
       }
     }
   }
 }
Exemple #9
0
 /**
  * Stop contacting the tracker and talking with peers
  *
  * @param fast if true, limit the life of the unannounce threads
  * @since 0.9.1
  */
 public synchronized void stopTorrent(boolean fast) {
   stopped = true;
   TrackerClient tc = trackerclient;
   if (tc != null) tc.halt(fast);
   PeerCoordinator pc = coordinator;
   if (pc != null) pc.halt();
   Storage st = storage;
   if (st != null) {
     // TODO: Cache the config-in-mem to compare vs config-on-disk
     // (needed for auto-save to not double-save in some cases)
     // boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
     boolean changed = true;
     try {
       storage.close();
     } catch (IOException ioe) {
       System.out.println("Error closing " + torrent);
       ioe.printStackTrace();
     }
     if (changed && completeListener != null) completeListener.updateStatus(this);
   }
   if (pc != null && _peerCoordinatorSet != null) _peerCoordinatorSet.remove(pc);
   if (_peerCoordinatorSet == null) _util.disconnect();
 }
Exemple #10
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();
    }
  }
Exemple #11
0
  /**
   * multitorrent
   *
   * @param baseFile if null, use rootDir/torrentName; if non-null, use it instead
   * @throws RuntimeException via fatal()
   * @since 0.9.11
   */
  public Snark(
      I2PSnarkUtil util,
      String torrent,
      String ip,
      int user_port,
      StorageListener slistener,
      CoordinatorListener clistener,
      CompleteListener complistener,
      PeerCoordinatorSet peerCoordinatorSet,
      ConnectionAcceptor connectionAcceptor,
      boolean start,
      String rootDir,
      File baseFile) {
    if (slistener == null) slistener = this;

    completeListener = complistener;
    _util = util;
    _log = util.getContext().logManager().getLog(Snark.class);
    _peerCoordinatorSet = peerCoordinatorSet;
    acceptor = connectionAcceptor;

    this.torrent = torrent;
    this.rootDataDir = new File(rootDir);

    stopped = true;
    activity = "Network setup";

    id = generateID();
    if (_log.shouldLog(Log.INFO)) _log.info("My peer id: " + PeerID.idencode(id));

    /*
     * Don't start a tunnel if the torrent isn't going to be started.
     * If we are starting,
     * startTorrent() will force a connect.
     *
        boolean ok = util.connect();
        if (!ok) fatal("Unable to connect to I2P");
        I2PServerSocket serversocket = util.getServerSocket();
        if (serversocket == null)
            fatal("Unable to listen for I2P connections");
        else {
            Destination d = serversocket.getManager().getSession().getMyDestination();
            debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
        }
    */

    // Figure out what the torrent argument represents.
    File f = null;
    InputStream in = null;
    byte[] x_infoHash = null;
    try {
      f = new File(torrent);
      if (f.exists()) in = new FileInputStream(f);
      else {
        /**
         * ** No, we don't ever fetch a torrent file this way and we don't want to block in the
         * constructor activity = "Getting torrent"; File torrentFile = _util.get(torrent, 3); if
         * (torrentFile == null) { fatal("Unable to fetch " + torrent); if (false) return; // never
         * reached - fatal(..) throws } else { torrentFile.deleteOnExit(); in = new
         * FileInputStream(torrentFile); } ***
         */
        throw new IOException("not found");
      }
      meta = new MetaInfo(in);
      x_infoHash = meta.getInfoHash();
    } catch (IOException ioe) {
      // OK, so it wasn't a torrent metainfo file.
      if (f != null && f.exists())
        if (ip == null)
          fatal(
              "'"
                  + torrent
                  + "' exists,"
                  + " but is not a valid torrent metainfo file."
                  + System.getProperty("line.separator"),
              ioe);
        else fatal("I2PSnark does not support creating and tracking a torrent at the moment");
      /*
         {
           // Try to create a new metainfo file
          debug
            ("Trying to create metainfo torrent for '" + torrent + "'",
             NOTICE);
          try
            {
              activity = "Creating torrent";
              storage = new Storage
                (f, "http://" + ip + ":" + port + "/announce", slistener);
              storage.create();
              meta = storage.getMetaInfo();
            }
          catch (IOException ioe2)
            {
              fatal("Could not create torrent for '" + torrent + "'", ioe2);
            }
         }
      */
      else fatal("Cannot open '" + torrent + "'", ioe);
    } catch (OutOfMemoryError oom) {
      fatal("ERROR - Out of memory, cannot create torrent " + torrent + ": " + oom.getMessage());
    } finally {
      if (in != null)
        try {
          in.close();
        } catch (IOException ioe) {
        }
    }

    infoHash = x_infoHash; // final
    if (_log.shouldLog(Log.INFO)) _log.info(meta.toString());

    // When the metainfo torrent was created from an existing file/dir
    // it already exists.
    if (storage == null) {
      try {
        activity = "Checking storage";
        boolean shouldPreserve =
            completeListener != null && completeListener.getSavedPreserveNamesSetting(this);
        if (baseFile == null) {
          String base = meta.getName();
          if (!shouldPreserve) base = Storage.filterName(base);
          if (_util.getFilesPublic()) baseFile = new File(rootDataDir, base);
          else baseFile = new SecureFile(rootDataDir, base);
        }
        storage = new Storage(_util, baseFile, meta, slistener, shouldPreserve);
        if (completeListener != null) {
          storage.check(
              completeListener.getSavedTorrentTime(this),
              completeListener.getSavedTorrentBitField(this));
        } else {
          storage.check();
        }
        // have to figure out when to reopen
        // if (!start)
        //    storage.close();
      } catch (IOException ioe) {
        try {
          storage.close();
        } catch (IOException ioee) {
          ioee.printStackTrace();
        }
        fatal("Could not check or create storage", ioe);
      }
    }

    /*
     * see comment above
     *
        activity = "Collecting pieces";
        coordinator = new PeerCoordinator(id, meta, storage, clistener, this);
        PeerCoordinatorSet set = PeerCoordinatorSet.instance();
        set.add(coordinator);
        ConnectionAcceptor acceptor = ConnectionAcceptor.instance();
        acceptor.startAccepting(set, serversocket);
        trackerclient = new TrackerClient(meta, coordinator);
    */

    savedUploaded = (completeListener != null) ? completeListener.getSavedUploaded(this) : 0;
    if (start) startTorrent();
  }
Exemple #12
0
 public boolean overUpBWLimit(long total) {
   long limit = 1024l * _util.getMaxUpBW();
   return total > limit;
 }