/// <remarks> /// Variables <code>head</code> and <code>tail</code> mark the start and /// end of the messages received, but not delivered yet. When a message is /// received, if its seqno is smaller than <code>head</code>, it is /// discarded (already received). If it is bigger than <code>tail</code>, /// we advance <code>tail</code> and add empty elements. If it is between /// <code>head</code> and <code>tail</code>, we set the corresponding /// missing (or already present) element. If it is equal to /// <code>tail</code>, we advance the latter by 1 and add the message /// (default case). /// </remarks> /// <summary> /// Adds a message according to its sequence number. /// </summary> /// <param name="seqno">Sequence number of the message.</param> /// <param name="msg">Message to add.</param> public void add(long seqno, Message msg) { Entry current = null; long old_tail; rwlock.writeLock(); try { old_tail = tail; if (seqno < head) { if (Trace.trace) { Trace.info("NakReceiverWindow.add()", "seqno " + seqno + " is smaller than " + head + "); discarding message"); } return; } // add at end (regular expected msg) if (seqno == tail) { msgs.Add(new Entry(seqno, msg)); tail++; } // gap detected // i. add placeholders, creating gaps // ii. add real msg // iii. tell retransmitter to retrieve missing msgs else if (seqno > tail) { for (long i = tail; i < seqno; i++) { msgs.Add(new Entry(i, null)); tail++; } msgs.Add(new Entry(seqno, msg)); tail = seqno + 1; if (retransmitter != null) { retransmitter.add(old_tail, seqno - 1); } // finally received missing message } else if (seqno < tail) { if (Trace.trace) { Trace.info("NakReceiverWindow.add()", "added missing msg " + msg.Source + "#" + seqno); } for (int i = 0; i < msgs.Count; i++) { current = (Entry)msgs[i]; // overwrite any previous message (e.g. added by down()) and // remove seqno from retransmitter if (seqno == current.seqno) { current.msg = msg; if (retransmitter != null) { retransmitter.remove(seqno); } break; } } } _updateLowestSeen(); _updateHighestSeen(); } finally { rwlock.writeUnlock(); } }