File: System\ServiceModel\Channels\ServerWebSocketTransportDuplexSessionChannel.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
// <copyright>
// Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
 
namespace System.ServiceModel.Channels
{
    using System;
    using System.Net.Http;
    using System.Net.WebSockets;
    using System.Runtime;
    using System.ServiceModel.Diagnostics.Application;
    using System.ServiceModel.Security;
    using System.Threading;
 
    class ServerWebSocketTransportDuplexSessionChannel : WebSocketTransportDuplexSessionChannel
    {
        WebSocketContext webSocketContext;
        HttpRequestContext httpRequestContext;
        HttpPipeline httpPipeline;
        HttpResponseMessage httpResponseMessage;
        string subProtocol;
        WebSocketMessageSource webSocketMessageSource;
        SessionOpenNotification sessionOpenNotification;
 
        public ServerWebSocketTransportDuplexSessionChannel(
                        HttpChannelListener channelListener, 
                        EndpointAddress localAddress, 
                        Uri localVia, 
                        ConnectionBufferPool bufferPool, 
                        HttpRequestContext httpRequestContext, 
                        HttpPipeline httpPipeline, 
                        HttpResponseMessage httpResponseMessage, 
                        string subProtocol)
            : base(channelListener, localAddress, localVia, bufferPool)
        {
            this.httpRequestContext = httpRequestContext;
            this.httpPipeline = httpPipeline;
            this.httpResponseMessage = httpResponseMessage;
            this.subProtocol = subProtocol;
        }
 
        protected override bool IsStreamedOutput
        {
            get { return TransferModeHelper.IsResponseStreamed(this.TransferMode); }
        }
 
        public override T GetProperty<T>()
        {
            if (typeof(T) == typeof(SessionOpenNotification))
            {
                if (this.sessionOpenNotification == null)
                {
                    this.sessionOpenNotification = new SessionOpenNotificationHelper(this);
                }
 
                return (T)(object)this.sessionOpenNotification;
            }
 
            return base.GetProperty<T>();
        }
 
        internal void SetWebSocketInfo(WebSocketContext webSocketContext, RemoteEndpointMessageProperty remoteEndpointMessageProperty, SecurityMessageProperty handshakeSecurityMessageProperty, byte[] innerBuffer, bool shouldDisposeWebSocketAfterClosed, HttpRequestMessage requestMessage)
        {
            Fx.Assert(webSocketContext != null, "webSocketContext should not be null.");
            this.ShouldDisposeWebSocketAfterClosed = shouldDisposeWebSocketAfterClosed;
            this.webSocketContext = webSocketContext;
            this.WebSocket = webSocketContext.WebSocket;
            this.InternalBuffer = innerBuffer;
 
            if (handshakeSecurityMessageProperty != null)
            {
                this.RemoteSecurity = handshakeSecurityMessageProperty;
            }
 
            bool inputUseStreaming = TransferModeHelper.IsRequestStreamed(this.TransferMode);
            this.webSocketMessageSource = new WebSocketMessageSource(
                            this,
                            this.webSocketContext,
                            inputUseStreaming,
                            remoteEndpointMessageProperty,
                            this,
                            requestMessage);
 
            this.SetMessageSource(this.webSocketMessageSource);
        }
 
        protected override void OnClosed()
        {
            base.OnClosed();
            ((IDisposable)this.httpRequestContext).Dispose();
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
            if (TD.WebSocketConnectionAcceptStartIsEnabled())
            {
                TD.WebSocketConnectionAcceptStart(this.httpRequestContext.EventTraceActivity);
            }
 
            this.httpRequestContext.AcceptWebSocket(this.httpResponseMessage, this.subProtocol, timeout);
 
            if (TD.WebSocketConnectionAcceptedIsEnabled())
            {
                TD.WebSocketConnectionAccepted(
                    this.httpRequestContext.EventTraceActivity,
                    this.WebSocket != null ? this.WebSocket.GetHashCode() : -1);
            }
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            if (TD.WebSocketConnectionAcceptStartIsEnabled())
            {
                TD.WebSocketConnectionAcceptStart(this.httpRequestContext.EventTraceActivity);
            }
 
            return this.httpRequestContext.BeginAcceptWebSocket(this.httpResponseMessage, this.subProtocol, callback, state);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            this.httpRequestContext.EndAcceptWebSocket(result);
 
            if (TD.WebSocketConnectionAcceptedIsEnabled())
            {
                TD.WebSocketConnectionAccepted(
                    this.httpRequestContext.EventTraceActivity,
                    this.WebSocket != null ? this.WebSocket.GetHashCode() : -1);
            }
        }
 
        protected override void OnOpened()
        {
            base.OnOpened();
 
            // We don't need the HttpPipeline any more once the HTTP handshake is finished. 
            // Close it to release the CancellationTokenSource and other possible resources.
            this.httpPipeline.Close();
        }
 
        class SessionOpenNotificationHelper : SessionOpenNotification
        {
            readonly ServerWebSocketTransportDuplexSessionChannel channel;
 
            public SessionOpenNotificationHelper(ServerWebSocketTransportDuplexSessionChannel channel)
            {
                this.channel = channel;
            }
 
            public override bool IsEnabled
            {
                get
                {
                    return this.channel.WebSocketSettings.CreateNotificationOnConnection;
                }
            }
 
            public override void UpdateMessageProperties(MessageProperties inboundMessageProperties)
            {
                this.channel.webSocketMessageSource.UpdateOpenNotificationMessageProperties(inboundMessageProperties);
            }
        }
    }
}