示例#1
0
        public ServerWebSocket(Stream innerStream,
                               string subProtocol,
                               int receiveBufferSize,
                               TimeSpan keepAliveInterval,
                               ArraySegment <byte> internalBuffer)
            : base(innerStream, subProtocol, keepAliveInterval,
                   WebSocketBuffer.CreateServerBuffer(internalBuffer, receiveBufferSize))
        {
            _properties    = InternalBuffer.CreateProperties(false);
            _sessionHandle = CreateWebSocketHandle();

            if (_sessionHandle == null || _sessionHandle.IsInvalid)
            {
                WebSocketValidate.ThrowPlatformNotSupportedException_WSPC();
            }

            StartKeepAliveTimer();
        }
示例#2
0
        public override Task CloseAsync(WebSocketCloseStatus closeStatus, string?statusDescription, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ThrowIfDisposed();

            WebSocketValidate.ValidateCloseStatus(closeStatus, statusDescription);

            var state = State;

            if (state == WebSocketState.None || state == WebSocketState.Closed)
            {
                throw new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState, state, "Connecting, Open, CloseSent, Aborted"));
            }

            return(state == WebSocketState.Open || state == WebSocketState.Connecting || state == WebSocketState.Aborted || state == WebSocketState.CloseSent
                ? CloseAsyncCore(closeStatus, statusDescription, state != WebSocketState.Aborted, cancellationToken)
                : Task.CompletedTask);
        }
示例#3
0
        internal static void ValidateOptions(string?subProtocol, int receiveBufferSize, int sendBufferSize, TimeSpan keepAliveInterval)
        {
            if (subProtocol != null)
            {
                WebSocketValidate.ValidateSubprotocol(subProtocol);
            }

            if (receiveBufferSize < MinReceiveBufferSize)
            {
                throw new ArgumentOutOfRangeException(nameof(receiveBufferSize), receiveBufferSize,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, MinReceiveBufferSize));
            }

            if (sendBufferSize < MinSendBufferSize)
            {
                throw new ArgumentOutOfRangeException(nameof(sendBufferSize), sendBufferSize,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, MinSendBufferSize));
            }

            if (receiveBufferSize > MaxBufferSize)
            {
                throw new ArgumentOutOfRangeException(nameof(receiveBufferSize), receiveBufferSize,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooBig,
                                                                nameof(receiveBufferSize),
                                                                receiveBufferSize,
                                                                MaxBufferSize));
            }

            if (sendBufferSize > MaxBufferSize)
            {
                throw new ArgumentOutOfRangeException(nameof(sendBufferSize), sendBufferSize,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooBig,
                                                                nameof(sendBufferSize),
                                                                sendBufferSize,
                                                                MaxBufferSize));
            }

            if (keepAliveInterval < Timeout.InfiniteTimeSpan) // -1 millisecond
            {
                throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, Timeout.InfiniteTimeSpan.ToString()));
            }
        }
示例#4
0
        internal static void ValidateOptions(string subProtocol,
                                             int receiveBufferSize,
                                             int sendBufferSize,
                                             TimeSpan keepAliveInterval)
        {
            // We allow the subProtocol to be null. Validate if it is not null.
            if (subProtocol != null)
            {
                WebSocketValidate.ValidateSubprotocol(subProtocol);
            }

            ValidateBufferSizes(receiveBufferSize, sendBufferSize);

            if (keepAliveInterval < Timeout.InfiniteTimeSpan) // -1
            {
                throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, Timeout.InfiniteTimeSpan.ToString()));
            }
        }
示例#5
0
        // This method is not thread safe. It must only be called after enforcing at most 1 outstanding send operation
        internal void PinSendBuffer(ArraySegment <byte> payload, out bool bufferHasBeenPinned)
        {
            bufferHasBeenPinned = false;
            WebSocketValidate.ValidateBuffer(payload.Array, payload.Offset, payload.Count);
            int previousState = Interlocked.Exchange(ref _sendBufferState, SendBufferState.SendPayloadSpecified);

            if (previousState != SendBufferState.None)
            {
                Debug.Assert(false, "'m_SendBufferState' MUST BE 'None' at this point.");
                // Indicates a violation in the API contract that could indicate
                // memory corruption because the pinned sendbuffer is shared between managed and native code
                throw new AccessViolationException();
            }
            _pinnedSendBuffer             = payload;
            _pinnedSendBufferHandle       = GCHandle.Alloc(_pinnedSendBuffer.Array, GCHandleType.Pinned);
            bufferHasBeenPinned           = true;
            _pinnedSendBufferStartAddress =
                Marshal.UnsafeAddrOfPinnedArrayElement(_pinnedSendBuffer.Array, _pinnedSendBuffer.Offset).ToInt64();
            _pinnedSendBufferEndAddress = _pinnedSendBufferStartAddress + _pinnedSendBuffer.Count;
        }
示例#6
0
        public static WebSocket CreateClientWebSocket(Stream innerStream,
                                                      string subProtocol, int receiveBufferSize, int sendBufferSize,
                                                      TimeSpan keepAliveInterval, bool useZeroMaskingKey, ArraySegment <byte> internalBuffer)
        {
            if (innerStream == null)
            {
                throw new ArgumentNullException(nameof(innerStream));
            }

            if (!innerStream.CanRead || !innerStream.CanWrite)
            {
                throw new ArgumentException(!innerStream.CanRead ? SR.NotReadableStream : SR.NotWriteableStream, nameof(innerStream));
            }

            if (subProtocol != null)
            {
                WebSocketValidate.ValidateSubprotocol(subProtocol);
            }

            if (keepAliveInterval != Timeout.InfiniteTimeSpan && keepAliveInterval < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall,
                                                                0));
            }

            if (receiveBufferSize <= 0 || sendBufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(
                          receiveBufferSize <= 0 ? nameof(receiveBufferSize) : nameof(sendBufferSize),
                          receiveBufferSize <= 0 ? receiveBufferSize : sendBufferSize,
                          SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 0));
            }

            Memory <byte> internalMemoryBuffer =
                internalBuffer.Count >= receiveBufferSize ? internalBuffer :
                receiveBufferSize >= ManagedWebSocket.MaxMessageHeaderLength ? new byte[receiveBufferSize] :
                Memory <byte> .Empty; // let ManagedWebSocket create it

            return(ManagedWebSocket.CreateFromConnectedStream(innerStream, false, subProtocol, keepAliveInterval, internalMemoryBuffer));
        }
示例#7
0
        public override Task SendAsync(ArraySegment <byte> buffer, WebSocketMessageType messageType, bool endOfMessage,
                                       CancellationToken cancellationToken)
        {
            ThrowIfNotConnected();

            if (!((messageType == WebSocketMessageType.Text) || (messageType == WebSocketMessageType.Binary)))
            {
                string errorMessage = SR.Format(
                    SR.net_WebSockets_Argument_InvalidMessageType,
                    "Close",
                    "SendAsync",
                    "Binary",
                    "Text",
                    "CloseOutputAsync");

                throw new ArgumentException(errorMessage, nameof(messageType));
            }

            WebSocketValidate.ValidateArraySegment <byte>(buffer, "buffer");
            return(_innerWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken));
        }
        public Task SendAsync(
            ArraySegment <byte> buffer,
            WebSocketMessageType messageType,
            bool endOfMessage,
            CancellationToken cancellationToken)
        {
            if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary)
            {
                string errorMessage = SR.Format(
                    SR.net_WebSockets_Argument_InvalidMessageType,
                    nameof(WebSocketMessageType.Close),
                    nameof(SendAsync),
                    nameof(WebSocketMessageType.Binary),
                    nameof(WebSocketMessageType.Text),
                    nameof(CloseOutputAsync));
                throw new ArgumentException(errorMessage, nameof(messageType));
            }

            WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer));

            return(_webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken));
        }
        public override ValueTask <ValueWebSocketReceiveResult> ReceiveAsync(Memory <byte> buffer, CancellationToken cancellationToken)
        {
            try
            {
                WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validReceiveStates);

                Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}");
                lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync
                {
                    ThrowIfOperationInProgress(_lastReceiveAsync);
                    ValueTask <ValueWebSocketReceiveResult> t = ReceiveAsyncPrivate <ValueWebSocketReceiveResultGetter, ValueWebSocketReceiveResult>(buffer, cancellationToken);
                    _lastReceiveAsync =
                        t.IsCompletedSuccessfully ? (t.Result.MessageType == WebSocketMessageType.Close ? s_cachedCloseTask : Task.CompletedTask) :
                        t.AsTask();
                    return(t);
                }
            }
            catch (Exception exc)
            {
                return(new ValueTask <ValueWebSocketReceiveResult>(Task.FromException <ValueWebSocketReceiveResult>(exc)));
            }
        }
示例#10
0
        internal static WebSocket Create(Stream innerStream,
                                         string subProtocol,
                                         int receiveBufferSize,
                                         TimeSpan keepAliveInterval,
                                         ArraySegment <byte> internalBuffer)
        {
            if (!WebSocketProtocolComponent.IsSupported)
            {
                WebSocketValidate.ThrowPlatformNotSupportedException_WSPC();
            }

            WebSocketValidate.ValidateInnerStream(innerStream);
            WebSocketValidate.ValidateOptions(subProtocol, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, keepAliveInterval);
            WebSocketValidate.ValidateArraySegment <byte>(internalBuffer, nameof(internalBuffer));
            WebSocketBuffer.Validate(internalBuffer.Count, receiveBufferSize, WebSocketBuffer.MinSendBufferSize, true);

            return(new ServerWebSocket(innerStream,
                                       subProtocol,
                                       receiveBufferSize,
                                       keepAliveInterval,
                                       internalBuffer));
        }
示例#11
0
文件: WebSocket.cs 项目: wilka/corefx
        public static WebSocket CreateClientWebSocket(Stream innerStream,
                                                      string subProtocol, int receiveBufferSize, int sendBufferSize,
                                                      TimeSpan keepAliveInterval, bool useZeroMaskingKey, ArraySegment <byte> internalBuffer)
        {
            if (innerStream == null)
            {
                throw new ArgumentNullException(nameof(innerStream));
            }

            if (!innerStream.CanRead || !innerStream.CanWrite)
            {
                throw new ArgumentException(!innerStream.CanRead ? SR.NotReadableStream : SR.NotWriteableStream, nameof(innerStream));
            }

            if (subProtocol != null)
            {
                WebSocketValidate.ValidateSubprotocol(subProtocol);
            }

            if (keepAliveInterval != Timeout.InfiniteTimeSpan && keepAliveInterval < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall,
                                                                0));
            }

            if (receiveBufferSize <= 0 || sendBufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(
                          receiveBufferSize <= 0 ? nameof(receiveBufferSize) : nameof(sendBufferSize),
                          receiveBufferSize <= 0 ? receiveBufferSize : sendBufferSize,
                          SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 0));
            }

            // Ignore useZeroMaskingKey. ManagedWebSocket doesn't currently support that debugging option.
            // Ignore internalBuffer. ManagedWebSocket uses its own small buffer for headers/control messages.

            return(ManagedWebSocket.CreateFromConnectedStream(innerStream, false, subProtocol, keepAliveInterval));
        }
        public void SetBuffer(int receiveBufferSize, int sendBufferSize, ArraySegment <byte> buffer)
        {
            ThrowIfReadOnly();

            if (receiveBufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(receiveBufferSize), receiveBufferSize, SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 1));
            }
            if (sendBufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(sendBufferSize), sendBufferSize, SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 1));
            }

            WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer));
            if (buffer.Count == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(buffer));
            }

            _receiveBufferSize = receiveBufferSize;
            _sendBufferSize    = sendBufferSize;
            _buffer            = buffer;
        }
示例#13
0
        /// <summary>Creates a <see cref="WebSocket"/> that operates on a <see cref="Stream"/> representing a web socket connection.</summary>
        /// <param name="stream">The <see cref="Stream"/> for the connection.</param>
        /// <param name="isServer"><code>true</code> if this is the server-side of the connection; <code>false</code> if it's the client side.</param>
        /// <param name="subProtocol">The agreed upon sub-protocol that was used when creating the connection.</param>
        /// <param name="keepAliveInterval">The keep-alive interval to use, or <see cref="Timeout.InfiniteTimeSpan"/> to disable keep-alives.</param>
        /// <returns>The created <see cref="WebSocket"/>.</returns>
        public static WebSocket CreateFromStream(Stream stream, bool isServer, string?subProtocol, TimeSpan keepAliveInterval)
        {
            ArgumentNullException.ThrowIfNull(stream);

            if (!stream.CanRead || !stream.CanWrite)
            {
                throw new ArgumentException(!stream.CanRead ? SR.NotReadableStream : SR.NotWriteableStream, nameof(stream));
            }

            if (subProtocol != null)
            {
                WebSocketValidate.ValidateSubprotocol(subProtocol);
            }

            if (keepAliveInterval != Timeout.InfiniteTimeSpan && keepAliveInterval < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval,
                                                      SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall,
                                                                0));
            }

            return(new ManagedWebSocket(stream, isServer, subProtocol, keepAliveInterval));
        }
        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            WebSocketValidate.ValidateBuffer(buffer, offset, count);

            return(WriteAsyncCore(buffer, offset, count, cancellationToken));
        }
示例#15
0
        private async Task <int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this, WebSocketValidate.GetTraceMsgForParameters(offset, count, cancellationToken));
            }

            CancellationTokenRegistration cancellationTokenRegistration = new CancellationTokenRegistration();

            int bytesRead = 0;

            try
            {
                if (cancellationToken.CanBeCanceled)
                {
                    cancellationTokenRegistration = cancellationToken.Register(s_OnCancel, this, false);
                }

                if (!_inOpaqueMode)
                {
                    bytesRead = await _inputStream.ReadAsync(buffer, offset, count, cancellationToken).SuppressContextFlow <int>();
                }
                else
                {
#if DEBUG
                    // When using fast path only one outstanding read is permitted. By switching into opaque mode
                    // via IWebSocketStream.SwitchToOpaqueMode (see more detailed comments in interface definition)
                    // caller takes responsibility for enforcing this constraint.
                    Debug.Assert(Interlocked.Increment(ref _outstandingOperations._reads) == 1,
                                 "Only one outstanding read allowed at any given time.");
#endif
                    _readTaskCompletionSource = new TaskCompletionSource <int>();
                    _readEventArgs.SetBuffer(buffer, offset, count);
                    if (!ReadAsyncFast(_readEventArgs))
                    {
                        if (_readEventArgs.Exception != null)
                        {
                            throw _readEventArgs.Exception;
                        }

                        bytesRead = _readEventArgs.BytesTransferred;
                    }
                    else
                    {
                        bytesRead = await _readTaskCompletionSource.Task.SuppressContextFlow <int>();
                    }
                }
            }
            catch (Exception error)
            {
                if (s_CanHandleException(error))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                throw;
            }
            finally
            {
                cancellationTokenRegistration.Dispose();

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Exit(this, bytesRead);
                }
            }

            return(bytesRead);
        }
示例#16
0
 // Must be called with Lock taken.
 public void CheckValidState(WebSocketState[] validStates)
 {
     WebSocketValidate.ThrowIfInvalidState(_state, _disposed, validStates);
 }
示例#17
0
        private static async Task <HttpListenerWebSocketContext> AcceptWebSocketAsyncCore(HttpListenerContext context,
                                                                                          string subProtocol,
                                                                                          int receiveBufferSize,
                                                                                          TimeSpan keepAliveInterval,
                                                                                          ArraySegment <byte> internalBuffer)
        {
            HttpListenerWebSocketContext webSocketContext = null;

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(null, context);
            }

            try
            {
                // get property will create a new response if one doesn't exist.
                HttpListenerResponse response = context.Response;
                HttpListenerRequest  request  = context.Request;
                ValidateWebSocketHeaders(context);

                string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion];

                // Optional for non-browser client
                string origin = request.Headers[HttpKnownHeaderNames.Origin];

                List <string> secWebSocketProtocols = new List <string>();
                string        outgoingSecWebSocketProtocolString;
                bool          shouldSendSecWebSocketProtocolHeader =
                    ProcessWebSocketProtocolHeader(
                        request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol],
                        subProtocol,
                        out outgoingSecWebSocketProtocolString);

                if (shouldSendSecWebSocketProtocolHeader)
                {
                    secWebSocketProtocols.Add(outgoingSecWebSocketProtocolString);
                    response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol,
                                         outgoingSecWebSocketProtocolString);
                }

                // negotiate the websocket key return value
                string secWebSocketKey    = request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
                string secWebSocketAccept = WebSocketValidate.GetSecWebSocketAcceptString(secWebSocketKey);

                response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
                response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketUpgradeToken);
                response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept);

                response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101
                response.ComputeCoreHeaders();
                ulong hresult = SendWebSocketHeaders(response);
                if (hresult != 0)
                {
                    throw new WebSocketException((int)hresult,
                                                 SR.Format(SR.net_WebSockets_NativeSendResponseHeaders,
                                                           nameof(AcceptWebSocketAsync),
                                                           hresult));
                }

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.Origin} = {origin}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketVersion} = {secWebSocketVersion}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketKey} = {secWebSocketKey}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketAccept} = {secWebSocketAccept}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketProtocol} = {request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol]}");
                    NetEventSource.Info(null, $"{HttpKnownHeaderNames.SecWebSocketProtocol} = {outgoingSecWebSocketProtocolString}");
                }

                await response.OutputStream.FlushAsync().SuppressContextFlow();

                HttpResponseStream responseStream = response.OutputStream as HttpResponseStream;
                Debug.Assert(responseStream != null, "'responseStream' MUST be castable to System.Net.HttpResponseStream.");
                ((HttpResponseStream)response.OutputStream).SwitchToOpaqueMode();
                HttpRequestStream requestStream = new HttpRequestStream(context);
                requestStream.SwitchToOpaqueMode();
                WebSocketHttpListenerDuplexStream webSocketStream =
                    new WebSocketHttpListenerDuplexStream(requestStream, responseStream, context);
                WebSocket webSocket = ServerWebSocket.Create(webSocketStream,
                                                             subProtocol,
                                                             receiveBufferSize,
                                                             keepAliveInterval,
                                                             internalBuffer);

                webSocketContext = new HttpListenerWebSocketContext(
                    request.Url,
                    request.Headers,
                    request.Cookies,
                    context.User,
                    request.IsAuthenticated,
                    request.IsLocal,
                    request.IsSecureConnection,
                    origin,
                    secWebSocketProtocols.AsReadOnly(),
                    secWebSocketVersion,
                    secWebSocketKey,
                    webSocket);

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Associate(context, webSocketContext);
                    NetEventSource.Associate(webSocketContext, webSocket);
                }
            }
            catch (Exception ex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(context, ex);
                }
                throw;
            }
            finally
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Exit(context);
                }
            }

            return(webSocketContext);
        }