Ejemplo n.º 1
0
        /// <summary>
        /// Parses the SHUTDOWN chunk fields.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpShutdownChunk ParseChunk(byte[] buffer, int posn)
        {
            var shutdownChunk = new SctpShutdownChunk();

            shutdownChunk.CumulativeTsnAck = NetConvert.ParseUInt32(buffer, posn + SCTP_CHUNK_HEADER_LENGTH);
            return(shutdownChunk);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parses an SCTP chunk from a buffer.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        /// <returns>An SCTP chunk instance.</returns>
        public static SctpChunk Parse(byte[] buffer, int posn)
        {
            if (buffer.Length < posn + SCTP_CHUNK_HEADER_LENGTH)
            {
                throw new ApplicationException("Buffer did not contain the minimum of bytes for an SCTP chunk.");
            }

            byte chunkType = buffer[posn];

            if (Enum.IsDefined(typeof(SctpChunkType), chunkType))
            {
                switch ((SctpChunkType)chunkType)
                {
                case SctpChunkType.ABORT:
                    return(SctpAbortChunk.ParseChunk(buffer, posn, true));

                case SctpChunkType.DATA:
                    return(SctpDataChunk.ParseChunk(buffer, posn));

                case SctpChunkType.ERROR:
                    return(SctpErrorChunk.ParseChunk(buffer, posn, false));

                case SctpChunkType.SACK:
                    return(SctpSackChunk.ParseChunk(buffer, posn));

                case SctpChunkType.COOKIE_ACK:
                case SctpChunkType.COOKIE_ECHO:
                case SctpChunkType.HEARTBEAT:
                case SctpChunkType.HEARTBEAT_ACK:
                case SctpChunkType.SHUTDOWN_ACK:
                case SctpChunkType.SHUTDOWN_COMPLETE:
                    return(ParseBaseChunk(buffer, posn));

                case SctpChunkType.INIT:
                case SctpChunkType.INIT_ACK:
                    return(SctpInitChunk.ParseChunk(buffer, posn));

                case SctpChunkType.SHUTDOWN:
                    return(SctpShutdownChunk.ParseChunk(buffer, posn));

                default:
                    logger.LogDebug($"TODO: Implement parsing logic for well known chunk type {(SctpChunkType)chunkType}.");
                    return(ParseBaseChunk(buffer, posn));
                }
            }

            // Shouldn't reach this point. The SCTP packet parsing logic checks if the chunk is
            // recognised before attempting to parse it.
            throw new ApplicationException($"SCTP chunk type of {chunkType} was not recognised.");
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Initiates the shutdown of the association by sending a shutdown
        /// control chunk to the remote party.
        /// </summary>
        public void Shutdown()
        {
            if (!_wasAborted)
            {
                SetState(SctpAssociationState.ShutdownPending);

                // TODO: Check outstanding data chunks.

                // If no DATA chunks have been received use the initial TSN - 1 from
                // the remote party. Seems weird to use the - 1, and couldn't find anything
                // in the RFC that says to do it, but that's what usrsctp accepts.
                uint?ackTSN = _dataReceiver.CumulativeAckTSN ?? _remoteInitialTSN - 1;

                logger.LogTrace($"SCTP sending shutdown for association {ID}, ACK TSN {ackTSN}.");

                SetState(SctpAssociationState.ShutdownSent);

                SctpShutdownChunk shutdownChunk = new SctpShutdownChunk(ackTSN);
                SendChunk(shutdownChunk);

                _dataSender.Close();
            }
        }