Changeset ffa4d65


Ignore:
Timestamp:
Mar 1, 2016 1:09:18 PM (5 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
50d038a
Parents:
bf2f376
Message:

i2psnark: Fix handling of HAVE messages received before metainfo

File:
1 edited

Legend:

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

    rbf2f376 rffa4d65  
    3838  /** Fixme, used by Peer.disconnect() to get to the coordinator */
    3939  final PeerListener listener;
     40  /** Null before we have it. locking: this */
    4041  private MetaInfo metainfo;
     42  /** Null unless needed. Contains -1 for all. locking: this */
     43  private List<Integer> havesBeforeMetaInfo;
    4144
    4245  // Interesting and choking describes whether we are interested in or
     
    5053  volatile boolean choked = true;
    5154
    52   /** the pieces the peer has */
     55  /** the pieces the peer has. locking: this */
    5356  BitField bitfield;
    5457
     
    6770  public final static int PARTSIZE = 16*1024; // outbound request
    6871  private final static int MAX_PARTSIZE = 64*1024; // Don't let anybody request more than this
     72  private static final Integer PIECE_ALL = Integer.valueOf(-1);
    6973
    7074  /**
     
    132136    if (_log.shouldLog(Log.DEBUG))
    133137      _log.debug(peer + " rcv have(" + piece + ")");
    134     // FIXME we will lose these until we get the metainfo
    135     if (metainfo == null)
    136         return;
    137138    // Sanity check
    138     if (piece < 0 || piece >= metainfo.getPieces())
    139       {
    140         // XXX disconnect?
    141         if (_log.shouldLog(Log.WARN))
     139    if (piece < 0) {
     140        if (_log.shouldWarn())
    142141            _log.warn("Got strange 'have: " + piece + "' message from " + peer);
    143142        return;
    144       }
    145 
    146     synchronized(this)
    147       {
     143    }
     144
     145    synchronized(this) {
     146        if (metainfo == null) {
     147            if (_log.shouldWarn())
     148                _log.warn("Got HAVE " + piece + " before metainfo from " + peer);
     149            if (bitfield != null) {
     150                if (piece < bitfield.size())
     151                      bitfield.set(piece);
     152            } else {
     153                // note reception for later
     154                if (havesBeforeMetaInfo == null) {
     155                    havesBeforeMetaInfo = new ArrayList<Integer>(8);
     156                } else if (havesBeforeMetaInfo.size() > 1000) {
     157                    // don't blow up
     158                    if (_log.shouldWarn())
     159                        _log.warn("Got too many haves before metainfo from " + peer);
     160                    return;
     161                }
     162                havesBeforeMetaInfo.add(Integer.valueOf(piece));
     163            }
     164            return;
     165        }
     166
     167        // Sanity check
     168        if (piece >= metainfo.getPieces()) {
     169            // XXX disconnect?
     170            if (_log.shouldLog(Log.WARN))
     171                _log.warn("Got strange 'have: " + piece + "' message from " + peer);
     172            return;
     173        }
     174
    148175        // Can happen if the other side never send a bitfield message.
    149176        if (bitfield == null)
    150           bitfield = new BitField(metainfo.getPieces());
    151 
     177            bitfield = new BitField(metainfo.getPieces());
    152178        bitfield.set(piece);
    153       }
     179    }
    154180
    155181    if (listener.gotHave(peer, piece))
     
    175201            _log.debug(peer + " rcv bitfield HAVE_NONE");
    176202    }
     203
    177204    synchronized(this) {
    178205        if (bitfield != null)
     
    185212       
    186213        // XXX - Check for weird bitfield and disconnect?
    187         // FIXME will have to regenerate the bitfield after we know exactly
     214        // Will have to regenerate the bitfield after we know exactly
    188215        // how many pieces there are, as we don't know how many spare bits there are.
     216        // This happens in setMetaInfo() below.
    189217        if (metainfo == null) {
    190218            if (bitmap != null) {
    191219                bitfield = new BitField(bitmap, bitmap.length * 8);
    192220            } else {
    193                 // we can't handle this situation
    194221                if (_log.shouldLog(Log.WARN))
    195222                    _log.warn("have_x w/o metainfo: " + isAll);
    196                 return;
     223                if (isAll) {
     224                    // note reception for later
     225                    if (havesBeforeMetaInfo == null)
     226                        havesBeforeMetaInfo = new ArrayList<Integer>(1);
     227                    else
     228                        havesBeforeMetaInfo.clear();
     229                    havesBeforeMetaInfo.add(PIECE_ALL);
     230                } // else HAVE_NONE, ignore
    197231            }
     232            return;
    198233        } else {
    199234            if (bitmap != null) {
     
    205240            }
    206241        }
    207       }
    208     if (metainfo == null)
    209         return;
     242    }  // synch
     243
    210244    boolean interest = listener.gotBitField(peer, bitfield);
    211245    setInteresting(interest);
     
    567601   *  @since 0.8.4
    568602   */
    569   public void setMetaInfo(MetaInfo meta) {
     603  public synchronized void setMetaInfo(MetaInfo meta) {
    570604      if (metainfo != null)
    571605          return;
    572       BitField oldBF = bitfield;
    573       if (oldBF != null) {
    574           if (oldBF.size() != meta.getPieces())
     606      if (bitfield != null) {
     607          if (bitfield.size() != meta.getPieces())
    575608              // fix bitfield, it was too big by 1-7 bits
    576               bitfield = new BitField(oldBF.getFieldBytes(), meta.getPieces());
     609              bitfield = new BitField(bitfield.getFieldBytes(), meta.getPieces());
    577610          // else no extra
     611      } else if (havesBeforeMetaInfo != null) {
     612          // initialize it now
     613          bitfield = new BitField(meta.getPieces());
    578614      } else {
    579615          // it will be initialized later
     
    581617      }
    582618      metainfo = meta;
    583       if (bitfield != null && bitfield.count() > 0)
    584           setInteresting(true);
     619      if (bitfield != null) {
     620          if (havesBeforeMetaInfo != null) {
     621              // set all 'haves' we got before the metainfo in the bitfield
     622              for (Integer i : havesBeforeMetaInfo) {
     623                  if (i.equals(PIECE_ALL)) {
     624                      bitfield.setAll();
     625                      if (_log.shouldLog(Log.WARN))
     626                          _log.warn("set have_all after rcv metainfo");
     627                      break;
     628                  }
     629                  int piece = i.intValue();
     630                  if (piece >= 0 && piece < meta.getPieces())
     631                      bitfield.set(piece);
     632                  if (_log.shouldLog(Log.WARN))
     633                      _log.warn("set have " + piece + " after rcv metainfo");
     634              }
     635              havesBeforeMetaInfo = null;
     636          }
     637          if (bitfield.count() > 0)
     638              setInteresting(true);
     639      }
    585640  }
    586641
Note: See TracChangeset for help on using the changeset viewer.