Changeset de4d47d


Ignore:
Timestamp:
May 19, 2015 6:13:32 PM (5 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
65ff2c0
Parents:
2dc3d684
Message:

i2psnark: Add support for fast extensions (BEP 6)
untested

Location:
apps/i2psnark/java/src/org/klomp/snark
Files:
6 edited

Legend:

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

    r2dc3d684 rde4d47d  
    2020
    2121package org.klomp.snark;
     22
     23import java.util.Arrays;
    2224
    2325
     
    6769  /**
    6870   * This returns the actual byte array used.  Changes to this array
    69    * effect this BitField.  Note that some bits at the end of the byte
     71   * affect this BitField.  Note that some bits at the end of the byte
    7072   * array are supposed to be always unset if they represent bits
    7173   * bigger then the size of the bitfield.
     
    104106        }
    105107    }
     108  }
     109
     110  /**
     111   * Sets all bits to true.
     112   *
     113   * @since 0.9.21
     114   */
     115  public void setAll() {
     116      Arrays.fill(bitfield, (byte) 0xff);
     117      count = size;
    106118  }
    107119
  • apps/i2psnark/java/src/org/klomp/snark/Message.java

    r2dc3d684 rde4d47d  
    5656
    5757  // Used for HAVE, REQUEST, PIECE and CANCEL messages.
     58  // Also SUGGEST, REJECT, ALLOWED_FAST
    5859  // low byte used for EXTENSION message
    5960  // low two bytes used for PORT message
     
    6162
    6263  // Used for REQUEST, PIECE and CANCEL messages.
     64  // Also REJECT
    6365  int begin;
    6466  int length;
     
    105107
    106108    // piece is 4 bytes.
    107     if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL)
     109    if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL ||
     110        type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
    108111      datalen += 4;
    109112
    110113    // begin/offset is 4 bytes
    111     if (type == REQUEST || type == PIECE || type == CANCEL)
     114    if (type == REQUEST || type == PIECE || type == CANCEL ||
     115        type == REJECT)
    112116      datalen += 4;
    113117
    114118    // length is 4 bytes
    115     if (type == REQUEST || type == CANCEL)
     119    if (type == REQUEST || type == CANCEL ||
     120        type == REJECT)
    116121      datalen += 4;
    117122
     
    132137
    133138    // Send additional info (piece number)
    134     if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL)
     139    if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL ||
     140        type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
    135141      dos.writeInt(piece);
    136142
    137143    // Send additional info (begin/offset)
    138     if (type == REQUEST || type == PIECE || type == CANCEL)
     144    if (type == REQUEST || type == PIECE || type == CANCEL ||
     145        type == REJECT)
    139146      dos.writeInt(begin);
    140147
    141148    // Send additional info (length); for PIECE this is implicit.
    142     if (type == REQUEST || type == CANCEL)
     149    if (type == REQUEST || type == CANCEL ||
     150        type == REJECT)
    143151        dos.writeInt(length);
    144152
     
    174182        return "UNINTERESTED";
    175183      case HAVE:
    176         return "HAVE(" + piece + ")";
     184        return "HAVE(" + piece + ')';
    177185      case BITFIELD:
    178186        return "BITFIELD";
    179187      case REQUEST:
    180         return "REQUEST(" + piece + "," + begin + "," + length + ")";
     188        return "REQUEST(" + piece + ',' + begin + ',' + length + ')';
    181189      case PIECE:
    182         return "PIECE(" + piece + "," + begin + "," + length + ")";
     190        return "PIECE(" + piece + ',' + begin + ',' + length + ')';
    183191      case CANCEL:
    184         return "CANCEL(" + piece + "," + begin + "," + length + ")";
     192        return "CANCEL(" + piece + ',' + begin + ',' + length + ')';
    185193      case PORT:
    186         return "PORT(" + piece + ")";
     194        return "PORT(" + piece + ')';
    187195      case EXTENSION:
    188196        return "EXTENSION(" + piece + ',' + data.length + ')';
     197      // fast extensions below here
     198      case SUGGEST:
     199        return "SUGGEST(" + piece + ')';
     200      case HAVE_ALL:
     201        return "HAVE_ALL";
     202      case HAVE_NONE:
     203        return "HAVE_NONE";
     204      case REJECT:
     205        return "REJECT(" + piece + ',' + begin + ',' + length + ')';
     206      case ALLOWED_FAST:
     207        return "ALLOWED_FAST(" + piece + ')';
    189208      default:
    190         return "<UNKNOWN>";
     209        return "UNKNOWN (" + type + ')';
    191210      }
    192211  }
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    r2dc3d684 rde4d47d  
    8080  private long downloaded_old[] = {-1,-1,-1};
    8181
    82   //  bytes per bt spec:                 0011223344556677
    83   static final long OPTION_EXTENSION = 0x0000000000100000l;
    84   static final long OPTION_FAST      = 0x0000000000000004l;
    85   static final long OPTION_DHT       = 0x0000000000000001l;
     82  //  bytes per bt spec:                         0011223344556677
     83  private static final long OPTION_EXTENSION = 0x0000000000100000l;
     84  private static final long OPTION_FAST      = 0x0000000000000004l;
     85  private static final long OPTION_DHT       = 0x0000000000000001l;
    8686  /** we use a different bit since the compact format is different */
    8787/* no, let's use an extension message
    8888  static final long OPTION_I2P_DHT   = 0x0000000040000000l;
    8989*/
    90   static final long OPTION_AZMP      = 0x1000000000000000l;
     90  private static final long OPTION_AZMP      = 0x1000000000000000l;
    9191  private long options;
    9292
     
    339339    // Handshake write - options
    340340    long myOptions = OPTION_EXTENSION;
     341    // we can't handle HAVE_ALL or HAVE_NONE if we don't know the number of pieces
     342    if (metainfo != null)
     343        myOptions |= OPTION_FAST;
    341344    // FIXME get util here somehow
    342345    //if (util.getDHT() != null)
     
    392395  }
    393396
    394   /** @since 0.8.4 */
    395   public long getOptions() {
    396       return options;
     397  /** @since 0.9.21 */
     398  public boolean supportsFast() {
     399      return (options & OPTION_FAST) != 0;
    397400  }
    398401
  • apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java

    r2dc3d684 rde4d47d  
    103103            switch (b)
    104104              {
    105               case 0:
     105              case Message.CHOKE:
    106106                ps.chokeMessage(true);
    107107                if (_log.shouldLog(Log.DEBUG))
    108108                    _log.debug("Received choke from " + peer);
    109109                break;
    110               case 1:
     110
     111              case Message.UNCHOKE:
    111112                ps.chokeMessage(false);
    112113                if (_log.shouldLog(Log.DEBUG))
    113114                    _log.debug("Received unchoke from " + peer);
    114115                break;
    115               case 2:
     116
     117              case Message.INTERESTED:
    116118                ps.interestedMessage(true);
    117119                if (_log.shouldLog(Log.DEBUG))
    118120                    _log.debug("Received interested from " + peer);
    119121                break;
    120               case 3:
     122
     123              case Message.UNINTERESTED:
    121124                ps.interestedMessage(false);
    122125                if (_log.shouldLog(Log.DEBUG))
    123126                    _log.debug("Received not interested from " + peer);
    124127                break;
    125               case 4:
     128
     129              case Message.HAVE:
    126130                piece = din.readInt();
    127131                ps.haveMessage(piece);
     
    129133                    _log.debug("Received havePiece(" + piece + ") from " + peer);
    130134                break;
    131               case 5:
     135
     136              case Message.BITFIELD:
    132137                byte[] bitmap = new byte[i-1];
    133138                din.readFully(bitmap);
     
    136141                    _log.debug("Received bitmap from " + peer  + ": size=" + (i-1) /* + ": " + ps.bitfield */ );
    137142                break;
    138               case 6:
     143
     144              case Message.REQUEST:
    139145                piece = din.readInt();
    140146                begin = din.readInt();
     
    144150                    _log.debug("Received request(" + piece + "," + begin + ") from " + peer);
    145151                break;
    146               case 7:
     152
     153              case Message.PIECE:
    147154                piece = din.readInt();
    148155                begin = din.readInt();
     
    166173                  }
    167174                break;
    168               case 8:
     175
     176              case Message.CANCEL:
    169177                piece = din.readInt();
    170178                begin = din.readInt();
     
    174182                    _log.debug("Received cancel(" + piece + "," + begin + ") from " + peer);
    175183                break;
    176               case 9:  // PORT message
     184
     185              case Message.PORT:
    177186                int port = din.readUnsignedShort();
    178187                ps.portMessage(port);
     
    180189                    _log.debug("Received port message from " + peer);
    181190                break;
    182               case 20:  // Extension message
     191
     192              case Message.EXTENSION:
    183193                int id = din.readUnsignedByte();
    184194                byte[] payload = new byte[i-2];
     
    188198                ps.extensionMessage(id, payload);
    189199                break;
     200
     201              // fast extensions below here
     202              case Message.SUGGEST:
     203                piece = din.readInt();
     204                ps.suggestMessage(piece);
     205                if (_log.shouldLog(Log.DEBUG))
     206                    _log.debug("Received suggest(" + piece + ") from " + peer);
     207                break;
     208
     209              case Message.HAVE_ALL:
     210                ps.haveMessage(true);
     211                if (_log.shouldLog(Log.DEBUG))
     212                    _log.debug("Received have_all from " + peer);
     213                break;
     214
     215              case Message.HAVE_NONE:
     216                ps.haveMessage(false);
     217                if (_log.shouldLog(Log.DEBUG))
     218                    _log.debug("Received have_none from " + peer);
     219                break;
     220
     221              case Message.REJECT:
     222                piece = din.readInt();
     223                begin = din.readInt();
     224                len = din.readInt();
     225                ps.rejectMessage(piece, begin, len);
     226                if (_log.shouldLog(Log.DEBUG))
     227                    _log.debug("Received reject(" + piece + ',' + begin + ',' + len + ") from " + peer);
     228                break;
     229
     230              case Message.ALLOWED_FAST:
     231                piece = din.readInt();
     232                ps.allowedFastMessage(piece);
     233                if (_log.shouldLog(Log.DEBUG))
     234                    _log.debug("Received allowed_fast(" + piece + ") from " + peer);
     235                break;
     236
    190237              default:
    191238                byte[] bs = new byte[i-1];
  • apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java

    r2dc3d684 rde4d47d  
    278278          {
    279279            Message m = it.next();
    280             if (m.type == type)
    281               {
     280            if (m.type == type) {
    282281                it.remove();
    283282                removed = true;
    284               }
     283                if (type == Message.PIECE && peer.supportsFast()) {
     284                    Message r = new Message();
     285                    r.type = Message.REJECT;
     286                    r.piece = m.piece;
     287                    r.begin = m.begin;
     288                    r.length = m.length;
     289                    try {
     290                        r.sendMessage(dout);
     291                    } catch (IOException ioe) {}
     292                }
     293            }
    285294          }
    286295        sendQueue.notifyAll();
     
    350359  void sendBitfield(BitField bitfield)
    351360  {
    352     Message m = new Message();
    353     m.type = Message.BITFIELD;
    354     m.data = bitfield.getFieldBytes();
    355     m.off = 0;
    356     m.len = m.data.length;
    357     addMessage(m);
     361    boolean fast = peer.supportsFast();
     362    if (fast && bitfield.complete()) {
     363        sendHaveAll();
     364    } else if (fast && bitfield.count() <= 0) {
     365        sendHaveNone();
     366    } else {
     367       Message m = new Message();
     368       m.type = Message.BITFIELD;
     369       m.data = bitfield.getFieldBytes();
     370       m.off = 0;
     371       m.len = m.data.length;
     372       addMessage(m);
     373    }
    358374  }
    359375
     
    560576    addMessage(m);
    561577  }
     578
     579  /**
     580   *  Unused
     581   *  @since 0.9.21
     582   */
     583  void sendSuggest(int piece) {
     584    Message m = new Message();
     585    m.type = Message.SUGGEST;
     586    m.piece = piece;
     587    addMessage(m);
     588  }
     589
     590  /** @since 0.9.21 */
     591  private void sendHaveAll() {
     592    Message m = new Message();
     593    m.type = Message.HAVE_ALL;
     594    addMessage(m);
     595  }
     596
     597  /** @since 0.9.21 */
     598  private void sendHaveNone() {
     599    Message m = new Message();
     600    m.type = Message.HAVE_NONE;
     601    addMessage(m);
     602  }
     603
     604  /** @since 0.9.21 */
     605  void sendReject(int piece, int begin, int length) {
     606    Message m = new Message();
     607    m.type = Message.REJECT;
     608    m.piece = piece;
     609    m.begin = begin;
     610    m.length = length;
     611    addMessage(m);
     612  }
     613
     614  /**
     615   *  Unused
     616   *  @since 0.9.21
     617   */
     618  void sendAllowedFast(int piece) {
     619    Message m = new Message();
     620    m.type = Message.ALLOWED_FAST;
     621    m.piece = piece;
     622    addMessage(m);
     623  }
    562624}
  • apps/i2psnark/java/src/org/klomp/snark/PeerState.java

    r2dc3d684 rde4d47d  
    156156  }
    157157
    158   void bitfieldMessage(byte[] bitmap)
    159   {
    160     synchronized(this)
    161       {
     158  void bitfieldMessage(byte[] bitmap) {
     159      bitfieldMessage(bitmap, false);
     160  }
     161
     162  /**
     163   *  @param bitmap null to use the isAll param
     164   *  @param isAll only if bitmap == null: true for have_all, false for have_none
     165   *  @since 0.9.21
     166   */
     167  private void bitfieldMessage(byte[] bitmap, boolean isAll) {
     168    synchronized(this) {
    162169        if (_log.shouldLog(Log.DEBUG))
    163170          _log.debug(peer + " rcv bitfield");
     
    173180        // FIXME will have to regenerate the bitfield after we know exactly
    174181        // how many pieces there are, as we don't know how many spare bits there are.
    175         if (metainfo == null)
    176             bitfield = new BitField(bitmap, bitmap.length * 8);
    177         else
    178             bitfield = new BitField(bitmap, metainfo.getPieces());
     182        if (metainfo == null) {
     183            if (bitmap != null) {
     184                bitfield = new BitField(bitmap, bitmap.length * 8);
     185            } else {
     186                // we can't handle this situation
     187                if (_log.shouldLog(Log.WARN))
     188                    _log.warn("have_x w/o metainfo: " + isAll);
     189                return;
     190            }
     191        } else {
     192            if (bitmap != null) {
     193                bitfield = new BitField(bitmap, metainfo.getPieces());
     194            } else {
     195                bitfield = new BitField(metainfo.getPieces());
     196                if (isAll)
     197                    bitfield.setAll();
     198            }
     199        }
    179200      }
    180201    if (metainfo == null)
     
    199220    if (metainfo == null)
    200221        return;
    201     if (choking)
    202       {
    203         if (_log.shouldLog(Log.INFO))
    204           _log.info("Request received, but choking " + peer);
     222    if (choking) {
     223        if (peer.supportsFast()) {
     224            if (_log.shouldInfo())
     225              _log.info("Request received, sending reject to choked " + peer);
     226            out.sendReject(piece, begin, length);
     227        } else {
     228            if (_log.shouldInfo())
     229              _log.info("Request received, but choking " + peer);
     230        }
    205231        return;
    206       }
     232    }
    207233
    208234    // Sanity check
     
    228254    if (out.queuedBytes() + length > MAX_PIPELINE_BYTES)
    229255      {
    230         if (_log.shouldLog(Log.WARN))
    231           _log.warn("Discarding request over pipeline limit from " + peer);
     256        if (peer.supportsFast()) {
     257            if (_log.shouldWarn())
     258                _log.warn("Rejecting request over pipeline limit from " + peer);
     259            out.sendReject(piece, begin, length);
     260        } else {
     261            if (_log.shouldWarn())
     262                _log.warn("Discarding request over pipeline limit from " + peer);
     263        }
    232264        return;
    233265      }
     
    537569  }
    538570
     571  /////////// fast message handlers /////////
     572
     573  /**
     574   *  BEP 6
     575   *  Treated as "have" for now
     576   *  @since 0.9.21
     577   */
     578  void suggestMessage(int piece) {
     579      if (_log.shouldInfo())
     580          _log.info("Handling suggest as have(" + piece + ") from " + peer);
     581      haveMessage(piece);
     582  }
     583
     584  /**
     585   *  BEP 6
     586   *  @param isAll true for have_all, false for have_none
     587   *  @since 0.9.21
     588   */
     589  void haveMessage(boolean isAll) {
     590      bitfieldMessage(null, isAll);
     591  }
     592
     593  /**
     594   *  BEP 6
     595   *  @since 0.9.21
     596   */
     597  void rejectMessage(int piece, int begin, int length) {
     598      if (_log.shouldInfo())
     599           _log.info("Got reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
     600      out.cancelRequest(piece, begin, length);
     601      synchronized(this) {
     602          for (Iterator<Request> iter = outstandingRequests.iterator(); iter.hasNext(); ) {
     603              Request req = iter.next();
     604              if (req.getPiece() == piece && req.off == begin && req.len == length)
     605                  iter.remove();
     606          }
     607          if (lastRequest != null && lastRequest.getPiece() == piece &&
     608              lastRequest.off == begin && lastRequest.len == length)
     609              lastRequest = null;
     610      }
     611  }
     612
     613  /**
     614   *  BEP 6
     615   *  Ignored for now
     616   *  @since 0.9.21
     617   */
     618  void allowedFastMessage(int piece) {
     619      if (_log.shouldInfo())
     620          _log.info("Ignoring allowed_fast(" + piece + ") from " + peer);
     621  }
     622
    539623  void unknownMessage(int type, byte[] bs)
    540624  {
     
    543627                  + " length: " + bs.length);
    544628  }
     629
     630  /////////// end message handlers /////////
    545631
    546632  /**
Note: See TracChangeset for help on using the changeset viewer.