Example #1
0
        private Chunk[] dataDeal(DataChunk dc)
        {
            List <Chunk> rep        = new List <Chunk>();
            List <uint>  duplicates = new List <uint>();

            uint tsn = dc.getTsn();

            if (tsn > _farTSN)
            {
                // put it in the pen.
                //logger.LogDebug("TSN:::" + tsn);
                DataChunk dup;
                if (_holdingPen.TryGetValue(tsn, out dup))
                {
                    duplicates.Add(tsn);
                }
                else
                {
                    _holdingPen.Add(tsn, dc);
                }

                // now see if we can deliver anything new to the streams
                bool gap = false;
                for (uint t = _farTSN + 1; !gap; t++)
                {
                    if (_holdingPen.TryGetValue(t, out dc))
                    {
                        _holdingPen.Remove(t);
                        ingest(dc, rep);
                    }
                    else
                    {
                        //logger.LogDebug("gap in inbound tsns at " + t);
                        gap = true;
                    }
                }
            }
            else
            {
                // probably wrong now..
                logger.LogWarning("Already seen . " + tsn + " expecting " + (_farTSN));
                duplicates.Add(tsn);
            }

            List <uint> l = new List <uint>();

            l.AddRange(_holdingPen.Keys);
            l.Sort();

            SackChunk sack = mkSack(l, duplicates);

            rep.Add(sack);
            return(rep.ToArray());
        }
Example #2
0
        private SackChunk mkSack(List <uint> pen, List <uint> dups)
        {
            SackChunk ret = new SackChunk();

            ret.setCumuTSNAck(_farTSN);
            int stashcap = calcStashCap();

            ret.setArWin((uint)(MAXBUFF - stashcap));
            ret.setGaps(pen);
            ret.setDuplicates(dups);
            //logger.LogDebug("made SACK " + ret.ToString());
            return(ret);
        }
Example #3
0
        /*
         *
         * D) Any time a SACK arrives, the endpoint performs the following:
         *
         * ...
         *
         * ToDo :
         *
         * iii) If the SACK is missing a TSN that was previously acknowledged
         * via a Gap Ack Block (e.g., the data receiver reneged on the
         * data), then consider the corresponding DATA that might be
         * possibly missing: Count one miss indication towards Fast
         * Retransmit as described in Section 7.2.4, and if no
         * retransmit timer is running for the destination address to
         * which the DATA chunk was originally transmitted, then T3-rtx
         * is started for that destination address.
         *
         * iv) If the Cumulative TSN Ack matches or exceeds the Fast
         * Recovery exitpoint (Section 7.2.4), Fast Recovery is exited.
         *
         */

        protected override Chunk[] sackDeal(SackChunk sack)
        {
            Chunk[] ret = { };

            /*
             *           i) If Cumulative TSN Ack is less than the Cumulative TSN Ack
             *           Point, then drop the SACK.  Since Cumulative TSN Ack is
             *           monotonically increasing, a SACK whose Cumulative TSN Ack is
             *           less than the Cumulative TSN Ack Point indicates an out-of-
             *           order SACK.
             */
            if (sack.getCumuTSNAck() >= this._lastCumuTSNAck)
            {
                long ackedTo    = sack.getCumuTSNAck();
                int  totalAcked = 0;
                long now        = TimeExtension.CurrentTimeMillis();
                // interesting SACK
                // process acks
                lock (_inFlight)
                {
                    List <long> removals = new List <long>();
                    foreach (var kvp in _inFlight)
                    {
                        if (kvp.Key <= ackedTo)
                        {
                            removals.Add(kvp.Key);
                        }
                    }

                    foreach (long k in removals)
                    {
                        DataChunk d = _inFlight[k];
                        _inFlight.Remove(k);
                        totalAcked += d.getDataSize();

                        /*
                         *                       todo     IMPLEMENTATION NOTE: RTT measurements should only be made using
                         *                       a chunk with TSN r if no chunk with TSN less than or equal to r
                         *                       is retransmitted since r is first sent.
                         */
                        setRTO(now - d.getSentTime());
                        try
                        {
                            int        sid    = d.getStreamId();
                            SCTPStream stream = getStream(sid);
                            if (stream != null)
                            {
                                stream.delivered(d);
                            }

                            lock (_freeBlocks)
                            {
                                _freeBlocks.Enqueue(d);
                            }
                        }
                        catch (Exception ex)
                        {
                            logger.LogError("eek - can't replace free block on list!?!");
                            logger.LogError(ex.ToString());
                        }
                    }
                }

                /*
                 *               Gap Ack Blocks:
                 *
                 *               These fields contain the Gap Ack Blocks.  They are repeated for
                 *               each Gap Ack Block up to the number of Gap Ack Blocks defined in
                 *               the Number of Gap Ack Blocks field.  All DATA chunks with TSNs
                 *               greater than or equal to (Cumulative TSN Ack + Gap Ack Block
                 *               Start) and less than or equal to (Cumulative TSN Ack + Gap Ack
                 *               Block End) of each Gap Ack Block are assumed to have been received
                 *               correctly.
                 */
                foreach (SackChunk.GapBlock gb in sack.getGaps())
                {
                    long ts = gb.getStart() + ackedTo;
                    long te = gb.getEnd() + ackedTo;
                    lock (_inFlight)
                    {
                        for (long t = ts; t <= te; t++)
                        {
                            //logger.LogDebug("gap block says far end has seen " + t);
                            DataChunk d;
                            if (_inFlight.TryGetValue(t, out d))
                            {
                                d.setGapAck(true);
                                totalAcked += d.getDataSize();
                            }
                            else
                            {
                                logger.LogDebug("Huh? gap for something not inFlight ?!? " + t);
                            }
                        }
                    }
                }

                /*
                 *               ii) Set rwnd equal to the newly received a_rwnd minus the number
                 *               of bytes still outstanding after processing the Cumulative
                 *               TSN Ack and the Gap Ack Blocks.
                 */
                int totalDataInFlight = 0;
                lock (_inFlight)
                {
                    foreach (var kvp in _inFlight)
                    {
                        DataChunk d = kvp.Value;
                        long      k = kvp.Key;
                        if (!d.getGapAck())
                        {
                            totalDataInFlight += d.getDataSize();
                        }
                    }
                }

                _rwnd = sack.getArWin() - totalDataInFlight;
                //logger.LogDebug("Setting rwnd to " + _rwnd);
                bool advanced = (_lastCumuTSNAck < ackedTo);
                adjustCwind(advanced, totalDataInFlight, totalAcked);
                _lastCumuTSNAck = ackedTo;
            }
            else
            {
                logger.LogDebug("Dumping Sack - already seen later sack.");
            }

            return(ret);
        }
Example #4
0
 abstract protected Chunk[] sackDeal(SackChunk sackChunk);
Example #5
0
        public static Chunk mkChunk(ByteBuffer pkt)
        {
            Chunk ret = null;

            if (pkt.remaining() >= 4)
            {
                ChunkType type   = (ChunkType)pkt.GetByte();
                byte      flags  = pkt.GetByte();
                int       length = pkt.GetUShort();
                switch (type)
                {
                case ChunkType.DATA:
                    ret = new DataChunk(flags, length, pkt);
                    break;

                case ChunkType.INIT:
                    ret = new InitChunk(type, flags, length, pkt);
                    break;

                case ChunkType.SACK:
                    ret = new SackChunk(type, flags, length, pkt);
                    break;

                case ChunkType.INITACK:
                    ret = new InitAckChunk(type, flags, length, pkt);
                    break;

                case ChunkType.COOKIE_ECHO:
                    ret = new CookieEchoChunk(type, flags, length, pkt);
                    break;

                case ChunkType.COOKIE_ACK:
                    ret = new CookieAckChunk(type, flags, length, pkt);
                    break;

                case ChunkType.ABORT:
                    ret = new AbortChunk(type, flags, length, pkt);
                    break;

                case ChunkType.HEARTBEAT:
                    ret = new HeartBeatChunk(type, flags, length, pkt);
                    break;

                case ChunkType.RE_CONFIG:
                    ret = new ReConfigChunk(type, flags, length, pkt);
                    break;

                case ChunkType.ERROR:
                    ret = new ErrorChunk(type, flags, length, pkt);
                    break;

                default:
                    logger.LogWarning($"SCTP unknown chunk type received {type}.");
                    ret = new FailChunk(type, flags, length, pkt);
                    break;
                }
                if (ret != null)
                {
                    if (pkt.hasRemaining())
                    {
                        int mod = ret.getLength() % 4;
                        if (mod != 0)
                        {
                            for (int pad = mod; pad < 4; pad++)
                            {
                                pkt.GetByte();
                            }
                        }
                    }
                }
            }
            return(ret);
        }