Changes in / [9b39f02:be308a0]


Ignore:
Files:
1 added
41 edited

Legend:

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

    r9b39f02 rbe308a0  
    153153    synchronized public boolean connect() {
    154154        if (_manager == null) {
     155            // try to find why reconnecting after stop
     156            if (_log.shouldLog(Log.DEBUG))
     157                _log.debug("Connecting to I2P", new Exception("I did it"));
    155158            Properties opts = new Properties();
    156159            if (_opts != null) {
     
    164167            if (opts.getProperty("outbound.nickname") == null)
    165168                opts.setProperty("outbound.nickname", "I2PSnark");
     169            // Dont do this for now, it is set in I2PSocketEepGet for announces,
     170            // we don't need fast handshake for peer connections.
     171            //if (opts.getProperty("i2p.streaming.connectDelay") == null)
     172            //    opts.setProperty("i2p.streaming.connectDelay", "500");
    166173            if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
    167174                opts.setProperty("i2p.streaming.inactivityTimeout", "240000");
     
    187194    public void disconnect() {
    188195        I2PSocketManager mgr = _manager;
     196        // FIXME this can cause race NPEs elsewhere
    189197        _manager = null;
    190198        _shitlist.clear();
     
    198206    /** connect to the given destination */
    199207    I2PSocket connect(PeerID peer) throws IOException {
     208        I2PSocketManager mgr = _manager;
     209        if (mgr == null)
     210            throw new IOException("No socket manager");
    200211        Destination addr = peer.getAddress();
    201212        if (addr == null)
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    r9b39f02 rbe308a0  
    5757  final static long CHECK_PERIOD = PeerCoordinator.CHECK_PERIOD; // 40 seconds
    5858  final static int RATE_DEPTH = PeerCoordinator.RATE_DEPTH; // make following arrays RATE_DEPTH long
    59   private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
    60   private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
     59  private long uploaded_old[] = {-1,-1,-1};
     60  private long downloaded_old[] = {-1,-1,-1};
    6161
    6262  /**
     
    118118
    119119  /**
    120    * Returns socket (for debug printing)
     120   * @return socket debug string (for debug printing)
    121121   */
    122122  public String getSocket()
    123123  {
     124    if (state != null) {
     125        String r = state.getRequests();
     126        if (r != null)
     127            return sock.toString() + "<br>Requests: " + r;
     128    }
    124129    return sock.toString();
    125130  }
     
    389394
    390395  /**
     396   * Tell the other side that we are no longer interested in any of
     397   * the outstanding requests (if any) for this piece.
     398   * @since 0.8.1
     399   */
     400  void cancel(int piece) {
     401    PeerState s = state;
     402    if (s != null)
     403      s.cancelPiece(piece);
     404  }
     405
     406  /**
     407   * Are we currently requesting the piece?
     408   * @since 0.8.1
     409   */
     410  boolean isRequesting(int p) {
     411    PeerState s = state;
     412    return s != null && s.isRequesting(p);
     413  }
     414
     415  /**
     416   * Update the request queue.
     417   * Call after adding wanted pieces.
     418   * @since 0.8.1
     419   */
     420  void request() {
     421    PeerState s = state;
     422    if (s != null)
     423      s.addRequest();
     424  }
     425
     426  /**
    391427   * Whether or not the peer is interested in pieces we have. Returns
    392428   * false if not connected.
     
    546582  public void setRateHistory(long up, long down)
    547583  {
    548     setRate(up, uploaded_old);
    549     setRate(down, downloaded_old);
    550   }
    551 
    552   private void setRate(long val, long array[])
    553   {
    554     synchronized(array) {
    555       for (int i = RATE_DEPTH-1; i > 0; i--)
    556         array[i] = array[i-1];
    557       array[0] = val;
    558     }
     584    PeerCoordinator.setRate(up, uploaded_old);
     585    PeerCoordinator.setRate(down, downloaded_old);
    559586  }
    560587
     
    564591  public long getUploadRate()
    565592  {
    566     return getRate(uploaded_old);
     593    return PeerCoordinator.getRate(uploaded_old);
    567594  }
    568595
    569596  public long getDownloadRate()
    570597  {
    571     return getRate(downloaded_old);
    572   }
    573 
    574   private long getRate(long array[])
    575   {
    576     long rate = 0;
    577     int i = 0;
    578     synchronized(array) {
    579       for ( ; i < RATE_DEPTH; i++){
    580         if (array[i] < 0)
    581             break;
    582         rate += array[i];
    583       }
    584     }
    585     if (i == 0)
    586         return 0;
    587     return rate / (i * CHECK_PERIOD / 1000);
    588   }
    589 
     598    return PeerCoordinator.getRate(downloaded_old);
     599  }
    590600}
  • apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java

    r9b39f02 rbe308a0  
    5858  private long uploaded;
    5959  private long downloaded;
    60   final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long
    61   private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
    62   private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
     60  final static int RATE_DEPTH = 3; // make following arrays RATE_DEPTH long
     61  private long uploaded_old[] = {-1,-1,-1};
     62  private long downloaded_old[] = {-1,-1,-1};
    6363
    6464  // synchronize on this when changing peers or downloaders
     
    7979  private final CoordinatorListener listener;
    8080  public I2PSnarkUtil _util;
     81  private static final Random _random = I2PAppContext.getGlobalContext().random();
    8182 
    8283  public String trackerProblems = null;
     
    9899    // Randomize the first start time so multiple tasks are spread out,
    99100    // this will help the behavior with global limits
    100     Random r = I2PAppContext.getGlobalContext().random();
    101     timer.schedule(new PeerCheckerTask(_util, this), (CHECK_PERIOD / 2) + r.nextInt((int) CHECK_PERIOD), CHECK_PERIOD);
     101    timer.schedule(new PeerCheckerTask(_util, this), (CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD), CHECK_PERIOD);
    102102  }
    103103 
     
    106106  {
    107107    // Make a list of pieces
     108    // FIXME synchronize, clear and re-add instead?
     109    // Don't replace something we are synchronizing on.
    108110    wantedPieces = new ArrayList();
    109111    BitField bitfield = storage.getBitField();
    110     for(int i = 0; i < metainfo.getPieces(); i++)
    111       if (!bitfield.get(i))
    112         wantedPieces.add(new Piece(i));
    113     Collections.shuffle(wantedPieces);
     112    int[] pri = storage.getPiecePriorities();
     113    for(int i = 0; i < metainfo.getPieces(); i++) {
     114      // only add if we don't have and the priority is >= 0
     115      if ((!bitfield.get(i)) &&
     116          (pri == null || pri[i] >= 0)) {
     117        Piece p = new Piece(i);
     118        if (pri != null)
     119            p.setPriority(pri[i]);
     120        wantedPieces.add(p);
     121      }
     122    }
     123    Collections.shuffle(wantedPieces, _random);
    114124  }
    115125
     
    184194  }
    185195
    186   private static void setRate(long val, long array[])
     196  static void setRate(long val, long array[])
    187197  {
    188198    synchronized(array) {
     
    215225  }
    216226
    217   private long getRate(long array[])
     227  static long getRate(long array[])
    218228  {
    219229    long rate = 0;
    220230    int i = 0;
     231    int factor = 0;
    221232    synchronized(array) {
    222233      for ( ; i < RATE_DEPTH; i++) {
    223234        if (array[i] < 0)
    224235            break;
    225         rate += array[i];
     236        int f = RATE_DEPTH - i;
     237        rate += array[i] * f;
     238        factor += f;
    226239      }
    227240    }
    228241    if (i == 0)
    229242        return 0;
    230     return rate / (i * CHECK_PERIOD / 1000);
     243    return rate / (factor * CHECK_PERIOD / 1000);
    231244  }
    232245
     
    455468
    456469  /**
    457    * Returns true if we don't have the given piece yet.
     470   * @return true if we still want the given piece
    458471   */
    459472  public boolean gotHave(Peer peer, int piece)
     
    501514
    502515  /**
     516   *  Max number of peers to get a piece from when in end game
     517   *  @since 0.8.1
     518   */
     519  private static final int MAX_PARALLEL_REQUESTS = 4;
     520
     521  /**
    503522   * Returns one of pieces in the given BitField that is still wanted or
    504523   * -1 if none of the given pieces are wanted.
     
    521540          {
    522541            Piece p = it.next();
     542            // sorted by priority, so when we hit a disabled piece we are done
     543            if (p.isDisabled())
     544                break;
    523545            if (havePieces.get(p.getId()) && !p.isRequested())
    524546              {
     
    539561                return -1;  // nothing to request and not in end game
    540562            // let's not all get on the same piece
    541             Collections.shuffle(requested);
     563            // Even better would be to sort by number of requests
     564            Collections.shuffle(requested, _random);
    542565            Iterator<Piece> it2 = requested.iterator();
    543566            while (piece == null && it2.hasNext())
    544567              {
    545568                Piece p = it2.next();
    546                 if (havePieces.get(p.getId()))
    547                   {
     569                if (havePieces.get(p.getId())) {
     570                    // limit number of parallel requests
     571                    int requestedCount = 0;
     572                    synchronized(peers) {
     573                        for (Peer pr : peers) {
     574                            if (pr.isRequesting(p.getId())) {
     575                                if (pr.equals(peer)) {
     576                                    // don't give it to him again
     577                                    requestedCount = MAX_PARALLEL_REQUESTS;
     578                                    break;
     579                                }
     580                                if (++requestedCount >= MAX_PARALLEL_REQUESTS)
     581                                    break;
     582                            }
     583                        }
     584                    }
     585                    if (requestedCount >= MAX_PARALLEL_REQUESTS)
     586                        continue;
    548587                    piece = p;
    549                   }
     588                }
    550589              }
    551590            if (piece == null) {
     
    556595                return -1; //If we still can't find a piece we want, so be it.
    557596            } else {
    558                 // Should be a lot smarter here - limit # of parallel attempts and
     597                // Should be a lot smarter here -
    559598                // share blocks rather than starting from 0 with each peer.
    560599                // This is where the flaws of the snark data model are really exposed.
     
    564603            }
    565604        }
     605        if (_log.shouldLog(Log.DEBUG))
     606            _log.debug("Now requesting: piece " + piece + " priority " + piece.getPriority());
    566607        piece.setRequested(true);
    567608        return piece.getId();
     609      }
     610  }
     611
     612  /**
     613   *  Maps file priorities to piece priorities.
     614   *  Call after updating file priorities Storage.setPriority()
     615   *  @since 0.8.1
     616   */
     617  public void updatePiecePriorities() {
     618      int[] pri = storage.getPiecePriorities();
     619      if (pri == null) {
     620          _log.debug("Updated piece priorities called but no priorities to set?");
     621          return;
     622      }
     623      synchronized(wantedPieces) {
     624          // Add incomplete and previously unwanted pieces to the list
     625          // Temp to avoid O(n**2)
     626          BitField want = new BitField(pri.length);
     627          for (Piece p : wantedPieces) {
     628              want.set(p.getId());
     629          }
     630          BitField bitfield = storage.getBitField();
     631          for (int i = 0; i < pri.length; i++) {
     632              if (pri[i] >= 0 && !bitfield.get(i)) {
     633                  if (!want.get(i)) {
     634                      Piece piece = new Piece(i);
     635                      wantedPieces.add(piece);
     636                      // As connections are already up, new Pieces will
     637                      // not have their PeerID list populated, so do that.
     638                      synchronized(peers) {
     639                          for (Peer p : peers) {
     640                              PeerState s = p.state;
     641                              if (s != null) {
     642                                  BitField bf = s.bitfield;
     643                                  if (bf != null && bf.get(i))
     644                                      piece.addPeer(p);
     645                              }
     646                          }
     647                      }
     648                  }
     649              }
     650          }
     651          // now set the new priorities and remove newly unwanted pieces
     652          for (Iterator<Piece> iter = wantedPieces.iterator(); iter.hasNext(); ) {
     653               Piece p = iter.next();
     654               int priority = pri[p.getId()];
     655               if (priority >= 0) {
     656                   p.setPriority(priority);
     657               } else {
     658                   iter.remove();
     659                   // cancel all peers
     660                   synchronized(peers) {
     661                       for (Peer peer : peers) {
     662                           peer.cancel(p.getId());
     663                       }
     664                   }
     665               }
     666          }
     667          if (_log.shouldLog(Log.DEBUG))
     668              _log.debug("Updated piece priorities, now wanted: " + wantedPieces);
     669          // if we added pieces, they will be in-order unless we shuffle
     670          Collections.shuffle(wantedPieces, _random);
     671
     672          // update request queues, in case we added wanted pieces
     673          // and we were previously uninterested
     674          synchronized(peers) {
     675              for (Peer peer : peers) {
     676                  peer.request();
     677              }
     678          }
    568679      }
    569680  }
     
    633744            // No need to announce have piece to peers.
    634745            // Assume we got a good piece, we don't really care anymore.
    635             return true;
     746            // Well, this could be caused by a change in priorities, so
     747            // only return true if we already have it, otherwise might as well keep it.
     748            if (storage.getBitField().get(piece))
     749                return true;
    636750          }
    637751       
     
    640754            if (storage.putPiece(piece, bs))
    641755              {
    642                 _log.info("Got valid piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName());
     756                if (_log.shouldLog(Log.INFO))
     757                    _log.info("Got valid piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName());
    643758              }
    644759            else
  • apps/i2psnark/java/src/org/klomp/snark/PeerState.java

    r9b39f02 rbe308a0  
    5656
    5757  // Outstanding request
    58   private final List outstandingRequests = new ArrayList();
     58  private final List<Request> outstandingRequests = new ArrayList();
     59  /** the tail (NOT the head) of the request queue */
    5960  private Request lastRequest = null;
    60 
    61   // If we have te resend outstanding requests (true after we got choked).
    62   private boolean resend = false;
    6361
    6462  private final static int MAX_PIPELINE = 5;               // this is for outbound requests
     
    9290        _log.debug(peer + " rcv " + (choke ? "" : "un") + "choked");
    9391
     92    boolean resend = choked && !choke;
    9493    choked = choke;
    95     if (choked)
    96       resend = true;
    9794
    9895    listener.gotChoke(peer, choke);
    9996
    100     if (!choked && interesting)
    101       request();
     97    if (interesting && !choked)
     98      request(resend);
    10299  }
    103100
     
    279276  {
    280277    for (int i = 0; i < outstandingRequests.size(); i++)
    281       if (((Request)outstandingRequests.get(i)).piece == piece)
     278      if (outstandingRequests.get(i).piece == piece)
    282279        return i;
    283280    return -1;
     
    314311    synchronized(this)
    315312      {
    316         req = (Request)outstandingRequests.get(r);
     313        req = outstandingRequests.get(r);
    317314        while (req.piece == piece && req.off != begin
    318315               && r < outstandingRequests.size() - 1)
    319316          {
    320317            r++;
    321             req = (Request)outstandingRequests.get(r);
     318            req = outstandingRequests.get(r);
    322319          }
    323320       
     
    343340            for (int i = 0; i < r; i++)
    344341              {
    345                 Request dropReq = (Request)outstandingRequests.remove(0);
     342                Request dropReq = outstandingRequests.remove(0);
    346343                outstandingRequests.add(dropReq);
    347344                if (!choked)
     
    367364    Request req = null;
    368365    for (int i = 0; i < outstandingRequests.size(); i++) {
    369       Request r1 = (Request)outstandingRequests.get(i);
     366      Request r1 = outstandingRequests.get(i);
    370367      int j = getFirstOutstandingRequest(r1.piece);
    371368      if (j == -1)
    372369        continue;
    373       Request r2 = (Request)outstandingRequests.get(j);
     370      Request r2 = outstandingRequests.get(j);
    374371      if (r2.off > 0 && ((req == null) || (r2.off > req.off)))
    375372        req = r2;
     
    399396    Request req = null;
    400397    for (int i = 0; i < size; i++) {
    401       Request r1 = (Request)outstandingRequests.get(i);
     398      Request r1 = outstandingRequests.get(i);
    402399      if (pc != r1.piece) {
    403400        pc = r1.piece;
     
    424421  }
    425422
     423  /**
     424   *  We now have this piece.
     425   *  Tell the peer and cancel any requests for the piece.
     426   */
    426427  void havePiece(int piece)
    427428  {
     
    429430      _log.debug("Tell " + peer + " havePiece(" + piece + ")");
    430431
    431     synchronized(this)
    432       {
    433432        // Tell the other side that we are no longer interested in any of
    434433        // the outstanding requests for this piece.
     434    cancelPiece(piece);
     435
     436    // Tell the other side that we really have this piece.
     437    out.sendHave(piece);
     438   
     439    // Request something else if necessary.
     440    addRequest();
     441   
     442    synchronized(this)
     443      {
     444        // Is the peer still interesting?
     445        if (lastRequest == null)
     446          setInteresting(false);
     447      }
     448  }
     449
     450  /**
     451   * Tell the other side that we are no longer interested in any of
     452   * the outstanding requests (if any) for this piece.
     453   * @since 0.8.1
     454   */
     455  synchronized void cancelPiece(int piece) {
    435456        if (lastRequest != null && lastRequest.piece == piece)
    436457          lastRequest = null;
    437458       
    438         Iterator it = outstandingRequests.iterator();
     459        Iterator<Request> it = outstandingRequests.iterator();
    439460        while (it.hasNext())
    440461          {
    441             Request req = (Request)it.next();
     462            Request req = it.next();
    442463            if (req.piece == piece)
    443464              {
     
    448469              }
    449470          }
    450       }
    451    
    452     // Tell the other side that we really have this piece.
    453     out.sendHave(piece);
    454    
    455     // Request something else if necessary.
    456     addRequest();
    457    
    458     synchronized(this)
    459       {
    460         // Is the peer still interesting?
    461         if (lastRequest == null)
    462           setInteresting(false);
    463       }
    464   }
    465 
    466   // Starts or resumes requesting pieces.
    467   private void request()
     471  }
     472
     473  /**
     474   * Are we currently requesting the piece?
     475   * @since 0.8.1
     476   */
     477  synchronized boolean isRequesting(int piece) {
     478      for (Request req : outstandingRequests) {
     479          if (req.piece == piece)
     480              return true;
     481      }
     482      return false;
     483  }
     484
     485  /**
     486   * Starts or resumes requesting pieces.
     487   * @param resend should we resend outstanding requests?
     488   */
     489  private void request(boolean resend)
    468490  {
    469491    // Are there outstanding requests that have to be resend?
     
    473495            out.sendRequests(outstandingRequests);
    474496        }
    475         resend = false;
    476497      }
    477498
     
    482503  /**
    483504   * Adds a new request to the outstanding requests list.
    484    */
    485   synchronized private void addRequest()
     505   * Then send interested if we weren't.
     506   * Then send new requests if not choked.
     507   * If nothing to request, send not interested if we were.
     508   */
     509  synchronized void addRequest()
    486510  {
    487511    boolean more_pieces = true;
     
    527551   * Starts requesting first chunk of next piece. Returns true if
    528552   * something has been added to the requests, false otherwise.
     553   * Caller should synchronize.
    529554   */
    530555  private boolean requestNextPiece()
     
    554579        }
    555580        int nextPiece = listener.wantPiece(peer, bitfield);
    556         if (_log.shouldLog(Log.DEBUG))
    557           _log.debug(peer + " want piece " + nextPiece);
    558             if (nextPiece != -1
    559                 && (lastRequest == null || lastRequest.piece != nextPiece))
    560               {
     581        if (nextPiece != -1
     582            && (lastRequest == null || lastRequest.piece != nextPiece)) {
     583                if (_log.shouldLog(Log.DEBUG))
     584                    _log.debug(peer + " want piece " + nextPiece);
    561585                // Fail safe to make sure we are interested
    562586                // When we transition into the end game we may not be interested...
     
    585609                lastRequest = req;
    586610                return true;
    587               }
    588       }
    589 
     611          } else {
     612                if (_log.shouldLog(Log.DEBUG))
     613                    _log.debug(peer + " no more pieces to request");
     614          }
     615      }
     616
     617    // failsafe
     618    if (outstandingRequests.isEmpty())
     619        lastRequest = null;
     620
     621    // If we are not in the end game, we may run out of things to request
     622    // because we are asking other peers. Set not-interesting now rather than
     623    // wait for those other requests to be satisfied via havePiece()
     624    if (interesting && lastRequest == null) {
     625        interesting = false;
     626        out.sendInterest(false);
     627        if (_log.shouldLog(Log.DEBUG))
     628            _log.debug(peer + " nothing more to request, now uninteresting");
     629    }
    590630    return false;
    591631  }
     
    602642
    603643        if (interesting && !choked)
    604           request();
     644          request(true);  // we shouldnt have any pending requests, but if we do, resend them
    605645      }
    606646  }
     
    628668        out.retransmitRequests(outstandingRequests);
    629669  }
     670
     671  /**
     672   *  debug
     673   *  @return string or null
     674   *  @since 0.8.1
     675   */
     676  synchronized String getRequests() {
     677      if (outstandingRequests.isEmpty())
     678          return null;
     679      else
     680          return outstandingRequests.toString();
     681  }
    630682}
  • apps/i2psnark/java/src/org/klomp/snark/Piece.java

    r9b39f02 rbe308a0  
    22
    33import java.util.Collections;
    4 import java.util.HashSet;
    54import java.util.Set;
     5
     6import net.i2p.util.ConcurrentHashSet;
    67
    78public class Piece implements Comparable {
    89
    910    private int id;
    10     private Set peers;
     11    private Set<PeerID> peers;
    1112    private boolean requested;
     13    /** @since 0.8.1 */
     14    private int priority;
    1215   
    1316    public Piece(int id) {
    1417        this.id = id;
    15         this.peers = Collections.synchronizedSet(new HashSet());
    16         this.requested = false;
     18        this.peers = new ConcurrentHashSet();
    1719    }
    1820   
     21    /**
     22     *  Highest priority first,
     23     *  then rarest first
     24     */
    1925    public int compareTo(Object o) throws ClassCastException {
     26        int pdiff = ((Piece)o).priority - this.priority;   // reverse
     27        if (pdiff != 0)
     28            return pdiff;
    2029        return this.peers.size() - ((Piece)o).peers.size();
    2130    }
     
    3847   
    3948    public int getId() { return this.id; }
    40     public Set getPeers() { return this.peers; }
     49    /** @deprecated unused */
     50    public Set<PeerID> getPeers() { return this.peers; }
    4151    public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); }
    4252    public boolean removePeer(Peer peer) { return this.peers.remove(peer.getPeerID()); }
     
    4454    public void setRequested(boolean requested) { this.requested = requested; }
    4555   
     56    /** @return default 0 @since 0.8.1 */
     57    public int getPriority() { return this.priority; }
     58
     59    /** @since 0.8.1 */
     60    public void setPriority(int p) { this.priority = p; }
     61
     62    /** @since 0.8.1 */
     63    public boolean isDisabled() { return this.priority < 0; }
     64
     65    /** @since 0.8.1 */
     66    public void setDisabled() { this.priority = -1; }
     67
    4668    @Override
    4769    public String toString() {
  • apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java

    r9b39f02 rbe308a0  
    5555    public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
    5656    public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
     57    public static final String PROP_META_PRIORITY_SUFFIX = ".priority";
    5758
    5859    private static final String CONFIG_FILE = "i2psnark.config";
     
    511512                                            _peerCoordinatorSet, _connectionAcceptor,
    512513                                            false, dataDir.getPath());
     514                        loadSavedFilePriorities(torrent);
    513515                        torrent.completeListener = this;
    514516                        synchronized (_snarks) {
     
    589591   
    590592    /**
     593     * Get the saved priorities for a torrent from the config file.
     594     * @since 0.8.1
     595     */
     596    public void loadSavedFilePriorities(Snark snark) {
     597        MetaInfo metainfo = snark.meta;
     598        if (metainfo.getFiles() == null)
     599            return;
     600        byte[] ih = metainfo.getInfoHash();
     601        String infohash = Base64.encode(ih);
     602        infohash = infohash.replace('=', '$');
     603        String pri = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX);
     604        if (pri == null)
     605            return;
     606        int filecount = metainfo.getFiles().size();
     607        int[] rv = new int[filecount];
     608        String[] arr = pri.split(",");
     609        for (int i = 0; i < filecount && i < arr.length; i++) {
     610            if (arr[i].length() > 0) {
     611                try {
     612                    rv[i] = Integer.parseInt(arr[i]);
     613                } catch (Throwable t) {}
     614            }
     615        }
     616        snark.storage.setFilePriorities(rv);
     617    }
     618   
     619    /**
    591620     * Save the completion status of a torrent and the current time in the config file
    592621     * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield".
     
    596625     * The status is either a bitfield converted to Base64 or "." for a completed
    597626     * torrent to save space in the config file and in memory.
    598      */
    599     public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) {
     627     * @param priorities may be null
     628     */
     629    public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities) {
    600630        byte[] ih = metainfo.getInfoHash();
    601631        String infohash = Base64.encode(ih);
     
    610640        }
    611641        _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs);
     642
     643        // now the file priorities
     644        String prop = PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX;
     645        if (priorities != null) {
     646            boolean nonzero = false;
     647            for (int i = 0; i < priorities.length; i++) {
     648                if (priorities[i] != 0) {
     649                    nonzero = true;
     650                    break;
     651                }
     652            }
     653            if (nonzero) {
     654                // generate string like -5,,4,3,,,,,,-2 where no number is zero.
     655                StringBuilder buf = new StringBuilder(2 * priorities.length);
     656                for (int i = 0; i < priorities.length; i++) {
     657                    if (priorities[i] != 0)
     658                        buf.append(Integer.toString(priorities[i]));
     659                    if (i != priorities.length - 1)
     660                        buf.append(',');
     661                }
     662                _config.setProperty(prop, buf.toString());
     663            } else {
     664                _config.remove(prop);
     665            }
     666        } else {
     667            _config.remove(prop);
     668        }
     669
    612670        saveConfig();
    613671    }
     
    622680        infohash = infohash.replace('=', '$');
    623681        _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
     682        _config.remove(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX);
    624683        saveConfig();
    625684    }
     
    743802   
    744803    public void updateStatus(Snark snark) {
    745         saveTorrentStatus(snark.meta, snark.storage.getBitField());
     804        saveTorrentStatus(snark.meta, snark.storage.getBitField(), snark.storage.getFilePriorities());
    746805    }
    747806   
  • apps/i2psnark/java/src/org/klomp/snark/Storage.java

    r9b39f02 rbe308a0  
    4343  private long[] RAFtime;    // when was RAF last accessed, or 0 if closed
    4444  private File[] RAFfile;    // File to make it easier to reopen
     45  /** priorities by file; default 0; may be null. @since 0.8.1 */
     46  private int[] priorities;
    4547
    4648  private final StorageListener listener;
     
    229231    RAFtime = new long[size];
    230232    RAFfile = new File[size];
     233    priorities = new int[size];
     234
    231235
    232236    int i = 0;
     
    332336
    333337  /**
     338   *  @param file canonical path (non-directory)
     339   *  @since 0.8.1
     340   */
     341  public int getPriority(String file) {
     342      if (complete() || metainfo.getFiles() == null || priorities == null)
     343          return 0;
     344      for (int i = 0; i < rafs.length; i++) {
     345          File f = RAFfile[i];
     346          // use canonical in case snark dir or sub dirs are symlinked
     347          if (f != null) {
     348              try {
     349                  String canonical = f.getCanonicalPath();
     350                  if (canonical.equals(file))
     351                      return priorities[i];
     352              } catch (IOException ioe) {}
     353          }
     354      }
     355      return 0;
     356  }
     357
     358  /**
     359   *  Must call setPiecePriorities() after calling this
     360   *  @param file canonical path (non-directory)
     361   *  @param priority default 0; <0 to disable
     362   *  @since 0.8.1
     363   */
     364  public void setPriority(String file, int pri) {
     365      if (complete() || metainfo.getFiles() == null || priorities == null)
     366          return;
     367      for (int i = 0; i < rafs.length; i++) {
     368          File f = RAFfile[i];
     369          // use canonical in case snark dir or sub dirs are symlinked
     370          if (f != null) {
     371              try {
     372                  String canonical = f.getCanonicalPath();
     373                  if (canonical.equals(file)) {
     374                      priorities[i] = pri;
     375                      return;
     376                  }
     377              } catch (IOException ioe) {}
     378          }
     379      }
     380  }
     381
     382  /**
     383   *  Get the file priorities array.
     384   *  @return null on error, if complete, or if only one file
     385   *  @since 0.8.1
     386   */
     387  public int[] getFilePriorities() {
     388      return priorities;
     389  }
     390
     391  /**
     392   *  Set the file priorities array.
     393   *  Only call this when stopped, but after check()
     394   *  @param p may be null
     395   *  @since 0.8.1
     396   */
     397  void setFilePriorities(int[] p) {
     398      priorities = p;
     399  }
     400
     401  /**
     402   *  Call setPriority() for all changed files first,
     403   *  then call this.
     404   *  Set the piece priority to the highest priority
     405   *  of all files spanning the piece.
     406   *  Caller must pass array to the PeerCoordinator.
     407   *  @return null on error, if complete, or if only one file
     408   *  @since 0.8.1
     409   */
     410  public int[] getPiecePriorities() {
     411      if (complete() || metainfo.getFiles() == null || priorities == null)
     412          return null;
     413      int[] rv = new int[metainfo.getPieces()];
     414      int file = 0;
     415      long pcEnd = -1;
     416      long fileEnd = lengths[0] - 1;
     417      int psz = metainfo.getPieceLength(0);
     418      for (int i = 0; i < rv.length; i++) {
     419          pcEnd += psz;
     420          int pri = priorities[file];
     421          while (fileEnd <= pcEnd && file < lengths.length - 1) {
     422              file++;
     423              long oldFileEnd = fileEnd;
     424              fileEnd += lengths[file];
     425              if (priorities[file] > pri && oldFileEnd < pcEnd)
     426                  pri = priorities[file];
     427          }
     428          rv[i] = pri;
     429      }
     430      return rv;
     431  }
     432
     433  /**
    334434   * The BitField that tells which pieces this storage contains.
    335435   * Do not change this since this is the current state of the storage.
     
    437537      checkCreateFiles();
    438538    }
    439     if (complete())
     539    if (complete()) {
    440540        _util.debug("Torrent is complete", Snark.NOTICE);
    441     else
     541    } else {
     542        // fixme saved priorities
     543        if (files != null)
     544            priorities = new int[files.size()];
    442545        _util.debug("Still need " + needed + " out of " + metainfo.getPieces() + " pieces", Snark.NOTICE);
     546    }
    443547  }
    444548
     
    566670          synchronized(RAFlock[i]) {
    567671              allocateFile(i);
     672              // close as we go so we don't run out of file descriptors
     673              try {
     674                  closeRAF(i);
     675              } catch (IOException ioe) {}
    568676          }
    569677        } else {
     
    574682              checkRAF(i);
    575683              rafs[i].setLength(lengths[i]);
    576           }
    577           // will be closed below
     684              try {
     685                  closeRAF(i);
     686              } catch (IOException ioe) {}
     687          }
    578688        }
    579689      }
     
    584694        pieces = metainfo.getPieces();
    585695        byte[] piece = new byte[metainfo.getPieceLength(0)];
     696        int file = 0;
     697        long fileEnd = lengths[0];
     698        long pieceEnd = 0;
    586699        for (int i = 0; i < pieces; i++)
    587700          {
    588701            int length = getUncheckedPiece(i, piece);
    589702            boolean correctHash = metainfo.checkPiece(i, piece, 0, length);
     703            // close as we go so we don't run out of file descriptors
     704            pieceEnd += length;
     705            while (fileEnd <= pieceEnd) {
     706                synchronized(RAFlock[file]) {
     707                    try {
     708                        closeRAF(file);
     709                    } catch (IOException ioe) {}
     710                }
     711                if (++file >= rafs.length)
     712                    break;
     713                fileEnd += lengths[file];
     714            }
    590715            if (correctHash)
    591716              {
     
    602727    // close all the files so we don't end up with a zillion open ones;
    603728    // we will reopen as needed
    604     for (int i = 0; i < rafs.length; i++) {
    605       synchronized(RAFlock[i]) {
    606         try {
    607           closeRAF(i);
    608         } catch (IOException ioe) {}
    609       }
    610     }
     729    // Now closed above to avoid running out of file descriptors
     730    //for (int i = 0; i < rafs.length; i++) {
     731    //  synchronized(RAFlock[i]) {
     732    //    try {
     733    //      closeRAF(i);
     734    //    } catch (IOException ioe) {}
     735    //  }
     736    //}
    611737
    612738    if (listener != null) {
     
    617743  }
    618744
     745  /** this calls openRAF(); caller must synnchronize and call closeRAF() */
    619746  private void allocateFile(int nr) throws IOException
    620747  {
     
    625752    listener.storageCreateFile(this, names[nr], lengths[nr]);
    626753    final int ZEROBLOCKSIZE = metainfo.getPieceLength(0);
    627     byte[] zeros = new byte[ZEROBLOCKSIZE];
     754    byte[] zeros;
     755    try {
     756        zeros = new byte[ZEROBLOCKSIZE];
     757    } catch (OutOfMemoryError oom) {
     758        throw new IOException(oom.toString());
     759    }
    628760    int i;
    629761    for (i = 0; i < lengths[nr]/ZEROBLOCKSIZE; i++)
  • apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java

    r9b39f02 rbe308a0  
    267267                        // from them (duh)
    268268                        List ordered = new ArrayList(peers);
    269                         Collections.shuffle(ordered);
     269                        Collections.shuffle(ordered, r);
    270270                        Iterator it = ordered.iterator();
    271                         while (it.hasNext()) {
     271                        while ((!stop) && it.hasNext()) {
    272272                          Peer cur = (Peer)it.next();
    273273                          // FIXME if id == us || dest == us continue;
     
    358358      + "&downloaded=" + downloaded
    359359      + "&left=" + left
    360       + "&compact"
     360      + "&compact=1"   // NOTE: opentracker will return 400 for &compact alone
    361361      + ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
    362362    if (left <= 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
  • apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java

    r9b39f02 rbe308a0  
    134134                String pathInfo = req.getPathInfo();
    135135                String pathInContext = URI.addPaths(path, pathInfo);
     136                req.setCharacterEncoding("UTF-8");
    136137                resp.setCharacterEncoding("UTF-8");
    137138                resp.setContentType("text/html; charset=UTF-8");
     
    141142                } else {
    142143                    String base = URI.addPaths(req.getRequestURI(), "/");
    143                     String listing = getListHTML(resource, base, true);
     144                    String listing = getListHTML(resource, base, true, method.equals("POST") ? req.getParameterMap() : null);
    144145                    if (listing != null)
    145146                        resp.getWriter().write(listing);
     
    242243        out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/status.png\"");
    243244        out.write(" title=\"");
    244         out.write(_("Torrent Status"));
     245        out.write(_("Status"));
    245246        out.write("\">");
    246247        out.write(_("Status"));
     
    250251            if (peerParam != null) {
    251252                out.write("\">");
    252         out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/showpeers.png\" title=\"");
    253         out.write(_("Toggle Peer Visibility"));
    254         out.write("\" alt=\"");
    255         out.write(_("Hide Peers"));
    256         out.write("\">");
     253                out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/showpeers.png\" title=\"");
     254                out.write(_("Hide Peers"));
     255                out.write("\" alt=\"");
     256                out.write(_("Hide Peers"));
     257                out.write("\">");
    257258            } else {
    258259                out.write("?p=1\">");
    259         out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/hidepeers.png\" title=\"");
    260         out.write(_("Toggle Peer Visibility"));
    261         out.write("\" alt=\"");
    262         out.write(_("Show Peers"));
    263         out.write("\">");
     260                out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/hidepeers.png\" title=\"");
     261                out.write(_("Show Peers"));
     262                out.write("\" alt=\"");
     263                out.write(_("Show Peers"));
     264                out.write("\">");
    264265            }
    265266            out.write("</a><br>\n");
     
    267268        out.write("</th>\n<th align=\"left\">");
    268269        out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/torrent.png\" title=\"");
    269         out.write(_("Loaded Torrents"));
     270        out.write(_("Torrent"));
    270271        out.write("\">");
    271272        out.write(_("Torrent"));
     
    277278        out.write("</th>\n<th align=\"center\">");
    278279        out.write("<img border=\"0\" src=\"/themes/console/images/inbound.png\" title=\"");
    279         out.write(_("Data Downloaded"));
     280        out.write(_("Downloaded"));
    280281        out.write("\">");
    281282        out.write(_("RX"));
    282283        out.write("</th>\n<th align=\"center\">");
    283284        out.write("<img border=\"0\" src=\"/themes/console/images/outbound.png\" title=\"");
    284         out.write(_("Data Uploaded"));
     285        out.write(_("Uploaded"));
    285286        out.write("\">");
    286287        out.write(_("TX"));
    287288        out.write("</th>\n<th align=\"center\">");
    288289        out.write("<img border=\"0\" src=\"/themes/console/images/inbound.png\" title=\"");
    289         out.write(_("Download Speed"));
     290        out.write(_("Down Rate"));
    290291        out.write("\">Rate");
    291292        out.write("</th>\n<th align=\"center\">");
    292293        out.write("<img border=\"0\" src=\"/themes/console/images/outbound.png\" title=\"");
    293         out.write(_("Upload Speed"));
     294        out.write(_("Up Rate"));
    294295        out.write("\">");
    295296        out.write(_("Rate"));
     
    302303            out.write("\">");
    303304            out.write("<img src=\"/themes/snark/ubergine/images/stop_all.png\" title=\"");
    304             out.write(_("Stop All Torrents"));
     305            out.write(_("Stop all torrents and the I2P tunnel"));
    305306            out.write("\" alt=\"");
    306307            out.write(_("Stop All"));
     
    313314            out.write("\">");
    314315            out.write("<img src=\"/themes/snark/ubergine/images/start_all.png\" title=\"");
    315             out.write(_("Start All Torrents"));
     316            out.write(_("Start all torrents and the I2P tunnel"));
    316317            out.write("\" alt=\"Start All\">");
    317318            out.write("</a>");
     
    538539                        if (torrentFile.exists())
    539540                            throw new IOException("Cannot overwrite an existing .torrent file: " + torrentFile.getPath());
    540                         _manager.saveTorrentStatus(info, s.getBitField()); // so addTorrent won't recheck
     541                        _manager.saveTorrentStatus(info, s.getBitField(), null); // so addTorrent won't recheck
    541542                        // DirMonitor could grab this first, maybe hold _snarks lock?
    542543                        FileOutputStream out = new FileOutputStream(torrentFile);
     
    565566            }
    566567            if (_manager.util().connected()) {
     568                // Give the stopped announces time to get out
     569                try { Thread.sleep(2000); } catch (InterruptedException ie) {}
    567570                _manager.util().disconnect();
    568571                _manager.addMessage(_("I2P tunnel closed."));
     
    719722                               ngettext("1 peer", "{0} peers", knownPeers)  + "</a>";
    720723            else
    721                 statusString = "<img border=\"0\" src=\"/themes/snark/ubergine/images/complete.png\" title=\"" + _("Complete") + "\">" + _("Not Seeding");
     724                statusString = "<img border=\"0\" src=\"/themes/snark/ubergine/images/complete.png\" title=\"" + _("Complete") + "\">" + _("Complete");
    722725        } else {
    723726            if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
     
    728731            else if (isRunning && curPeers > 0 && downBps > 0)
    729732                statusString = "<img border=\"0\" src=\"/themes/snark/ubergine/images/downloading.png\" title=\"" + _("Downloading") + "\">" +
    730   " (" + curPeers + "/" +
     733                              curPeers + "/" +
    731734                               ngettext("1 peer", "{0} peers", knownPeers);
    732735            else if (isRunning && curPeers > 0 && !showPeers)
     
    791794                out.write("&nbsp;<a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash=");
    792795                out.write(TrackerClient.urlencode(snark.meta.getInfoHash()));
    793                 out.write("\" title=\"" + name + _("Tracker") + "\" target=\"_blank\">");
     796                out.write("\" title=\"" + name + ' ' + _("Tracker") + "\" target=\"_blank\">");
    794797                out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/details.png\">");
    795798                out.write("</a>");
     
    805808        out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
    806809        if (remaining > 0)
    807             out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB
     810            out.write(formatSize(total-remaining) + "&thinsp;/&thinsp;" + formatSize(total)); // 18MB/3GB; thin space so it will line break well
    808811        else
    809812            out.write(formatSize(total)); // 3GB
     
    829832            out.write("\">");
    830833            out.write("<img src=\"/themes/snark/ubergine/images/stop.png\" title=\"");
    831             out.write(_("Stop Torrent"));
     834            out.write(_("Stop"));
    832835            out.write("\" alt=\"");
    833836            out.write(_("Stop"));
     
    841844                out.write("\">");
    842845                out.write("<img src=\"/themes/snark/ubergine/images/start.png\" title=\"");
    843                 out.write(_("Start Torrent"));
     846                out.write(_("Start the torrent"));
    844847                out.write("\" alt=\"");
    845848                out.write(_("Start"));
     
    857860            out.write("')) { return false; }\">");
    858861            out.write("<img src=\"/themes/snark/ubergine/images/remove.png\" title=\"");
    859             out.write(_("Remove Torrent"));
     862            out.write(_("Remove"));
    860863            out.write("\" alt=\"");
    861864            out.write(_("Remove"));
     
    872875            out.write("')) { return false; }\">");
    873876            out.write("<img src=\"/themes/snark/ubergine/images/delete.png\" title=\"");
    874             out.write(_("Delete Torrent + Data"));
     877            out.write(_("Delete"));
    875878            out.write("\" alt=\"");
    876879            out.write(_("Delete"));
     
    10081011        out.write("\" name=\"foo\" ><br>\n");
    10091012        out.write("<tr><td>&nbsp;<td><span class=\"snarkAddInfo\">");
    1010         out.write(_("You can also copy .torrent files to: {0}.", "<code>" + _manager.getDataDir().getAbsolutePath ())) + "</code>";
     1013        out.write(_("You can also copy .torrent files to: {0}.", "<code>" + _manager.getDataDir().getAbsolutePath () + "</code>"));
    10111014        out.write("\n");
    10121015        out.write(_("Removing a .torrent will cause it to stop."));
     
    12631266    private static String formatSize(long bytes) {
    12641267        if (bytes < 5*1024)
    1265             return bytes + " B";
     1268            return bytes + "&nbsp;B";
    12661269        else if (bytes < 5*1024*1024)
    1267             return ((bytes + 512)/1024) + " KB";
     1270            return ((bytes + 512)/1024) + "&nbsp;KB";
    12681271        else if (bytes < 10*1024*1024*1024l)
    1269             return ((bytes + 512*1024)/(1024*1024)) + " MB";
     1272            return ((bytes + 512*1024)/(1024*1024)) + "&nbsp;MB";
    12701273        else
    1271             return ((bytes + 512*1024*1024)/(1024*1024*1024)) + " GB";
     1274            return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "&nbsp;GB";
    12721275    }
    12731276   
     
    12751278    private static String urlify(String s) {
    12761279        StringBuilder buf = new StringBuilder(256);
    1277         buf.append("<a href=\"").append(s).append("\">").append(s).append("</a>");
     1280        // browsers seem to work without doing this but let's be strict
     1281        String link = s.replace("&", "&amp;");
     1282        buf.append("<a href=\"").append(link).append("\">").append(link).append("</a>");
    12781283        return buf.toString();
    12791284    }
     
    13141319     * @param base The base URL
    13151320     * @param parent True if the parent directory should be included
     1321     * @param postParams map of POST parameters or null if not a POST
    13161322     * @return String of HTML
    13171323     * @since 0.7.14
    13181324     */
    1319     private String getListHTML(Resource r, String base, boolean parent)
     1325    private String getListHTML(Resource r, String base, boolean parent, Map postParams)
    13201326        throws IOException
    13211327    {
     
    13421348            torrentName = title;
    13431349        Snark snark = _manager.getTorrentByBaseName(torrentName);
     1350
     1351        if (snark != null && postParams != null)
     1352            savePriorities(snark, postParams);
     1353
    13441354        if (title.endsWith("/"))
    13451355            title = title.substring(0, title.length() - 1);
     
    13481358        buf.append("</TITLE>").append(HEADER).append("<link rel=\"shortcut icon\" href=\"/themes/snark/ubergine/favicon.ico\"></HEAD><BODY>\n<center><div class=\"snarknavbar\"> <a href=\"/i2psnark/\" title=\"Torrents\"");
    13491359        buf.append(" class=\"snarkRefresh\">I2PSnark</a>").append("</div>");
    1350        
    1351         buf.append("<div class=\"page\"><div class=\"mainsection\">" +
    1352                    "<TABLE BORDER=0 class=\"snarkTorrents\" cellpadding=\"5px 10px\">" +
     1360       
     1361        if (parent)
     1362        {
     1363            buf.append("\n<br><A HREF=\"");
     1364            // corrupts utf-8
     1365            //buf.append(URI.encodePath(URI.addPaths(base,"../")));
     1366            buf.append(URI.addPaths(base,"../"));
     1367            buf.append("\"><img border=\"0\" src=\"/themes/console/images/outbound.png\"> ")
     1368               .append(_("Up to higher level directory")).append("</A>\n");
     1369        }
     1370       
     1371        buf.append("</div><div class=\"page\"><div class=\"mainsection\">");
     1372        boolean showPriority = snark != null && !snark.storage.complete();
     1373        if (showPriority)
     1374            buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
     1375        buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" cellpadding=\"5px 10px\">" +
    13531376                   "<thead><tr><th>").append("<img border=\"0\" src=\"/themes/snark/ubergine/images/file.png\" title=\"").append(_("File")).append("\" alt=\"").append(_("File")).append("\">&nbsp;").append(title).append("</th><th align=\"right\">").append("<img border=\"0\" src=\"/themes/snark/ubergine/images/size.png\" title=\"").append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">").append(_("Size"));
    1354           buf.append("</th><th>").append("<img border=\"0\" src=\"/themes/snark/ubergine/images/status.png\" title=\"").append(_("Download Status")).append("\">").append(_("Status")).append("</th></tr></thead>");
     1377        buf.append("</th><th>").append("<img border=\"0\" src=\"/themes/snark/ubergine/images/status.png\" title=\"").append(_("Download Status")).append("\">").append(_("Status")).append("</th>");
     1378        if (showPriority)
     1379            buf.append("<th>").append(_("Priority")).append("</th>");
     1380        buf.append("</tr></thead>\n");
    13551381        //DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
    13561382        //                                               DateFormat.MEDIUM);
     1383        boolean showSaveButton = false;
    13571384        for (int i=0 ; i< ls.length ; i++)
    13581385        {   
     
    13921419                                status = toImg("tick") + _("Complete");
    13931420                            } else {
    1394                                 status = toImg("clock") +
     1421                                status =
     1422                                         (snark.storage.getPriority(f.getCanonicalPath()) < 0 ? toImg("cancel") : toImg("clock")) +
    13951423                                         (100 * (length - remaining) / length) + "% " + _("complete") +
    13961424                                         " (" + DataHelper.formatSize2(remaining) + _("bytes remaining") + ")";
     
    14361464            //buf.append(dfmt.format(new Date(item.lastModified())));
    14371465            buf.append(status);
    1438             buf.append("</TD></TR>\n");
    1439         }
    1440 
    1441             if (parent)
    1442         {
    1443             buf.append("<tfoot align=\"left\"><tr><td colspan=\"3\"><A HREF=\"");
    1444             // corrupts utf-8
    1445             //buf.append(URI.encodePath(URI.addPaths(base,"../")));
    1446             buf.append(URI.addPaths(base,"../"));
    1447             buf.append("\"><img border=\"0\" src=\"/themes/snark/ubergine/images/up.png\"> ")
    1448                .append(_("Up to higher level directory")).append("</A></td></tr></thead>\n");
    1449         }
    1450 
    1451 
     1466            buf.append("</TD>");
     1467            if (showPriority) {
     1468                buf.append("<td>");
     1469                File f = item.getFile();
     1470                if ((!complete) && (!item.isDirectory()) && f != null) {
     1471                    int pri = snark.storage.getPriority(f.getCanonicalPath());
     1472                    buf.append("<input type=\"radio\" value=\"5\" name=\"pri.").append(f.getCanonicalPath()).append("\" ");
     1473                    if (pri > 0)
     1474                        buf.append("checked=\"true\"");
     1475                    buf.append('>').append(_("High"));
     1476
     1477                    buf.append("<input type=\"radio\" value=\"0\" name=\"pri.").append(f.getCanonicalPath()).append("\" ");
     1478                    if (pri == 0)
     1479                        buf.append("checked=\"true\"");
     1480                    buf.append('>').append(_("Normal"));
     1481
     1482                    buf.append("<input type=\"radio\" value=\"-9\" name=\"pri.").append(f.getCanonicalPath()).append("\" ");
     1483                    if (pri < 0)
     1484                        buf.append("checked=\"true\"");
     1485                    buf.append('>').append(_("Do not download"));
     1486                    showSaveButton = true;
     1487                }
     1488                buf.append("</td>");
     1489            }
     1490            buf.append("</TR>\n");
     1491        }
     1492        if (showSaveButton) {
     1493            buf.append("<thead><tr><th colspan=\"3\">&nbsp;</th><th align=\"center\"><input type=\"submit\" value=\"");
     1494            buf.append(_("Save priorities"));
     1495            buf.append("\" name=\"foo\" ></th></tr></thead>\n");
     1496        }
    14521497        buf.append("</TABLE>\n");
    1453 buf.append("</div></div></center></BODY></HTML>\n");
     1498        if (showPriority)
     1499            buf.append("</form>");
     1500        buf.append("</div></div></BODY></HTML>\n");
    14541501       
    14551502        return buf.toString();
     
    15161563    }
    15171564
     1565    /** @since 0.8.1 */
     1566    private void savePriorities(Snark snark, Map postParams) {
     1567        Set<Map.Entry> entries = postParams.entrySet();
     1568        for (Map.Entry entry : entries) {
     1569            String key = (String)entry.getKey();
     1570            if (key.startsWith("pri.")) {
     1571                try {
     1572                    String file = key.substring(4);
     1573                    String val = ((String[])entry.getValue())[0];   // jetty arrays
     1574                    int pri = Integer.parseInt(val);
     1575                    snark.storage.setPriority(file, pri);
     1576                    //System.err.println("Priority now " + pri + " for " + file);
     1577                } catch (Throwable t) { t.printStackTrace(); }
     1578            }
     1579        }
     1580        if (snark.coordinator != null)
     1581            snark.coordinator.updatePiecePriorities();
     1582        _manager.saveTorrentStatus(snark.storage.getMetaInfo(), snark.storage.getBitField(), snark.storage.getFilePriorities());
     1583    }
     1584
    15181585
    15191586/** inner class, don't bother reindenting */
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java

    r9b39f02 rbe308a0  
    176176   
    177177    public String getAccessList(int tunnel) {
    178         return getProperty(tunnel, "i2cp.accessList", "").replaceAll(",", "\n");
     178        return getProperty(tunnel, "i2cp.accessList", "").replace(",", "\n");
    179179    }
    180180   
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java

    r9b39f02 rbe308a0  
    667667    public void setAccessList(String val) {
    668668        if (val != null)
    669             _otherOptions.put("i2cp.accessList", val.trim().replaceAll("\r\n", ",").replaceAll("\n", ",").replaceAll(" ", ","));
     669            _otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
    670670    }
    671671    public void setCloseTime(String val) {
  • apps/i2ptunnel/jsp/editClient.jsp

    r9b39f02 rbe308a0  
    160160                </label>
    161161                <input type="text" size="30" id="targetDestination" name="targetDestination" title="Destination of the Tunnel" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext" />               
    162                 <span class="comment">(<%=intl._("name or destination")%>)</span>
     162                <span class="comment">(<%=intl._("name or destination")%>; <%=intl._("b32 not recommended")%>)</span>
    163163            </div>
    164164         <% } %>
  • apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java

    r9b39f02 rbe308a0  
    4646    private I2PSocket _socket;
    4747   
     48    /** from ConnectionOptions */
     49    private static final String PROP_CONNECT_DELAY = "i2p.streaming.connectDelay";
     50    private static final String CONNECT_DELAY = "500";
     51
    4852    public I2PSocketEepGet(I2PAppContext ctx, I2PSocketManager mgr, int numRetries, String outputFile, String url) {
    4953        this(ctx, mgr, numRetries, -1, -1, outputFile, null, url);
     
    124128                props.setProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT, "" + CONNECT_TIMEOUT);
    125129                props.setProperty(I2PSocketOptions.PROP_READ_TIMEOUT, "" + INACTIVITY_TIMEOUT);
     130                // This is important - even if the underlying socket doesn't have a connect delay,
     131                // we want to set it for this connection, so the request headers will go out
     132                // in the SYN packet, saving one RTT.
     133                props.setProperty(PROP_CONNECT_DELAY, CONNECT_DELAY);
    126134                I2PSocketOptions opts = _socketManager.buildOptions(props);
    127135                _socket = _socketManager.connect(dest, opts);
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java

    r9b39f02 rbe308a0  
    2525        int bytes = _context.logManager().getFileSize();
    2626        if (bytes <= 0) return "1.00 MB";
    27         return DataHelper.formatSize2(bytes) + 'B';
     27        // "&nbsp;" comes back in the POST as 0xc2 0xa0
     28        // non-breaking space is U+00A0 which is 0xc2 0xa0 in UTF-8.
     29        // we could figure out where the UTF-8 problem is but why bother.
     30        return DataHelper.formatSize2(bytes).replace("&nbsp;", " ") + 'B';
    2831    }
    2932    public String getLogLevelTable() {
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java

    r9b39f02 rbe308a0  
    143143
    144144        if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
    145             _updateURL = _updateURL.replaceAll("\r\n", ",").replaceAll("\n", ",");
     145            _updateURL = _updateURL.replace("\r\n", ",").replace("\n", ",");
    146146            String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
    147147            if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
     
    152152
    153153        if ( (_trustedKeys != null) && (_trustedKeys.length() > 0) ) {
    154             _trustedKeys = _trustedKeys.replaceAll("\r\n", ",").replaceAll("\n", ",");
     154            _trustedKeys = _trustedKeys.replace("\r\n", ",").replace("\n", ",");
    155155            String oldKeys = new TrustedUpdate(_context).getTrustedKeysString();
    156156            if ( (oldKeys == null) || (!_trustedKeys.equals(oldKeys)) ) {
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java

    r9b39f02 rbe308a0  
    4141        String url = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL);
    4242        if (url != null)
    43             return url.replaceAll(",", "\n");
     43            return url.replace(",", "\n");
    4444        else
    4545            return ConfigUpdateHandler.DEFAULT_UPDATE_URL;
  • apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java

    r9b39f02 rbe308a0  
    3232        String str = FileUtil.readTextFile(f.getAbsolutePath(), 250, false);
    3333        if (str == null)
    34             return "";
     34            return _("File not found") + ": <b><code>" + f.getAbsolutePath() + "</code></b>";
    3535        else {
    36             str = str.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
     36            str = str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    3737            return _("File location") + ": <b><code>" + f.getAbsolutePath() + "</code></b> <pre>" + str + "</pre>";
    3838        }
     
    5555        for (int i = msgs.size(); i > 0; i--) {
    5656            String msg = msgs.get(i - 1);
     57            msg = msg.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    5758            buf.append("<li>");
    5859            if (colorize) {
     
    6162                // http://www.dhs.gov/xinfoshare/programs/Copy_of_press_release_0046.shtm
    6263                // but pink instead of yellow for WARN
     64                // FIXME doesnt work for translated levels
    6365                if (msg.contains("CRIT"))
    6466                    color = "#cc0000";
     
    7274                    color = "#006600";
    7375                buf.append("<font color=\"").append(color).append("\">");
    74                 buf.append(msg.replaceAll("<", "&lt;").replaceAll(">", "&gt;"));
     76                buf.append(msg);
    7577                buf.append("</font>");
    7678            } else {
  • apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java

    r9b39f02 rbe308a0  
    113113                lifetime = 10*60;
    114114            int bps = 1024 * (int) cfg.getProcessedMessagesCount() / lifetime;
    115             out.write("<td class=\"cells\" align=\"center\">" + bps + "Bps</td>");
     115            out.write("<td class=\"cells\" align=\"center\">" + bps + " Bps</td>");
    116116            if (cfg.getSendTo() == null)
    117117                out.write("<td class=\"cells\" align=\"center\">" + _("Outbound Endpoint") + "</td>");
  • apps/routerconsole/locale/messages_de.po

    r9b39f02 rbe308a0  
    1616"Content-Type: text/plain; charset=UTF-8\n"
    1717"Content-Transfer-Encoding: 8bit\n"
     18"Plural-Forms: nplurals=2; plural=(n != 1)\n"
    1819"X-Poedit-Language: German\n"
    1920
  • apps/routerconsole/locale/messages_fr.po

    r9b39f02 rbe308a0  
    1616"Content-Type: text/plain; charset=UTF-8\n"
    1717"Content-Transfer-Encoding: 8bit\n"
    18 "X-Poedit-Language: German\n"
    19 "X-Poedit-Basepath: /home/lee/work/i2p/monotone/i2p.i2p/apps/routerconsole/java\n"
     18"X-Poedit-Language: French\n"
     19"Plural-Forms: nplurals=2; plural=(n != 1)\n"
    2020
    2121#: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/config_jsp.java:106
  • apps/routerconsole/locale/messages_nl.po

    r9b39f02 rbe308a0  
    1616"Content-Type: text/plain; charset=UTF-8\n"
    1717"Content-Transfer-Encoding: 8bit\n"
     18"Plural-Forms: nplurals=2; plural=(n != 1)\n"
    1819"X-Poedit-Language: Dutch\n"
    1920
  • apps/streaming/java/src/net/i2p/client/streaming/ConnectionOptions.java

    r9b39f02 rbe308a0  
    4747    private int _maxTotalConnsPerHour;
    4848    private int _maxTotalConnsPerDay;
     49
     50    // NOTE - almost all the options are below, but see
     51    // I2PSocketOptions in ministreaming for a few more
    4952
    5053    public static final int PROFILE_BULK = 1;
  • apps/systray/java/src/net/i2p/apps/systray/SysTray.java

    r9b39f02 rbe308a0  
    185185        refreshDisplay();
    186186    }
     187
     188    /**
     189     *  Starts SysTray, even on linux (but requires kde3 libsystray4j.so to do anything)
     190     *  @since 0.8.1
     191     */
     192    public static void main(String args[]) {
     193        System.err.println("SysTray4j version " + SysTrayMenu.VERSION);
     194        System.err.println("Hit ^C to exit");
     195        new SysTray();
     196        Thread t = Thread.currentThread();
     197        synchronized(t) {
     198            try {
     199                t.wait();
     200            } catch (InterruptedException ie) {}
     201        }
     202    }
    187203}
  • build.xml

    r9b39f02 rbe308a0  
    66    <!--
    77        <property name="javac.compilerargs" value="-warn:-unchecked,raw,unused,serial" />
     8    -->
     9    <!-- Add Apache Harmony's Pack200 library if you don't have java.util.jar.Pack200
     10         See core/java/src/net/i2p/util/FileUtil.java for code changes required
     11         to use this library instead of Sun's version.
     12         Or to comment it all out if you don't have either.
     13    -->
     14    <!--
     15        <property name="javac.classpath" value="/PATH/TO/pack200.jar" />
    816    -->
    917
  • core/java/build.xml

    r9b39f02 rbe308a0  
    1818    <!-- only used if not set by a higher build.xml -->
    1919    <property name="javac.compilerargs" value="" />
     20    <property name="javac.classpath" value="" />
    2021    <target name="compile" depends="depend">
    2122        <mkdir dir="./build" />
    2223        <mkdir dir="./build/obj" />
    23         <javac srcdir="./src" debug="true" source="1.5" target="1.5" deprecation="on" destdir="./build/obj" >
     24        <javac srcdir="./src" debug="true" source="1.5" target="1.5" deprecation="on" destdir="./build/obj" classpath="${javac.classpath}" >
    2425            <compilerarg line="${javac.compilerargs}" />
    2526        </javac>
  • core/java/src/net/i2p/data/DataHelper.java

    r9b39f02 rbe308a0  
    10771077   
    10781078    /**
    1079      * Like formatSize but with a space after the number
     1079     * Like formatSize but with a non-breaking space after the number
     1080     * Use only in HTML
    10801081     * @since 0.7.14
    10811082     */
     
    10921093        String str = fmt.format(val);
    10931094        switch (scale) {
    1094             case 1: return str + " K";
    1095             case 2: return str + " M";
    1096             case 3: return str + " G";
    1097             case 4: return str + " T";
    1098             default: return bytes + " ";
     1095            case 1: return str + "&nbsp;K";
     1096            case 2: return str + "&nbsp;M";
     1097            case 3: return str + "&nbsp;G";
     1098            case 4: return str + "&nbsp;T";
     1099            default: return bytes + "&nbsp;";
    10991100        }
    11001101    }
  • core/java/src/net/i2p/util/FileUtil.java

    r9b39f02 rbe308a0  
    1414import java.util.List;
    1515import java.util.jar.JarOutputStream;
    16 import java.util.jar.Pack200;
    1716import java.util.zip.ZipEntry;
    1817import java.util.zip.ZipFile;
    1918
     19// Pack200 import
     20// you must also uncomment the correct line in unpack() below
     21// For gcj, gij, etc., comment both out
     22//
     23// For Sun, OpenJDK, IcedTea, etc, use this
     24import java.util.jar.Pack200;
     25
     26// For Apache Harmony or if you put its pack200.jar in your library directory use this
     27//import org.apache.harmony.unpack200.Archive;
    2028
    2129/**
     
    120128                            target = new File(targetDir, entry.getName().substring(0, entry.getName().length() - ".pack".length()));
    121129                            JarOutputStream fos = new JarOutputStream(new FileOutputStream(target));
    122                             Pack200.newUnpacker().unpack(in, fos);
     130                            unpack(in, fos);
    123131                            fos.close();
    124132                            System.err.println("INFO: File [" + entry.getName() + "] extracted and unpacked");
     
    190198                    if (p200TestRequired &&
    191199                        (entry.getName().endsWith(".jar.pack") || entry.getName().endsWith(".war.pack"))) {
    192                         try {
    193                             Class.forName("java.util.jar.Pack200", false, ClassLoader.getSystemClassLoader());
    194                         } catch (Exception e) {  // ClassNotFoundException but compiler not happy with that
     200                        if (!isPack200Supported()) {
    195201                            System.err.println("ERROR: Zip verify failed, your JVM does not support unpack200");
    196202                            return false;
     
    226232   
    227233    /**
     234     * This won't work right if one of the two options in unpack() is commented out.
     235     * @since 0.8.1
     236     */
     237    private static boolean isPack200Supported() {
     238        try {
     239            Class.forName("java.util.jar.Pack200", false, ClassLoader.getSystemClassLoader());
     240            return true;
     241        } catch (Exception e) {}
     242        try {
     243            Class.forName("org.apache.harmony.pack200.Archive", false, ClassLoader.getSystemClassLoader());
     244            return true;
     245        } catch (Exception e) {}
     246        return false;
     247    }
     248
     249    /**
     250     * Caller must close streams
     251     * @since 0.8.1
     252     */
     253    private static void unpack(InputStream in, JarOutputStream out) throws Exception {
     254        // For Sun, OpenJDK, IcedTea, etc, use this
     255        Pack200.newUnpacker().unpack(in, out);
     256
     257        // ------------------
     258        // For Apache Harmony or if you put its pack200.jar in your library directory use this
     259        //(new Archive(in, out)).unpack();
     260
     261
     262        // ------------------
     263        // For gcj, gij, etc., use this
     264        //throw new IOException("Pack200 not supported");
     265    }
     266
     267    /**
    228268     * Read in the last few lines of a (newline delimited) textfile, or null if
    229269     * the file doesn't exist. 
     
    353393            if (!copied)
    354394                System.err.println("Error copying [" + args[1] + "] to [" + args[2] + "]");
     395        } else if ("unzip".equals(args[0])) {
     396            File f = new File(args[1]);
     397            File to = new File("tmp");
     398            to.mkdir();
     399            boolean copied = verifyZip(f);
     400            if (!copied)
     401                System.err.println("Error verifying " + args[1]);
     402            copied = extractZip(f,  to);
     403            if (copied)
     404                System.err.println("Unzipped [" + args[1] + "] to [" + to + "]");
     405            else
     406                System.err.println("Error unzipping [" + args[1] + "] to [" + to + "]");
    355407        }
    356408    }
  • core/java/src/net/i2p/util/LogManager.java

    r9b39f02 rbe308a0  
    1414import java.io.FileOutputStream;
    1515import java.io.IOException;
     16import java.text.DecimalFormat;
    1617import java.text.SimpleDateFormat;
    1718import java.util.ArrayList;
     
    430431            char mod = v.charAt(v.length() - 1);
    431432            if (!Character.isDigit(mod)) v = v.substring(0, v.length() - 1);
    432             double val = Double.parseDouble(v);
     433            // output to form was in current locale, so have to parse it back that way
     434            double val = (new DecimalFormat()).parse(v.trim()).doubleValue();
    433435            switch (mod) {
    434436                case 'K':
  • core/java/src/net/i2p/util/SecureFileOutputStream.java

    r9b39f02 rbe308a0  
    5757     *  ignores errors
    5858     */
    59     private static void setPerms(File f) {
     59    public static void setPerms(File f) {
    6060        if (!canSetPerms)
    6161            return;
  • history.txt

    r9b39f02 rbe308a0  
     12010-11-03 zzz
     2    * Merge and snark fixups
     3
     42010-11-01 zzz
     5    * ClientConnectionRunner: Add synch to fix race causing AIOOBE
     6                              (http://forum.i2p/viewtopic.php?t=5061)
     7    * configlogging.jsp: Parse log limit with current locale
     8                (ticket #118)
     9    * i2psnark:
     10      - Limit number of parallel requests of a single piece when in the end game
     11      - Shorten and weight the speed tracker so the display is more
     12        reflective of current speed
     13    * logs.jsp: Add message if wrapper log not found
     14                (ticket #103)
     15
     162010-10-30 zzz
     17    * i2psnark:
     18      - Priority mapping bugfix
     19      - Close files as we go when creating/checking
     20        so we don't run out of file descriptors
     21      - Update request queues after priority change
     22      - Only add wanted pieces to wanted list at startup
     23      - Make sure lastRequest is null when it should be
     24      - Delay during StopAll so we don't close the tunnel before the
     25        stopped announces go out and reopen it
     26      - Logging tweaks
     27
     282010-10-27 zzz
     29    * i2psnark:
     30      - Don't stay interested if we run out of pieces
     31        to request (thanks sponge)
     32      - Enhance debug mode to show requests
     33      - Priority mapping bugfix
     34    * Transport: Avoid rare NPE at startup
     35
     362010-10-24 zzz
     37    * FileUtil: Make it easier to compile without Pack200, or with
     38                Apache Harmony's Pack200, add unzip to main()
     39    * i2psnark: Catch a race after disconnect()
     40    * NTCP: Catch a race after stop()
     41    * Router: Set permissions on wrapper.log when not called by RouterLaunch
     42    * Systray: New doc and main()
     43
     442010-10-19 zzz
     45    * Escape & in logs and i2psnark (much more to do)
     46    * JobImpl: Deprecate two debugging methods
     47    * replaceAll() -> replace() when we don't need regex
     48
     492010-10-15 zzz
     50    * i2psnark: Add file priority feature
     51    * I2PSocketEepGet: Set connect delay to save a RTT, will
     52      speed announces in i2psnark
     53
     542010-10-12 zzz
     55    *** 1.6 or higher JDK now required to build
     56    * configlogging.jsp:
     57      - Add easy way to add an override
     58      - Make file size specifier more flexible
     59    * Console:
     60      - Sort RouterAddress options on netdb.jsp and peers.jsp
     61      - Remove unused web-*.xml file from war
     62    * Crypto:
     63      - Convert all ArrayList caching to LBQs in YKGenerator,
     64        HMACGenerator, and AESKeyCache.
     65      - Change DSAEngine params from Hash to new SHA1Hash, since
     66        these were really 20 byte hashes, not 32 byte Hashes.
     67      - Add stats to track YKGenerator caching success
     68      - Fix YKGenerator precalculation to be much more useful by
     69        increasing the cache size and dramatically shortening the delay
     70      - Option cleanups
     71      - YKGenerator cleanups
     72      - Mark HMAC256Generator unused
     73    * EepGet: Reset length variable on redirect
     74    * Files: Change permissions to 600/700 for all written files/directories.
     75      Now requires Java 1.6 to build, but only 1.5+ to run.
     76      (requires 1.6 to set permissiomns)
     77    * GeoIP: Fix locking bug causing lookups to stop
     78    * Hash: Throw IAE if data length is not 32 bytes,
     79      now that DSAEngine abuse is gone
     80    * HTTPResponseOutputStream:
     81      - More caching
     82      - Stats cleanup
     83      - Max header length check
     84      - Catch OOM
     85      - Initializer cleanup
     86      - Javadoc
     87    * I2CP:
     88      - Add new option i2cp.messageReliability=none, which prevents the
     89        router from sending MessageStatusMessages back in reply to an
     90        outbound SendMessageMessage. Since the streaming lib always ignored
     91        the MSMs anyway, make it the default for streaming.
     92        This will reduce the I2CP traffic significantly.
     93        MSM handling now avoided, but it is still fairly broken, see
     94        comments in I2PSessionImpl2.
     95      - Cleanups to replace method calls with fields
     96      - More cleanups, javadoc, rate reduction
     97    * i2psnark:
     98      - Compact response format
     99      - Add link to finished torrent in message box
     100      - Don't let one bad torrent prevent others from
     101        starting or stopping
     102      - Sort peers by completion %
     103      - Add some missing mime types to web.xml
     104      - shouldLog() cleanup
     105    * i2ptunnel:
     106      - Now that streaming flush() is fixed, use it in IRCClient, and
     107        for initial data in I2PTunnel runner, to avoid the 250 ms
     108        passive flush delay
     109      - Add hostname DSA signature field, to be used for addkey forms.
     110        Experimental, may be commented out later.
     111      - More header blocking (thanks telecomix!)
     112      - Remove unused web-*.xml file from war
     113    * Installer: Add startup hint for non-x86
     114    * Javadoc updates all over the place
     115    * LogConsoleBuffer: Java 5
     116    * Naming:
     117      - Increase cache size and expiration time
     118      - Add clearCache() method
     119      - Don't use EepGet or Exec for b32
     120      - Javadoc updates
     121    * NetDB:
     122      - Expire unreachable routers quickly, even if they don't have introducers,
     123        so we don't have old data on routers that ran out of introducers.
     124      - Fix rare NPEs at shutdown
     125    * NTCP:
     126      - Cleanups
     127    * Streaming:
     128      - Make flush() block less, by waiting only for "accept" into the
     129        streaming queue rather than "completion" (i.e. ACK from the far end).
     130        This prevents complete stalls when flushing, and should help performance
     131        of apps that use flush(), like i2psnark (and SAM?).
     132        close() still does a flush that waits for completion, as i2ptunnel
     133        doesn't like a fast return from close().
     134      - cleanups
     135    * SusiDNS:
     136      - Remove unused web-*.xml file from war
     137    * TransportManager: Convert _transports from a List to a CHM
     138      to prevent a rare concurrent exception
     139    * Tunnels:
     140      - Don't use peers < 0.7.9 for tunnels due to the old
     141        message corruption bugs
     142      - Javadoc
     143      - Cleanups
     144    * UDP:
     145      - Beginnings of destroy message support
     146      - Try to avoid running out of introducers by relaxing selection criteria
     147        and increasing minimum number of potential introducers
     148      - Avoid rare AIOOBE
     149      - PacketBuilder refactor
     150      - Make most classes package private
     151      - Comments
     152      - Logging cleanup
     153      - Comment out a main()
     154
    11552010-10-22 sponge
    2156    * Sanity and some fixs for slackware package
  • router/java/src/net/i2p/router/JobImpl.java

    r9b39f02 rbe308a0  
    4040    }
    4141   
     42    /**
     43     *  @deprecated
     44     *  As of 0.8.1, this is a noop, as it just adds classes to the log manager
     45     *  class list for no good reason. Logging in jobs is almost always
     46     *  set explicitly rather than by class name.
     47     */
    4248    void addedToQueue() {
    43         if (_context.logManager().getLog(getClass()).shouldLog(Log.DEBUG))
    44             _addedBy = new Exception();
     49        //if (_context.logManager().getLog(getClass()).shouldLog(Log.DEBUG))
     50        //    _addedBy = new Exception();
    4551    }
    4652   
     53    /**
     54     *  @deprecated
     55     *  @return null always
     56     */
    4757    public Exception getAddedBy() { return _addedBy; }
    4858    public long getMadeReadyOn() { return _madeReadyOn; }
  • router/java/src/net/i2p/router/JobQueue.java

    r9b39f02 rbe308a0  
    143143        if (job == null || !_alive) return;
    144144
    145         if (job instanceof JobImpl)
    146             ((JobImpl)job).addedToQueue();
     145        // This does nothing
     146        //if (job instanceof JobImpl)
     147        //    ((JobImpl)job).addedToQueue();
    147148
    148149        long numReady = 0;
  • router/java/src/net/i2p/router/Router.java

    r9b39f02 rbe308a0  
    218218        // NOW we start all the activity
    219219        _context.initAll();
     220
     221        // Set wrapper.log permissions.
     222        // Just hope this is the right location, we don't know for sure,
     223        // but this is the same method used in LogsHelper and we have no complaints.
     224        // (we could look for the wrapper.config file and parse it I guess...)
     225        // If we don't have a wrapper, RouterLaunch does this for us.
     226        if (System.getProperty("wrapper.version") != null) {
     227            File f = new File(System.getProperty("java.io.tmpdir"), "wrapper.log");
     228            if (!f.exists())
     229                f = new File(_context.getBaseDir(), "wrapper.log");
     230            if (f.exists())
     231                SecureFileOutputStream.setPerms(f);
     232        }
    220233
    221234        _routerInfo = null;
  • router/java/src/net/i2p/router/RouterVersion.java

    r9b39f02 rbe308a0  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 05;
     21    public final static long BUILD = 9;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/client/ClientConnectionRunner.java

    r9b39f02 rbe308a0  
    362362        //  so the comparison will always work.
    363363        int leases = set.getLeaseCount();
    364         if (_currentLeaseSet != null && _currentLeaseSet.getLeaseCount() == leases) {
    365             for (int i = 0; i < leases; i++) {
    366                 if (! _currentLeaseSet.getLease(i).getTunnelId().equals(set.getLease(i).getTunnelId()))
    367                     break;
    368                 if (! _currentLeaseSet.getLease(i).getGateway().equals(set.getLease(i).getGateway()))
    369                     break;
    370                 if (i == leases - 1) {
    371                     if (_log.shouldLog(Log.INFO))
    372                         _log.info("Requested leaseSet hasn't changed");
    373                     if (onCreateJob != null)
    374                         _context.jobQueue().addJob(onCreateJob);
    375                     return; // no change
     364        // synch so _currentLeaseSet isn't changed out from under us
     365        synchronized (this) {
     366            if (_currentLeaseSet != null && _currentLeaseSet.getLeaseCount() == leases) {
     367                for (int i = 0; i < leases; i++) {
     368                    if (! _currentLeaseSet.getLease(i).getTunnelId().equals(set.getLease(i).getTunnelId()))
     369                        break;
     370                    if (! _currentLeaseSet.getLease(i).getGateway().equals(set.getLease(i).getGateway()))
     371                        break;
     372                    if (i == leases - 1) {
     373                        if (_log.shouldLog(Log.INFO))
     374                            _log.info("Requested leaseSet hasn't changed");
     375                        if (onCreateJob != null)
     376                            _context.jobQueue().addJob(onCreateJob);
     377                        return; // no change
     378                    }
    376379                }
    377380            }
     
    591594                              + "] (with nonce=2), retrying after ["
    592595                              + (_context.clock().now() - _lastTried)
    593                               + "]", getAddedBy());
     596                              + "]");
    594597            } else {
    595598                if (_log.shouldLog(Log.DEBUG))
  • router/java/src/net/i2p/router/message/SendMessageDirectJob.java

    r9b39f02 rbe308a0  
    7777            if (_log.shouldLog(Log.WARN))
    7878                _log.warn("Timed out sending message " + _message + " directly (expiration = "
    79                            + new Date(_expiration) + ") to " + _targetHash.toBase64(), getAddedBy());
     79                           + new Date(_expiration) + ") to " + _targetHash.toBase64());
    8080            if (_onFail != null)
    8181                getContext().jobQueue().addJob(_onFail);
     
    105105                        _log.warn("Unable to find the router to send to: " + _targetHash
    106106                                  + " after searching for " + (getContext().clock().now()-_searchOn)
    107                                   + "ms, message: " + _message, getAddedBy());
     107                                  + "ms, message: " + _message);
    108108                    if (_onFail != null)
    109109                        getContext().jobQueue().addJob(_onFail);
  • router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java

    r9b39f02 rbe308a0  
    137137    @Override
    138138    public boolean isBacklogged(Hash dest) {
    139         return _manager.isBacklogged(dest);
     139        return _manager != null && _manager.isBacklogged(dest);
    140140    }
    141141   
    142142    @Override
    143143    public boolean isEstablished(Hash dest) {
    144         return _manager.isEstablished(dest);
     144        return _manager != null && _manager.isEstablished(dest);
    145145    }
    146146   
    147147    @Override
    148148    public boolean wasUnreachable(Hash dest) {
    149         return _manager.wasUnreachable(dest);
     149        return _manager != null && _manager.wasUnreachable(dest);
    150150    }
    151151   
  • router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java

    r9b39f02 rbe308a0  
    616616                    _log.info("Type " + msg.getMessage().getType() + " pri " + msg.getPriority() + " slot " + slot);
    617617                boolean removed = _outbound.remove(msg);
    618                 if ((!removed) && _log.shouldLog(Log.ERROR))
    619                     _log.info("Already removed??? " + msg.getMessage().getType());
     618                if ((!removed) && _log.shouldLog(Log.WARN))
     619                    _log.warn("Already removed??? " + msg.getMessage().getType());
    620620            }
    621621            _currentOutbound = msg;
  • router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java

    r9b39f02 rbe308a0  
    33import java.util.concurrent.Executors;
    44import java.util.concurrent.LinkedBlockingQueue;
     5import java.util.concurrent.RejectedExecutionException;
    56import java.util.concurrent.ThreadPoolExecutor;
    67import java.util.concurrent.TimeUnit;
     
    2526public class NTCPSendFinisher {
    2627    private static final int THREADS = 4;
    27     private I2PAppContext _context;
    28     private NTCPTransport _transport;
    29     private Log _log;
     28    private final I2PAppContext _context;
     29    private final NTCPTransport _transport;
     30    private final Log _log;
    3031    private int _count;
    3132    private ThreadPoolExecutor _executor;
     
    4849
    4950    public void add(OutNetMessage msg) {
    50         _executor.execute(new RunnableEvent(msg));
     51        try {
     52            _executor.execute(new RunnableEvent(msg));
     53        } catch (RejectedExecutionException ree) {
     54            // race with stop()
     55            _log.warn("NTCP send finisher stopped, discarding msg.afterSend()");
     56        }
    5157    }
    5258   
  • router/java/src/net/i2p/router/tunnel/pool/TestJob.java

    r9b39f02 rbe308a0  
    318318        public void runJob() {
    319319            if (_log.shouldLog(Log.WARN))
    320                 _log.warn("Timeout: found? " + _found, getAddedBy());
     320                _log.warn("Timeout: found? " + _found);
    321321            if (!_found) {
    322322                // don't clog up the SKM with old one-tag tagsets
  • router/java/test/net/i2p/router/message/SendGarlicJob.java

    r9b39f02 rbe308a0  
    8282        if ( (after - before) > 1000) {
    8383            if (_log.shouldLog(Log.WARN))
    84                 _log.warn("Building the garlic took too long [" + (after-before)+" ms]", getAddedBy());
     84                _log.warn("Building the garlic took too long [" + (after-before)+" ms]");
    8585        } else {
    8686            if (_log.shouldLog(Log.DEBUG))
Note: See TracChangeset for help on using the changeset viewer.