internal override SCTPMessage makeMessage(string bytes, BlockingSCTPStream s) { SCTPMessage m = null; if (base.canSend()) { if (bytes.Length < this.maxMessageSize()) { m = new SCTPMessage(bytes, s); lock (s) { int mseq = s.getNextMessageSeqOut(); s.setNextMessageSeqOut(mseq + 1); m.setSeq(mseq); } } else { logger.LogWarning("Message too long " + bytes.Length + " > " + this.maxMessageSize()); } } else { logger.LogWarning("Can't send a message right now"); } return(m); }
internal override void sendAndBlock(SCTPMessage m) { while (m.hasMoreData()) { DataChunk dc; lock (_freeBlocks) { dc = _freeBlocks.Count > 0 ? _freeBlocks.Dequeue() : new DataChunk(); } m.fill(dc); //logger.LogDebug("thinking about waiting for congestion " + dc.getTsn()); lock (_congestion) { //logger.LogDebug("In congestion sync block "); while (!this.maySend(dc.getDataSize())) { //logger.LogDebug("about to wait for congestion for " + this.getT3()); Monitor.Wait(_congestion, (int)this.getT3()); // wholly wrong } } // todo check rollover - will break at maxint. enqueue(dc); } }
public override void send(byte[] message) { lock (this) { Association a = base.getAssociation(); SCTPMessage m = a.makeMessage(message, this); undeliveredOutboundMessages.Add(m.getSeq(), m); a.sendAndBlock(m); } }
public override void send(string message) { lock (this) { Association a = base.getAssociation(); SCTPMessage m = a.makeMessage(message, this); if (m == null) { logger.LogError("SCTPMessage cannot be null, but it is"); } a.sendAndBlock(m); } }
public override async Task sendasync(string message) { await semaphore.WaitAsync().ConfigureAwait(false); try { Association a = base.getAssociation(); SCTPMessage m = a.makeMessage(message, this); if (m == null) { logger.LogError("SCTPMessage cannot be null, but it is"); return; } a.sendAndBlock(m); } finally { semaphore.Release(); } }
public override async Task sendasync(byte[] message) { await semaphore.WaitAsync().ConfigureAwait(false); try { Association a = base.getAssociation(); SCTPMessage m = a.makeMessage(message, this); if (m == null) { logger.LogError("SCTPMessage cannot be null, but it is"); return; } undeliveredOutboundMessages.AddOrUpdate(m.getSeq(), m, (id, b) => m); a.sendAndBlock(m); } finally { semaphore.Release(); } }
internal override SCTPMessage makeMessage(byte[] bytes, BlockingSCTPStream s) { lock (this) { SCTPMessage m = null; if (base.canSend()) { if (bytes.Length < this.maxMessageSize()) { m = new SCTPMessage(bytes, s); lock (s) { int mseq = s.getNextMessageSeqOut(); s.setNextMessageSeqOut(mseq + 1); m.setSeq(mseq); } } } return(m); } }
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>(); 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; if (lookingForOrderedMessages && (tsn != expectedTsn)) { logger.LogDebug("Hole in chunk sequence " + tsn + " expected " + expectedTsn); break; } switch (flags) { case DataChunk.SINGLEFLAG: if (_ordered && (messageNo != dc.getSSeqNo())) { logger.LogDebug("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: case DataChunk.ENDFLAG: case DataChunk.CONTINUEFLAG: if (_ordered && (messageNo != dc.getSSeqNo())) { logger.LogDebug("Hole (single) in message sequence " + dc.getSSeqNo() + " expected " + messageNo); break; // not the message we are looking for... } var orderedMessage = _orderedMessageHandler.GetMessage(dc.getSSeqNo()) .Add(dc, flags); if (orderedMessage.IsReady) { orderedMessage.Finish(() => { SCTPMessage deliverable = new SCTPMessage(s, orderedMessage.ToArray()); if (deliverable.deliver(l)) { _orderedMessageHandler.RemoveMessage(orderedMessage); orderedMessage.AddToList(delivered); messageNo++; s.setNextMessageSeqIn(messageNo); } }); } break; default: throw new Exception("[IllegalStateException] Impossible value in stream logic"); } expectedTsn = tsn + 1; } stash.RemoveWhere((dc) => { return(delivered.Contains(dc)); }); }
internal override void deliverMessage(SCTPMessage message) { message.run(); }
abstract internal void deliverMessage(SCTPMessage message);
abstract internal void sendAndBlock(SCTPMessage m);
internal override void deliverMessage(SCTPMessage message) { ThreadPool.QueueUserWorkItem((obj) => { message.run(); }); }
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.LogDebug("Hole in chunk sequence " + tsn + " expected " + expectedTsn); break; } switch (flags) { case DataChunk.SINGLEFLAG: // singles are easy - just dispatch. if (_ordered && (messageNo != dc.getSSeqNo())) { logger.LogDebug("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.LogDebug("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.LogDebug("new message no" + dc.getSSeqNo() + " starts with " + dc.getTsn()); break; case 0: // middle if (message != null) { message.Add(dc); logger.LogDebug("continued message no" + dc.getSSeqNo() + " with " + dc.getTsn()); } else { // perhaps check sno ? logger.LogDebug("Middle with no start" + dc.getSSeqNo() + " tsn " + dc.getTsn()); } break; case DataChunk.ENDFLAG: if (message != null) { message.Add(dc); logger.LogDebug("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.LogDebug("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)); }); }