A managed implementation of a web socket that sends and receives data via a Stream.
Thread-safety: - It's acceptable to call ReceiveAsync and SendAsync in parallel. One of each may run concurrently. - It's acceptable to have a pending ReceiveAsync while CloseOutputAsync or CloseAsync is called. - Attemping to invoke any other operations in parallel may corrupt the instance. Attempting to invoke a send operation while another is in progress or a receive operation while another is in progress will result in an exception.
Inheritance: WebSocket
        public static WebSocket CreateFromStream(
            Stream stream,
            bool isServer,
            string?subProtocol,
            TimeSpan keepAliveInterval)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(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(ManagedWebSocket.CreateFromConnectedStream(stream, isServer, subProtocol, keepAliveInterval));
        }
Esempio n. 2
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));
        }
Esempio n. 3
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));
            }

            // 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));
        }
Esempio n. 4
0
        public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
        {
            // TODO: Not currently implemented:
            // - ClientWebSocketOptions.Credentials
            // - ClientWebSocketOptions.Proxy

            // Establish connection to the server
            CancellationTokenRegistration registration = cancellationToken.Register(s => ((WebSocketHandle)s).Abort(), this);
            try
            {
                // Connect to the remote server
                Socket connectedSocket = await ConnectSocketAsync(uri.Host, uri.Port, cancellationToken).ConfigureAwait(false);
                Stream stream = new AsyncEventArgsNetworkStream(connectedSocket);

                // Upgrade to SSL if needed
                if (uri.Scheme == UriScheme.Wss)
                {
                    var sslStream = new SslStream(stream);
                    await sslStream.AuthenticateAsClientAsync(
                        uri.Host,
                        options.ClientCertificates,
                        SecurityProtocol.AllowedSecurityProtocols,
                        checkCertificateRevocation: false).ConfigureAwait(false);
                    stream = sslStream;
                }

                // Create the security key and expected response, then build all of the request headers
                KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept();
                byte[] requestHeader = BuildRequestHeader(uri, options, secKeyAndSecWebSocketAccept.Key);

                // Write out the header to the connection
                await stream.WriteAsync(requestHeader, 0, requestHeader.Length, cancellationToken).ConfigureAwait(false);

                // Parse the response and store our state for the remainder of the connection
                string subprotocol = await ParseAndValidateConnectResponseAsync(stream, options, secKeyAndSecWebSocketAccept.Value, cancellationToken).ConfigureAwait(false);

                _webSocket = ManagedWebSocket.CreateFromConnectedStream(stream, false, subprotocol);

                // If a concurrent Abort or Dispose came in before we set _webSocket, make sure to update it appropriately
                if (_state == WebSocketState.Aborted)
                {
                    _webSocket.Abort();
                }
                else if (_state == WebSocketState.Closed)
                {
                    _webSocket.Dispose();
                }
            }
            catch (Exception exc)
            {
                if (_state < WebSocketState.Closed)
                {
                    _state = WebSocketState.Closed;
                }

                Abort();

                if (exc is WebSocketException)
                {
                    throw;
                }
                throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc);
            }
            finally
            {
                registration.Dispose();
            }
        }
Esempio n. 5
0
        internal static async Task <HttpListenerWebSocketContext> AcceptWebSocketAsyncCore(HttpListenerContext context,
                                                                                           string subProtocol,
                                                                                           int receiveBufferSize,
                                                                                           TimeSpan keepAliveInterval,
                                                                                           ArraySegment <byte>?internalBuffer = null)
        {
            // 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];

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

            if (shouldSendSecWebSocketProtocolHeader)
            {
                secWebSocketProtocols = new string[] { outgoingSecWebSocketProtocolString };
                response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol, outgoingSecWebSocketProtocolString);
            }

            // negotiate the websocket key return value
            string secWebSocketKey    = request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
            string secWebSocketAccept = HttpWebSocket.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.StatusDescription = HttpStatusDescription.Get(HttpStatusCode.SwitchingProtocols);

            HttpResponseStream responseStream = response.OutputStream as HttpResponseStream;

            // Send websocket handshake headers
            await responseStream.WriteWebSocketHandshakeHeadersAsync().ConfigureAwait(false);

            WebSocket webSocket = ManagedWebSocket.CreateFromConnectedStream(context.Connection.ConnectedStream, true, subProtocol, keepAliveInterval, receiveBufferSize, internalBuffer);

            HttpListenerWebSocketContext webSocketContext = new HttpListenerWebSocketContext(
                request.Url,
                request.Headers,
                request.Cookies,
                context.User,
                request.IsAuthenticated,
                request.IsLocal,
                request.IsSecureConnection,
                origin,
                secWebSocketProtocols != null ? secWebSocketProtocols : Array.Empty <string>(),
                secWebSocketVersion,
                secWebSocketKey,
                webSocket);

            return(webSocketContext);
        }