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()); }
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"); }
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; }
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 "); }
/* * 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()); } } }