Changeset b37bb93


Ignore:
Timestamp:
Dec 15, 2005 8:58:30 AM (15 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
3ec92c8
Parents:
369b693
git-author:
jrandom <jrandom> (12/15/05 08:58:30)
git-committer:
zzz <zzz@…> (12/15/05 08:58:30)
Message:

2005-12-15 jrandom

  • Added multitorrent support to I2PSnark, accessible currently by running "i2psnark.jar —config i2psnark.config" (which may or may not exist). It then joins the swarm for any torrents in ./i2psnark/*.torrent, saving their data in that directory as well. Removing the .torrent file stops participation, and it is currently set to seed indefinitely. Completion is logged to the logger and standard output, with further UI interaction left to the (work in progress) web UI.
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java

    r369b693 rb37bb93  
    146146        int pathStart = origAnnounce.indexOf('/', destEnd);
    147147        String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
    148         _log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");
     148        //_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");
    149149        return rv;
    150150    }
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    r369b693 rb37bb93  
    2929
    3030import net.i2p.client.streaming.I2PSocket;
     31import net.i2p.util.Log;
    3132
    3233public class Peer implements Comparable
    3334{
     35  private Log _log = new Log(Peer.class);
    3436  // Identifying property, the peer id of the other side.
    3537  private final PeerID peerID;
     
    5961    this.my_id = my_id;
    6062    this.metainfo = metainfo;
     63    _log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating"));
    6164  }
    6265
     
    7982    byte[] id  = handshake(bis, bos);
    8083    this.peerID = new PeerID(id, sock.getPeerDestination());
     84    _log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating"));
    8185  }
    8286
     
    146150      throw new IllegalStateException("Peer already started");
    147151
     152    _log.debug("Running connection to " + peerID.getAddress().calculateHash().toBase64(), new Exception("connecting"));   
    148153    try
    149154      {
  • apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java

    r369b693 rb37bb93  
    2323import java.io.*;
    2424import java.net.*;
     25import java.util.Iterator;
    2526
    2627import net.i2p.client.streaming.I2PSocket;
     28import net.i2p.data.Base64;
     29import net.i2p.data.DataHelper;
    2730
    2831/**
     
    3538{
    3639  private final PeerCoordinator coordinator;
     40  private final PeerCoordinatorSet coordinators;
    3741
    3842  public PeerAcceptor(PeerCoordinator coordinator)
    3943  {
    4044    this.coordinator = coordinator;
     45    this.coordinators = null;
    4146  }
     47 
     48  public PeerAcceptor(PeerCoordinatorSet coordinators)
     49  {
     50    this.coordinators = coordinators;
     51    this.coordinator = null;
     52  }
     53
     54  private static final int LOOKAHEAD_SIZE = "19".length() +
     55                                            "BitTorrent protocol".length() +
     56                                            8 + // blank, reserved
     57                                            20; // infohash
    4258
    4359  public void connection(I2PSocket socket,
     
    4561    throws IOException
    4662  {
    47     if (coordinator.needPeers())
    48       {
    49         // XXX: inside this Peer constructor's handshake is where you'd deal with the other
    50         //      side saying they want to communicate with another torrent - aka multitorrent
    51         //      support.  you'd then want to grab the meta info /they/ want, look that up in
    52         //      our own list of active torrents, and put it on the right coordinator for it.
    53         //      this currently, however, throws an IOException if the metainfo doesn't match
    54         //      coodinator.getMetaInfo (Peer.java:242)
    55         Peer peer = new Peer(socket, bis, bos, coordinator.getID(),
    56                              coordinator.getMetaInfo());
    57         coordinator.addPeer(peer);
    58       }
    59     else
    60       socket.close();
     63    // inside this Peer constructor's handshake is where you'd deal with the other
     64    // side saying they want to communicate with another torrent - aka multitorrent
     65    // support, but because of how the protocol works, we can get away with just reading
     66    // ahead the first $LOOKAHEAD_SIZE bytes to figure out which infohash they want to
     67    // talk about, and we can just look for that in our list of active torrents.
     68    bis.mark(LOOKAHEAD_SIZE);
     69    byte peerInfoHash[] = readHash(bis);
     70    bis.reset();
     71    if (coordinator != null) {
     72        // single torrent capability
     73        MetaInfo meta = coordinator.getMetaInfo();
     74        if (DataHelper.eq(meta.getInfoHash(), peerInfoHash)) {
     75            if (coordinator.needPeers())
     76              {
     77                Peer peer = new Peer(socket, bis, bos, coordinator.getID(),
     78                                     coordinator.getMetaInfo());
     79                coordinator.addPeer(peer);
     80              }
     81            else
     82              socket.close();
     83        } else {
     84          // its for another infohash, but we are only single torrent capable.  b0rk.
     85            throw new IOException("Peer wants another torrent (" + Base64.encode(peerInfoHash)
     86                                  + ") while we only support (" + Base64.encode(meta.getInfoHash()) + ")");
     87        }
     88    } else {
     89        // multitorrent capable, so lets see what we can handle
     90        for (Iterator iter = coordinators.iterator(); iter.hasNext(); ) {
     91            PeerCoordinator cur = (PeerCoordinator)iter.next();
     92            MetaInfo meta = cur.getMetaInfo();
     93           
     94            if (DataHelper.eq(meta.getInfoHash(), peerInfoHash)) {
     95                if (cur.needPeers())
     96                  {
     97                    Peer peer = new Peer(socket, bis, bos, cur.getID(),
     98                                         cur.getMetaInfo());
     99                    cur.addPeer(peer);
     100                    return;
     101                  }
     102                else
     103                  {
     104                    socket.close();
     105                    return;
     106                  }
     107            }
     108        }
     109        // this is only reached if none of the coordinators match the infohash
     110        throw new IOException("Peer wants another torrent (" + Base64.encode(peerInfoHash)
     111                              + ") while we don't support that hash");
     112    }
     113  }
     114
     115  /**
     116   * Read ahead to the infohash, throwing an exception if there isn't enough data
     117   */
     118  private byte[] readHash(InputStream in) throws IOException {
     119    byte buf[] = new byte[LOOKAHEAD_SIZE];
     120    int read = DataHelper.read(in, buf);
     121    if (read != buf.length)
     122        throw new IOException("Unable to read the hash (read " + read + ")");
     123    byte rv[] = new byte[20];
     124    System.arraycopy(buf, buf.length-rv.length-1, rv, 0, rv.length);
     125    return rv;
    61126  }
    62127}
  • apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java

    r369b693 rb37bb93  
    2424import java.io.IOException;
    2525
     26import net.i2p.util.Log;
     27
    2628/**
    2729 * Coordinates what peer does what.
     
    2931public class PeerCoordinator implements PeerListener
    3032{
     33  private final Log _log = new Log(PeerCoordinator.class);
    3134  final MetaInfo metainfo;
    3235  final Storage storage;
     
    8184    timer.schedule(new PeerCheckerTask(this), CHECK_PERIOD, CHECK_PERIOD);
    8285  }
     86 
     87  public Storage getStorage() { return storage; }
     88  public CoordinatorListener getListener() { return listener; }
    8389
    8490  public byte[] getID()
     
    138144      }
    139145  }
     146 
     147  public boolean halted() { return halted; }
    140148
    141149  public void halt()
     
    216224    if (need_more)
    217225      {
     226        _log.debug("Addng a peer " + peer.getPeerID().getAddress().calculateHash().toBase64(), new Exception("add/run"));
     227
    218228        // Run the peer with us as listener and the current bitfield.
    219229        final PeerListener listener = this;
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    r369b693 rb37bb93  
    8686
    8787  // String indicating main activity
    88   static String activity = "Not started";
     88  String activity = "Not started";
    8989 
    9090  public static void main(String[] args)
     
    9393    System.out.println();
    9494
     95    if ( (args.length > 0) && ("--config".equals(args[0])) ) {
     96        SnarkManager sm = SnarkManager.instance();
     97        if (args.length > 1)
     98            sm.loadConfig(args[1]);
     99        System.out.println("Running in multitorrent mode");
     100        while (true) {
     101            try {
     102                synchronized (sm) {
     103                    sm.wait();
     104                }
     105            } catch (InterruptedException ie) {}
     106        }
     107    }
     108   
    95109    // Parse debug, share/ip and torrent file options.
    96110    Snark snark = parseArguments(args);
     
    102116                          snark.trackerclient,
    103117                          snark);
    104     Runtime.getRuntime().addShutdownHook(snarkhook);
     118    //Runtime.getRuntime().addShutdownHook(snarkhook);
    105119
    106120    Timer timer = new Timer(true);
     
    131145                else if ("list".equals(line))
    132146                  {
    133                     synchronized(coordinator.peers)
     147                    synchronized(snark.coordinator.peers)
    134148                      {
    135                         System.out.println(coordinator.peers.size()
     149                        System.out.println(snark.coordinator.peers.size()
    136150                                           + " peers -"
    137151                                           + " (i)nterested,"
     
    139153                                           + " (c)hoking,"
    140154                                           + " (C)hoked:");
    141                         Iterator it = coordinator.peers.iterator();
     155                        Iterator it = snark.coordinator.peers.iterator();
    142156                        while (it.hasNext())
    143157                          {
     
    153167                else if ("info".equals(line))
    154168                  {
    155                     System.out.println("Name: " + meta.getName());
    156                     System.out.println("Torrent: " + torrent);
    157                     System.out.println("Tracker: " + meta.getAnnounce());
    158                     List files = meta.getFiles();
     169                    System.out.println("Name: " + snark.meta.getName());
     170                    System.out.println("Torrent: " + snark.torrent);
     171                    System.out.println("Tracker: " + snark.meta.getAnnounce());
     172                    List files = snark.meta.getFiles();
    159173                    System.out.println("Files: "
    160174                                       + ((files == null) ? 1 : files.size()));
    161                     System.out.println("Pieces: " + meta.getPieces());
     175                    System.out.println("Pieces: " + snark.meta.getPieces());
    162176                    System.out.println("Piece size: "
    163                                        + meta.getPieceLength(0) / 1024
     177                                       + snark.meta.getPieceLength(0) / 1024
    164178                                       + " KB");
    165179                    System.out.println("Total size: "
    166                                        + meta.getTotalLength() / (1024 * 1024)
     180                                       + snark.meta.getTotalLength() / (1024 * 1024)
    167181                                       + " MB");
    168182                  }
     
    196210  }
    197211
    198   static String torrent;
    199   static MetaInfo meta;
    200   static Storage storage;
    201   static PeerCoordinator coordinator;
    202   static ConnectionAcceptor acceptor;
    203   static TrackerClient trackerclient;
    204 
    205   private Snark(String torrent, String ip, int user_port,
    206                 StorageListener slistener, CoordinatorListener clistener)
     212  String torrent;
     213  MetaInfo meta;
     214  Storage storage;
     215  PeerCoordinator coordinator;
     216  ConnectionAcceptor acceptor;
     217  TrackerClient trackerclient;
     218  String rootDataDir = ".";
     219
     220  Snark(String torrent, String ip, int user_port,
     221        StorageListener slistener, CoordinatorListener clistener) {
     222    this(torrent, ip, user_port, slistener, clistener, true, ".");
     223  }
     224  Snark(String torrent, String ip, int user_port,
     225        StorageListener slistener, CoordinatorListener clistener, boolean start, String rootDir)
    207226  {
    208227    if (slistener == null)
     
    213232
    214233    this.torrent = torrent;
     234    this.rootDataDir = rootDir;
    215235
    216236    activity = "Network setup";
     
    320340            activity = "Checking storage";
    321341            storage = new Storage(meta, slistener);
    322             storage.check();
     342            storage.check(rootDataDir);
    323343          }
    324344        catch (IOException ioe)
     
    330350    activity = "Collecting pieces";
    331351    coordinator = new PeerCoordinator(id, meta, storage, clistener);
    332     PeerAcceptor peeracceptor = new PeerAcceptor(coordinator);
     352    PeerCoordinatorSet set = PeerCoordinatorSet.instance();
     353    set.add(coordinator);
     354    PeerAcceptor peeracceptor = new PeerAcceptor(set); //coordinator);
    333355    ConnectionAcceptor acceptor = new ConnectionAcceptor(serversocket,
    334356                                                         peeracceptor);
    335357
    336358    trackerclient = new TrackerClient(meta, coordinator);
     359    if (start)
     360        startTorrent();
     361  }
     362  /**
     363   * Start up contacting peers and querying the tracker
     364   */
     365  public void startTorrent() {
     366    boolean coordinatorChanged = false;
     367    if (coordinator.halted()) {
     368        // ok, we have already started and stopped, but the coordinator seems a bit annoying to
     369        // restart safely, so lets build a new one to replace the old
     370        PeerCoordinatorSet set = PeerCoordinatorSet.instance();
     371        set.remove(coordinator);
     372        PeerCoordinator newCoord = new PeerCoordinator(coordinator.getID(), coordinator.getMetaInfo(),
     373                                                       coordinator.getStorage(), coordinator.getListener());
     374        set.add(newCoord);
     375        coordinator = newCoord;
     376        coordinatorChanged = true;
     377    }
     378    if (trackerclient.halted() || coordinatorChanged) {
     379        TrackerClient newClient = new TrackerClient(coordinator.getMetaInfo(), coordinator);
     380        if (!trackerclient.halted())
     381            trackerclient.halt();
     382        trackerclient = newClient;
     383    }
    337384    trackerclient.start();
    338 
     385  }
     386  /**
     387   * Stop contacting the tracker and talking with peers
     388   */
     389  public void stopTorrent() {
     390    trackerclient.halt();
     391    coordinator.halt();
     392    try {
     393        storage.close();
     394    } catch (IOException ioe) {
     395        System.out.println("Error closing " + torrent);
     396        ioe.printStackTrace();
     397    }
     398    PeerCoordinatorSet.instance().remove(coordinator);
    339399  }
    340400
     
    589649    checking = false;
    590650  }
     651 
     652  public void storageCompleted(Storage storage)
     653  {
     654    Snark.debug("Completely received " + torrent, Snark.INFO);
     655    //storage.close();
     656    System.out.println("Completely received: " + torrent);
     657  }
    591658
    592659  public void shutdown()
  • apps/i2psnark/java/src/org/klomp/snark/Storage.java

    r369b693 rb37bb93  
    128128
    129129  // Creates piece hases for a new storage.
    130   public void create() throws IOException
     130  private void create() throws IOException
    131131  {
    132132    // Calculate piece_hashes
     
    241241   * Creates (and/or checks) all files from the metainfo file list.
    242242   */
    243   public void check() throws IOException
    244   {
    245     File base = new File(filterName(metainfo.getName()));
     243  public void check(String rootDir) throws IOException
     244  {
     245    File base = new File(rootDir, filterName(metainfo.getName()));
    246246
    247247    List files = metainfo.getFiles();
     
    369369      }
    370370
    371     if (listener != null)
     371    if (listener != null) {
    372372      listener.storageAllChecked(this);
     373      if (needed <= 0)
     374        listener.storageCompleted(this);
     375    }
    373376  }
    374377
     
    484487      }
    485488
     489    if (complete) {
     490      listener.storageCompleted(this);
     491      // do we also need to close all of the files and reopen
     492      // them readonly?
     493    }
     494
    486495    return true;
    487496  }
  • apps/i2psnark/java/src/org/klomp/snark/StorageListener.java

    r369b693 rb37bb93  
    5050   */
    5151  void storageAllChecked(Storage storage);
     52 
     53  /**
     54   * Called the one time when the data is completely received and checked.
     55   *
     56   */
     57  void storageCompleted(Storage storage);
    5258}
  • apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java

    r369b693 rb37bb93  
    6565  }
    6666
     67  public void start() {
     68      stop = false;
     69      super.start();
     70  }
     71 
     72  public boolean halted() { return stop; }
     73 
    6774  /**
    6875   * Interrupts this Thread to stop it.
     
    101108                                             uploaded, downloaded, left,
    102109                                             STARTED_EVENT);
    103                 Iterator it = info.getPeers().iterator();
    104                 while (it.hasNext())
    105                   coordinator.addPeer((Peer)it.next());
     110                if (!completed) {
     111                    Iterator it = info.getPeers().iterator();
     112                    while (it.hasNext()) {
     113                      Peer cur = (Peer)it.next();
     114                      coordinator.addPeer(cur);
     115                      int delay = 3000;
     116                      int c = ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
     117                      try { Thread.sleep(delay * c); } catch (InterruptedException ie) {}
     118                    }
     119                }
    106120                started = true;
    107121              }
     
    169183                                                 event);
    170184
    171                     Iterator it = info.getPeers().iterator();
    172                     while (it.hasNext())
    173                       coordinator.addPeer((Peer)it.next());
     185                    if ( (left > 0) && (!completed) ) {
     186                        // we only want to talk to new people if we need things
     187                        // from them (duh)
     188                        Iterator it = info.getPeers().iterator();
     189                        while (it.hasNext()) {
     190                          Peer cur = (Peer)it.next();
     191                          coordinator.addPeer(cur);
     192                          int delay = 3000;
     193                          int c = ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
     194                          try { Thread.sleep(delay * c); } catch (InterruptedException ie) {}
     195                        }
     196                    }
    174197                  }
    175198                catch (IOException ioe)
  • history.txt

    r369b693 rb37bb93  
    1 $Id: history.txt,v 1.354 2005/12/13 16:56:41 jrandom Exp $
     1$Id: history.txt,v 1.355 2005/12/14 04:32:52 jrandom Exp $
     2
     32005-12-15  jrandom
     4    * Added multitorrent support to I2PSnark, accessible currently by running
     5      "i2psnark.jar --config i2psnark.config" (which may or may not exist).
     6      It then joins the swarm for any torrents in ./i2psnark/*.torrent, saving
     7      their data in that directory as well.  Removing the .torrent file stops
     8      participation, and it is currently set to seed indefinitely.  Completion
     9      is logged to the logger and standard output, with further UI interaction
     10      left to the (work in progress) web UI.
    211
    3122005-12-14  jrandom
Note: See TracChangeset for help on using the changeset viewer.