public IConnection GetRawConnection()
        {
            IConnection result = null;

            if (rawConnection != null)
            {
                result        = rawConnection;
                rawConnection = null;
                if (size > 0)
                {
                    PreReadConnection preReadConnection = result as PreReadConnection;
                    if (preReadConnection != null) // make sure we don't keep wrapping
                    {
                        preReadConnection.AddPreReadData(buffer, offset, size);
                    }
                    else
                    {
                        result = new PreReadConnection(result, buffer, offset, size);
                    }
                }
            }

            return(result);
        }
Beispiel #2
0
        public async Task <Message> ReceiveAsync(CancellationToken token)
        {
            //byte[] buffer = Fx.AllocateByteArray(connection.AsyncReadBufferSize);

            //if (size > 0)
            //{
            //    Buffer.BlockCopy(connection.AsyncReadBuffer, offset, buffer, offset, size);
            //}
            var timeoutHelper = new TimeoutHelper(TimeoutHelper.GetOriginalTimeout(token));

            for (;;)
            {
                if (DecodeBytes(connection.AsyncReadBuffer, ref offset, ref size, ref isAtEof))
                {
                    break;
                }

                if (isAtEof)
                {
                    await DoneReceivingAsync(true, token);

                    return(null);
                }

                if (size == 0)
                {
                    offset = 0;
                    size   = await connection.ReadAsync(0, connection.AsyncReadBufferSize, timeoutHelper.RemainingTime());

                    if (size == 0)
                    {
                        await DoneReceivingAsync(true, token);

                        return(null);
                    }
                }
            }

            // we're ready to read a message
            IConnection singletonConnection = connection;

            if (size > 0)
            {
                singletonConnection = new PreReadConnection(singletonConnection, offset, size);
            }

            Stream connectionStream = new SingletonInputConnectionStream(this, singletonConnection, transportSettings);

            inputStream = new MaxMessageSizeStream(connectionStream, transportSettings.MaxReceivedMessageSize);
            Message message = null;

            try
            {
                message = transportSettings.MessageEncoderFactory.Encoder.ReadMessage(
                    inputStream, transportSettings.MaxBufferSize, ContentType);
            }
            catch (XmlException xmlException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                          new ProtocolException(SR.Format(SR.MessageXmlProtocolError), xmlException));
            }

            PrepareMessage(message);

            return(message);
        }
Beispiel #3
0
        public async Task <IConnection> CompletePreambleAsync(TimeSpan timeout)
        {
            var timeoutHelper = new TimeoutHelper(timeout);
            var parent        = this;

            if (!transportSettings.MessageEncoderFactory.Encoder.IsContentTypeSupported(Decoder.ContentType))
            {
                SendFault(FramingEncodingString.ContentTypeInvalidFault, ref timeoutHelper);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.Format(
                                                                                                    SR.ContentTypeMismatch, Decoder.ContentType, parent.transportSettings.MessageEncoderFactory.Encoder.ContentType)));
            }

            IStreamUpgradeChannelBindingProvider channelBindingProvider = null;
            StreamUpgradeAcceptor upgradeAcceptor = null;

            if (transportSettings.Upgrade != null)
            {
                channelBindingProvider = transportSettings.Upgrade.GetProperty <IStreamUpgradeChannelBindingProvider>();
                upgradeAcceptor        = transportSettings.Upgrade.CreateUpgradeAcceptor();
            }

            var          currentConnection = Connection;
            UpgradeState upgradeState      = UpgradeState.None;

            while (true)
            {
                if (size == 0 && CanReadAndDecode(upgradeState))
                {
                    size = await currentConnection.ReadAsync(0, connectionBuffer.Length, timeoutHelper.RemainingTime());

                    if (size == 0)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Decoder.CreatePrematureEOFException());
                    }
                }

                while (true)
                {
                    if (CanReadAndDecode(upgradeState))
                    {
                        int bytesRead = Decoder.Decode(connectionBuffer, offset, size);
                        if (bytesRead > 0)
                        {
                            offset += bytesRead;
                            size   -= bytesRead;
                        }
                    }

                    switch (Decoder.CurrentState)
                    {
                    case ServerSingletonDecoder.State.UpgradeRequest:
                        switch (upgradeState)
                        {
                        case UpgradeState.None:
                            //change the state so that we don't read/decode until it is safe
                            ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                            break;

                        case UpgradeState.VerifyingUpgradeRequest:
                            if (upgradeAcceptor == null)
                            {
                                SendFault(FramingEncodingString.UpgradeInvalidFault, ref timeoutHelper);
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                          new ProtocolException(SR.Format(SR.UpgradeRequestToNonupgradableService, Decoder.Upgrade)));
                            }

                            if (!upgradeAcceptor.CanUpgrade(Decoder.Upgrade))
                            {
                                SendFault(FramingEncodingString.UpgradeInvalidFault, ref timeoutHelper);
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.Format(SR.UpgradeProtocolNotSupported, Decoder.Upgrade)));
                            }

                            ChangeUpgradeState(ref upgradeState, UpgradeState.WritingUpgradeAck);
                            // accept upgrade
                            await currentConnection.WriteAsync(ServerSingletonEncoder.UpgradeResponseBytes, 0, ServerSingletonEncoder.UpgradeResponseBytes.Length,
                                                               true, timeoutHelper.RemainingTime());

                            ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeAckSent);
                            break;

                        case UpgradeState.UpgradeAckSent:
                            IConnection connectionToUpgrade = currentConnection;
                            if (size > 0)
                            {
                                connectionToUpgrade = new PreReadConnection(connectionToUpgrade, connectionBuffer, offset, size);
                            }
                            ChangeUpgradeState(ref upgradeState, UpgradeState.BeginUpgrade);
                            break;

                        case UpgradeState.BeginUpgrade:
                            try
                            {
                                currentConnection = await InitialServerConnectionReader.UpgradeConnectionAsync(currentConnection, upgradeAcceptor, transportSettings);

                                connectionBuffer = currentConnection.AsyncReadBuffer;
                                if (channelBindingProvider != null &&
                                    channelBindingProvider.IsChannelBindingSupportEnabled &&
                                    channelBindingToken == null)        //first one wins in the case of multiple upgrades.
                                {
                                    channelBindingToken = channelBindingProvider.GetChannelBinding(upgradeAcceptor, ChannelBindingKind.Endpoint);
                                }
                                ChangeUpgradeState(ref upgradeState, UpgradeState.EndUpgrade);
                                ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeComplete);
                            }
                            catch (Exception exception)
                            {
                                if (Fx.IsFatal(exception))
                                {
                                    throw;
                                }

                                WriteAuditFailure(upgradeAcceptor as StreamSecurityUpgradeAcceptor, exception);
                                throw;
                            }
                            break;

                        case UpgradeState.UpgradeComplete:
                            //Client is doing more than one upgrade, reset the state
                            ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                            break;
                        }
                        break;

                    case ServerSingletonDecoder.State.Start:
                        SetupSecurityIfNecessary(upgradeAcceptor);

                        if (upgradeState == UpgradeState.UpgradeComplete ||  //We have done at least one upgrade, but we are now done.
                            upgradeState == UpgradeState.None)       //no upgrade, just send the preample end bytes
                        {
                            ChangeUpgradeState(ref upgradeState, UpgradeState.WritingPreambleEnd);
                            // we've finished the preamble. Ack and return.
                            await currentConnection.WriteAsync(ServerSessionEncoder.AckResponseBytes, 0, ServerSessionEncoder.AckResponseBytes.Length,
                                                               true, timeoutHelper.RemainingTime());

                            //terminal state
                            ChangeUpgradeState(ref upgradeState, UpgradeState.PreambleEndSent);
                        }

                        //we are done, this.currentConnection is the upgraded connection
                        return(currentConnection);
                    }

                    if (size == 0)
                    {
                        break;
                    }
                }
            }
        }
            // perform security handshake and ACK connection
            protected override async Task OnOpenAsync(CancellationToken token)
            {
                bool success = false;

                try
                {
                    // TODO: Sort out the timeout here
                    var timeoutHelper = new TimeoutHelper(TimeSpan.FromSeconds(30));
                    // first validate our content type
                    ValidateContentType(ref timeoutHelper);

                    // next read any potential upgrades and finish consuming the preamble
                    for (;;)
                    {
                        if (size == 0)
                        {
                            offset = 0;
                            size   = await Connection.ReadAsync(0, connectionBuffer.Length, timeoutHelper.RemainingTime());

                            if (size == 0)
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException());
                            }
                        }

                        for (;;)
                        {
                            DecodeBytes();
                            switch (decoder.CurrentState)
                            {
                            case ServerSessionDecoder.State.UpgradeRequest:
                                ProcessUpgradeRequest(ref timeoutHelper);

                                // accept upgrade
                                await Connection.WriteAsync(ServerSessionEncoder.UpgradeResponseBytes, 0, ServerSessionEncoder.UpgradeResponseBytes.Length, true, timeoutHelper.RemainingTime());

                                IConnection connectionToUpgrade = Connection;
                                if (size > 0)
                                {
                                    // TODO: Switch to using PreReadConnection constructor which doesn't take a buffer. This is currently causing an extra buffer allocation.
                                    connectionToUpgrade = new PreReadConnection(connectionToUpgrade, connectionBuffer, offset, size);
                                }

                                try
                                {
                                    Connection = await InitialServerConnectionReader.UpgradeConnectionAsync(connectionToUpgrade, upgradeAcceptor, this);

                                    if (channelBindingProvider != null && channelBindingProvider.IsChannelBindingSupportEnabled)
                                    {
                                        SetChannelBinding(channelBindingProvider.GetChannelBinding(upgradeAcceptor, ChannelBindingKind.Endpoint));
                                    }

                                    connectionBuffer = Connection.AsyncReadBuffer;
                                }
                                catch (Exception exception)
                                {
                                    if (Fx.IsFatal(exception))
                                    {
                                        throw;
                                    }

                                    // Audit Authentication Failure
                                    WriteAuditFailure(upgradeAcceptor as StreamSecurityUpgradeAcceptor, exception);
                                    throw;
                                }
                                break;

                            case ServerSessionDecoder.State.Start:
                                SetupSecurityIfNecessary();

                                // we've finished the preamble. Ack and return.
                                await Connection.WriteAsync(ServerSessionEncoder.AckResponseBytes, 0,
                                                            ServerSessionEncoder.AckResponseBytes.Length, true, timeoutHelper.RemainingTime());

                                SetupSessionReader();
                                success = true;
                                return;
                            }

                            if (size == 0)
                            {
                                break;
                            }
                        }
                    }
                }
                finally
                {
                    if (!success)
                    {
                        Connection.Abort();
                    }
                }
            }