Esempio n. 1
0
        /// <summary>
        /// Create a new SCTP association instance where the INIT will be generated
        /// from this end of the connection.
        /// </summary>
        /// <param name="sctpTransport">The transport layer doing the actual sending and receiving of
        /// packets, e.g. UDP, DTLS, raw sockets etc.</param>
        /// <param name="destination">Optional. The remote destination end point for this association.
        /// Some transports, such as DTLS, are already established and do not use this parameter.</param>
        /// <param name="sctpSourcePort">The source port for the SCTP packet header.</param>
        /// <param name="sctpDestinationPort">The destination port for the SCTP packet header.</param>
        /// <param name="defaultMTU">The default Maximum Transmission Unit (MTU) for the underlying
        /// transport. This determines the maximum size of an SCTP packet that will be used with
        /// the transport.</param>
        /// <param name="localTransportPort">Optional. The local transport (e.g. UDP or DTLS) port being
        /// used for the underlying SCTP transport. This be set on the SCTP association's ID to aid in
        /// diagnostics.</param>
        public SctpAssociation(
            SctpTransport sctpTransport,
            IPEndPoint destination,
            ushort sctpSourcePort,
            ushort sctpDestinationPort,
            ushort defaultMTU,
            int localTransportPort,
            ushort numberOutboundStreams = DEFAULT_NUMBER_OUTBOUND_STREAMS,
            ushort numberInboundStreams  = DEFAULT_NUMBER_INBOUND_STREAMS)
        {
            _sctpTransport         = sctpTransport;
            Destination            = destination;
            _sctpSourcePort        = sctpSourcePort;
            _sctpDestinationPort   = sctpDestinationPort;
            _defaultMTU            = defaultMTU;
            _numberOutboundStreams = numberOutboundStreams;
            _numberInboundStreams  = numberInboundStreams;
            VerificationTag        = Crypto.GetRandomUInt(true);

            ID    = $"{sctpSourcePort}:{sctpDestinationPort}:{localTransportPort}";
            ARwnd = DEFAULT_ADVERTISED_RECEIVE_WINDOW;

            _dataReceiver = new SctpDataReceiver(ARwnd, _defaultMTU, 0);
            _dataSender   = new SctpDataSender(ID, this.SendChunk, defaultMTU, Crypto.GetRandomUInt(true), DEFAULT_ADVERTISED_RECEIVE_WINDOW);

            State = SctpAssociationState.Closed;
        }
Esempio n. 2
0
        /// <summary>
        /// Initialises the association state based on the echoed cookie (the cookie that we sent
        /// to the remote party and was then echoed back to us). An association can only be initialised
        /// from a cookie prior to it being used and prior to it ever having entered the established state.
        /// </summary>
        /// <param name="cookie">The echoed cookie that was returned from the remote party.</param>
        public void GotCookie(SctpTransportCookie cookie)
        {
            // The CookieEchoed state is allowed, even though a cookie should be creating a brand
            // new association rather than one that has already sent an INIT, in order to deal with
            // a race condition where both SCTP end points attempt to establish the association at
            // the same time using the same ports.
            if (_wasAborted || _wasShutdown)
            {
                logger.LogWarning($"SCTP association cannot initialise with a cookie after an abort or shutdown.");
            }
            else if (!(State == SctpAssociationState.Closed || State == SctpAssociationState.CookieEchoed))
            {
                throw new ApplicationException($"SCTP association cannot initialise with a cookie in state {State}.");
            }
            else
            {
                _sctpSourcePort      = cookie.SourcePort;
                _sctpDestinationPort = cookie.DestinationPort;
                VerificationTag      = cookie.Tag;
                ARwnd       = cookie.ARwnd;
                Destination = !string.IsNullOrEmpty(cookie.RemoteEndPoint) ?
                              IPSocket.Parse(cookie.RemoteEndPoint) : null;

                if (_dataReceiver == null)
                {
                    _dataReceiver = new SctpDataReceiver(ARwnd, _defaultMTU, cookie.RemoteTSN);
                }

                if (_dataSender == null)
                {
                    _dataSender = new SctpDataSender(ID, this.SendChunk, _defaultMTU, cookie.TSN, cookie.RemoteARwnd);
                }

                InitRemoteProperties(cookie.RemoteTag, cookie.RemoteTSN, cookie.RemoteARwnd);

                var cookieAckChunk = new SctpChunk(SctpChunkType.COOKIE_ACK);
                SendChunk(cookieAckChunk);

                SetState(SctpAssociationState.Established);
                _dataSender.StartSending();
                CancelTimers();
            }
        }