public void testDeliverVeryManyMessages() { Console.WriteLine("--> deliver very many messages"); string[] teststrings = new string[10000]; for (int i = 0; i < teststrings.Length; i++) { teststrings[i] = "Test string " + i; } SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); List <string> result = new List <string>(); ushort mo = (ushort)0; foreach (string ts in teststrings) { DataChunk single = new DataChunk(); single.setTsn(_tsn++); single.setsSeqNo((int)mo++); single.setData(ts.getBytes()); single.setPpid(DataChunk.WEBRTCstring); single.setFlags(DataChunk.SINGLEFLAG); stash.Add(single); result.Add(ts); } SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); instance.deliver(s, stash, l); }
public void testDeliverTwo() { Console.WriteLine("--> deliver two"); SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); string[] teststrings = new string[] { "Test string A", "Test string B" }; List <string> result = new List <string>(); int n = 0; foreach (string ts in teststrings) { DataChunk single = new DataChunk(); single.setTsn(_tsn++); single.setsSeqNo(n++); single.setData(ts.getBytes()); single.setPpid(DataChunk.WEBRTCstring); single.setFlags(DataChunk.SINGLEFLAG); stash.Add(single); result.Add(ts); } SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); instance.deliver(s, stash, l); int remain = result.Count; Assert.AreEqual(remain, 0); }
public void testMakeMessage_string_BlockingSCTPStream() { Console.WriteLine("---->makeMessage string"); StringBuilder rightout = new StringBuilder(); SCTPStreamListener rsl = new ASCTPStreamListenerImpl(rightout); DatagramTransport[] trans = mkMockTransports(); MockAssociationListener listenLeft = new MockAssociationListener(); MockAssociationListener listenRight = new MockAssociationListenerImpl(rsl); ThreadedAssociation instanceLeft = new ThreadedAssociation(trans[0], listenLeft); ThreadedAssociation instanceRight = new ThreadedAssociation(trans[1], listenRight); instanceLeft.associate(); lock (listenLeft) { Monitor.Wait(listenLeft, 2000); Assert.IsTrue(listenLeft.associated); Assert.IsTrue(listenRight.associated); } int id = 10; SCTPStream s = instanceLeft.mkStream(id); Assert.IsTrue(typeof(BlockingSCTPStream).IsAssignableFrom(s.GetType())); string test = "Test message"; SCTPMessage m = instanceLeft.makeMessage(test, (BlockingSCTPStream)s); instanceLeft.sendAndBlock(m); lock (rightout) { Monitor.Wait(rightout, 2000); Assert.AreEqual(rightout.ToString(), test); } }
public void testDeliverSingle() { Console.WriteLine("--> deliver single"); SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); DataChunk single = new DataChunk(); string teststring = "Test string"; single.setData(teststring.getBytes()); single.setPpid(DataChunk.WEBRTCstring); single.setFlags(DataChunk.SINGLEFLAG); single.setTsn(_tsn++); single.setsSeqNo(0); stash.Add(single); List <string> result = new List <string>(); result.Add(teststring); SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); instance.deliver(s, stash, l); int remain = result.Count; Assert.AreEqual(remain, 0); }
public override void onMessage(SCTPStream s, string message) { lock (this) { Console.WriteLine("onmessage : " + message); rightout.Append(message); Monitor.Pulse(this); } }
/// <summary> /// Event handler for a new data channel being created by the remote peer. /// </summary> /// <param name="s">The SCTP stream that was created.</param> /// <param name="label">The label for the stream. Can be empty and can also be a duplicate.</param> /// <param name="payloadProtocolID">The payload protocol ID of the new stream.</param> public void onDCEPStream(SCTPStream s, string label, int payloadProtocolID) { logger.LogDebug($"SCTP data channel stream opened for label {label}, ppid {payloadProtocolID}, stream id {s.getNum()}."); bool isLocalStreamID = (_isClient) ? s.getNum() % 2 == 0 : s.getNum() % 2 != 0; OnSCTPStreamOpen?.Invoke(s, isLocalStreamID); }
public void onMessage(SCTPStream s, byte[] message) { rightout.Put(message); Console.WriteLine("Byte onmessage : " + message.Length); lock (rightout) { Monitor.Pulse(rightout); } }
public void onMessage(SCTPStream s, string message) { empty.Append(message); Console.WriteLine("string onmessage : " + message); lock (rightout) { Monitor.Pulse(rightout); } }
public void testDCEPStreamSend() { Console.WriteLine("---->testDCEPStreamSend string"); StringBuilder rightout = new StringBuilder(); StringBuilder rightLabel = new StringBuilder(); SCTPStreamListener rsl = new ASCTPStreamListenerImpl(rightout); DatagramTransport[] trans = mkMockTransports(); MockAssociationListener listenLeft = new MockAssociationListenerImpl2(); MockAssociationListener listenRight = new MockAssociationListenerImpl3(rightLabel, rsl); ThreadedAssociation instanceLeft = new ThreadedAssociation(trans[0], listenLeft); ThreadedAssociation instanceRight = new ThreadedAssociation(trans[1], listenRight); instanceLeft.associate(); lock (listenLeft) { Monitor.Wait(listenLeft, 2000); Assert.IsTrue(listenLeft.associated); Assert.IsTrue(listenRight.associated); } int id = 10; string label = "test Stream"; SCTPStream s = instanceLeft.mkStream(id, label); lock (rightLabel) { Monitor.Wait(rightLabel, 2000); Assert.AreEqual(rightLabel.ToString(), label); } Assert.IsTrue(typeof(BlockingSCTPStream).IsAssignableFrom(s.GetType())); BlockingSCTPStream bs = (BlockingSCTPStream)s; StringBuilder longTestMessage = new StringBuilder(); for (int i = 0; i < 10000; i++) { longTestMessage.Append(" " + i); } string teststring = longTestMessage.ToString(); Console.WriteLine("-------> string length = " + teststring.Length); Thread st = new Thread(() => { try { s.send(teststring); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }); st.Name = "sender "; st.Start(); lock (rightout) { Monitor.Wait(rightout, 10000); Assert.AreEqual(teststring, rightout.ToString()); } }
void oneMissingPartMessages(string[] teststrings, string es, int ec) { SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); List <string> result = new List <string>(); int n = 0; int expectedToRemain = 0; bool skip = false; foreach (string ts in teststrings) { for (int i = 0; i < ts.Length; i++) { DataChunk single = new DataChunk(); single.setTsn(_tsn++); single.setsSeqNo(n); string letter = ts.Substring(i, 1); single.setData(letter.getBytes()); single.setPpid(DataChunk.WEBRTCstring); if (i == 0) { single.setFlags(DataChunk.BEGINFLAG); } else if (i == ts.Length - 1) { single.setFlags(DataChunk.ENDFLAG); } if ((ec != i) || !ts.Equals(es)) { stash.Add(single); } } if (ts.Equals(es)) { skip = true; } if (skip) { expectedToRemain++; } result.Add(ts); n++; } SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); instance.deliver(s, stash, l); int remain = result.Count; //Console.WriteLine("expected:" + expectedToRemain + " remain:" + remain); Assert.AreEqual(remain, expectedToRemain); }
public void deliverUnorderedPackets(int seed) { Random rand = new Random(seed); // deliberately not crypto random so test is repeatable // Console.WriteLine("seed = "+seed); string[] teststrings = { "Test string A, ", "Test string B ", "and Test string C" }; SCTPStream s = mockStream(); List <string> result = new List <string>(); int n = 0; List <DataChunk> all = new List <DataChunk>(); foreach (string ts in teststrings) { for (int i = 0; i < ts.Length; i++) { DataChunk single = new DataChunk(); single.setTsn(_tsn++); single.setsSeqNo(n); string letter = ts.Substring(i, 1); single.setData(letter.getBytes()); single.setPpid(DataChunk.WEBRTCstring); if (i == 0) { single.setFlags(DataChunk.BEGINFLAG); } else if (i == ts.Length - 1) { single.setFlags(DataChunk.ENDFLAG); } all.Add(single); } result.Add(ts); n++; } SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); while (all.Count > 0) { int v = rand.Next(all.Count); DataChunk c = all[v]; all.RemoveAt(v); stash.Add(c); instance.deliver(s, stash, l); } int remain = result.Count; Assert.AreEqual(remain, 0); }
public void deliver(SCTPStream s, SortedArray <DataChunk> a, SCTPStreamListener l) { Logger.Debug("in deliver() for stream " + s.getLabel() + " with " + a.Count + " chunks. "); // strictly this should be looking at flags etc, and bundling the result into a message foreach (DataChunk dc in a) { if (dc.getDCEP() != null) { Logger.Debug("in deliver() for a DCEP message " + dc.getDataAsString()); } else { Logger.Debug("inbound data chunk is " + dc.ToString()); l.onMessage(s, dc.getDataAsString()); } } a.Clear(); }
public void testMkStream() { Console.WriteLine("--> mkStream"); DatagramTransport[] trans = mkMockTransports(); MockAssociationListener listenLeft = new MockAssociationListener(); MockAssociationListener listenRight = new MockAssociationListener(); ThreadedAssociation instanceLeft = new ThreadedAssociation(trans[0], listenLeft); ThreadedAssociation instanceRight = new ThreadedAssociation(trans[1], listenRight); instanceLeft.associate(); lock (listenLeft) { Monitor.Wait(listenLeft, 1000); Assert.IsTrue(listenLeft.associated); Assert.IsTrue(listenRight.associated); } int id = 10; SCTPStream result = instanceLeft.mkStream(id); Assert.IsTrue(typeof(BlockingSCTPStream).IsAssignableFrom(result.GetType())); }
void multiPartMessage(string[] teststrings) { SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); List <string> result = new List <string>(); int n = 0; StringBuilder bs = new StringBuilder(); foreach (string ts in teststrings) { DataChunk single = new DataChunk(); single.setTsn((uint)_tsn++); single.setsSeqNo(0); single.setData(ts.getBytes()); single.setPpid(DataChunk.WEBRTCstring); if (n == 0) { single.setFlags(DataChunk.BEGINFLAG); } else if (n == teststrings.Length - 1) { single.setFlags(DataChunk.ENDFLAG); } n++; bs.Append(ts); stash.Add(single); } result.Add(bs.ToString()); SCTPStreamListener l = new CheckingStreamListener(result); UnorderedStreamBehaviour instance = new UnorderedStreamBehaviour(); instance.deliver(s, stash, l); int remain = result.Count; Assert.AreEqual(remain, 0); }
void dontDeliverOnePart(int flag) { SCTPStream s = mockStream(); SortedArray <DataChunk> stash = new SortedArray <DataChunk>(); DataChunk single = new DataChunk(); string teststring = "Test string"; single.setData(teststring.getBytes()); single.setPpid(DataChunk.WEBRTCstring); single.setFlags(flag); single.setTsn(_tsn++); single.setsSeqNo(0); stash.Add(single); List <string> result = new List <string>(); result.Add(teststring); SCTPStreamListener l = new CheckingStreamListener(result); OrderedStreamBehaviour instance = new OrderedStreamBehaviour(); instance.deliver(s, stash, l); int remain = result.Count; Assert.AreEqual(1, remain); }
public void testMakeMessage_byteArr_BlockingSCTPStream() { Console.WriteLine("---->makeMessage bytes"); ByteBuffer rightout = new ByteBuffer(new byte[10000]); StringBuilder empty = new StringBuilder(); SCTPByteStreamListener rsl = new SCTPByteStreamListenerImpl(empty, rightout); DatagramTransport[] trans = mkMockTransports(); MockAssociationListener listenLeft = new MockAssociationListener(); MockAssociationListener listenRight = new MockAssociationListenerImpl(rsl); ThreadedAssociation instanceLeft = new ThreadedAssociation(trans[0], listenLeft); ThreadedAssociation instanceRight = new ThreadedAssociation(trans[1], listenRight); instanceLeft.associate(); lock (listenLeft) { Monitor.Wait(listenLeft, 2000); Assert.IsTrue(listenLeft.associated); Assert.IsTrue(listenRight.associated); } int id = 10; SCTPStream s = instanceLeft.mkStream(id); Assert.IsTrue(typeof(BlockingSCTPStream).IsAssignableFrom(s.GetType())); string test = "Test message"; SCTPMessage m = instanceLeft.makeMessage(test.getBytes(), (BlockingSCTPStream)s); instanceLeft.sendAndBlock(m); lock (rightout) { Monitor.Wait(rightout, 2000); int l = rightout.Position; string res = rightout.Data.getString(0, l); Assert.AreEqual(res, test); Assert.AreEqual(empty.Length, 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 = Time.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.Error("eek - can't replace free block on list!?!"); Logger.Error(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.Trace("gap block says far end has seen " + t); DataChunk d; if (_inFlight.TryGetValue(t, out d)) { d.setGapAck(true); totalAcked += d.getDataSize(); } else { Logger.Debug("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.Debug("Setting rwnd to " + _rwnd); bool advanced = (_lastCumuTSNAck < ackedTo); adjustCwind(advanced, totalDataInFlight, totalAcked); _lastCumuTSNAck = ackedTo; } else { Logger.Debug("Dumping Sack - already seen later sack."); } return(ret); }
public Chunk[] respond(SCTPStream a) { Logger.Debug("in respond() for a opened stream " + a.getLabel()); return(null); }
internal void SetStream(SCTPStream s) { _sctpStream = s; s.setSCTPStreamListener(this); s.OnOpen = OnStreamOpened; }
public void onMessage(SCTPStream s, string message) { //logger.LogDebug($"Data channel received message (label={s.getLabel()}, streamID={s.getNum()}): {message}."); onmessage?.Invoke(message); }
public void onDataMessage(SCTPStream s, byte[] data) { //logger.LogDebug($"Data channel received message (label={s.getLabel()}, streamID={s.getNum()}): {message}."); onDatamessage?.Invoke(data); }
public void close(SCTPStream s) { IsOpened = false; logger.LogDebug($"Data channel stream closed id {s.getNum()}."); onclose?.Invoke(); }
/// <summary> /// Event handler that gets fired as part of creating a new data channel. /// </summary> public void onRawStream(SCTPStream s) { // Do nothing. }
public void deliver(SCTPStream s, SortedArray <DataChunk> stash, SCTPStreamListener l) { //stash is the list of all DataChunks that have not yet been turned into whole messages //we assume that it is sorted by stream sequence number. List <DataChunk> delivered = new List <DataChunk>(); SortedArray <DataChunk> message = null; if (stash.Count == 0) { return; // I'm not fond of these early returns } long expectedTsn = stash.First.getTsn(); // This ignores gaps - but _hopefully_ messageNo will catch any // gaps we care about - ie gaps in the sequence for _this_ stream // we can deliver ordered messages on this stream even if earlier messages from other streams are missing // - this does assume that the tsn's of a message are contiguous -which is odd. foreach (DataChunk dc in stash) { int messageNo = s.getNextMessageSeqIn(); int flags = dc.getFlags() & DataChunk.SINGLEFLAG; // mask to the bits we want long tsn = dc.getTsn(); bool lookingForOrderedMessages = _ordered || (message != null); // which is to say for unordered messages we can tolerate gaps _between_ messages // but not within them if (lookingForOrderedMessages && (tsn != expectedTsn)) { Logger.Debug("Hole in chunk sequence " + tsn + " expected " + expectedTsn); break; } switch (flags) { case DataChunk.SINGLEFLAG: // singles are easy - just dispatch. if (_ordered && (messageNo != dc.getSSeqNo())) { Logger.Debug("Hole (single) in message sequence " + dc.getSSeqNo() + " expected " + messageNo); break; // not the message we are looking for... } SCTPMessage single = new SCTPMessage(s, dc); if (single.deliver(l)) { delivered.Add(dc); messageNo++; s.setNextMessageSeqIn(messageNo); } break; case DataChunk.BEGINFLAG: if (_ordered && (messageNo != dc.getSSeqNo())) { Logger.Debug("Hole (begin) in message sequence " + dc.getSSeqNo() + " expected " + messageNo); break; // not the message we are looking for... } message = new SortedArray <DataChunk>(); message.Add(dc); Logger.Trace("new message no" + dc.getSSeqNo() + " starts with " + dc.getTsn()); break; case 0: // middle if (message != null) { message.Add(dc); Logger.Trace("continued message no" + dc.getSSeqNo() + " with " + dc.getTsn()); } else { // perhaps check sno ? Logger.Debug("Middle with no start" + dc.getSSeqNo() + " tsn " + dc.getTsn()); } break; case DataChunk.ENDFLAG: if (message != null) { message.Add(dc); Logger.Trace("finished message no" + dc.getSSeqNo() + " with " + dc.getTsn()); SCTPMessage deliverable = new SCTPMessage(s, message); if (deliverable.deliver(l)) { message.AddToList(delivered); messageNo++; s.setNextMessageSeqIn(messageNo); } message = null; } else { Logger.Debug("End with no start" + dc.getSSeqNo() + " tsn " + dc.getTsn()); message = null; } break; default: throw new Exception("[IllegalStateException] Impossible value in stream logic"); } expectedTsn = tsn + 1; } stash.RemoveWhere((dc) => { return(delivered.Contains(dc)); }); }
public void setUp() { a = null; id = 1000; stream = new SCTPStreamImpl(a, id); }
public Chunk[] respond(SCTPStream a) { return(null); }
public void close(SCTPStream aThis) { Console.WriteLine("close '"); }
public void onMessage(SCTPStream s, string message) { Console.WriteLine("delivered '" + message + "'"); Assert.IsTrue(_results.Contains(message)); _results.Remove(message); }
public void onRawStream(SCTPStream s) { }
public void onDCEPStream(SCTPStream s, string label, int type) { }