Ignore:
Timestamp:
Dec 22, 2010 10:22:38 PM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
b97ad6c5
Parents:
9734074
Message:
  • Protection against modifying metainfos
  • Announce peers to local tracker
  • Ping node on port reception
  • More info on directory pages
  • Cleanups
Location:
apps/i2psnark/java/src/org/klomp/snark
Files:
9 edited

Legend:

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

    r9734074 r97f0c13  
    5555  private final String name;
    5656  private final String name_utf8;
    57   private final List files;
    58   private final List files_utf8;
    59   private final List lengths;
     57  private final List<List<String>> files;
     58  private final List<List<String>> files_utf8;
     59  private final List<Long> lengths;
    6060  private final int piece_length;
    6161  private final byte[] piece_hashes;
    6262  private final long length;
    63   private Map infoMap;
     63  private Map<String, BEValue> infoMap;
    6464
    6565  /**
     
    6767   *
    6868   *  @param announce may be null
    69    */
    70   MetaInfo(String announce, String name, String name_utf8, List files, List lengths,
     69   *  @param files null for single-file torrent
     70   *  @param lengths null for single-file torrent
     71   */
     72  MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
    7173           int piece_length, byte[] piece_hashes, long length)
    7274  {
     
    7476    this.name = name;
    7577    this.name_utf8 = name_utf8;
    76     this.files = files;
     78    this.files = files == null ? null : Collections.unmodifiableList(files);
    7779    this.files_utf8 = null;
    78     this.lengths = lengths;
     80    this.lengths = lengths == null ? null : Collections.unmodifiableList(lengths);
    7981    this.piece_length = piece_length;
    8082    this.piece_hashes = piece_hashes;
     
    132134        throw new InvalidBEncodingException("Missing info map");
    133135    Map info = val.getMap();
    134     infoMap = info;
     136    infoMap = Collections.unmodifiableMap(info);
    135137
    136138    val = (BEValue)info.get("name");
     
    172174            ("Missing length number and/or files list");
    173175
    174         List list = val.getList();
     176        List<BEValue> list = val.getList();
    175177        int size = list.size();
    176178        if (size == 0)
    177179          throw new InvalidBEncodingException("zero size files list");
    178180
    179         files = new ArrayList(size);
    180         files_utf8 = new ArrayList(size);
    181         lengths = new ArrayList(size);
     181        List<List<String>> m_files = new ArrayList(size);
     182        List<List<String>> m_files_utf8 = new ArrayList(size);
     183        List<Long> m_lengths = new ArrayList(size);
    182184        long l = 0;
    183185        for (int i = 0; i < list.size(); i++)
    184186          {
    185             Map desc = ((BEValue)list.get(i)).getMap();
    186             val = (BEValue)desc.get("length");
     187            Map<String, BEValue> desc = list.get(i).getMap();
     188            val = desc.get("length");
    187189            if (val == null)
    188190              throw new InvalidBEncodingException("Missing length number");
    189191            long len = val.getLong();
    190             lengths.add(new Long(len));
     192            m_lengths.add(new Long(len));
    191193            l += len;
    192194
     
    194196            if (val == null)
    195197              throw new InvalidBEncodingException("Missing path list");
    196             List path_list = val.getList();
     198            List<BEValue> path_list = val.getList();
    197199            int path_length = path_list.size();
    198200            if (path_length == 0)
    199201              throw new InvalidBEncodingException("zero size file path list");
    200202
    201             List file = new ArrayList(path_length);
    202             Iterator it = path_list.iterator();
     203            List<String> file = new ArrayList(path_length);
     204            Iterator<BEValue> it = path_list.iterator();
    203205            while (it.hasNext())
    204               file.add(((BEValue)it.next()).getString());
    205 
    206             files.add(file);
     206              file.add(it.next().getString());
     207
     208            m_files.add(Collections.unmodifiableList(file));
    207209           
    208210            val = (BEValue)desc.get("path.utf-8");
     
    214216                    it = path_list.iterator();
    215217                    while (it.hasNext())
    216                         file.add(((BEValue)it.next()).getString());
    217                     files_utf8.add(file);
     218                        file.add(it.next().getString());
     219                    m_files_utf8.add(Collections.unmodifiableList(file));
    218220                }
    219221            }
    220222          }
     223        files = Collections.unmodifiableList(m_files);
     224        files_utf8 = Collections.unmodifiableList(m_files_utf8);
     225        lengths = Collections.unmodifiableList(m_lengths);
    221226        length = l;
    222227      }
     
    266271   * getLengths().
    267272   */
    268   public List getFiles()
    269   {
    270     // XXX - Immutable?
     273  public List<List<String>> getFiles()
     274  {
    271275    return files;
    272276  }
     
    277281   * the list returned by getFiles().
    278282   */
    279   public List getLengths()
    280   {
    281     // XXX - Immutable?
     283  public List<Long> getLengths()
     284  {
    282285    return lengths;
    283286  }
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    r9734074 r97f0c13  
    3333import net.i2p.client.streaming.I2PSocket;
    3434import net.i2p.data.DataHelper;
     35import net.i2p.data.Destination;
    3536import net.i2p.util.Log;
    3637
     
    385386  }
    386387
     388  /** @since 0.8.4 */
     389  public Destination getDestination() {
     390      if (sock == null)
     391          return null;
     392      return sock.getPeerDestination();
     393  }
     394
    387395  /**
    388396   *  Shared state across all peers, callers must sync on returned object
  • apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java

    r9734074 r97f0c13  
    3838
    3939  private final PeerCoordinator coordinator;
    40   public I2PSnarkUtil _util;
     40  private final I2PSnarkUtil _util;
     41  private int _runCount;
    4142
    4243  PeerCheckerTask(I2PSnarkUtil util, PeerCoordinator coordinator)
     
    5051  public void run()
    5152  {
     53        _runCount++;
    5254        List<Peer> peerList = coordinator.peerList();
    5355        if (peerList.isEmpty() || coordinator.halted()) {
     
    205207            peer.retransmitRequests();
    206208            peer.keepAlive();
     209            // announce them to local tracker (TrackerClient does this too)
     210            if (_util.getDHT() != null && (_runCount % 5) == 0) {
     211                _util.getDHT().announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
     212            }
    207213          }
    208214
     
    246252        // close out unused files, but we don't need to do it every time
    247253        Storage storage = coordinator.getStorage();
    248         if (storage != null && random.nextInt(4) == 0) {
     254        if (storage != null && (_runCount % 4) == 0) {
    249255                storage.cleanRAFs();
     256        }
     257
     258        // announce ourselves to local tracker (TrackerClient does this too)
     259        if (_util.getDHT() != null && (_runCount % 16) == 0) {
     260            _util.getDHT().announce(coordinator.getInfoHash());
    250261        }
    251262  }
  • apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java

    r9734074 r97f0c13  
    3636import net.i2p.util.Log;
    3737import net.i2p.util.SimpleTimer2;
     38
     39import org.klomp.snark.dht.KRPC;
    3840
    3941/**
     
    11871189  /**
    11881190   *  PeerListener callback
     1191   *  Tell the DHT to ping it, this will get back the node info
    11891192   *  @since 0.8.4
    11901193   */
    11911194  public void gotPort(Peer peer, int port) {
    1192       // send to DHT
     1195      KRPC krpc = _util.getDHT();
     1196      if (krpc != null)
     1197          krpc.ping(peer.getDestination(), port);
    11931198  }
    11941199
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    r9734074 r97f0c13  
    777777
    778778    /**
    779      *  @return needed of all torrent files, or total of metainfo file if fetching magnet, or -1
     779     *  @return number of pieces still needed (magnet mode or not), or -1 if unknown
    780780     *  @since 0.8.4
    781781     */
     
    787787            return meta.getTotalLength();
    788788        // FIXME fake
    789         return 16 * 16 * 1024;
     789        return -1;
    790790    }
    791791
     
    799799            return meta.getPieceLength(p);
    800800        return 16*1024;
     801    }
     802
     803    /**
     804     *  @return number of pieces
     805     *  @since 0.8.4
     806     */
     807    public int getPieces() {
     808        if (meta != null)
     809            return meta.getPieces();
     810        // FIXME else return metainfo pieces if available
     811        return -1;
    801812    }
    802813
  • apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java

    r9734074 r97f0c13  
    6969    public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
    7070    public static final String PROP_META_PRIORITY_SUFFIX = ".priority";
     71    public static final String PROP_META_MAGNET_SUFFIX = ".magnet";
    7172
    7273    private static final String CONFIG_FILE = "i2psnark.config";
     
    10321033            }
    10331034
     1035//start magnets
     1036
     1037
    10341038            // here because we need to delay until I2CP is up
    10351039            // although the user will see the default until then
     
    12461250                    snark.stopTorrent();
    12471251            }
     1252//save magnets
    12481253        }
    12491254    }
  • apps/i2psnark/java/src/org/klomp/snark/Storage.java

    r9734074 r97f0c13  
    101101   
    102102    long total = 0;
    103     ArrayList lengthsList = new ArrayList();
     103    ArrayList<Long> lengthsList = new ArrayList();
    104104    for (int i = 0; i < lengths.length; i++)
    105105      {
     
    123123    needed = 0;
    124124
    125     List files = new ArrayList();
     125    List<List<String>> files = new ArrayList();
    126126    for (int i = 0; i < names.length; i++)
    127127      {
    128         List file = new ArrayList();
     128        List<String> file = new ArrayList();
    129129        StringTokenizer st = new StringTokenizer(names[i], File.separator);
    130130        while (st.hasMoreTokens())
  • apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java

    r9734074 r97f0c13  
    278278                    tr.started = true;
    279279
    280                     Set peers = info.getPeers();
     280                    Set<Peer> peers = info.getPeers();
    281281                    tr.seenPeers = info.getPeerCount();
    282282                    if (snark.getTrackerSeenPeers() < tr.seenPeers) // update rising number quickly
    283283                        snark.setTrackerSeenPeers(tr.seenPeers);
     284
     285                    // pass everybody over to our tracker
     286                    if (_util.getDHT() != null) {
     287                        for (Peer peer : peers) {
     288                            _util.getDHT().announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
     289                        }
     290                    }
     291
    284292                    if ( (left > 0) && (!completed) ) {
    285293                        // we only want to talk to new people if we need things
    286294                        // from them (duh)
    287                         List ordered = new ArrayList(peers);
     295                        List<Peer> ordered = new ArrayList(peers);
    288296                        Collections.shuffle(ordered, r);
    289                         Iterator it = ordered.iterator();
     297                        Iterator<Peer> it = ordered.iterator();
    290298                        while ((!stop) && it.hasNext()) {
    291                           Peer cur = (Peer)it.next();
     299                          Peer cur = it.next();
    292300                          // FIXME if id == us || dest == us continue;
    293301                          // only delay if we actually make an attempt to add peer
  • apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java

    r9734074 r97f0c13  
    77import java.io.PrintWriter;
    88import java.text.Collator;
     9import java.text.DecimalFormat;
    910import java.util.ArrayList;
    1011import java.util.Arrays;
     
    876877            icon = toIcon(meta.getName());
    877878        else
    878             // todo get a nice magnet icon?
    879             icon = "page_white";
     879            icon = "magnet";
    880880        if (remaining == 0 || isMultiFile) {
    881881            out.write(toImg(icon, _("Open")));
     
    13761376            ih = Base32.decode(ihash);
    13771377        } else if (ihash.length() == 40) {
     1378            //  Like DataHelper.fromHexString() but ensures no loss of leading zero bytes
    13781379            ih = new byte[20];
    13791380            try {
     
    15401541        if (title.endsWith("/"))
    15411542            title = title.substring(0, title.length() - 1);
     1543        String directory = title;
    15421544        title = _("Torrent") + ": " + title;
    15431545        buf.append(title);
     
    15511553        if (showPriority)
    15521554            buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
    1553         buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" >" +
    1554             "<thead><tr><th>")
     1555        buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" ><thead>");
     1556        if (snark != null) {
     1557            // first row - torrent info
     1558            // FIXME center
     1559            buf.append("<tr><th colspan=\"" + (showPriority ? '4' : '3') + "\"><div>")
     1560                .append(_("Torrent")).append(": ").append(snark.getBaseName());
     1561            int pieces = snark.getPieces();
     1562            double completion = (pieces - snark.getNeeded()) / (double) pieces;
     1563            if (completion < 1.0)
     1564                buf.append("<br>").append(_("Completion")).append(": ").append((new DecimalFormat("0.00%")).format(completion));
     1565            else
     1566                buf.append("<br>").append(_("Complete"));
     1567            // else unknown
     1568            buf.append("<br>").append(_("Size")).append(": ").append(formatSize(snark.getTotalLength()));
     1569            MetaInfo meta = snark.getMetaInfo();
     1570            if (meta != null) {
     1571                List files = meta.getFiles();
     1572                int fileCount = files != null ? files.size() : 1;
     1573                buf.append("<br>").append(_("Files")).append(": ").append(fileCount);
     1574            }
     1575            buf.append("<br>").append(_("Pieces")).append(": ").append(pieces);
     1576            buf.append("<br>").append(_("Piece size")).append(": ").append(formatSize(snark.getPieceLength(0)));
     1577            String hex = toHex(snark.getInfoHash());
     1578            buf.append("<br>").append(_("Magnet link")).append(": <a href=\"").append(MAGNET).append(hex).append("\">")
     1579               .append(MAGNET).append(hex).append("</a>");
     1580            // We don't have the hash of the torrent file
     1581            //buf.append("<br>").append(_("Maggot link")).append(": <a href=\"").append(MAGGOT).append(hex).append(':').append(hex).append("\">")
     1582            //   .append(MAGGOT).append(hex).append(':').append(hex).append("</a>");
     1583            buf.append("</div></th></tr>");
     1584        }
     1585        // second row - dir info
     1586        buf.append("<tr><th>")
    15551587            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" >&nbsp;")
    1556             .append(title).append("</th><th align=\"right\">")
     1588            .append(_("Directory")).append(": ").append(directory).append("</th><th align=\"right\">")
    15571589            .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "size.png\" >&nbsp;")
    15581590            .append(_("Size"));
     
    17681800    }
    17691801
     1802    /**
     1803     *  Like DataHelper.toHexString but ensures no loss of leading zero bytes
     1804     *  @since 0.8.4
     1805     */
     1806    private static String toHex(byte[] b) {
     1807        StringBuilder buf = new StringBuilder(40);
     1808        for (int i = 0; i < b.length; i++) {
     1809            int bi = b[i] & 0xff;
     1810            if (bi < 16)
     1811                buf.append('0');
     1812            buf.append(Integer.toHexString(bi));
     1813        }
     1814        return buf.toString();
     1815    }
     1816
    17701817    /** @since 0.8.1 */
    17711818    private void savePriorities(Snark snark, Map postParams) {
Note: See TracChangeset for help on using the changeset viewer.