Пример #1
0
        public override void enqueue(DataChunk d)
        {
            // todo - this worries me - 2 nested synchronized
            Logger.Trace(" Aspiring to enqueue " + d.ToString());

            lock (this) {
                long now = Time.CurrentTimeMillis();
                d.setTsn(_nearTSN++);
                d.setGapAck(false);
                d.setRetryTime(now + getT3() - 1);
                d.setSentTime(now);
                SimpleSCTPTimer.setRunnable(run, getT3());
                reduceRwnd(d.getDataSize());
                //_outbound.put(new Long(d.getTsn()), d);
                Logger.Trace(" DataChunk enqueued " + d.ToString());
                // all sorts of things wrong here - being in a synchronized not the least of them

                Chunk[] toSend = addSackIfNeeded(d);
                try {
                    send(toSend);
                    Logger.Trace("sent, syncing on inFlight... " + d.getTsn());
                    lock (_inFlight) {
                        _inFlight.Add(d.getTsn(), d);
                    }
                    Logger.Trace("added to inFlight... " + d.getTsn());
                }
                catch (SctpPacketFormatException ex) {
                    Logger.Error("badly formatted chunk " + d.ToString());
                    Logger.Error(ex.ToString());
                }
                catch (EndOfStreamException end) {
                    unexpectedClose(end);
                    Logger.Error(end.ToString());
                }
                catch (IOException ex) {
                    Logger.Error("Can not send chunk " + d.ToString());
                    Logger.Error(ex.ToString());
                }
            }
            Logger.Trace("leaving enqueue" + d.getTsn());
        }
Пример #2
0
        public void testAss()
        {
            DatagramTransportImpl   mock = new DatagramTransportImpl(null);
            AssociationListenerImpl al   = new AssociationListenerImpl(null);
            MockAssociation         ass  = new MockAssociation(mock, al);

            ass.setMyVerTag(335297160);
            ByteBuffer b = ByteBuffer.wrap(sampleDataOpen);
            Packet     p = new Packet(b);

            ass.deal(p);

            Packet       ack    = new Packet(mock.sent);
            List <Chunk> chunks = ack.getChunkList();

            Assert.AreEqual(1, chunks.Count, "Expecting 1 chunk ");
            DataChunk dat = chunks[0] as DataChunk;

            Assert.AreEqual(dat.getType(), DataChunk.CType.DATA, "Expecting a Data chunk");
            Console.WriteLine("got " + dat.GetType().Name + " chunk" + dat.ToString());
            Assert.AreEqual(dat.getSSeqNo(), 0, "Expecting seqno of zero");
            Assert.AreEqual(dat.getStreamId(), 0, "Expecting stream of zero");
            Assert.AreEqual(dat.getPpid(), 50, "Expecting an DCEP");
            Assert.AreEqual(dat.getData(), null, "Data should be zero");
            Assert.AreEqual(dat.getDCEP() != null, true, "Expected  to parse a DCEP packet");
            Assert.AreEqual(dat.getDCEP().isAck(), true, "Expected an ack DCEP packet ");

            Assert.AreEqual((al.stream == null), false, "expecting a stream");
            al.stream.send("hello");
            // ugh - uses a side effect on the sent buffer, which we capture.
            Packet pack = new Packet(mock.sent);

            chunks = pack.getChunkList();
            Assert.AreEqual(1, chunks.Count, "Expecting 1 chunk ");
            dat = chunks[0] as DataChunk;
            Assert.AreEqual(dat.getType(), Chunk.CType.DATA, "Expecting a Data chunk");
            Console.WriteLine("got " + dat.GetType().Name + " chunk" + dat.ToString());
            Assert.AreEqual(dat.getSSeqNo(), 1, "Expecting seqno of one");             // we've done a DCEP ack by now.
            Assert.AreEqual(dat.getStreamId(), 0, "Expecting stream of zero");
            Assert.AreEqual(dat.getDataAsString(), "hello", "Expecting hello in the data");
        }
Пример #3
0
        private void ingest(DataChunk dc, List <Chunk> rep)
        {
            Logger.Trace("ingesting " + dc.ToString());
            Chunk      closer = null;
            int        sno    = dc.getStreamId();
            uint       tsn    = dc.getTsn();
            SCTPStream _in;

            if (!_streams.TryGetValue(sno, out _in))
            {
                _in = mkStream(sno);
                _streams.Add(sno, _in);
                _al.onRawStream(_in);
            }
            Chunk[] repa;
            // todo dcep logic belongs in behave - not here.
            if (dc.getDCEP() != null)
            {
                repa = dcepDeal(_in, dc, dc.getDCEP());
                // delay 'till after first packet so we can get the label etc set
                // _however_ this should be in behave -as mentioned above.
                try {
                    _al.onDCEPStream(_in, _in.getLabel(), dc.getPpid());
                    if (_in.OnOpen != null)
                    {
                        _in.OnOpen.Invoke();
                    }
                }
                catch (Exception x) {
                    closer = _in.immediateClose();
                    Logger.Error(x.ToString());
                }
            }
            else
            {
                repa = _in.append(dc);
            }

            if (repa != null)
            {
                foreach (Chunk r in repa)
                {
                    rep.Add(r);
                }
            }
            if (closer != null)
            {
                rep.Add(closer);
            }
            _in.inbound(dc);
            _farTSN = tsn;
        }
Пример #4
0
        public void testOpenDataChunk()
        {
            ByteBuffer   b      = ByteBuffer.wrap(sampleData);
            Packet       p      = new Packet(b);
            List <Chunk> chunks = p.getChunkList();

            Assert.AreEqual(1, chunks.Count, "Expecting 1 chunk ");
            DataChunk dat = chunks[0] as DataChunk;

            Assert.AreEqual(dat.getType(), Chunk.CType.DATA, "Expecting a Data chunk");
            Console.WriteLine("got " + dat.GetType().Name + " chunk" + dat.ToString());
            Assert.AreEqual(dat.getSSeqNo(), 0, "Expecting seqno of zero");
            Assert.AreEqual(dat.getStreamId(), 0, "Expecting stream of zero");
            Assert.AreEqual(dat.getPpid(), 50, "Expecting an DCEP");
            Assert.AreEqual(dat.getData(), null, "Data should be zero");
            Assert.AreEqual(dat.getDCEP() != null, true, "Expected  to parse a DCEP packet");
            Assert.AreEqual(dat.getDCEP().isAck(), false, "Expected an open DCEP packet ");
        }
Пример #5
0
        /*
         * In instances where its peer endpoint is multi-homed, if an endpoint
         * receives a SACK that advances its Cumulative TSN Ack Point, then it
         * should update its cwnd (or cwnds) apportioned to the destination
         * addresses to which it transmitted the acknowledged data.  However, if
         *
         *
         *
         * Stewart                     Standards Track                    [Page 96]
         * 
         * RFC 4960          Stream Control Transmission Protocol    September 2007
         *
         *
         * the received SACK does not advance the Cumulative TSN Ack Point, the
         * endpoint MUST NOT adjust the cwnd of any of the destination
         * addresses.
         *
         * Because an endpoint's cwnd is not tied to its Cumulative TSN Ack
         * Point, as duplicate SACKs come in, even though they may not advance
         * the Cumulative TSN Ack Point an endpoint can still use them to clock
         * out new data.  That is, the data newly acknowledged by the SACK
         * diminishes the amount of data now in flight to less than cwnd, and so
         * the current, unchanged value of cwnd now allows new data to be sent.
         * On the other hand, the increase of cwnd must be tied to the
         * Cumulative TSN Ack Point advancement as specified above.  Otherwise,
         * the duplicate SACKs will not only clock out new data, but also will
         * adversely clock out more new data than what has just left the
         * network, during a time of possible congestion.
         *
         * o  When the endpoint does not transmit data on a given transport
         * address, the cwnd of the transport address should be adjusted to
         * max(cwnd/2, 4*MTU) per RTO.
         *
         */

        // timer goes off,
        public void run()
        {
            if (canSend())
            {
                long now = Time.CurrentTimeMillis();
                Logger.Trace("retry timer went off at " + now);
                List <DataChunk> dcs = new List <DataChunk>();
                int  space           = _transpMTU - 12;      // room for packet header
                bool resetTimer      = false;
                lock (_inFlight) {
                    foreach (var kvp in _inFlight)
                    {
                        DataChunk d = kvp.Value;
                        long      k = kvp.Key;
                        if (d.getGapAck())
                        {
                            Logger.Trace("skipping gap-acked tsn " + d.getTsn());
                            continue;
                        }
                        if (d.getRetryTime() <= now)
                        {
                            space -= d.getChunkLength();
                            Logger.Debug("available space in pkt is " + space);
                            if (space <= 0)
                            {
                                resetTimer = true;
                                break;
                            }
                            else
                            {
                                dcs.Add(d);
                                d.setRetryTime(now + getT3() - 1);
                            }
                        }
                        else
                        {
                            Logger.Trace("retry not yet due for  " + d.ToString());
                            resetTimer = true;
                        }
                    }
                }
                if (dcs.Count != 0)
                {
                    dcs.Sort();
                    DataChunk[] da = new DataChunk[dcs.Count];
                    int         i  = 0;
                    foreach (DataChunk d in dcs)
                    {
                        da[i++] = d;
                    }
                    resetTimer = true;
                    try {
                        Logger.Debug("Sending retry for  " + da.Length + " data chunks");
                        this.send(da);
                    }
                    catch (EndOfStreamException end) {
                        Logger.Debug("Retry send failed " + end.ToString());
                        unexpectedClose(end);
                        resetTimer = false;
                    }
                    catch (Exception ex) {
                        Logger.Error("Cant send retry - eek " + ex.ToString());
                    }
                }
                else
                {
                    Logger.Trace("Nothing to do ");
                }
                if (resetTimer)
                {
                    SimpleSCTPTimer.setRunnable(run, getT3());
                    Logger.Trace("Try again in a while  " + getT3());
                }
            }
        }