Exemplo n.º 1
0
        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)); });
        }
        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)); });
        }